From dca823e5c590005ac4ccdf5ae34eafe5831239d3 Mon Sep 17 00:00:00 2001 From: Chris Brame Date: Fri, 9 Nov 2018 01:05:11 -0500 Subject: [PATCH] fix(mobile): secure assets not loading --- mobile/index.html | 4 ++ mobile/js/dist/td.app.js | 40 +++++++++++++++--- mobile/js/dist/td.app.min.js | 4 +- mobile/lib/angular-img-http-src/.bower.json | 40 ++++++++++++++++++ mobile/lib/angular-img-http-src/LICENSE | 22 ++++++++++ mobile/lib/angular-img-http-src/README.md | 8 ++++ mobile/lib/angular-img-http-src/bower.json | 29 +++++++++++++ mobile/lib/angular-img-http-src/index.js | 42 +++++++++++++++++++ mobile/lib/angular-img-http-src/package.json | 25 +++++++++++ mobile/lib/ionic/js/ionic-angular.js | 11 ++++- mobile/lib/ionic/js/ionic.bundle.js | 10 ++++- mobile/templates/conversation.html | 12 +++--- mobile/templates/modals/modal-addComment.html | 3 +- mobile/templates/modals/modal-addNote.html | 3 +- .../modal-messages-newconversation.html | 4 +- mobile/templates/tab-account.html | 2 +- mobile/templates/tab-messages.html | 42 ++++++++++++++++--- mobile/templates/tab-tickets.html | 4 +- mobile/templates/ticket-detail.html | 13 +++--- src/middleware/index.js | 2 +- src/middleware/middleware.js | 2 + src/webserver.js | 2 +- 22 files changed, 288 insertions(+), 36 deletions(-) create mode 100644 mobile/lib/angular-img-http-src/.bower.json create mode 100644 mobile/lib/angular-img-http-src/LICENSE create mode 100644 mobile/lib/angular-img-http-src/README.md create mode 100644 mobile/lib/angular-img-http-src/bower.json create mode 100644 mobile/lib/angular-img-http-src/index.js create mode 100644 mobile/lib/angular-img-http-src/package.json diff --git a/mobile/index.html b/mobile/index.html index 6102d2929..5ae6f191f 100644 --- a/mobile/index.html +++ b/mobile/index.html @@ -17,6 +17,9 @@ + + + @@ -39,6 +42,7 @@ + diff --git a/mobile/js/dist/td.app.js b/mobile/js/dist/td.app.js index bce0847d1..de30f32d3 100644 --- a/mobile/js/dist/td.app.js +++ b/mobile/js/dist/td.app.js @@ -28,10 +28,17 @@ angular.module('trudesk', [ 'ngCropper', 'monospaced.elastic', 'angularMoment', - 'jett.ionic.filter.bar' + 'jett.ionic.filter.bar', + 'angular.img' ]) -.run(function($ionicPlatform, $rootScope, $location, $localStorage, $state) { +.run(function($ionicPlatform, $rootScope, $location, $localStorage, $state, $http) { + if ($localStorage.accessToken) { + $http.defaults.headers.common.accesstoken = $localStorage.accessToken; + } else { + $http.defaults.headers.common.accesstoken = ''; + } + $ionicPlatform.ready(function() { // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard // for form inputs) @@ -71,7 +78,7 @@ angular.module('trudesk', [ } }); - setTimeout(function() { + setTimeout(function() { angular.element(document.querySelector('#loader')).addClass('hide'); }, 900); }); @@ -291,7 +298,6 @@ angularPeity.directive('lineChart', function() { return peityDirective('line'); }); - var fileOnChange = angular.module('fileOnChange', []); fileOnChange.directive('fileOnChange', function() { @@ -353,7 +359,7 @@ hideTabBar.directive('hideTabBar', function($timeout) { restrict: 'A', compile: function(element, attr) { var tabBar = document.querySelector('.tab-nav'); - console.log(tabBar); + return function($scope, $element, $attr) { var scroll = $element[0].querySelector('.scroll-content'); $scope.$on('$ionicView.beforeEnter', function() { @@ -725,6 +731,19 @@ angular.module('trudesk.services', []) }) .factory('Users', function($q, $http, $localStorage) { return { + getImage: function(url) { + return new Promise(function(resolve, reject) { + $http.get(url, { + method: 'GET', + headers: { + 'accesstoken': $localStorage.accessToken + } + }).then(function(response) { + var objectUrl = URL.createObjectURL(response.blob()); + return resolve(objectUrl); + }).catch(function(err) { return reject(err); }); + }); + }, get: function(username) { return $http.get('/api/v1/users/' + username, { headers: { @@ -1132,6 +1151,8 @@ angular.module('trudesk.controllers.login', []).controller('LoginCtrl', function $localStorage.accessToken = response.data.accessToken; $localStorage.loggedInUser = response.data.user; + $http.defaults.headers.common.accesstoken = $localStorage.accessToken; + //OneSignal if (window.plugins && window.plugins.OneSignal) { window.plugins.OneSignal.setSubscription(true); @@ -1276,6 +1297,7 @@ angular.module('trudesk.controllers.accounts', []) ionic.trigger('$trudesk.clearLoginForm', {}); $localStorage.server = undefined; $localStorage.accessToken = undefined; + $http.defaults.headers.common.accesstoken = $localStorage.accessToken; if (window.plugins && window.plugins.OneSignal) window.plugins.OneSignal.setSubscription(false); $ionicHistory.clearCache(); @@ -2450,6 +2472,14 @@ angular.module('trudesk.controllers.tickets', []).controller('TicketsCtrl', func }); }; + $scope.getUserImage = function(imageFile) { + var url = 'http://' + $localStorage.server + '/uploads/users/' + imageFile; + + return Users.getImage(url).then(function(image) { + console.log(image); + }); + } + $scope.fetchTickets = function() { angular.element(document).find('ion-item').removeClass('item-remove-animate'); if ($scope.page == undefined) diff --git a/mobile/js/dist/td.app.min.js b/mobile/js/dist/td.app.min.js index a82fd75af..5141e2d63 100644 --- a/mobile/js/dist/td.app.min.js +++ b/mobile/js/dist/td.app.min.js @@ -1,2 +1,2 @@ -function ensureLogin($localStorage,$state){if(void 0===$localStorage.server||void 0===$localStorage.accessToken)return $state.go("login")}function ensureLogin($localStorage,$state){if(void 0===$localStorage.server||void 0===$localStorage.accessToken)return $state.go("login")}function ensureLogin($localStorage,$state){if(void 0===$localStorage.server||void 0===$localStorage.accessToken)return $state.go("login")}function ensureLogin($localStorage,$state){if(void 0===$localStorage.server||void 0===$localStorage.accessToken)return $state.go("login")}angular.module("underscore",[]).factory("_",["$window",function($window){return $window._}]),angular.module("snackbar",[]).factory("Snackbar",["$window",function($window){return $window.Snackbar}]),angular.module("trudesk",["ionic","ngCordova","ngStorage","underscore","trudesk.controllers","trudesk.services","fileOnChange","angular-peity","snackbar","ngCropper","monospaced.elastic","angularMoment","jett.ionic.filter.bar"]).run(function($ionicPlatform,$rootScope,$location,$localStorage,$state){$ionicPlatform.ready(function(){window.cordova&&window.cordova.plugins&&window.cordova.plugins.Keyboard&&(cordova.plugins.Keyboard.hideKeyboardAccessoryBar(!0),cordova.plugins.Keyboard.disableScroll(!0)),window.StatusBar&&window.StatusBar.styleLightContent();var notificationOpenedCallback=function(jsonData){if(jsonData.notification.payload&&jsonData.notification.payload.additionalData){var ticketUid=jsonData.notification.payload.additionalData.ticketUid;ticketUid&&($state.go("tab.tickets"),setTimeout(function(){return $state.go("tab.tickets-details",{ticketuid:ticketUid})},850))}};window.plugins&&window.plugins.OneSignal&&window.plugins.OneSignal.startInit("f8e19190-b53b-4b72-bac8-210e7f31bebb").handleNotificationOpened(notificationOpenedCallback).endInit(),$rootScope.$on("$stateChangeStart",function(event,next,current){if("/login"!==$location.url()&&(void 0==$localStorage.accessToken||void 0==$localStorage.server))return $location.path("/login")}),setTimeout(function(){angular.element(document.querySelector("#loader")).addClass("hide")},900)})}).filter("htmlToPlaintext",function(){return function(text){return text=text?String(text).replace(/<[^>]+>/gm,""):"",text=text?String(text).replace(/&/gm,"&"):"",text=text?String(text).replace(/"/gm,'"'):"",text=text?String(text).replace(/'/gm,"'"):""}}).filter("removeHTMLTags",function(){return function(text){return text?String(text).replace(/<[^>]+>/gm," "):""}}).filter("nl2br",["$filter",function($filter){return function(data){return data?data.replace(/\n\r?/g,"
"):data}}]).filter("sanitize",["$sce",function($sce){return function(htmlCode){return $sce.trustAsHtml(htmlCode)}}]).filter("currentdate",["$filter",function($filter){return function(){return $filter("date")(new Date,"M/dd/yy h:mm a")}}]).filter("statusMap",function(){return function(s){var status;switch(s){case 0:status="New";break;case 1:status="Open";break;case 2:status="Pending";break;case 3:status="Closed"}return status}}).filter("assigneeMap",function(){return function(a){return void 0===a||null===a?"No Assignee":a}}).filter("conversationFrom",function(){return function(p,loggedInUser){for(var final,i=0;i").html(".has-tabs.no-tabs:not(.has-tabs-top) { bottom: 0; }\n.no-tabs.has-tabs-top { top: 44px; }");return document.body.appendChild(style[0]),{restrict:"A",compile:function(element,attr){var tabBar=document.querySelector(".tab-nav");return console.log(tabBar),function($scope,$element,$attr){var scroll=$element[0].querySelector(".scroll-content");$scope.$on("$ionicView.beforeEnter",function(){tabBar.classList.add("slide-away"),scroll.classList.add("no-tabs")}),$scope.$on("$ionicView.beforeLeave",function(){tabBar.classList.remove("slide-away"),scroll.classList.remove("no-tabs")})}}}}),angular.module("ionic").directive("ionInfiniteScrollReverse",["$timeout",function($timeout){return{restrict:"E",require:["?^$ionicScroll","ionInfiniteScrollReverse"],template:function($element,$attrs){return $attrs.icon?'':''},scope:!0,controller:"$ionInfiniteScrollReverse",link:function($scope,$element,$attrs,ctrls){var infiniteScrollCtrl=ctrls[1],scrollCtrl=infiniteScrollCtrl.scrollCtrl=ctrls[0],jsScrolling=infiniteScrollCtrl.jsScrolling=!scrollCtrl.isNative();if(jsScrolling)infiniteScrollCtrl.scrollView=scrollCtrl.scrollView,$scope.scrollingType="js-scrolling",scrollCtrl.$element.on("scroll",infiniteScrollCtrl.checkBounds);else{var scrollEl=ionic.DomUtil.getParentOrSelfWithClass($element[0].parentNode,"overflow-scroll");if(infiniteScrollCtrl.scrollEl=scrollEl,!scrollEl)throw"Infinite scroll must be used inside a scrollable div";infiniteScrollCtrl.scrollEl.addEventListener("scroll",infiniteScrollCtrl.checkBounds)}var doImmediateCheck=!angular.isDefined($attrs.immediateCheck)||$scope.$eval($attrs.immediateCheck);doImmediateCheck&&$timeout(function(){infiniteScrollCtrl.checkBounds()})}}}]),angular.module("ionic").controller("$ionInfiniteScrollReverse",["$scope","$attrs","$element","$timeout",function($scope,$attrs,$element,$timeout){function onInfinite(){ionic.requestAnimationFrame(function(){$element[0].classList.add("active")}),self.isLoading=!0,$scope.$parent&&$scope.$parent.$apply($attrs.onInfinite||"")}function finishInfiniteScroll(){ionic.requestAnimationFrame(function(){$element[0].classList.remove("active")}),$timeout(function(){self.jsScrolling&&self.scrollView.resize(),(self.jsScrolling&&self.scrollView.__container&&self.scrollView.__container.offsetHeight>0||!self.jsScrolling)&&self.checkBounds()},30,!1),self.isLoading=!1}function checkInfiniteBounds(){if(!self.isLoading){var maxScroll={};if(self.jsScrolling){maxScroll=self.getJSMaxScroll();var scrollValues=self.scrollView.getValues();$attrs.reverse?(maxScroll.left!==-1&&scrollValues.left<=maxScroll.left||maxScroll.top!==-1&&scrollValues.top<=maxScroll.top)&&onInfinite():(maxScroll.left!==-1&&scrollValues.left>=maxScroll.left||maxScroll.top!==-1&&scrollValues.top>=maxScroll.top)&&onInfinite()}else maxScroll=self.getNativeMaxScroll(),$attrs.reverse?(maxScroll.left!==-1&&self.scrollEl.scrollLeft<=maxScroll.left||maxScroll.top!==-1&&self.scrollEl.scrollTop<=maxScroll.top)&&onInfinite():(maxScroll.left!==-1&&self.scrollEl.scrollLeft>=maxScroll.left-self.scrollEl.clientWidth||maxScroll.top!==-1&&self.scrollEl.scrollTop>=maxScroll.top-self.scrollEl.clientHeight)&&onInfinite()}}function calculateMaxValue(maximum){var distance=($attrs.distance||"2.5%").trim(),isPercent=distance.indexOf("%")!==-1;return $attrs.reverse?isPercent?maximum-maximum*(1-parseFloat(distance)/100):parseFloat(distance):isPercent?maximum*(1-parseFloat(distance)/100):maximum-parseFloat(distance)}var self=this;self.isLoading=!1,$scope.icon=function(){return angular.isDefined($attrs.icon)?$attrs.icon:"ion-load-d"},$scope.spinner=function(){return angular.isDefined($attrs.spinner)?$attrs.spinner:""},$scope.$on("scroll.infiniteScrollComplete",function(){finishInfiniteScroll()}),$scope.$on("$destroy",function(){self.scrollCtrl&&self.scrollCtrl.$element&&self.scrollCtrl.$element.off("scroll",self.checkBounds),self.scrollEl&&self.scrollEl.removeEventListener&&self.scrollEl.removeEventListener("scroll",self.checkBounds)}),self.checkBounds=ionic.Utils.throttle(checkInfiniteBounds,300),self.getJSMaxScroll=function(){var maxValues=self.scrollView.getScrollMax();return{left:self.scrollView.options.scrollingX?calculateMaxValue(maxValues.left):-1,top:self.scrollView.options.scrollingY?calculateMaxValue(maxValues.top):-1}},self.getNativeMaxScroll=function(){var maxValues={left:self.scrollEl.scrollWidth,top:self.scrollEl.scrollHeight},computedStyle=window.getComputedStyle(self.scrollEl)||{};return{left:!maxValues.left||"scroll"!==computedStyle.overflowX&&"auto"!==computedStyle.overflowX&&"scroll"!==self.scrollEl.style["overflow-x"]?-1:calculateMaxValue(maxValues.left),top:!maxValues.top||"scroll"!==computedStyle.overflowY&&"auto"!==computedStyle.overflowY&&"scroll"!==self.scrollEl.style["overflow-y"]?-1:calculateMaxValue(maxValues.top)}},self.__finishInfiniteScroll=finishInfiniteScroll}]),angular.module("trudesk.services",[]).factory("WebSocket",function($q,$rootScope,$timeout,$http,$localStorage){var message,dataStream=io.connect("/",{query:"token="+$localStorage.accessToken});return dataStream.on("connect",function(){console.log("Connected to Server: "+$localStorage.server)}),dataStream.on("disconnect",function(){console.log("Disconnected from Server: "+$localStorage.server)}),dataStream.on("error",function(e){console.log("Error",e)}),dataStream.on("joinSuccessfully",function(){console.log("Joined Messaging Server.")}),dataStream.removeAllListeners("chatMessage"),dataStream.on("chatMessage",function(data){window.dispatchEvent(new CustomEvent("$trudesk.converstation.chatmessage",{detail:data}))}),dataStream.on("updateUsers",function(users){window.dispatchEvent(new CustomEvent("$trudesk.conversation.updateusers",{detail:users}))}),dataStream.on("chatTyping",function(data){ionic.trigger("$trudesk.conversation.usertyping",data)}),dataStream.on("chatStopTyping",function(data){ionic.trigger("$trudesk.conversation.userstoptyping",data)}),{message:message,socket:dataStream,startTyping:function(convoId,partnerId,loggedInUserId){dataStream.emit("chatTyping",{cid:convoId,to:partnerId,from:loggedInUserId})},stopTyping:function(convoId,partnerId){dataStream.emit("chatStopTyping",{cid:convoId,to:partnerId})},send:function(convoId,partnerId,loggedInUserId,messageId,messageBody){dataStream.emit("chatMessage",{conversation:convoId,to:partnerId,from:loggedInUserId,type:"s",messageId:messageId,message:messageBody})},updateUsers:function(){return dataStream.emit("updateUsers")},checkConnection:function(){void 0!=dataStream&&dataStream.connected||(console.log("Reconnecting to: "+$localStorage.server),dataStream=void 0,dataStream=io.connect("http://"+$localStorage.server,{query:"token="+$localStorage.accessToken}))},close:function(){return console.log("Closing Socket..."),dataStream.disconnect()}}}).factory("Users",function($q,$http,$localStorage){return{get:function(username){return $http.get("/api/v1/users/"+username,{headers:{accesstoken:$localStorage.accessToken}})},getUsers:function(){return $http.get("/api/v1/users?limit=-1",{headers:{accesstoken:$localStorage.accessToken}})},getAssignees:function(){return $http.get("/api/v1/users/getassignees",{headers:{accesstoken:$localStorage.accessToken}})},getRoles:function(){return $http.get("/api/v1/roles",{headers:{accesstoken:$localStroage.accessToken}})},getLoggedInUser:function(){var deferred=$q.defer();return $localStorage.loggedInUser?(deferred.resolve($localStorage.loggedInUser),deferred.promise):($localStorage.username?$http.get("/api/v1/users/"+$localStorage.username,{headers:{accesstoken:$localStorage.accessToken}}).then(function(response){response.data.user?($localStorage.loggedInUser=response.data.user,void 0===$localStorage.loggedInUser.image&&($localStorage.loggedInUser.image="defaultProfile.jpg"),deferred.resolve($localStorage.loggedInUser)):deferred.reject("Unable to get user")},function(response){console.log(response),deferred.reject("Error Occured!")}):deferred.reject("No username stored."),deferred.promise)},isUserOnline:function(onlineUsers,userObj){return void 0!==userObj&&(void 0!==onlineUsers&&void 0!==onlineUsers[userObj.username])}}}).factory("Tickets",function($http,$localStorage){return{all:function(page){void 0===page&&(page=0);var queryString="/api/v1/tickets?limit=10&status[]=0&status[]=1&status[]=2&page="+page;return void 0!==$localStorage.showClosedTickets&&$localStorage.showClosedTickets===!0&&(queryString+="&status[]=3"),void 0!==$localStorage.showOnlyAssigned&&$localStorage.showOnlyAssigned===!0&&(queryString+="&assignedself=true"),$http.get(queryString,{headers:{accesstoken:$localStorage.accessToken}})},get:function(uid){return $http.get("/api/v1/tickets/"+uid,{headers:{accesstoken:$localStorage.accessToken}})},create:function(ticket){return $http.post("/api/v1/tickets/create",ticket,{headers:{accesstoken:$localStorage.accessToken}})},search:function(search){return $http.get("/api/v1/tickets/search/?search="+search,{headers:{accesstoken:$localStorage.accessToken}})},update:function(ticket){return $http.put("/api/v1/tickets/"+ticket._id,ticket,{headers:{accesstoken:$localStorage.accessToken}})},addComment:function(ticket,comment){return $http.post("/api/v1/tickets/addcomment",{_id:ticket._id,comment:comment.comment,ownerId:comment.ownerId},{headers:{accesstoken:$localStorage.accessToken}})},addNote:function(ticket,note){return $http.post("/api/v1/tickets/addnote",{ticketid:ticket._id,note:note.note,owner:note.ownerId},{headers:{accesstoken:$localStorage.accessToken}})},ticketStats:function(timespan){return $http.get("/api/v1/tickets/stats/"+timespan,{headers:{accesstoken:$localStorage.accessToken}})}}}).factory("Groups",function($http,$localStorage){return{all:function(){return $http.get("/api/v1/groups",{headers:{accesstoken:$localStorage.accessToken}})},get:function(_id){return $http.get("/api/v1/groups/"+_id,{headers:{accesstoken:$localStorage.accessToken}})}}}).factory("TicketTypes",function($http,$localStorage){return{all:function(){return $http.get("/api/v1/tickets/types",{headers:{accesstoken:$localStorage.accessToken}})},get:function(typeId){return $http.get("http://"+$localStorage.server+"/api/v1/tickets/type/"+typeId,{headers:{accesstoken:$localStorage.accessToken}})}}}).factory("Priorities",function($http,$localStorage){return{all:function(){return $http.get("http://"+$localStorage.server+"/api/v1/tickets/priorities",{headers:{accesstoken:$localStorage.accessToken}})}}}).factory("Messages",function($http,$localStorage){return{getConversation:function(convoId,page){void 0===page&&(page=0);var queryString="/api/v1/messages/conversation/"+convoId+"?page="+page;return $http.get(queryString,{headers:{accesstoken:$localStorage.accessToken}})},getRecent:function(){return $http.get("/api/v1/messages/conversations/recent",{headers:{accesstoken:$localStorage.accessToken}})},sendMessage:function(convoId,message){return $http.post("/api/v1/messages/send",{cId:convoId,owner:message.ownerId,body:message.body},{headers:{accesstoken:$localStorage.accessToken}})},startConversation:function(userId){return $http.post("/api/v1/messages/conversation/start",{owner:$localStorage.loggedInUser._id,participants:[$localStorage.loggedInUser._id,userId]},{headers:{accesstoken:$localStorage.accessToken}})},deleteConversation:function(convoId){return $http["delete"]("/api/v1/messages/conversation/"+convoId,{headers:{accesstoken:$localStorage.accessToken}})}}}).factory("Graphs",function($http,$localStorage){return{topGroups:function(){return $http.get("/api/v1/tickets/count/topgroups",{headers:{accesstoken:$localStorage.accessToken}})}}}).factory("Camera",function($q,$cordovaCamera){return{open:function(){var deferred=$q.defer();if(ionic.Platform.isWebView()){var options={quality:80,destinationType:Camera.DestinationType.FILE_URI,sourceType:Camera.PictureSourceType.CAMERA,encodingType:Camera.EncodingType.JPEG};$cordovaCamera.getPicture(options).then(function(fileURL){deferred.resolve(fileURL)})}else deferred.reject("Not Supported in browser");return deferred.promise},library:function(){var deferred=$q.defer();if(ionic.Platform.isWebView()){var options={quality:80,destinationType:Camera.DestinationType.FILE_URI,sourceType:Camera.PictureSourceType.PHOTOLIBRARY,encodingType:Camera.EncodingType.JPEG};$cordovaCamera.getPicture(options).then(function(fileURL){deferred.resolve(fileURL)})}else deferred.reject("Not Supported in browser");return deferred.promise}}}).factory("Upload",function($q,$cordovaCamera,$cordovaFileTransfer,$localStorage){return{profilePicture:function(fileURL){var deferred=$q.defer();if(ionic.Platform.isWebView()){var serverURL="/api/v1/users/"+$localStorage.username+"/uploadprofilepic",uploadOptions=new FileUploadOptions;uploadOptions.fileKey="file",uploadOptions.fileName=fileURL.substr(fileURL.lastIndexOf("/")+1),uploadOptions.mimeType="image/jpeg";var ft=new FileTransfer;ft.upload(fileURL,encodeURI(serverURL),function(result){var response=result.response,responseObj=JSON.parse(response);deferred.resolve(responseObj)},function(err){deferred.reject(err)},uploadOptions)}else deferred.reject("Not Supported");return deferred.promise}}}),function(){return angular.module("trudesk.controllers",["trudesk.controllers.login","trudesk.controllers.dashboard","trudesk.controllers.tickets","trudesk.controllers.ticketDetails","trudesk.controllers.accounts","trudesk.controllers.messages","trudesk.controllers.messages.conversation","trudesk.controllers.imgCrop","trudesk.controllers.graphs"])}(),angular.module("trudesk.controllers.login",[]).controller("LoginCtrl",function($http,$scope,$state,$localStorage,$ionicLoading,$ionicPopup){function showError(err){var alertPopup=$ionicPopup.alert({title:"Error",template:err,okType:"button-assertive"});alertPopup.then(function(){})}$ionicLoading.show({templateUrl:"templates/modals/modal-loading.html",noBackdrop:!0,duration:1200}),$scope.auth={server:"",username:"",password:""},$scope.invalid={server:!1,username:!1,password:!1},$scope.login=function(loginForm){loginForm.$valid?($scope.invalid.server=!1,$scope.invalid.username=!1,$scope.invalid.password=!1,$ionicLoading.show({templateUrl:"templates/modals/modal-loading.html",noBackdrop:!0}),$scope.auth.server=$scope.auth.server.replace(/^https?:\/\//,""),$http.post("/api/v1/login",{username:$scope.auth.username,password:$scope.auth.password}).then(function(response){response.data.success===!1?showError(response.data.error):void 0!==response.data.accessToken&&($localStorage.server="",$localStorage.username=$scope.auth.username,$localStorage.accessToken=response.data.accessToken,$localStorage.loggedInUser=response.data.user,window.plugins&&window.plugins.OneSignal&&(window.plugins.OneSignal.setSubscription(!0),window.plugins.OneSignal.sendTags({host:$localStorage.server,user:$localStorage.loggedInUser._id})),$http.get("/api/v1/roles",{headers:{accesstoken:$localStorage.accessToken}}).then(function(response){$localStorage.roles=response.data},function(response){console.log("Error",response)}).then(function(){$state.go("tab.dash")}))},function(response){switch(console.error(response),response.status){case-1:showError("Could not connect. Please check server and try again.");break;case 401:showError("Invalid Username / Password");break;default:showError("Could not connect. Please check server and try again.")}}).then(function(){setTimeout(function(){$ionicLoading.hide()},500)})):($scope.invalid.server=loginForm.server.$invalid,$scope.invalid.username=loginForm.username.$invalid,$scope.invalid.password=loginForm.password.$invalid)},ionic.on("$trudesk.clearLoginForm",function(){$scope.auth.server="",$scope.auth.username="",$scope.auth.password=""}),$scope.$on("$ionicView.enter",function(){setTimeout(function(){return void 0!==$localStorage.server&&void 0!==$localStorage.accessToken?$state.go("tab.dash"):(window.StatusBar&&window.StatusBar.styleDefault(),angular.element(document).find("ion-view").removeClass("hide"),void(window.plugins&&window.plugins.OneSignal&&window.plugins.OneSignal.setSubscription(!1)))},600)})}),angular.module("trudesk.controllers.accounts",[]).controller("AccountCtrl",function($q,$scope,$state,$http,$timeout,$localStorage,$ionicHistory,$ionicActionSheet,$ionicModal,$cordovaCamera,Camera,Users,Upload){$scope.server=$localStorage.server,$ionicModal.fromTemplateUrl("templates/modals/modal-imgcrop.html",{scope:$scope,animation:"slide-in-up"}).then(function(modal){$scope.imgcropModal=modal}),ionic.on("$trudesk.showCropper",function(){$scope.imgcropModal.show()}),ionic.on("$trudesk.hideCropper",function(){$scope.imgcropModal.hide()}),$scope.showActionSheet=function(event){if(ionic.Platform.isWebView()){$ionicActionSheet.show({buttons:[{text:"Take Photo"},{text:"Open Photo Library"}],titleText:"Account Picture",cancelText:"Cancel",cancel:function(){},buttonClicked:function(index){switch(index){case 0:return $scope.openCamera(),!0;case 1:return $scope.openPhotoLibrary(),!0;default:return!0}}})}},$scope.openCamera=function(){Camera.open().then(function(fileURL){ionic.trigger("$trudesk.imgcrop.setImage",{image:fileURL}),ionic.trigger("$trudesk.imgcrop.showCropper",{}),$scope.imgcropModal.show()})},$scope.openPhotoLibrary=function(){Camera.library().then(function(fileURL){ionic.trigger("$trudesk.imgcrop.setImage",{image:fileURL}),ionic.trigger("$trudesk.imgcrop.showCropper",{}),$scope.imgcropModal.show()}),ionic.on("$trudesk.account.updateImage",function(data){$scope.updateAccountImage()})},$scope.logout=function($event){$event.preventDefault(),$http.get("/logout/",{timeout:2e3}).then(function(response){},function(response){})["finally"](function(){return ionic.trigger("$trudesk.clearLoginForm",{}),$localStorage.server=void 0,$localStorage.accessToken=void 0,window.plugins&&window.plugins.OneSignal&&window.plugins.OneSignal.setSubscription(!1),$ionicHistory.clearCache(),$state.go("login")})},$scope.updateAccountImage=function(){$localStorage.loggedInUser=null,Users.getLoggedInUser().then(function(user){$scope.loggedInUser=user,user.image?$scope.accountProfile="/uploads/users/"+$scope.loggedInUser.image+"?time="+(new Date).getTime():$scope.accountProfile="/uploads/users/defaultProfile.jpg"},function(err){console.log(err)})},$scope.$on("$ionicView.beforeEnter",function(){$scope.accountProfile||($scope.accountProfile="/uploads/users/defaultProfile.jpg"),$scope.updateAccountImage()})}),angular.module("trudesk.controllers.dashboard",[]).controller("DashCtrl",function($http,$scope,$state,$location,$ionicNavBarDelegate,$localStorage,Tickets){function getStats(timespan){Tickets.ticketStats(timespan).then(function(response){$scope.totalTickets=response.data.ticketCount?response.data.ticketCount:0;var closedCount=Number(response.data.closedCount);$scope.closedPercent=Math.round(closedCount/$scope.totalTickets*100),$scope.closedPercent=isNaN($scope.closedPercent)?"--":$scope.closedPercent,$scope.closedPercentPie=$scope.closedPercent+"/100",$scope.ticketAvg=response.data.ticketAvg?response.data.ticketAvg:0})}var path=$location.path();path.indexOf("dashboard")===-1?$ionicNavBarDelegate.showBackButton(!1):$ionicNavBarDelegate.showBackButton(!0),$scope.totalTickets=0,$scope.timespans=[{label:"30 Days",value:30},{label:"60 Days",value:60},{label:"90 Days",value:90},{label:"180 Days",value:180},{label:"365 Days",value:365}],$scope.selectedTimespan=30,$scope.barChart=[5,3,9,6,5,9,7],$scope.lineChart=[5,3,9,6,5,9,7,3,5,2],getStats(30),$scope.timespanChange=function($event){$scope.selectedTimespan=this.selectedTimespan,getStats($scope.selectedTimespan)},$scope.$on("$ionicView.enter",function(){window.StatusBar&&window.StatusBar.styleLightContent()}),$scope.$on("$ionicView.beforeEnter",function(){ensureLogin($localStorage,$state)})}),angular.module("trudesk.controllers.graphs",[]).controller("GraphCtrl",function($scope,$http,_,Graphs){$scope.renderGraphs=function(){Graphs.topGroups().then(function(response){var arr=[];_.size(response.data.items)<1&&(response.data.items=[{name:"No Data",count:1}]),arr=_.map(response.data.items,function(v,k){return[v.name,v.count]});var colors=["#e74c3c","#3498db","#9b59b6","#34495e","#1abc9c","#2ecc71","#03A9F4","#00BCD4","#009688","#4CAF50","#FF5722","#CDDC39","#FFC107","#00E5FF","#E040FB","#607D8B"];colors=_.shuffle(colors);var c=_.object(_.map(arr,function(v,i){return v[0]}),colors);c3.generate({bindto:"#topGroupsChart",size:{height:150,width:315},data:{columns:arr,type:"pie",colors:c},tooltip:{show:!1},pie:{label:{format:function(v,r,id){return""}}}})},function(err){console.error(err)})}}),angular.module("trudesk.controllers.imgCrop",[]).controller("imgCrop",function($scope,$state,$timeout,$localStorage,$cordovaCamera,Cropper,Camera,Upload,Users){function showCropper(){$scope.$broadcast($scope.showEvent)}function hideCropper(){$scope.$broadcast($scope.hideEvent)}$scope.options={maximize:!0,aspectRatio:1,checkImageOrigin:!0,rotatable:!0,viewMode:1,dragMode:"move",checkOrientation:!0},$scope.cropper={},$scope.cropperProxy="cropper.first",Users.getLoggedInUser().then(function(user){$scope.loggedInUser=user},function(error){console.log(error)}),$scope.showEvent="showCropper",$scope.hideEvent="hideCropper",$scope.close=function(){ionic.trigger("$trudesk.hideCropper",{})},$scope.save=function(){if($scope.cropper.first){var canvas=$scope.cropper.first("getCroppedCanvas",{width:256,height:256}),image=canvas.toDataURL();Upload.profilePicture(image).then(function(response){ionic.trigger("$trudesk.account.updateImage",{image:response.user.image})},function(err){console.log(err)})["finally"](function(){$scope.close()})}},ionic.on("$trudesk.imgcrop.showCropper",function(){$timeout(function(){hideCropper(),showCropper()},0)}),ionic.on("$trudesk.imgcrop.setImage",function(data){return void 0===data.detail||void 0===data.detail.image?console.log("Invalid data.detail.image"):void($scope.o=data.detail.image)})}),angular.module("trudesk.controllers.messages",[]).controller("MessagesCtrl",function($scope,$state,$stateParams,$localStorage,$ionicListDelegate,$ionicNavBarDelegate,$ionicModal,$ionicPopup,$ionicActionSheet,$ionicLoading,$ionicScrollDelegate,$ionicFilterBarConfig,$ionicFilterBar,$timeout,$q,WebSocket,Messages,Users){function onUpdateUsers(data){$timeout(function(){$scope.onlineUsers=data.detail,delete $scope.onlineUsers[$scope.loggedInUser.username],$ionicScrollDelegate.$getByHandle("activeUsersScroll").resize()},0)}$ionicNavBarDelegate.showBackButton(!0),$ionicFilterBarConfig.theme="dark",$ionicModal.fromTemplateUrl("templates/modals/modal-messages-newconversation.html",{scope:$scope,animation:"slide-in-up"}).then(function(modal){$scope.newConversation=modal}),$scope.server=$localStorage.server,$scope.socket=WebSocket,$scope.recentConversations=[],$scope.isUserOnline=Users.isUserOnline,$scope.onlineUsers=[],$scope.userList=[],$scope.$on("$ionicView.beforeEnter",function(){ensureLogin($localStorage,$state),$scope.server=$localStorage.server,Users.getLoggedInUser().then(function(user){$scope.loggedInUser=user},function(err){console.log(err)}).then(function(){ionic.on("$trudesk.conversation.updateusers",onUpdateUsers,window),$timeout(function(){$scope.loadRecentConversations()},0)})}),$scope.$on("$ionicView.enter",function(scopes,states){}),$scope.$on("$stateChangeStart",function(e){ionic.off("$trudesk.conversation.updateusers",onUpdateUsers,window)}),$scope.loadRecentConversations=function(){Messages.getRecent().then(function(response){$scope.recentConversations=response.data.conversations,$scope.showRecentConversations=_.size($scope.recentConversations)>=1},function(err){console.log(err),$scope.showRecentConversations=!1})},$scope.showNewConversation=function(){$scope.getUserList().then(function(){$scope.newConversation.show()})},$scope.hideNewConversation=function(){filterBarInstance&&(filterBarInstance(),filterBarInstance=null),$scope.newConversation.hide()},$scope.startConversation=function(userId){Messages.startConversation(userId).then(function(response){var convoId=response.data.conversation._id;return void 0!==convoId?(void 0!==$scope.newConversation&&$scope.hideNewConversation(),$state.go("tab.messages-conversation",{conversationid:convoId})):void $scope.showSnackbar("Invalid Conversation Id",!0)},function(error){$scope.showSnackbar(error,!0),console.log(error)})},$scope.deleteConversation=function(convoId){Messages.deleteConversation(convoId).then(function(response){if(response.data.success){var convo=_.find($scope.recentConversations,function(obj){return obj._id.toString()===convoId.toString()}),idx=$scope.recentConversations.indexOf(convo);idx!==-1&&$scope.recentConversations.splice(idx,1)}},function(error){$scope.showSnackbar(error,!0),console.log(error)})["finally"](function(){$timeout(function(){$scope.loadRecentConversations()},0)})},$scope.getUserList=function(){return Users.getUsers().then(function(res){for(var list=res.data.users,i=0;i0&&($scope.messages=_.uniq(_.union(a,response.data.messages),!1,function(i,k,a){return i._id})),$scope.messages=_.sortBy($scope.messages,function(message){return message.createdAt})}_.size(response.data.messages)<10&&($scope.hasMore=!1)},function(err){console.log(err)}).then(function(){$timeout(function(){0==$scope.page?scrollBottom():$timeout(function(){viewScroll.scrollBy(0,150,!0)}),$scope.page++,$scope.$broadcast("scroll.infiniteScrollComplete")},0)})},$scope.$on("elastic:resize",function(event,element,oldHeight,newHeight){$(".message-textbox").css("max-height",newHeight+"px").css("height",newHeight+"px"),element.css("max-height",newHeight-1+"px"),newHeight>=100?(element.css("max-height","99px"),element.css({bottom:"5px"}),$(".message-textbox").css("max-height","105px").css("height","105px")):element.css({bottom:"0"})}),$scope.chatTyping=function(event){if(!(event.shiftKey&13===event.keyCode||13===event.keyCode&&ionic.Platform.isWebView())){if(13===event.keyCode&&!ionic.Platform.isWebView())return event.preventDefault(),$scope.sendChatMessage();if(isTyping)return clearTimeout(typingTimer),void(typingTimer=setTimeout(stopTyping,5e3));isTyping=!0,void 0==typingTimer&&(typingTimer=setTimeout(stopTyping,5e3)),WebSocket.startTyping($scope.conversation._id,$scope.conversation.partner._id,$localStorage.loggedInUser._id)}},$scope.shouldShowDate=function(date){var now=moment(),dMoment=moment(date),timeDiff=now.diff(dMoment,"minutes");return timeDiff>60},$scope.canFetchMoreMessages=function(){return void 0===$scope.hasMore&&($scope.hasMore=!0),$scope.hasMore},$scope.loadMore=function(){if(console.log("loading more"),i++,i>10&&($scope.hasMore=!1),void 0!==$scope.conversation)for(var j=0;j<11;j++){var message={createdAt:new Date,body:"here",owner:$localStorage.loggedInUser,_id:Math.random()};$scope.conversation.messages.unshift(message)}$timeout(function(){viewScroll.scrollBy(0,150,!0)}),$timeout(function(){$scope.$broadcast("scroll.infiniteScrollComplete")},3e3)},$scope.sendChatMessage=function(){if(_.isEmpty($scope.message.body))return!1;$scope.message.ownerId=$scope.loggedInUser._id;var scopeMessageClone=_.clone($scope.message);$scope.message.body="",Messages.sendMessage($scope.conversation._id,scopeMessageClone).then(function(response){var message=response.data.message;WebSocket.send($scope.conversation._id,$scope.conversation.partner._id,$scope.loggedInUser._id,message._id,message.body),stopTyping(),keepKeyboardOpen(),scrollBottom()},function(err){console.log(err)})}}),angular.module("trudesk.controllers.ticketDetails",[]).controller("TicketsDetailCtrl",function($scope,$state,$stateParams,$ionicHistory,$ionicNavBarDelegate,$localStorage,$ionicModal,$ionicPopover,$ionicActionSheet,Tickets,Users){$ionicNavBarDelegate.showBackButton(!0),$scope.showSnackbar=function(text,error){_.isUndefined(error)&&(error=!1);var textColor="#FFFFFF";error&&(textColor="#ef473a"),Snackbar.show({text:text,showAction:!1,duration:3e3,textColor:textColor})},$scope.server=$localStorage.server,$scope.loggedInUser=void 0,$scope.commentModalForm={comment:""},$scope.noteModalForm={note:""},$scope.isSupport="admin"===$localStorage.loggedInUser.role||"mod"===$localStorage.loggedInUser.role||"support"===$localStorage.loggedInUser.role,$ionicModal.fromTemplateUrl("templates/modals/modal-ticket-details.html",{scope:$scope,animation:"slide-in-up"}).then(function(modal){$scope.ticketDetailModal=modal}),$ionicModal.fromTemplateUrl("templates/modals/modal-addComment.html",{scope:$scope,animation:"slide-in-up"}).then(function(modal){$scope.addCommentModal=modal}),$ionicModal.fromTemplateUrl("templates/modals/modal-addNote.html",{scope:$scope,animation:"slide-in-up"}).then(function(modal){$scope.addNoteModal=modal}),$ionicModal.fromTemplateUrl("templates/modals/modal-ticket-setAssignee.html",{scope:$scope,animation:"slide-in-up",focusFirstInput:!0}).then(function(modal){$scope.setAssigneeModal=modal}),Tickets.get($stateParams.ticketuid).then(function(response){$scope.ticket=response.data.ticket,$scope.ticket.assignee&&($scope.selectedAssignee=$scope.ticket.assignee._id),void 0===$scope.ticket.owner.image&&($scope.ticket.owner.image="defaultProfile.jpg"),$scope.hasAssignee="hide",void 0!==$scope.ticket.assignee&&($scope.hasAssignee="show"),void 0!==$scope.ticket.assignee&&void 0===$scope.ticket.assignee.image&&($scope.ticket.assignee.image="defaultProfile.jpg"),$scope.isSupport?$scope.ticket.commentsMerged=_.sortBy(_.union($scope.ticket.comments,$scope.ticket.notes),"date"):$scope.ticket.commentsMerged=$scope.ticket.comments}),Users.getAssignees().then(function(response){$scope.assignees=response.data.users},function(response){console.log(response)}),$scope.popover=$ionicPopover.fromTemplateUrl("templates/popover/popover-ticket-details.html",{scope:$scope}).then(function(popover){$scope.popover=popover}),$scope.showStatusActionSheet=function(){$scope.popover.hide(),$ionicActionSheet.show({buttons:[{text:"Open"},{text:"Pending"},{text:"Closed"}],titleText:"Set Ticket Status",cancelText:"Cancel",cancel:function(){return!0},buttonClicked:function(index){switch(index){case 0:var reqTicket={_id:$scope.ticket._id};return reqTicket.status=1,Tickets.update(reqTicket).then(function(response){$scope.ticket.status=1,$scope.showSnackbar("Ticket status set to Open")},function(response){console.log(response)}),!0;case 1:var reqTicket={_id:$scope.ticket._id};return reqTicket.status=2,Tickets.update(reqTicket).then(function(response){$scope.ticket.status=2,$scope.showSnackbar("Ticket status set to Pending")},function(response){console.log(response)}),!0;case 2:var reqTicket={_id:$scope.ticket._id};return reqTicket.status=3,$scope.ticket.status=3,Tickets.update(reqTicket).then(function(response){ionic.trigger("$trudesk.refreshTickets",{}),$scope.popover.hide(),$ionicHistory.goBack()},function(response){console.log(response)}),!0;default:return!0}}})},$scope.setAssigneeChanged=function(){$scope.selectedAssignee=this.selectedAssignee},$scope.showAddComment=function($event){Users.getLoggedInUser().then(function(user){$scope.loggedInUser=user}).then(function(){$scope.addCommentModal.show(),$scope.popover.hide()})},$scope.closeAddComment=function(){$scope.commentModalForm.comment="",$scope.addCommentModal.hide()},$scope.showAddNote=function($event){Users.getLoggedInUser().then(function(user){$scope.loggedInUser=user}).then(function(){$scope.addNoteModal.show(),$scope.popover.hide()})},$scope.closeAddNote=function(){$scope.noteModalForm.note="",$scope.addNoteModal.hide()},$scope.openSetAssigneeModal=function(){$scope.setAssigneeModal.show(),$scope.popover.hide()},$scope.closeSetAssigneeModal=function(){void 0!==$scope.setAssigneeModal&&$scope.setAssigneeModal.hide()},$scope.showTicketDetails=function(){$scope.ticketDetailModal.show(),$scope.popover.hide()},$scope.closeTicketDetailsModal=function(){$scope.ticketDetailModal.hide()},$scope.closeTicket=function(){$scope.ticket.status=3,Tickets.update($scope.ticket).then(function(response){ionic.trigger("$trudesk.refreshTickets",{}),$scope.popover.hide(),$ionicHistory.goBack()},function(response){console.log(response)})},$scope.addCommentFormSubmit=function(){var comment={ownerId:$scope.loggedInUser._id,comment:this.commentModalForm.comment};Tickets.addComment($scope.ticket,comment).then(function(response){},function(err){console.log(err),$scope.showSnackbar(err,!0)}).then(function(){Tickets.get($stateParams.ticketuid).then(function(response){$scope.ticket=response.data.ticket,$scope.isSupport?$scope.ticket.commentsMerged=_.sortBy(_.union($scope.ticket.comments,$scope.ticket.notes),"date"):$scope.ticket.commentsMerged=$scope.ticket.comments,void 0===$scope.ticket.owner.image&&($scope.ticket.owner.image="defaultProfile.jpg")}).then(function(){$scope.commentModalForm.comment="",$scope.closeAddComment()})})},$scope.addNoteFormSubmit=function(){var note={ownerId:$scope.loggedInUser._id,note:this.noteModalForm.note};Tickets.addNote($scope.ticket,note).then(function(response){},function(err){console.log(err),$scope.showSnackbar(err,!0)}).then(function(){Tickets.get($stateParams.ticketuid).then(function(response){$scope.ticket=response.data.ticket,$scope.isSupport?$scope.ticket.commentsMerged=_.sortBy(_.union($scope.ticket.comments,$scope.ticket.notes),"date"):$scope.ticket.commentsMerged=$scope.tickets.comments,void 0===$scope.ticket.owner.image&&($scope.ticket.owner.image="defaultProfile.jpg")}).then(function(){$scope.noteModalForm.note="",$scope.closeAddNote()})})},$scope.setAssigneeFormSubmit=function(){return $scope.ticket?$scope.ticket.assignee&&$scope.ticket.assignee._id===$scope.selectedAssignee?void $scope.setAssigneeModal.hide():($scope.ticket.assignee=$scope.selectedAssignee,void Tickets.update($scope.ticket).then(function(response){$scope.ticket=response.data.ticket,$scope.hasAssignee="hide",void 0!==$scope.ticket.assignee&&($scope.hasAssignee="show"),void 0!==$scope.ticket.assignee&&void 0===$scope.ticket.assignee.image&&($scope.ticket.assignee.image="defaultProfile.jpg"),$scope.isSupport?$scope.ticket.commentsMerged=_.sortBy(_.union($scope.ticket.comments,$scope.ticket.notes),"date"):$scope.ticket.commentsMerged=$scope.ticket.comments,$scope.setAssigneeModal.hide()},function(response){console.log(response.data),$scope.showSnackbar("Error: "+response.data,!0)})):void $scope.showSnackbar("Invalid Ticket Object",!0)},$scope.$on("$ionicView.beforeEnter",function(){ensureLogin($localStorage,$state)}),$scope.$on("$destroy",function(){$scope.popover.remove(),$scope.addCommentModal.remove(),$scope.addNoteModal.remove(),$scope.ticketDetailModal.remove(),$scope.setAssigneeModal.remove()})}),angular.module("trudesk.controllers.tickets",[]).controller("TicketsCtrl",function($scope,$state,$timeout,$stateParams,$localStorage,$ionicListDelegate,$ionicNavBarDelegate,$ionicModal,$ionicPopup,$ionicActionSheet,$ionicLoading,$q,Tickets,Users,Groups,TicketTypes){$ionicNavBarDelegate.showBackButton(!0),$ionicModal.fromTemplateUrl("templates/modals/modal-newticket.html",{scope:$scope,animation:"slide-in-up"}).then(function(modal){$scope.newTicketModal=modal}),$ionicModal.fromTemplateUrl("templates/modals/modal-ticket-filter.html",{scope:$scope,animation:"slide-in-up"}).then(function(modal){$scope.filterTicketModal=modal}),$ionicModal.fromTemplateUrl("templates/modals/modal-addComment.html",{scope:$scope,animation:"slide-in-up"}).then(function(modal){$scope.addCommentModal=modal}),$scope.showLoadingTickets=!0,$scope.search={term:""},$scope.filter={},$scope.filter.showClosedTickets=$localStorage.showClosedTickets,$scope.filter.showOnlyAssigned=$localStorage.showOnlyAssigned,$scope.commentModalForm={comment:"",ticket:""},$scope.isSupport="admin"==$localStorage.loggedInUser.role||"mod"==$localStorage.loggedInUser.role||"support"==$localStorage.loggedInUser.role,$scope.showSnackbar=function(text,error){_.isUndefined(error)&&(error=!1);var textColor="#FFFFFF";error&&(textColor="#ef473a"),Snackbar.show({text:text,showAction:!0,actionText:"X",actionTextColor:"#ccc",duration:3e3,textColor:textColor})},$scope.showActionSheet=function($event,$ticket){$ionicListDelegate.closeOptionButtons();var buttons=[{text:"Add Comment"}];$scope.isSupport&&(buttons.push({text:"Open"}),buttons.push({text:"Pending"}),buttons.push({text:"Closed"}));$ionicActionSheet.show({buttons:buttons,titleText:"Ticket Options",cancelText:"Cancel",cancel:function(){},buttonClicked:function(index){switch(index){case 0:var t=_.find($scope.tickets,function(obj){return obj._id==$ticket._id});return $scope.commentModalForm.ticket=t,$scope.addCommentModal.show(),!0;case 1:var t=_.find($scope.tickets,function(obj){return obj._id==$ticket._id}),reqTicket={_id:t._id};return reqTicket.status=1,Tickets.update(reqTicket).then(function(response){t.status=1,$scope.showSnackbar("Ticket status set to Open")},function(response){console.log(response)}),!0;case 2:var t=_.find($scope.tickets,function(obj){return obj._id==$ticket._id}),reqTicket={_id:t._id};return reqTicket.status=2,Tickets.update(reqTicket).then(function(response){t.status=2,$scope.showSnackbar("Ticket status set to Pending")},function(response){console.log(response)}),!0;case 3:var t=_.find($scope.tickets,function(obj){return obj._id==$ticket._id}),reqTicket={_id:t._id};return reqTicket.status=3,Tickets.update(reqTicket).then(function(response){var idx=$scope.tickets.indexOf(t);idx!=-1&&$scope.tickets.splice(idx,1),$scope.showSnackbar("Ticket status set to Closed")},function(response){console.log(response)})["finally"](function(){_.size($scope.tickets)<1?$scope.showNoTickets=!0:$scope.showNoTickets=!1}),!0;default:return!0}}})},$scope.doRefresh=function(){$scope.search.term="",$scope.shouldRefresh=!0,$scope.fetchTickets()["finally"](function(){$scope.$broadcast("scroll.refreshComplete")})},$scope.fetchTickets=function(){return angular.element(document).find("ion-item").removeClass("item-remove-animate"),void 0==$scope.page&&($scope.page=0),$scope.shouldRefresh&&($scope.page=0,$scope.hasMoreTickets=!0,$scope.shouldRefresh=!1),Tickets.all($scope.page).then(function(response){if(_.size(response.data)<1)return void($scope.hasMoreTickets=!1);if(0==$scope.page)$scope.tickets=response.data;else{var a=$scope.tickets;_.size(a)>0&&($scope.tickets=_.uniq(_.union(a,response.data),!1,function(i,k,a){return i._id}))}},function(error){return $scope.$broadcast("scroll.infiniteScrollComplete"),$scope.hasMoreTickets=!1,error.status===-1?$scope.showAlert("Error","Connection Refused."):401===error.status?(ionic.trigger("$trudesk.clearLoginForm",{}),$localStorage.server=void 0,$localStorage.accessToken=void 0,$state.go("login"),$scope.showAlert("Error","You have been logged out.")):void $scope.showAlert("Error","Error Status: "+error.status)})["finally"](function(){$scope.showLoadingTickets=!1,_.size($scope.tickets)>0?$scope.showNoTickets=!1:$scope.showNoTickets=!0,$scope.page++,$scope.$broadcast("scroll.infiniteScrollComplete")})},$scope.canFetchMoreTickets=function(){return void 0===$scope.hasMoreTickets&&($scope.hasMoreTickets=!0),$scope.hasMoreTickets},$scope.selected={group:"",ticketType:"",priority:""},$scope.$watch("selected.ticketType",function(newValue,oldValue,scope){newValue&&newValue.priorities&&($scope.selected.priority=newValue.priorities[0])},!0),$scope.openNewTicket=function(){var groups=Groups.all(),types=TicketTypes.all();$q.all([groups,types]).then(function(results){$scope.groups=results[0].data.groups,$scope.ticketTypes=results[1].data,$scope.ticketTypes[0]&&$scope.ticketTypes[0]._id&&($scope.selected.ticketType=$scope.ticketTypes[0]),$scope.modalNewTicketForm={subject:"",issue:""},$scope.selected.group=""},function(error){console.error("Error - "+error)}).then(function(){$scope.newTicketModal.show()})},$scope.closeNewTicket=function(){$scope.newTicketModal.hide()},$scope.openFilterTicket=function(){$scope.filterTicketModal.show()},$scope.applyTicketFilter=function(){$scope.closeTicketFilter()},$scope.closeTicketFilter=function(){return""!==$scope.search.term?($scope.tickets=[],$scope.filterTicketModal.hide(),Snackbar.show({text:"Loading...",showAction:!1,duration:2147483647,textColor:"#FFFFFF"}),Tickets.search($scope.search.term).then(function(response){$scope.tickets=response.data.tickets,$timeout(function(){_.size($scope.tickets)<1?$scope.showNoTickets=!0:$scope.showNoTickets=!1},0),$scope.hasMoreTickets=!1,Snackbar.close()},function(response){console.log(response)})):($scope.filterTicketModal.hide(),void($scope.shouldRefresh&&$scope.fetchTickets()))},$scope.clearTicketFilter=function(){$scope.search.term="",$scope.tickets=null,$scope.filter.showClosedTickets=!1,$scope.filter.showOnlyAssigned=!1,$localStorage.showClosedTickets=!1,$localStorage.showOnlyAssigned=!1,ionic.trigger("$trudesk.refreshTickets",{}),$scope.filterTicketModal.hide()},$scope.searchTermChanged=function(){$scope.shouldRefresh=!0},$scope.showClosedTicketsChanged=function(){$scope.filter.showClosedTickets=this.filter.showClosedTickets,$localStorage.showClosedTickets=$scope.filter.showClosedTickets,$scope.shouldRefresh=!0},$scope.showOnlyAssigneedChanged=function(){$scope.filtershowOnlyAssigneed=this.filter.showOnlyAssigned,$localStorage.showOnlyAssigned=$scope.filter.showOnlyAssigned,$scope.shouldRefresh=!0},$scope.closeAddComment=function(){$scope.addCommentModal.hide()},$scope.modalNewTicketForm={subject:"",issue:""},$scope.addCommentFormSubmit=function(){var comment={ownerId:$scope.loggedInUser._id,comment:this.commentModalForm.comment};Tickets.addComment($scope.commentModalForm.ticket,comment).then(function(response){},function(err){console.log(err),$scope.showSnackbar(err,!0)}).then(function(){$scope.commentModalForm.comment="",$scope.commentModalForm.ticket="",$scope.closeAddComment()})},$scope.submitNewTicket=function($event){$event.preventDefault();var ticket={type:$scope.selected.ticketType,subject:this.modalNewTicketForm.subject,issue:this.modalNewTicketForm.issue,group:$scope.selected.group,priority:$scope.selected.priority};ticket.type&&ticket.subject&&ticket.issue&&ticket.group&&ticket.priority&&Tickets.create(ticket).then(function(response){ionic.trigger("$trudesk.refreshTickets",{}),$scope.modalNewTicketForm={subject:"",issue:""},$scope.closeNewTicket()},function(response){console.log("Error----"),console.log(response),$scope.showAlert("Error: "+response.statusText,response.data.error.message)}).then(function(){})},$scope.showAlert=function(title,text,button){return void 0===button&&(button="button-assertive"),$ionicPopup.alert({title:title,template:text,okType:button})},ionic.on("$trudesk.refreshTickets",function(){$scope.doRefresh()}),$scope.$on("$ionicView.beforeEnter",function(){ensureLogin($localStorage,$state),$scope.server=$localStorage.server,Users.getLoggedInUser().then(function(user){$scope.loggedInUser=user},function(err){console.log(err)})}),$scope.$on("$ionicView.enter",function(){_.size($scope.tickets)<1&&$scope.doRefresh()}),$scope.$on("$destroy",function(){$scope.newTicketModal.remove(),$scope.filterTicketModal.remove(),$scope.addCommentModal.remove()})}); \ No newline at end of file +function ensureLogin($localStorage,$state){if(void 0===$localStorage.server||void 0===$localStorage.accessToken)return $state.go("login")}function ensureLogin($localStorage,$state){if(void 0===$localStorage.server||void 0===$localStorage.accessToken)return $state.go("login")}function ensureLogin($localStorage,$state){if(void 0===$localStorage.server||void 0===$localStorage.accessToken)return $state.go("login")}function ensureLogin($localStorage,$state){if(void 0===$localStorage.server||void 0===$localStorage.accessToken)return $state.go("login")}angular.module("underscore",[]).factory("_",["$window",function($window){return $window._}]),angular.module("snackbar",[]).factory("Snackbar",["$window",function($window){return $window.Snackbar}]),angular.module("trudesk",["ionic","ngCordova","ngStorage","underscore","trudesk.controllers","trudesk.services","fileOnChange","angular-peity","snackbar","ngCropper","monospaced.elastic","angularMoment","jett.ionic.filter.bar","angular.img"]).run(function($ionicPlatform,$rootScope,$location,$localStorage,$state,$http){$localStorage.accessToken?$http.defaults.headers.common.accesstoken=$localStorage.accessToken:$http.defaults.headers.common.accesstoken="",$ionicPlatform.ready(function(){window.cordova&&window.cordova.plugins&&window.cordova.plugins.Keyboard&&(cordova.plugins.Keyboard.hideKeyboardAccessoryBar(!0),cordova.plugins.Keyboard.disableScroll(!0)),window.StatusBar&&window.StatusBar.styleLightContent();var notificationOpenedCallback=function(jsonData){if(jsonData.notification.payload&&jsonData.notification.payload.additionalData){var ticketUid=jsonData.notification.payload.additionalData.ticketUid;ticketUid&&($state.go("tab.tickets"),setTimeout(function(){return $state.go("tab.tickets-details",{ticketuid:ticketUid})},850))}};window.plugins&&window.plugins.OneSignal&&window.plugins.OneSignal.startInit("f8e19190-b53b-4b72-bac8-210e7f31bebb").handleNotificationOpened(notificationOpenedCallback).endInit(),$rootScope.$on("$stateChangeStart",function(event,next,current){if("/login"!==$location.url()&&(void 0==$localStorage.accessToken||void 0==$localStorage.server))return $location.path("/login")}),setTimeout(function(){angular.element(document.querySelector("#loader")).addClass("hide")},900)})}).filter("htmlToPlaintext",function(){return function(text){return text=text?String(text).replace(/<[^>]+>/gm,""):"",text=text?String(text).replace(/&/gm,"&"):"",text=text?String(text).replace(/"/gm,'"'):"",text=text?String(text).replace(/'/gm,"'"):""}}).filter("removeHTMLTags",function(){return function(text){return text?String(text).replace(/<[^>]+>/gm," "):""}}).filter("nl2br",["$filter",function($filter){return function(data){return data?data.replace(/\n\r?/g,"
"):data}}]).filter("sanitize",["$sce",function($sce){return function(htmlCode){return $sce.trustAsHtml(htmlCode)}}]).filter("currentdate",["$filter",function($filter){return function(){return $filter("date")(new Date,"M/dd/yy h:mm a")}}]).filter("statusMap",function(){return function(s){var status;switch(s){case 0:status="New";break;case 1:status="Open";break;case 2:status="Pending";break;case 3:status="Closed"}return status}}).filter("assigneeMap",function(){return function(a){return void 0===a||null===a?"No Assignee":a}}).filter("conversationFrom",function(){return function(p,loggedInUser){for(var final,i=0;i").html(".has-tabs.no-tabs:not(.has-tabs-top) { bottom: 0; }\n.no-tabs.has-tabs-top { top: 44px; }");return document.body.appendChild(style[0]),{restrict:"A",compile:function(element,attr){var tabBar=document.querySelector(".tab-nav");return function($scope,$element,$attr){var scroll=$element[0].querySelector(".scroll-content");$scope.$on("$ionicView.beforeEnter",function(){tabBar.classList.add("slide-away"),scroll.classList.add("no-tabs")}),$scope.$on("$ionicView.beforeLeave",function(){tabBar.classList.remove("slide-away"),scroll.classList.remove("no-tabs")})}}}}),angular.module("ionic").directive("ionInfiniteScrollReverse",["$timeout",function($timeout){return{restrict:"E",require:["?^$ionicScroll","ionInfiniteScrollReverse"],template:function($element,$attrs){return $attrs.icon?'':''},scope:!0,controller:"$ionInfiniteScrollReverse",link:function($scope,$element,$attrs,ctrls){var infiniteScrollCtrl=ctrls[1],scrollCtrl=infiniteScrollCtrl.scrollCtrl=ctrls[0],jsScrolling=infiniteScrollCtrl.jsScrolling=!scrollCtrl.isNative();if(jsScrolling)infiniteScrollCtrl.scrollView=scrollCtrl.scrollView,$scope.scrollingType="js-scrolling",scrollCtrl.$element.on("scroll",infiniteScrollCtrl.checkBounds);else{var scrollEl=ionic.DomUtil.getParentOrSelfWithClass($element[0].parentNode,"overflow-scroll");if(infiniteScrollCtrl.scrollEl=scrollEl,!scrollEl)throw"Infinite scroll must be used inside a scrollable div";infiniteScrollCtrl.scrollEl.addEventListener("scroll",infiniteScrollCtrl.checkBounds)}var doImmediateCheck=!angular.isDefined($attrs.immediateCheck)||$scope.$eval($attrs.immediateCheck);doImmediateCheck&&$timeout(function(){infiniteScrollCtrl.checkBounds()})}}}]),angular.module("ionic").controller("$ionInfiniteScrollReverse",["$scope","$attrs","$element","$timeout",function($scope,$attrs,$element,$timeout){function onInfinite(){ionic.requestAnimationFrame(function(){$element[0].classList.add("active")}),self.isLoading=!0,$scope.$parent&&$scope.$parent.$apply($attrs.onInfinite||"")}function finishInfiniteScroll(){ionic.requestAnimationFrame(function(){$element[0].classList.remove("active")}),$timeout(function(){self.jsScrolling&&self.scrollView.resize(),(self.jsScrolling&&self.scrollView.__container&&self.scrollView.__container.offsetHeight>0||!self.jsScrolling)&&self.checkBounds()},30,!1),self.isLoading=!1}function checkInfiniteBounds(){if(!self.isLoading){var maxScroll={};if(self.jsScrolling){maxScroll=self.getJSMaxScroll();var scrollValues=self.scrollView.getValues();$attrs.reverse?(maxScroll.left!==-1&&scrollValues.left<=maxScroll.left||maxScroll.top!==-1&&scrollValues.top<=maxScroll.top)&&onInfinite():(maxScroll.left!==-1&&scrollValues.left>=maxScroll.left||maxScroll.top!==-1&&scrollValues.top>=maxScroll.top)&&onInfinite()}else maxScroll=self.getNativeMaxScroll(),$attrs.reverse?(maxScroll.left!==-1&&self.scrollEl.scrollLeft<=maxScroll.left||maxScroll.top!==-1&&self.scrollEl.scrollTop<=maxScroll.top)&&onInfinite():(maxScroll.left!==-1&&self.scrollEl.scrollLeft>=maxScroll.left-self.scrollEl.clientWidth||maxScroll.top!==-1&&self.scrollEl.scrollTop>=maxScroll.top-self.scrollEl.clientHeight)&&onInfinite()}}function calculateMaxValue(maximum){var distance=($attrs.distance||"2.5%").trim(),isPercent=distance.indexOf("%")!==-1;return $attrs.reverse?isPercent?maximum-maximum*(1-parseFloat(distance)/100):parseFloat(distance):isPercent?maximum*(1-parseFloat(distance)/100):maximum-parseFloat(distance)}var self=this;self.isLoading=!1,$scope.icon=function(){return angular.isDefined($attrs.icon)?$attrs.icon:"ion-load-d"},$scope.spinner=function(){return angular.isDefined($attrs.spinner)?$attrs.spinner:""},$scope.$on("scroll.infiniteScrollComplete",function(){finishInfiniteScroll()}),$scope.$on("$destroy",function(){self.scrollCtrl&&self.scrollCtrl.$element&&self.scrollCtrl.$element.off("scroll",self.checkBounds),self.scrollEl&&self.scrollEl.removeEventListener&&self.scrollEl.removeEventListener("scroll",self.checkBounds)}),self.checkBounds=ionic.Utils.throttle(checkInfiniteBounds,300),self.getJSMaxScroll=function(){var maxValues=self.scrollView.getScrollMax();return{left:self.scrollView.options.scrollingX?calculateMaxValue(maxValues.left):-1,top:self.scrollView.options.scrollingY?calculateMaxValue(maxValues.top):-1}},self.getNativeMaxScroll=function(){var maxValues={left:self.scrollEl.scrollWidth,top:self.scrollEl.scrollHeight},computedStyle=window.getComputedStyle(self.scrollEl)||{};return{left:!maxValues.left||"scroll"!==computedStyle.overflowX&&"auto"!==computedStyle.overflowX&&"scroll"!==self.scrollEl.style["overflow-x"]?-1:calculateMaxValue(maxValues.left),top:!maxValues.top||"scroll"!==computedStyle.overflowY&&"auto"!==computedStyle.overflowY&&"scroll"!==self.scrollEl.style["overflow-y"]?-1:calculateMaxValue(maxValues.top)}},self.__finishInfiniteScroll=finishInfiniteScroll}]),angular.module("trudesk.services",[]).factory("WebSocket",function($q,$rootScope,$timeout,$http,$localStorage){var message,dataStream=io.connect("/",{query:"token="+$localStorage.accessToken});return dataStream.on("connect",function(){console.log("Connected to Server: "+$localStorage.server)}),dataStream.on("disconnect",function(){console.log("Disconnected from Server: "+$localStorage.server)}),dataStream.on("error",function(e){console.log("Error",e)}),dataStream.on("joinSuccessfully",function(){console.log("Joined Messaging Server.")}),dataStream.removeAllListeners("chatMessage"),dataStream.on("chatMessage",function(data){window.dispatchEvent(new CustomEvent("$trudesk.converstation.chatmessage",{detail:data}))}),dataStream.on("updateUsers",function(users){window.dispatchEvent(new CustomEvent("$trudesk.conversation.updateusers",{detail:users}))}),dataStream.on("chatTyping",function(data){ionic.trigger("$trudesk.conversation.usertyping",data)}),dataStream.on("chatStopTyping",function(data){ionic.trigger("$trudesk.conversation.userstoptyping",data)}),{message:message,socket:dataStream,startTyping:function(convoId,partnerId,loggedInUserId){dataStream.emit("chatTyping",{cid:convoId,to:partnerId,from:loggedInUserId})},stopTyping:function(convoId,partnerId){dataStream.emit("chatStopTyping",{cid:convoId,to:partnerId})},send:function(convoId,partnerId,loggedInUserId,messageId,messageBody){dataStream.emit("chatMessage",{conversation:convoId,to:partnerId,from:loggedInUserId,type:"s",messageId:messageId,message:messageBody})},updateUsers:function(){return dataStream.emit("updateUsers")},checkConnection:function(){void 0!=dataStream&&dataStream.connected||(console.log("Reconnecting to: "+$localStorage.server),dataStream=void 0,dataStream=io.connect("http://"+$localStorage.server,{query:"token="+$localStorage.accessToken}))},close:function(){return console.log("Closing Socket..."),dataStream.disconnect()}}}).factory("Users",function($q,$http,$localStorage){return{getImage:function(url){return new Promise(function(resolve,reject){$http.get(url,{method:"GET",headers:{accesstoken:$localStorage.accessToken}}).then(function(response){var objectUrl=URL.createObjectURL(response.blob());return resolve(objectUrl)})["catch"](function(err){return reject(err)})})},get:function(username){return $http.get("/api/v1/users/"+username,{headers:{accesstoken:$localStorage.accessToken}})},getUsers:function(){return $http.get("/api/v1/users?limit=-1",{headers:{accesstoken:$localStorage.accessToken}})},getAssignees:function(){return $http.get("/api/v1/users/getassignees",{headers:{accesstoken:$localStorage.accessToken}})},getRoles:function(){return $http.get("/api/v1/roles",{headers:{accesstoken:$localStroage.accessToken}})},getLoggedInUser:function(){var deferred=$q.defer();return $localStorage.loggedInUser?(deferred.resolve($localStorage.loggedInUser),deferred.promise):($localStorage.username?$http.get("/api/v1/users/"+$localStorage.username,{headers:{accesstoken:$localStorage.accessToken}}).then(function(response){response.data.user?($localStorage.loggedInUser=response.data.user,void 0===$localStorage.loggedInUser.image&&($localStorage.loggedInUser.image="defaultProfile.jpg"),deferred.resolve($localStorage.loggedInUser)):deferred.reject("Unable to get user")},function(response){console.log(response),deferred.reject("Error Occured!")}):deferred.reject("No username stored."),deferred.promise)},isUserOnline:function(onlineUsers,userObj){return void 0!==userObj&&(void 0!==onlineUsers&&void 0!==onlineUsers[userObj.username])}}}).factory("Tickets",function($http,$localStorage){return{all:function(page){void 0===page&&(page=0);var queryString="/api/v1/tickets?limit=10&status[]=0&status[]=1&status[]=2&page="+page;return void 0!==$localStorage.showClosedTickets&&$localStorage.showClosedTickets===!0&&(queryString+="&status[]=3"),void 0!==$localStorage.showOnlyAssigned&&$localStorage.showOnlyAssigned===!0&&(queryString+="&assignedself=true"),$http.get(queryString,{headers:{accesstoken:$localStorage.accessToken}})},get:function(uid){return $http.get("/api/v1/tickets/"+uid,{headers:{accesstoken:$localStorage.accessToken}})},create:function(ticket){return $http.post("/api/v1/tickets/create",ticket,{headers:{accesstoken:$localStorage.accessToken}})},search:function(search){return $http.get("/api/v1/tickets/search/?search="+search,{headers:{accesstoken:$localStorage.accessToken}})},update:function(ticket){return $http.put("/api/v1/tickets/"+ticket._id,ticket,{headers:{accesstoken:$localStorage.accessToken}})},addComment:function(ticket,comment){return $http.post("/api/v1/tickets/addcomment",{_id:ticket._id,comment:comment.comment,ownerId:comment.ownerId},{headers:{accesstoken:$localStorage.accessToken}})},addNote:function(ticket,note){return $http.post("/api/v1/tickets/addnote",{ticketid:ticket._id,note:note.note,owner:note.ownerId},{headers:{accesstoken:$localStorage.accessToken}})},ticketStats:function(timespan){return $http.get("/api/v1/tickets/stats/"+timespan,{headers:{accesstoken:$localStorage.accessToken}})}}}).factory("Groups",function($http,$localStorage){return{all:function(){return $http.get("/api/v1/groups",{headers:{accesstoken:$localStorage.accessToken}})},get:function(_id){return $http.get("/api/v1/groups/"+_id,{headers:{accesstoken:$localStorage.accessToken}})}}}).factory("TicketTypes",function($http,$localStorage){return{all:function(){return $http.get("/api/v1/tickets/types",{headers:{accesstoken:$localStorage.accessToken}})},get:function(typeId){return $http.get("http://"+$localStorage.server+"/api/v1/tickets/type/"+typeId,{headers:{accesstoken:$localStorage.accessToken}})}}}).factory("Priorities",function($http,$localStorage){return{all:function(){return $http.get("http://"+$localStorage.server+"/api/v1/tickets/priorities",{headers:{accesstoken:$localStorage.accessToken}})}}}).factory("Messages",function($http,$localStorage){return{getConversation:function(convoId,page){void 0===page&&(page=0);var queryString="/api/v1/messages/conversation/"+convoId+"?page="+page;return $http.get(queryString,{headers:{accesstoken:$localStorage.accessToken}})},getRecent:function(){return $http.get("/api/v1/messages/conversations/recent",{headers:{accesstoken:$localStorage.accessToken}})},sendMessage:function(convoId,message){return $http.post("/api/v1/messages/send",{cId:convoId,owner:message.ownerId,body:message.body},{headers:{accesstoken:$localStorage.accessToken}})},startConversation:function(userId){return $http.post("/api/v1/messages/conversation/start",{owner:$localStorage.loggedInUser._id,participants:[$localStorage.loggedInUser._id,userId]},{headers:{accesstoken:$localStorage.accessToken}})},deleteConversation:function(convoId){return $http["delete"]("/api/v1/messages/conversation/"+convoId,{headers:{accesstoken:$localStorage.accessToken}})}}}).factory("Graphs",function($http,$localStorage){return{topGroups:function(){return $http.get("/api/v1/tickets/count/topgroups",{headers:{accesstoken:$localStorage.accessToken}})}}}).factory("Camera",function($q,$cordovaCamera){return{open:function(){var deferred=$q.defer();if(ionic.Platform.isWebView()){var options={quality:80,destinationType:Camera.DestinationType.FILE_URI,sourceType:Camera.PictureSourceType.CAMERA,encodingType:Camera.EncodingType.JPEG};$cordovaCamera.getPicture(options).then(function(fileURL){deferred.resolve(fileURL)})}else deferred.reject("Not Supported in browser");return deferred.promise},library:function(){var deferred=$q.defer();if(ionic.Platform.isWebView()){var options={quality:80,destinationType:Camera.DestinationType.FILE_URI,sourceType:Camera.PictureSourceType.PHOTOLIBRARY,encodingType:Camera.EncodingType.JPEG};$cordovaCamera.getPicture(options).then(function(fileURL){deferred.resolve(fileURL)})}else deferred.reject("Not Supported in browser");return deferred.promise}}}).factory("Upload",function($q,$cordovaCamera,$cordovaFileTransfer,$localStorage){return{profilePicture:function(fileURL){var deferred=$q.defer();if(ionic.Platform.isWebView()){var serverURL="/api/v1/users/"+$localStorage.username+"/uploadprofilepic",uploadOptions=new FileUploadOptions;uploadOptions.fileKey="file",uploadOptions.fileName=fileURL.substr(fileURL.lastIndexOf("/")+1),uploadOptions.mimeType="image/jpeg";var ft=new FileTransfer;ft.upload(fileURL,encodeURI(serverURL),function(result){var response=result.response,responseObj=JSON.parse(response);deferred.resolve(responseObj)},function(err){deferred.reject(err)},uploadOptions)}else deferred.reject("Not Supported");return deferred.promise}}}),function(){return angular.module("trudesk.controllers",["trudesk.controllers.login","trudesk.controllers.dashboard","trudesk.controllers.tickets","trudesk.controllers.ticketDetails","trudesk.controllers.accounts","trudesk.controllers.messages","trudesk.controllers.messages.conversation","trudesk.controllers.imgCrop","trudesk.controllers.graphs"])}(),angular.module("trudesk.controllers.login",[]).controller("LoginCtrl",function($http,$scope,$state,$localStorage,$ionicLoading,$ionicPopup){function showError(err){var alertPopup=$ionicPopup.alert({title:"Error",template:err,okType:"button-assertive"});alertPopup.then(function(){})}$ionicLoading.show({templateUrl:"templates/modals/modal-loading.html",noBackdrop:!0,duration:1200}),$scope.auth={server:"",username:"",password:""},$scope.invalid={server:!1,username:!1,password:!1},$scope.login=function(loginForm){loginForm.$valid?($scope.invalid.server=!1,$scope.invalid.username=!1,$scope.invalid.password=!1,$ionicLoading.show({templateUrl:"templates/modals/modal-loading.html",noBackdrop:!0}),$scope.auth.server=$scope.auth.server.replace(/^https?:\/\//,""),$http.post("/api/v1/login",{username:$scope.auth.username,password:$scope.auth.password}).then(function(response){response.data.success===!1?showError(response.data.error):void 0!==response.data.accessToken&&($localStorage.server="",$localStorage.username=$scope.auth.username,$localStorage.accessToken=response.data.accessToken,$localStorage.loggedInUser=response.data.user,$http.defaults.headers.common.accesstoken=$localStorage.accessToken,window.plugins&&window.plugins.OneSignal&&(window.plugins.OneSignal.setSubscription(!0),window.plugins.OneSignal.sendTags({host:$localStorage.server,user:$localStorage.loggedInUser._id})),$http.get("/api/v1/roles",{headers:{accesstoken:$localStorage.accessToken}}).then(function(response){$localStorage.roles=response.data},function(response){console.log("Error",response)}).then(function(){$state.go("tab.dash")}))},function(response){switch(console.error(response),response.status){case-1:showError("Could not connect. Please check server and try again.");break;case 401:showError("Invalid Username / Password");break;default:showError("Could not connect. Please check server and try again.")}}).then(function(){setTimeout(function(){$ionicLoading.hide()},500)})):($scope.invalid.server=loginForm.server.$invalid,$scope.invalid.username=loginForm.username.$invalid,$scope.invalid.password=loginForm.password.$invalid)},ionic.on("$trudesk.clearLoginForm",function(){$scope.auth.server="",$scope.auth.username="",$scope.auth.password=""}),$scope.$on("$ionicView.enter",function(){setTimeout(function(){return void 0!==$localStorage.server&&void 0!==$localStorage.accessToken?$state.go("tab.dash"):(window.StatusBar&&window.StatusBar.styleDefault(),angular.element(document).find("ion-view").removeClass("hide"),void(window.plugins&&window.plugins.OneSignal&&window.plugins.OneSignal.setSubscription(!1)))},600)})}),angular.module("trudesk.controllers.accounts",[]).controller("AccountCtrl",function($q,$scope,$state,$http,$timeout,$localStorage,$ionicHistory,$ionicActionSheet,$ionicModal,$cordovaCamera,Camera,Users,Upload){$scope.server=$localStorage.server,$ionicModal.fromTemplateUrl("templates/modals/modal-imgcrop.html",{scope:$scope,animation:"slide-in-up"}).then(function(modal){$scope.imgcropModal=modal}),ionic.on("$trudesk.showCropper",function(){$scope.imgcropModal.show()}),ionic.on("$trudesk.hideCropper",function(){$scope.imgcropModal.hide()}),$scope.showActionSheet=function(event){if(ionic.Platform.isWebView()){$ionicActionSheet.show({buttons:[{text:"Take Photo"},{text:"Open Photo Library"}],titleText:"Account Picture",cancelText:"Cancel",cancel:function(){},buttonClicked:function(index){switch(index){case 0:return $scope.openCamera(),!0;case 1:return $scope.openPhotoLibrary(),!0;default:return!0}}})}},$scope.openCamera=function(){Camera.open().then(function(fileURL){ionic.trigger("$trudesk.imgcrop.setImage",{image:fileURL}),ionic.trigger("$trudesk.imgcrop.showCropper",{}),$scope.imgcropModal.show()})},$scope.openPhotoLibrary=function(){Camera.library().then(function(fileURL){ionic.trigger("$trudesk.imgcrop.setImage",{image:fileURL}),ionic.trigger("$trudesk.imgcrop.showCropper",{}),$scope.imgcropModal.show()}),ionic.on("$trudesk.account.updateImage",function(data){$scope.updateAccountImage()})},$scope.logout=function($event){$event.preventDefault(),$http.get("/logout/",{timeout:2e3}).then(function(response){},function(response){})["finally"](function(){return ionic.trigger("$trudesk.clearLoginForm",{}),$localStorage.server=void 0,$localStorage.accessToken=void 0,$http.defaults.headers.common.accesstoken=$localStorage.accessToken,window.plugins&&window.plugins.OneSignal&&window.plugins.OneSignal.setSubscription(!1),$ionicHistory.clearCache(),$state.go("login")})},$scope.updateAccountImage=function(){$localStorage.loggedInUser=null,Users.getLoggedInUser().then(function(user){$scope.loggedInUser=user,user.image?$scope.accountProfile="/uploads/users/"+$scope.loggedInUser.image+"?time="+(new Date).getTime():$scope.accountProfile="/uploads/users/defaultProfile.jpg"},function(err){console.log(err)})},$scope.$on("$ionicView.beforeEnter",function(){$scope.accountProfile||($scope.accountProfile="/uploads/users/defaultProfile.jpg"),$scope.updateAccountImage()})}),angular.module("trudesk.controllers.dashboard",[]).controller("DashCtrl",function($http,$scope,$state,$location,$ionicNavBarDelegate,$localStorage,Tickets){function getStats(timespan){Tickets.ticketStats(timespan).then(function(response){$scope.totalTickets=response.data.ticketCount?response.data.ticketCount:0;var closedCount=Number(response.data.closedCount);$scope.closedPercent=Math.round(closedCount/$scope.totalTickets*100),$scope.closedPercent=isNaN($scope.closedPercent)?"--":$scope.closedPercent,$scope.closedPercentPie=$scope.closedPercent+"/100",$scope.ticketAvg=response.data.ticketAvg?response.data.ticketAvg:0})}var path=$location.path();path.indexOf("dashboard")===-1?$ionicNavBarDelegate.showBackButton(!1):$ionicNavBarDelegate.showBackButton(!0),$scope.totalTickets=0,$scope.timespans=[{label:"30 Days",value:30},{label:"60 Days",value:60},{label:"90 Days",value:90},{label:"180 Days",value:180},{label:"365 Days",value:365}],$scope.selectedTimespan=30,$scope.barChart=[5,3,9,6,5,9,7],$scope.lineChart=[5,3,9,6,5,9,7,3,5,2],getStats(30),$scope.timespanChange=function($event){$scope.selectedTimespan=this.selectedTimespan,getStats($scope.selectedTimespan)},$scope.$on("$ionicView.enter",function(){window.StatusBar&&window.StatusBar.styleLightContent()}),$scope.$on("$ionicView.beforeEnter",function(){ensureLogin($localStorage,$state)})}),angular.module("trudesk.controllers.graphs",[]).controller("GraphCtrl",function($scope,$http,_,Graphs){$scope.renderGraphs=function(){Graphs.topGroups().then(function(response){var arr=[];_.size(response.data.items)<1&&(response.data.items=[{name:"No Data",count:1}]),arr=_.map(response.data.items,function(v,k){return[v.name,v.count]});var colors=["#e74c3c","#3498db","#9b59b6","#34495e","#1abc9c","#2ecc71","#03A9F4","#00BCD4","#009688","#4CAF50","#FF5722","#CDDC39","#FFC107","#00E5FF","#E040FB","#607D8B"];colors=_.shuffle(colors);var c=_.object(_.map(arr,function(v,i){return v[0]}),colors);c3.generate({bindto:"#topGroupsChart",size:{height:150,width:315},data:{columns:arr,type:"pie",colors:c},tooltip:{show:!1},pie:{label:{format:function(v,r,id){return""}}}})},function(err){console.error(err)})}}),angular.module("trudesk.controllers.imgCrop",[]).controller("imgCrop",function($scope,$state,$timeout,$localStorage,$cordovaCamera,Cropper,Camera,Upload,Users){function showCropper(){$scope.$broadcast($scope.showEvent)}function hideCropper(){$scope.$broadcast($scope.hideEvent)}$scope.options={maximize:!0,aspectRatio:1,checkImageOrigin:!0,rotatable:!0,viewMode:1,dragMode:"move",checkOrientation:!0},$scope.cropper={},$scope.cropperProxy="cropper.first",Users.getLoggedInUser().then(function(user){$scope.loggedInUser=user},function(error){console.log(error)}),$scope.showEvent="showCropper",$scope.hideEvent="hideCropper",$scope.close=function(){ionic.trigger("$trudesk.hideCropper",{})},$scope.save=function(){if($scope.cropper.first){var canvas=$scope.cropper.first("getCroppedCanvas",{width:256,height:256}),image=canvas.toDataURL();Upload.profilePicture(image).then(function(response){ionic.trigger("$trudesk.account.updateImage",{image:response.user.image})},function(err){console.log(err)})["finally"](function(){$scope.close()})}},ionic.on("$trudesk.imgcrop.showCropper",function(){$timeout(function(){hideCropper(),showCropper()},0)}),ionic.on("$trudesk.imgcrop.setImage",function(data){return void 0===data.detail||void 0===data.detail.image?console.log("Invalid data.detail.image"):void($scope.o=data.detail.image)})}),angular.module("trudesk.controllers.messages",[]).controller("MessagesCtrl",function($scope,$state,$stateParams,$localStorage,$ionicListDelegate,$ionicNavBarDelegate,$ionicModal,$ionicPopup,$ionicActionSheet,$ionicLoading,$ionicScrollDelegate,$ionicFilterBarConfig,$ionicFilterBar,$timeout,$q,WebSocket,Messages,Users){function onUpdateUsers(data){$timeout(function(){$scope.onlineUsers=data.detail,delete $scope.onlineUsers[$scope.loggedInUser.username],$ionicScrollDelegate.$getByHandle("activeUsersScroll").resize()},0)}$ionicNavBarDelegate.showBackButton(!0),$ionicFilterBarConfig.theme="dark",$ionicModal.fromTemplateUrl("templates/modals/modal-messages-newconversation.html",{scope:$scope,animation:"slide-in-up"}).then(function(modal){$scope.newConversation=modal}),$scope.server=$localStorage.server,$scope.socket=WebSocket,$scope.recentConversations=[],$scope.isUserOnline=Users.isUserOnline,$scope.onlineUsers=[],$scope.userList=[],$scope.$on("$ionicView.beforeEnter",function(){ensureLogin($localStorage,$state),$scope.server=$localStorage.server,Users.getLoggedInUser().then(function(user){$scope.loggedInUser=user},function(err){console.log(err)}).then(function(){ionic.on("$trudesk.conversation.updateusers",onUpdateUsers,window),$timeout(function(){$scope.loadRecentConversations()},0)})}),$scope.$on("$ionicView.enter",function(scopes,states){}),$scope.$on("$stateChangeStart",function(e){ionic.off("$trudesk.conversation.updateusers",onUpdateUsers,window)}),$scope.loadRecentConversations=function(){Messages.getRecent().then(function(response){$scope.recentConversations=response.data.conversations,$scope.showRecentConversations=_.size($scope.recentConversations)>=1},function(err){console.log(err),$scope.showRecentConversations=!1})},$scope.showNewConversation=function(){$scope.getUserList().then(function(){$scope.newConversation.show()})},$scope.hideNewConversation=function(){filterBarInstance&&(filterBarInstance(),filterBarInstance=null),$scope.newConversation.hide()},$scope.startConversation=function(userId){Messages.startConversation(userId).then(function(response){var convoId=response.data.conversation._id;return void 0!==convoId?(void 0!==$scope.newConversation&&$scope.hideNewConversation(),$state.go("tab.messages-conversation",{conversationid:convoId})):void $scope.showSnackbar("Invalid Conversation Id",!0)},function(error){$scope.showSnackbar(error,!0),console.log(error)})},$scope.deleteConversation=function(convoId){Messages.deleteConversation(convoId).then(function(response){if(response.data.success){var convo=_.find($scope.recentConversations,function(obj){return obj._id.toString()===convoId.toString()}),idx=$scope.recentConversations.indexOf(convo);idx!==-1&&$scope.recentConversations.splice(idx,1)}},function(error){$scope.showSnackbar(error,!0),console.log(error)})["finally"](function(){$timeout(function(){$scope.loadRecentConversations()},0)})},$scope.getUserList=function(){return Users.getUsers().then(function(res){for(var list=res.data.users,i=0;i0&&($scope.messages=_.uniq(_.union(a,response.data.messages),!1,function(i,k,a){return i._id})),$scope.messages=_.sortBy($scope.messages,function(message){return message.createdAt})}_.size(response.data.messages)<10&&($scope.hasMore=!1)},function(err){console.log(err)}).then(function(){$timeout(function(){0==$scope.page?scrollBottom():$timeout(function(){viewScroll.scrollBy(0,150,!0)}),$scope.page++,$scope.$broadcast("scroll.infiniteScrollComplete")},0)})},$scope.$on("elastic:resize",function(event,element,oldHeight,newHeight){$(".message-textbox").css("max-height",newHeight+"px").css("height",newHeight+"px"),element.css("max-height",newHeight-1+"px"),newHeight>=100?(element.css("max-height","99px"),element.css({bottom:"5px"}),$(".message-textbox").css("max-height","105px").css("height","105px")):element.css({bottom:"0"})}),$scope.chatTyping=function(event){if(!(event.shiftKey&13===event.keyCode||13===event.keyCode&&ionic.Platform.isWebView())){if(13===event.keyCode&&!ionic.Platform.isWebView())return event.preventDefault(),$scope.sendChatMessage();if(isTyping)return clearTimeout(typingTimer),void(typingTimer=setTimeout(stopTyping,5e3));isTyping=!0,void 0==typingTimer&&(typingTimer=setTimeout(stopTyping,5e3)),WebSocket.startTyping($scope.conversation._id,$scope.conversation.partner._id,$localStorage.loggedInUser._id)}},$scope.shouldShowDate=function(date){var now=moment(),dMoment=moment(date),timeDiff=now.diff(dMoment,"minutes");return timeDiff>60},$scope.canFetchMoreMessages=function(){return void 0===$scope.hasMore&&($scope.hasMore=!0),$scope.hasMore},$scope.loadMore=function(){if(console.log("loading more"),i++,i>10&&($scope.hasMore=!1),void 0!==$scope.conversation)for(var j=0;j<11;j++){var message={createdAt:new Date,body:"here",owner:$localStorage.loggedInUser,_id:Math.random()};$scope.conversation.messages.unshift(message)}$timeout(function(){viewScroll.scrollBy(0,150,!0)}),$timeout(function(){$scope.$broadcast("scroll.infiniteScrollComplete")},3e3)},$scope.sendChatMessage=function(){if(_.isEmpty($scope.message.body))return!1;$scope.message.ownerId=$scope.loggedInUser._id;var scopeMessageClone=_.clone($scope.message);$scope.message.body="",Messages.sendMessage($scope.conversation._id,scopeMessageClone).then(function(response){var message=response.data.message;WebSocket.send($scope.conversation._id,$scope.conversation.partner._id,$scope.loggedInUser._id,message._id,message.body),stopTyping(),keepKeyboardOpen(),scrollBottom()},function(err){console.log(err)})}}),angular.module("trudesk.controllers.ticketDetails",[]).controller("TicketsDetailCtrl",function($scope,$state,$stateParams,$ionicHistory,$ionicNavBarDelegate,$localStorage,$ionicModal,$ionicPopover,$ionicActionSheet,Tickets,Users){$ionicNavBarDelegate.showBackButton(!0),$scope.showSnackbar=function(text,error){_.isUndefined(error)&&(error=!1);var textColor="#FFFFFF";error&&(textColor="#ef473a"),Snackbar.show({text:text,showAction:!1,duration:3e3,textColor:textColor})},$scope.server=$localStorage.server,$scope.loggedInUser=void 0,$scope.commentModalForm={comment:""},$scope.noteModalForm={note:""},$scope.isSupport="admin"===$localStorage.loggedInUser.role||"mod"===$localStorage.loggedInUser.role||"support"===$localStorage.loggedInUser.role,$ionicModal.fromTemplateUrl("templates/modals/modal-ticket-details.html",{scope:$scope,animation:"slide-in-up"}).then(function(modal){$scope.ticketDetailModal=modal}),$ionicModal.fromTemplateUrl("templates/modals/modal-addComment.html",{scope:$scope,animation:"slide-in-up"}).then(function(modal){$scope.addCommentModal=modal}),$ionicModal.fromTemplateUrl("templates/modals/modal-addNote.html",{scope:$scope,animation:"slide-in-up"}).then(function(modal){$scope.addNoteModal=modal}),$ionicModal.fromTemplateUrl("templates/modals/modal-ticket-setAssignee.html",{scope:$scope,animation:"slide-in-up",focusFirstInput:!0}).then(function(modal){$scope.setAssigneeModal=modal}),Tickets.get($stateParams.ticketuid).then(function(response){$scope.ticket=response.data.ticket,$scope.ticket.assignee&&($scope.selectedAssignee=$scope.ticket.assignee._id),void 0===$scope.ticket.owner.image&&($scope.ticket.owner.image="defaultProfile.jpg"),$scope.hasAssignee="hide",void 0!==$scope.ticket.assignee&&($scope.hasAssignee="show"),void 0!==$scope.ticket.assignee&&void 0===$scope.ticket.assignee.image&&($scope.ticket.assignee.image="defaultProfile.jpg"),$scope.isSupport?$scope.ticket.commentsMerged=_.sortBy(_.union($scope.ticket.comments,$scope.ticket.notes),"date"):$scope.ticket.commentsMerged=$scope.ticket.comments}),Users.getAssignees().then(function(response){$scope.assignees=response.data.users},function(response){console.log(response)}),$scope.popover=$ionicPopover.fromTemplateUrl("templates/popover/popover-ticket-details.html",{scope:$scope}).then(function(popover){$scope.popover=popover}),$scope.showStatusActionSheet=function(){$scope.popover.hide(),$ionicActionSheet.show({buttons:[{text:"Open"},{text:"Pending"},{text:"Closed"}],titleText:"Set Ticket Status",cancelText:"Cancel",cancel:function(){return!0},buttonClicked:function(index){switch(index){case 0:var reqTicket={_id:$scope.ticket._id};return reqTicket.status=1,Tickets.update(reqTicket).then(function(response){$scope.ticket.status=1,$scope.showSnackbar("Ticket status set to Open")},function(response){console.log(response)}),!0;case 1:var reqTicket={_id:$scope.ticket._id};return reqTicket.status=2,Tickets.update(reqTicket).then(function(response){$scope.ticket.status=2,$scope.showSnackbar("Ticket status set to Pending")},function(response){console.log(response)}),!0;case 2:var reqTicket={_id:$scope.ticket._id};return reqTicket.status=3,$scope.ticket.status=3,Tickets.update(reqTicket).then(function(response){ionic.trigger("$trudesk.refreshTickets",{}),$scope.popover.hide(),$ionicHistory.goBack()},function(response){console.log(response)}),!0;default:return!0}}})},$scope.setAssigneeChanged=function(){$scope.selectedAssignee=this.selectedAssignee},$scope.showAddComment=function($event){Users.getLoggedInUser().then(function(user){$scope.loggedInUser=user}).then(function(){$scope.addCommentModal.show(),$scope.popover.hide()})},$scope.closeAddComment=function(){$scope.commentModalForm.comment="",$scope.addCommentModal.hide()},$scope.showAddNote=function($event){Users.getLoggedInUser().then(function(user){$scope.loggedInUser=user}).then(function(){$scope.addNoteModal.show(),$scope.popover.hide()})},$scope.closeAddNote=function(){$scope.noteModalForm.note="",$scope.addNoteModal.hide()},$scope.openSetAssigneeModal=function(){$scope.setAssigneeModal.show(),$scope.popover.hide()},$scope.closeSetAssigneeModal=function(){void 0!==$scope.setAssigneeModal&&$scope.setAssigneeModal.hide()},$scope.showTicketDetails=function(){$scope.ticketDetailModal.show(),$scope.popover.hide()},$scope.closeTicketDetailsModal=function(){$scope.ticketDetailModal.hide()},$scope.closeTicket=function(){$scope.ticket.status=3,Tickets.update($scope.ticket).then(function(response){ionic.trigger("$trudesk.refreshTickets",{}),$scope.popover.hide(),$ionicHistory.goBack()},function(response){console.log(response)})},$scope.addCommentFormSubmit=function(){var comment={ownerId:$scope.loggedInUser._id,comment:this.commentModalForm.comment};Tickets.addComment($scope.ticket,comment).then(function(response){},function(err){console.log(err),$scope.showSnackbar(err,!0)}).then(function(){Tickets.get($stateParams.ticketuid).then(function(response){$scope.ticket=response.data.ticket,$scope.isSupport?$scope.ticket.commentsMerged=_.sortBy(_.union($scope.ticket.comments,$scope.ticket.notes),"date"):$scope.ticket.commentsMerged=$scope.ticket.comments,void 0===$scope.ticket.owner.image&&($scope.ticket.owner.image="defaultProfile.jpg")}).then(function(){$scope.commentModalForm.comment="",$scope.closeAddComment()})})},$scope.addNoteFormSubmit=function(){var note={ownerId:$scope.loggedInUser._id,note:this.noteModalForm.note};Tickets.addNote($scope.ticket,note).then(function(response){},function(err){console.log(err),$scope.showSnackbar(err,!0)}).then(function(){Tickets.get($stateParams.ticketuid).then(function(response){$scope.ticket=response.data.ticket,$scope.isSupport?$scope.ticket.commentsMerged=_.sortBy(_.union($scope.ticket.comments,$scope.ticket.notes),"date"):$scope.ticket.commentsMerged=$scope.tickets.comments,void 0===$scope.ticket.owner.image&&($scope.ticket.owner.image="defaultProfile.jpg")}).then(function(){$scope.noteModalForm.note="",$scope.closeAddNote()})})},$scope.setAssigneeFormSubmit=function(){return $scope.ticket?$scope.ticket.assignee&&$scope.ticket.assignee._id===$scope.selectedAssignee?void $scope.setAssigneeModal.hide():($scope.ticket.assignee=$scope.selectedAssignee,void Tickets.update($scope.ticket).then(function(response){$scope.ticket=response.data.ticket,$scope.hasAssignee="hide",void 0!==$scope.ticket.assignee&&($scope.hasAssignee="show"),void 0!==$scope.ticket.assignee&&void 0===$scope.ticket.assignee.image&&($scope.ticket.assignee.image="defaultProfile.jpg"),$scope.isSupport?$scope.ticket.commentsMerged=_.sortBy(_.union($scope.ticket.comments,$scope.ticket.notes),"date"):$scope.ticket.commentsMerged=$scope.ticket.comments,$scope.setAssigneeModal.hide()},function(response){console.log(response.data),$scope.showSnackbar("Error: "+response.data,!0)})):void $scope.showSnackbar("Invalid Ticket Object",!0)},$scope.$on("$ionicView.beforeEnter",function(){ensureLogin($localStorage,$state)}),$scope.$on("$destroy",function(){$scope.popover.remove(),$scope.addCommentModal.remove(),$scope.addNoteModal.remove(),$scope.ticketDetailModal.remove(),$scope.setAssigneeModal.remove()})}),angular.module("trudesk.controllers.tickets",[]).controller("TicketsCtrl",function($scope,$state,$timeout,$stateParams,$localStorage,$ionicListDelegate,$ionicNavBarDelegate,$ionicModal,$ionicPopup,$ionicActionSheet,$ionicLoading,$q,Tickets,Users,Groups,TicketTypes){$ionicNavBarDelegate.showBackButton(!0),$ionicModal.fromTemplateUrl("templates/modals/modal-newticket.html",{scope:$scope,animation:"slide-in-up"}).then(function(modal){$scope.newTicketModal=modal}),$ionicModal.fromTemplateUrl("templates/modals/modal-ticket-filter.html",{scope:$scope,animation:"slide-in-up"}).then(function(modal){$scope.filterTicketModal=modal}),$ionicModal.fromTemplateUrl("templates/modals/modal-addComment.html",{scope:$scope,animation:"slide-in-up"}).then(function(modal){$scope.addCommentModal=modal}),$scope.showLoadingTickets=!0,$scope.search={term:""},$scope.filter={},$scope.filter.showClosedTickets=$localStorage.showClosedTickets,$scope.filter.showOnlyAssigned=$localStorage.showOnlyAssigned,$scope.commentModalForm={comment:"",ticket:""},$scope.isSupport="admin"==$localStorage.loggedInUser.role||"mod"==$localStorage.loggedInUser.role||"support"==$localStorage.loggedInUser.role,$scope.showSnackbar=function(text,error){_.isUndefined(error)&&(error=!1);var textColor="#FFFFFF";error&&(textColor="#ef473a"),Snackbar.show({text:text,showAction:!0,actionText:"X",actionTextColor:"#ccc",duration:3e3,textColor:textColor})},$scope.showActionSheet=function($event,$ticket){$ionicListDelegate.closeOptionButtons();var buttons=[{text:"Add Comment"}];$scope.isSupport&&(buttons.push({text:"Open"}),buttons.push({text:"Pending"}),buttons.push({text:"Closed"}));$ionicActionSheet.show({buttons:buttons,titleText:"Ticket Options",cancelText:"Cancel",cancel:function(){},buttonClicked:function(index){switch(index){case 0:var t=_.find($scope.tickets,function(obj){return obj._id==$ticket._id});return $scope.commentModalForm.ticket=t,$scope.addCommentModal.show(),!0;case 1:var t=_.find($scope.tickets,function(obj){return obj._id==$ticket._id}),reqTicket={_id:t._id};return reqTicket.status=1,Tickets.update(reqTicket).then(function(response){t.status=1,$scope.showSnackbar("Ticket status set to Open")},function(response){console.log(response)}),!0;case 2:var t=_.find($scope.tickets,function(obj){return obj._id==$ticket._id}),reqTicket={_id:t._id};return reqTicket.status=2,Tickets.update(reqTicket).then(function(response){t.status=2,$scope.showSnackbar("Ticket status set to Pending")},function(response){console.log(response)}),!0;case 3:var t=_.find($scope.tickets,function(obj){return obj._id==$ticket._id}),reqTicket={_id:t._id};return reqTicket.status=3,Tickets.update(reqTicket).then(function(response){var idx=$scope.tickets.indexOf(t);idx!=-1&&$scope.tickets.splice(idx,1),$scope.showSnackbar("Ticket status set to Closed")},function(response){console.log(response)})["finally"](function(){_.size($scope.tickets)<1?$scope.showNoTickets=!0:$scope.showNoTickets=!1}),!0;default:return!0}}})},$scope.doRefresh=function(){$scope.search.term="",$scope.shouldRefresh=!0,$scope.fetchTickets()["finally"](function(){$scope.$broadcast("scroll.refreshComplete")})},$scope.getUserImage=function(imageFile){var url="http://"+$localStorage.server+"/uploads/users/"+imageFile;return Users.getImage(url).then(function(image){console.log(image)})},$scope.fetchTickets=function(){return angular.element(document).find("ion-item").removeClass("item-remove-animate"),void 0==$scope.page&&($scope.page=0),$scope.shouldRefresh&&($scope.page=0,$scope.hasMoreTickets=!0,$scope.shouldRefresh=!1),Tickets.all($scope.page).then(function(response){if(_.size(response.data)<1)return void($scope.hasMoreTickets=!1);if(0==$scope.page)$scope.tickets=response.data;else{var a=$scope.tickets;_.size(a)>0&&($scope.tickets=_.uniq(_.union(a,response.data),!1,function(i,k,a){return i._id}))}},function(error){return $scope.$broadcast("scroll.infiniteScrollComplete"),$scope.hasMoreTickets=!1,error.status===-1?$scope.showAlert("Error","Connection Refused."):401===error.status?(ionic.trigger("$trudesk.clearLoginForm",{}),$localStorage.server=void 0,$localStorage.accessToken=void 0,$state.go("login"),$scope.showAlert("Error","You have been logged out.")):void $scope.showAlert("Error","Error Status: "+error.status)})["finally"](function(){$scope.showLoadingTickets=!1,_.size($scope.tickets)>0?$scope.showNoTickets=!1:$scope.showNoTickets=!0,$scope.page++,$scope.$broadcast("scroll.infiniteScrollComplete")})},$scope.canFetchMoreTickets=function(){return void 0===$scope.hasMoreTickets&&($scope.hasMoreTickets=!0),$scope.hasMoreTickets},$scope.selected={group:"",ticketType:"",priority:""},$scope.$watch("selected.ticketType",function(newValue,oldValue,scope){newValue&&newValue.priorities&&($scope.selected.priority=newValue.priorities[0])},!0),$scope.openNewTicket=function(){var groups=Groups.all(),types=TicketTypes.all();$q.all([groups,types]).then(function(results){$scope.groups=results[0].data.groups,$scope.ticketTypes=results[1].data,$scope.ticketTypes[0]&&$scope.ticketTypes[0]._id&&($scope.selected.ticketType=$scope.ticketTypes[0]),$scope.modalNewTicketForm={subject:"",issue:""},$scope.selected.group=""},function(error){console.error("Error - "+error)}).then(function(){$scope.newTicketModal.show()})},$scope.closeNewTicket=function(){$scope.newTicketModal.hide()},$scope.openFilterTicket=function(){$scope.filterTicketModal.show()},$scope.applyTicketFilter=function(){$scope.closeTicketFilter()},$scope.closeTicketFilter=function(){return""!==$scope.search.term?($scope.tickets=[],$scope.filterTicketModal.hide(),Snackbar.show({text:"Loading...",showAction:!1,duration:2147483647,textColor:"#FFFFFF"}),Tickets.search($scope.search.term).then(function(response){$scope.tickets=response.data.tickets,$timeout(function(){_.size($scope.tickets)<1?$scope.showNoTickets=!0:$scope.showNoTickets=!1},0),$scope.hasMoreTickets=!1,Snackbar.close()},function(response){console.log(response)})):($scope.filterTicketModal.hide(),void($scope.shouldRefresh&&$scope.fetchTickets()))},$scope.clearTicketFilter=function(){$scope.search.term="",$scope.tickets=null,$scope.filter.showClosedTickets=!1,$scope.filter.showOnlyAssigned=!1,$localStorage.showClosedTickets=!1,$localStorage.showOnlyAssigned=!1,ionic.trigger("$trudesk.refreshTickets",{}),$scope.filterTicketModal.hide()},$scope.searchTermChanged=function(){$scope.shouldRefresh=!0},$scope.showClosedTicketsChanged=function(){$scope.filter.showClosedTickets=this.filter.showClosedTickets,$localStorage.showClosedTickets=$scope.filter.showClosedTickets,$scope.shouldRefresh=!0},$scope.showOnlyAssigneedChanged=function(){$scope.filtershowOnlyAssigneed=this.filter.showOnlyAssigned,$localStorage.showOnlyAssigned=$scope.filter.showOnlyAssigned,$scope.shouldRefresh=!0},$scope.closeAddComment=function(){$scope.addCommentModal.hide()},$scope.modalNewTicketForm={subject:"",issue:""},$scope.addCommentFormSubmit=function(){var comment={ownerId:$scope.loggedInUser._id,comment:this.commentModalForm.comment};Tickets.addComment($scope.commentModalForm.ticket,comment).then(function(response){},function(err){console.log(err),$scope.showSnackbar(err,!0)}).then(function(){$scope.commentModalForm.comment="",$scope.commentModalForm.ticket="",$scope.closeAddComment()})},$scope.submitNewTicket=function($event){$event.preventDefault();var ticket={type:$scope.selected.ticketType,subject:this.modalNewTicketForm.subject,issue:this.modalNewTicketForm.issue,group:$scope.selected.group,priority:$scope.selected.priority};ticket.type&&ticket.subject&&ticket.issue&&ticket.group&&ticket.priority&&Tickets.create(ticket).then(function(response){ionic.trigger("$trudesk.refreshTickets",{}),$scope.modalNewTicketForm={subject:"",issue:""},$scope.closeNewTicket()},function(response){console.log("Error----"),console.log(response),$scope.showAlert("Error: "+response.statusText,response.data.error.message)}).then(function(){})},$scope.showAlert=function(title,text,button){return void 0===button&&(button="button-assertive"),$ionicPopup.alert({title:title,template:text,okType:button})},ionic.on("$trudesk.refreshTickets",function(){$scope.doRefresh()}),$scope.$on("$ionicView.beforeEnter",function(){ensureLogin($localStorage,$state),$scope.server=$localStorage.server,Users.getLoggedInUser().then(function(user){$scope.loggedInUser=user},function(err){console.log(err)})}),$scope.$on("$ionicView.enter",function(){_.size($scope.tickets)<1&&$scope.doRefresh()}),$scope.$on("$destroy",function(){$scope.newTicketModal.remove(),$scope.filterTicketModal.remove(),$scope.addCommentModal.remove()})}); \ No newline at end of file diff --git a/mobile/lib/angular-img-http-src/.bower.json b/mobile/lib/angular-img-http-src/.bower.json new file mode 100644 index 000000000..ab8ad7809 --- /dev/null +++ b/mobile/lib/angular-img-http-src/.bower.json @@ -0,0 +1,40 @@ +{ + "name": "angular-img-http-src", + "version": "1.0.1", + "authors": [ + "Doug Moscrop " + ], + "description": "Fetch images via $http and set src to a Blob URL", + "main": "index.js", + "moduleType": [ + "globals" + ], + "keywords": [ + "angular", + "img", + "http", + "token-based-auth" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "angular": "1.x" + }, + "homepage": "https://github.com/dmoscrop/angular-img-http-src", + "_release": "1.0.1", + "_resolution": { + "type": "version", + "tag": "v1.0.1", + "commit": "3835b5b271134daeeab0d323f792d0a1560eab87" + }, + "_source": "https://github.com/dmoscrop/angular-img-http-src.git", + "_target": "^1.0.1", + "_originalSource": "angular-img-http-src", + "_direct": true +} \ No newline at end of file diff --git a/mobile/lib/angular-img-http-src/LICENSE b/mobile/lib/angular-img-http-src/LICENSE new file mode 100644 index 000000000..d9a8d815e --- /dev/null +++ b/mobile/lib/angular-img-http-src/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014 Doug Moscrop + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/mobile/lib/angular-img-http-src/README.md b/mobile/lib/angular-img-http-src/README.md new file mode 100644 index 000000000..c36be2695 --- /dev/null +++ b/mobile/lib/angular-img-http-src/README.md @@ -0,0 +1,8 @@ +# angular-img-http-src +Status: Go horse. + +## Problem +You used token based auth and you need to serve images from secured routes. + +## Solution +Use `http-src` instead of `ng-src` and it will fetch images using the `$http` service - meaning Authorization headers added via interceptors will be present - then build a `Blob` and set the `src` to an [objectURL](https://developer.mozilla.org/en-US/docs/Web/API/URL.createObjectURL). diff --git a/mobile/lib/angular-img-http-src/bower.json b/mobile/lib/angular-img-http-src/bower.json new file mode 100644 index 000000000..b883a1be6 --- /dev/null +++ b/mobile/lib/angular-img-http-src/bower.json @@ -0,0 +1,29 @@ +{ + "name": "angular-img-http-src", + "version": "1.0.1", + "authors": [ + "Doug Moscrop " + ], + "description": "Fetch images via $http and set src to a Blob URL", + "main": "index.js", + "moduleType": [ + "globals" + ], + "keywords": [ + "angular", + "img", + "http", + "token-based-auth" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "angular": "1.x" + } +} diff --git a/mobile/lib/angular-img-http-src/index.js b/mobile/lib/angular-img-http-src/index.js new file mode 100644 index 000000000..d63b805a6 --- /dev/null +++ b/mobile/lib/angular-img-http-src/index.js @@ -0,0 +1,42 @@ +(function () { + 'use strict'; + /*global angular, Blob, URL */ + + angular.module('angular.img', [ + ]).directive('httpSrc', ['$http', function ($http) { + return { + link: function ($scope, elem, attrs) { + function revokeObjectURL() { + if ($scope.objectURL) { + URL.revokeObjectURL($scope.objectURL); + } + } + + $scope.$watch('objectURL', function (objectURL) { + elem.attr('src', objectURL); + }); + + $scope.$on('$destroy', function () { + revokeObjectURL(); + }); + + attrs.$observe('httpSrc', function (url) { + revokeObjectURL(); + + if(url && url.indexOf('data:') === 0) { + $scope.objectURL = url; + } else if(url) { + $http.get(url, { responseType: 'arraybuffer' }) + .then(function (response) { + var blob = new Blob( + [ response.data ], + { type: response.headers('Content-Type') } + ); + $scope.objectURL = URL.createObjectURL(blob); + }); + } + }); + } + }; + }]); +}()); diff --git a/mobile/lib/angular-img-http-src/package.json b/mobile/lib/angular-img-http-src/package.json new file mode 100644 index 000000000..921510dd1 --- /dev/null +++ b/mobile/lib/angular-img-http-src/package.json @@ -0,0 +1,25 @@ +{ + "name": "angular-img-http-src", + "version": "1.0.1", + "description": "Use $http service to fetch img src as objectURL", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/dougmoscrop/angular-img-http-src.git" + }, + "keywords": [ + "Angular" + ], + "author": "Doug Moscrop ", + "license": "MIT", + "bugs": { + "url": "https://github.com/dougmoscrop/angular-img-http-src/issues" + }, + "homepage": "https://github.com/dougmoscrop/angular-img-http-src#readme", + "peerDependencies": { + "angular": "1.x" + } +} diff --git a/mobile/lib/ionic/js/ionic-angular.js b/mobile/lib/ionic/js/ionic-angular.js index ae5bc96fb..c46547d39 100644 --- a/mobile/lib/ionic/js/ionic-angular.js +++ b/mobile/lib/ionic/js/ionic-angular.js @@ -2660,9 +2660,18 @@ function($rootScope, $ionicBody, $compile, $timeout, $ionicPlatform, $ionicTempl } return $timeout(function() { - if (!modalStack.length) { + var otherSibling = false; + for (var i = 0; i < modalStack.length; ++i) { + if (modalStack[i].viewType === self.viewType) { + // there are other modal (or popover, depending on viewType) + otherSibling = true; + break; + } + } + if (!otherSibling) { $ionicBody.removeClass(self.viewType + '-open'); } + self.el.classList.add('hide'); }, self.hideDelay || 320); }, diff --git a/mobile/lib/ionic/js/ionic.bundle.js b/mobile/lib/ionic/js/ionic.bundle.js index 2ee2a0e32..c9b53a8e5 100644 --- a/mobile/lib/ionic/js/ionic.bundle.js +++ b/mobile/lib/ionic/js/ionic.bundle.js @@ -55843,7 +55843,15 @@ function($rootScope, $ionicBody, $compile, $timeout, $ionicPlatform, $ionicTempl } return $timeout(function() { - if (!modalStack.length) { + var otherSibling = false; + for (var i = 0; i < modalStack.length; ++i) { + if (modalStack[i].viewType === self.viewType) { + // there are other modal (or popover, depending on viewType) + otherSibling = true; + break; + } + } + if (!otherSibling) { $ionicBody.removeClass(self.viewType + '-open'); } self.el.classList.add('hide'); diff --git a/mobile/templates/conversation.html b/mobile/templates/conversation.html index 43e982eda..1eb3c256a 100644 --- a/mobile/templates/conversation.html +++ b/mobile/templates/conversation.html @@ -11,8 +11,8 @@
- - + +

{{conversation.partner.fullname}}

@@ -37,8 +37,8 @@

{{conversation.partner.fullname}}

{{message.createdAt | amCalendar}}
- - + +
@@ -50,8 +50,8 @@

{{conversation.partner.fullname}}

diff --git a/mobile/templates/modals/modal-addComment.html b/mobile/templates/modals/modal-addComment.html index 1fd5615f3..638f2c05c 100644 --- a/mobile/templates/modals/modal-addComment.html +++ b/mobile/templates/modals/modal-addComment.html @@ -7,7 +7,8 @@

Add Comment

- + +
{{'' | currentdate}}

Ticket #{{ticket.uid}}

diff --git a/mobile/templates/modals/modal-addNote.html b/mobile/templates/modals/modal-addNote.html index 86f009c9c..cb811f088 100644 --- a/mobile/templates/modals/modal-addNote.html +++ b/mobile/templates/modals/modal-addNote.html @@ -7,7 +7,8 @@

Add Note

- + +
{{'' | currentdate}}

Ticket #{{ticket.uid}}

diff --git a/mobile/templates/modals/modal-messages-newconversation.html b/mobile/templates/modals/modal-messages-newconversation.html index 21a36a6cf..b22847d50 100644 --- a/mobile/templates/modals/modal-messages-newconversation.html +++ b/mobile/templates/modals/modal-messages-newconversation.html @@ -16,12 +16,12 @@

Start Conversation< style="min-height:50px;" ng-click="startConversation(user._id);">
- +
- +
diff --git a/mobile/templates/tab-account.html b/mobile/templates/tab-account.html index 77501d62c..81851ea04 100644 --- a/mobile/templates/tab-account.html +++ b/mobile/templates/tab-account.html @@ -15,7 +15,7 @@
- +

{{loggedInUser.fullname}}

{{loggedInUser.title}}

{{loggedInUser.email}}

diff --git a/mobile/templates/tab-messages.html b/mobile/templates/tab-messages.html index 8917caa27..60f2a0f30 100644 --- a/mobile/templates/tab-messages.html +++ b/mobile/templates/tab-messages.html @@ -28,8 +28,8 @@ ng-repeat="userObj in onlineUsers track by userObj.user._id | orderBy: 'user'" ng-click="startConversation(userObj.user._id);">
- - + +
@@ -55,8 +55,8 @@
{{userObj.user.fullname}}
ng-repeat="userObj in onlineUsers track by userObj.user._id | orderBy: 'user'" ng-click="startConversation(userObj.user._id);">
- - + +
@@ -71,12 +71,12 @@
{{userObj.user.fullname}}
ng-repeat="convo in recentConversations track by convo._id | orderBy:'-updatedAt'" style="min-height: 50px;" href="#/tab/messages/{{convo._id}}" ng-show="showRecentConversations">
- +
- +
@@ -96,6 +96,36 @@

{{(convo.partic + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/templates/tab-tickets.html b/mobile/templates/tab-tickets.html index d5dff0b0c..49e4dfe03 100644 --- a/mobile/templates/tab-tickets.html +++ b/mobile/templates/tab-tickets.html @@ -35,10 +35,10 @@
- +
- +

T.{{ticket.uid}} - {{ticket.owner.fullname}}

{{ticket.date | date: 'short'}} diff --git a/mobile/templates/ticket-detail.html b/mobile/templates/ticket-detail.html index 9d14e9e81..841249866 100644 --- a/mobile/templates/ticket-detail.html +++ b/mobile/templates/ticket-detail.html @@ -8,14 +8,15 @@

- + +
{{ticket.date | date: 'short'}}

Ticket #{{ticket.uid}}

{{ticket.owner.fullname}}
{{ticket.group.name}}
- +
{{ticket.assignee.fullname}}
@@ -29,11 +30,11 @@

Issue

-
- +
+
-
- +
+

{{comment.owner.fullname}}

{{comment.date | date: 'short'}} diff --git a/src/middleware/index.js b/src/middleware/index.js index c6b7524d4..fc6c90a69 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -91,7 +91,7 @@ module.exports = function(app, db, callback) { app.use('/mobile', express.static(path.join(__dirname, '../../', 'mobile'))); app.use('/assets', express.static(path.join(__dirname, '../../public/uploads/assets'))); - app.use('/uploads', middleware.redirectToLogin, express.static(path.join(__dirname, '../../public/uploads'))); + app.use('/uploads', middleware.hasAuth, express.static(path.join(__dirname, '../../public/uploads'))); app.use(express.static(path.join(__dirname, '../../public'))); diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index a1b762a74..ed24d5161 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -179,6 +179,8 @@ middleware.api = function(req, res, next) { }); }; +middleware.hasAuth = middleware.api; + middleware.isAdmin = function(req, res, next) { if (req.user.role === 'admin') return next(); diff --git a/src/webserver.js b/src/webserver.js index e7aaf203c..4a8d7682d 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -98,7 +98,7 @@ var async = require('async'), hbsHelpers.register(hbs.handlebars); app.use('/assets', express.static(path.join(__dirname, '../public/uploads/assets'))); - app.use('/uploads', routeMiddleware.redirectToLogin, express.static(path.join(__dirname, '../public/uploads'))); + app.use('/uploads', routeMiddleware.hasAuth, express.static(path.join(__dirname, '../public/uploads'))); app.use(express.static(path.join(__dirname, '../public'))); app.use(favicon(path.join(__dirname, '../public/img/favicon.ico')));