<commit_before>'use strict';

var app = angular.module('myApp.controllers', [
  'myApp.authentications.controller',
  'myApp.brands.controller',
  'myApp.boxes.controller',
  'myApp.events.controller',
  'myApp.heartbeats.controller',
  'myApp.jobs.controller',
  'myApp.invoices.controller',
  'myApp.locations.controller',
  'myApp.port_forwards.controller',
  'myApp.projects.controller',
  'myApp.reports.controller',
  'myApp.speedtests.controller',
  'myApp.splash_pages.controller',
  'myApp.registrations.controller',
  'myApp.zones.controller',
  'myApp.users.controller',
  'myApp.vouchers.controller'
]);

app.controller('MainCtrl', ['$rootScope', '$scope', '$localStorage', '$window', '$location', '$routeParams', 'AccessToken', 'RefreshToken', 'Auth', 'API_END_POINT', '$pusher', '$route', 'onlineStatus', '$cookies', 'Brand', 'locationHelper', 'BrandName', 'CTLogin', 'User', 'Me', 'AUTH_URL', 'menu', 'designer', '$mdSidenav', 'docs', '$mdMedia', '$q', 'INTERCOM', 'PUSHER', 'gettextCatalog', 'Translate', 'COMMITHASH', '$mdDialog',

  function ($rootScope, $scope, $localStorage, $window, $location, $routeParams, AccessToken, RefreshToken, Auth, API, $pusher, $route, onlineStatus, $cookies, Brand, locationHelper, BrandName, CTLogin, User, Me, AUTH_URL, menu, designer, $mdSidenav, docs, $mdMedia, $q, INTERCOM, PUSHER, gettextCatalog, Translate, COMMITHASH, $mdDialog) {

    var domain = 'ctapp.io';

    $scope.brandName  = BrandName;
    $scope.commit     = COMMITHASH;
    $scope.ct_login   = CTLogin;

    function isOpen(section) {
      return (menu.isSectionSelected(section) && menu.isOpen());
    }

    $scope.toggle = function(section){
      $mdSidenav(section || 'left').toggle();
    };

    var toggleOpen = function(){
      if ($mdMedia('gt-sm')) {
        vm.menu.isOpenLeft = false;
        menu.isOpen = !menu.isOpen;
        vm._ctm = !vm._ctm;
        $cookies.put('_ctm', !menu.isOpen);
      } else {
        vm.menu.isOpenLeft = !vm.menu.isOpenLeft;
      }
      $(window).trigger('resize');
    };

    function toggle(section) {
      menu.toggleSelectSection(section);
    }

    var vm = this;

    vm._ctm = $cookies.get('_ctm');
    vm.menu = menu;

    vm.designer = designer;
    vm.toggle = toggle;

    if ($cookies.get('_ctm') === 'true') {
      vm.menu.isOpenLeft = false;
      vm.menu.isOpen = false;
    }

    vm.menu.main = [];
    // vm.menu.reports = [];
    vm.settingsMenu = [];
    vm.menuRight = [];

    // vm.menu.reports.push({
    //   title: gettextCatalog.getString('Reports'),
    //   type: 'link',
    //   link: '/#/reports',
    //   icon: 'timeline'
    // });

    // vm.menu.reports.push({
    //   title: gettextCatalog.getString('Audit'),
    //   type: 'link',
    //   link: '/#/audit',
    //   icon: 'assignment'
    // });

    vm.status = {
      isFirstOpen: true,
      isFirstDisabled: false
    };

    vm.menuRight.push({
      name: gettextCatalog.getString('Home'),
      link: '/#/',
      type: 'link',
      icon: 'home'
    });

    vm.menuRight.push({
      name: gettextCatalog.getString('Locations'),
      link: '/#/locations',
      type: 'link',
      icon: 'business'
    });

    vm.menuRight.push({
      name: gettextCatalog.getString('Events'),
      link: '/#/events',
      type: 'link',
      icon: 'warning'
    });

    vm.menuRight.push({
      name: gettextCatalog.getString('Reports'),
      link: '/#/reports',
      type: 'link',
      icon: 'timeline'
    });

    // vm.menuRight.push({
    //   name: gettextCatalog.getString('Audit'),
    //   link: '/#/audit',
    //   type: 'link',
    //   icon: 'assignment'
    // });

    vm.menuRight.push({
      type: 'divider',
    });

    vm.menuRight.push({
      name: gettextCatalog.getString('Developer'),
      link: '/#/apps',
      type: 'link',
      icon: 'android'
    });

    // Permissions //
    if ($localStorage.user && !$localStorage.user.custom) {
      vm.menuRight.push({
        name: gettextCatalog.getString('Documentation'),
        link: 'http://docs.cucumberwifi.io',
        type: 'link',
        target: '_blank',
        icon: 'account_balance'
      });

      vm.menuRight.push({
        name: gettextCatalog.getString('Discussions'),
        link: 'https://discuss.cucumberwifi.io',
        target: '_blank',
        type: 'link',
        icon: 'forum'
      });

      vm.menuRight.push({
        name: gettextCatalog.getString('Support'),
        icon: 'get_app',
        id: 'intercom'
      });
    }

    vm.menuRight.push({
      name: gettextCatalog.getString('Support'),
      icon: 'get_app',
      id: 'intercom'
    });

    vm.menuRight.push({
      name: gettextCatalog.getString('Downloads'),
      link: '/#/downloads',
      type: 'link',
      icon: 'get_app'
    });

    vm.menuRight.push({
      type: 'divider',
    });

    vm.showPromo = function(offer) {
      $mdDialog.show({
        controller: TrialController,
        templateUrl: 'components/views/main/promos.tmpl.html',
        parent: angular.element(document.body),
        clickOutsideToClose:true,
        locals: {
          offer: offer
        },
        fullscreen: $scope.customFullscreen // Only for -xs, -sm breakpoints.
      });
    };

    function TrialController($scope, $mdDialog, $sce, offer) {
      $scope.offer = $sce.trustAsHtml(offer);
      $scope.hide = function() {
        $mdDialog.hide();
      };

      $scope.upgrade = function() {
        $mdDialog.hide();
        $location.path('/users/' + Auth.currentUser().slug + '/billing');
        $location.search({trial: 'y'});
      };
    }

    vm.showUpgrade = function() {
      $mdDialog.show({
        controller: DialogController,
        templateUrl: 'components/views/main/upgrade.tmpl.html',
        parent: angular.element(document.body),
        clickOutsideToClose:true,
        fullscreen: $scope.customFullscreen // Only for -xs, -sm breakpoints.
      });
    };

    function DialogController($scope, $mdDialog) {
      $scope.hide = function() {
        $mdDialog.hide();
      };

      $scope.upgrade = function() {
        $mdDialog.hide();
        $location.path('/users/' + Auth.currentUser().slug + '/billing');
      };
    }

    $scope.toggleOpen = toggleOpen;

    $scope.$on('logout', function(args) {
      logout().then(function(response) {
        $route.reload();
        console.log('Refreshing Token.');
      }, function() {
        Auth.fullLogin();
      });
    });

    var logout = function(args) {
      var deferred = $q.defer();
      var user = $localStorage.user;
      var path = $location.path();
      AccessToken.del();
      if ( user && user.refresh ) {
        var host  = locationHelper.domain();
        $cookies.put('_ctp', JSON.stringify(path) );
        RefreshToken.refresh(user.refresh, path).then(function(response) {
          Auth.refresh(response).then(function(a){
            deferred.resolve();
          });
        }, function(er) {
          deferred.reject();
        });
      } else {
        deferred.reject();
      }
      return deferred.promise;
    };

    $scope.$on('login', function(args,event) {
      console.log('Logging in...');
      var cname = event.data.cname;
      if ((cname === null || cname === '') && event.data.url !== 'default') {
        var sub   = locationHelper.subdomain();
        var host  = locationHelper.domain();
        if (event.data.url && (sub !== event.data.url)) {
          var newUrl = locationHelper.reconstructed(event.data.url);
          var reconstructed = newUrl + '/#/';
          $cookies.put('event', JSON.stringify(event), {'domain': host});
          window.location = reconstructed;
        } else {
          doLogin(event);
        }
      } else {
        doLogin(event);
      }
    });

    function doLogin(event) {
      Auth.login(event.data).then(function(a) {
        var path;
        $scope.loggedIn = true;
        if (event.path) {
          path = event.path;
        } else {
          var raw = $cookies.get('_ctp');
          if (raw) {
            try{
              path = JSON.parse(raw);
            }catch(e){
              console.log('Couldn\'t parse JSON to redirect');
            }
          }
        }
        $location.path(path || '/').search(event.search || {});
        if (event !== undefined && event.rdir !== undefined) {
          $location.search({rdir: event.rdir});
        }
        $cookies.remove('_ctp');
        $scope.ct_login = undefined;
        // Translate.load();
      });
    }

    $scope.$on('intercom', function(args,event) {
      if (Auth.currentUser() && (Auth.currentUser().chat_enabled !== false && !Auth.currentUser().custom && Auth.currentUser().user_hash !== undefined)) {
        vm.menu.Intercom = true;
        var settings = {
            app_id: INTERCOM,
            user_id: Auth.currentUser().accountId,
            email: Auth.currentUser().email,
            name: Auth.currentUser().username,
            created_at: Auth.currentUser().created_at,
            user_hash: Auth.currentUser().user_hash,
            brand_name: Auth.currentUser().url,
            cname: Auth.currentUser().cname,
            sense_active: Auth.currentUser().sense_active,
            plan_name: Auth.currentUser().plan_name,
            paid_plan: Auth.currentUser().paid_plan,
            locs: Auth.currentUser().locs,
            version: '2'
        };
        settings.widget = {
          activator: '#intercom'
        };
        window.Intercom('boot', settings);
      }
    });

    function promos() {
      User.promos({}, {
        action: 'promos',
        id: Auth.currentUser().slug
      }).$promise.then(function(results) {
        vm.promos = results;
      }, function() {
        if (Auth.currentUser().paid_plan !== true) {
          vm.upgrade = true;
        }
      });
    }

    function menuPush() {
      if (vm.menu.main.length === 0) {
        vm.menu.main.push({
          title: gettextCatalog.getString('Locations'),
          type: 'link',
          link: '/#/locations',
          icon: 'business'
        });

        vm.menu.main.push({
          title: gettextCatalog.getString('Events'),
          type: 'link',
          link: '/#/events',
          icon: 'warning'
        });

        if ($localStorage.user && $localStorage.user.custom) {
          vm.menu.main.push({
            title: gettextCatalog.getString('Brands'),
            type: 'link',
            link: '/#/brands',
            icon: 'branding_watermark'
          });

          vm.menu.main.push({
            title: gettextCatalog.getString('Users'),
            type: 'link',
            link: '/#/users',
            icon: 'people'
          });

          vm.menuRight.push({
            name: gettextCatalog.getString('Brands'),
            type: 'link',
            link: '/#/brands',
            icon: 'branding_watermark'
          });

          vm.menuRight.push({
            name: gettextCatalog.getString('Users'),
            type: 'link',
            link: '/#/users',
            icon: 'people'
          });

          vm.menu.main.push({
            title: gettextCatalog.getString('Projects'),
            type: 'link',
            link: '/#/projects',
            icon: 'dns'
          });

          vm.menuRight.push({
            type: 'divider',
          });
        }

        vm.menuRight.push({
          name: gettextCatalog.getString('Profile'),
          link: '/#/me',
          type: 'link',
          icon: 'face'
        });

        vm.menuRight.push({
          type: 'divider',
        });
      }

      if (Auth.currentUser().promo !== '' && Auth.currentUser().promo !== null && Auth.currentUser().promo !== undefined) {
        promos();
      } else if (Auth.currentUser().paid_plan !== true) {
        vm.upgrade = true;
      }
    }

    var setDefaultImages = function(sub) {
      $scope.brandName.name = 'CT';
    };

    function getBrand(sub, cname) {
      if (Auth.currentUser() && Auth.currentUser().url !== null) {
        sub = Auth.currentUser().url;
      }

      Brand.query({}, {
        id: sub,
        cname: cname,
        type: 'showcase'
      }).$promise.then(function(results) {
        // Decide to switch the brand here
        // Can we turn CT into a variable so we don't just set
        // Maybe use the config files - Simon TBD //

        var t = $cookies.get('_ctt');
        // if (t !== results.theme_primary) {
        $cookies.put('_ctt', results.theme_primary + '.' + results.theme_accent);
        // }
        $scope.brandName.name  = results.brand_name || 'CT';
        // Maybe use the config files - Simon TBD //
        $scope.brandName.admin = results.admin;
        $scope.brandName.url   = results.url;
        $scope.brandName.id    = results.id;
        $scope.brandName.logo_url = results.logo_url;
      }, function() {
        setDefaultImages(sub);
      });
    }

    var removeCtCookie = function() {
      $cookies.remove('_ct', { domain: domain });
    };

    function getSubdomain () {
      var sub   = locationHelper.subdomain();
      var host  = locationHelper.domain();
      var parts = $location.host().split('.');
      var cname;
      if (host !== 'ctapp.io' && host !== 'ctapp.dev') {
        getBrand(host, true);
      }
      else if (parts.length === 3) {
        sub = parts[0];
        if (sub !== 'my' && sub !== 'dashboard' ) {
          getBrand(sub);
          return;
        }
        setDefaultImages();
      } else {
        console.log('Domain error occured');
      }
    }

    function getMe() {
      Me.get({}).$promise.then(function(res) {
        Auth.login(res).then(function(a) {
          $scope.user = Auth.currentUser();
          $scope.loggedIn = true;
          menuPush();
          if ($scope.user.promo !== '') {
            console.log('Getting promo...');
          }
        });
      });
    }

    function routeChangeStart() {
      var pusher;

      // If user logged in, load pusher
      if (Auth.currentUser() && Auth.currentUser().key !== null) {
        $scope.$broadcast('intercom', {hi: 'user'});
        window.client = new Pusher(PUSHER, {
          authEndpoint: API + '/pusherAuth?token=' + Auth.currentUser().key
        });
        pusher = $pusher(client);
      }

      var a = AccessToken.get();
      if ( (!Auth.currentUser() && a ) || Auth.currentUser() && (Auth.currentUser().url !== 'default' )) {
        getMe();
      }
      getSubdomain();

      // Translate.load();
    }

    var setLoggedIn = function(isLoggedIn) {
      $scope.loggedIn = isLoggedIn;
      return isLoggedIn;
    };

    setLoggedIn(AccessToken.get() !== undefined);

    $scope.logout = function() {
      Auth.logout();
    };

    // $scope.onlineStatus = onlineStatus;
    // if ( $scope.loggedIn ) {
      // $scope.$watch('onlineStatus.isOnline()', function(online) {
      //   $scope.online_status_string = online ? 'online' : 'offline';
      //   if ($scope.online_status_string === 'offline') {
      //     $scope.open('md');
      //   } else if ($scope.online_status_string === 'online' ){
      //     // if ($scope.modalInstance !== undefined) {
      //     //   $scope.modalInstance.close();
      //     // }
      //   }
      // });
    // }

    $rootScope.$on('$routeChangeStart', function (event, next, current) {
      routeChangeStart();
    });

}]);

app.controller( 'ParentCtrl', function ParentCtrl($scope, onlineStatus) {
});
<commit_msg>redirect to dash<commit_after>'use strict';

var app = angular.module('myApp.controllers', [
  'myApp.authentications.controller',
  'myApp.brands.controller',
  'myApp.boxes.controller',
  'myApp.events.controller',
  'myApp.heartbeats.controller',
  'myApp.jobs.controller',
  'myApp.invoices.controller',
  'myApp.locations.controller',
  'myApp.port_forwards.controller',
  'myApp.projects.controller',
  'myApp.reports.controller',
  'myApp.speedtests.controller',
  'myApp.splash_pages.controller',
  'myApp.registrations.controller',
  'myApp.zones.controller',
  'myApp.users.controller',
  'myApp.vouchers.controller'
]);

app.controller('MainCtrl', ['$rootScope', '$scope', '$localStorage', '$window', '$location', '$routeParams', 'AccessToken', 'RefreshToken', 'Auth', 'API_END_POINT', '$pusher', '$route', 'onlineStatus', '$cookies', 'Brand', 'locationHelper', 'BrandName', 'CTLogin', 'User', 'Me', 'AUTH_URL', 'menu', 'designer', '$mdSidenav', 'docs', '$mdMedia', '$q', 'INTERCOM', 'PUSHER', 'gettextCatalog', 'Translate', 'COMMITHASH', '$mdDialog',

  function ($rootScope, $scope, $localStorage, $window, $location, $routeParams, AccessToken, RefreshToken, Auth, API, $pusher, $route, onlineStatus, $cookies, Brand, locationHelper, BrandName, CTLogin, User, Me, AUTH_URL, menu, designer, $mdSidenav, docs, $mdMedia, $q, INTERCOM, PUSHER, gettextCatalog, Translate, COMMITHASH, $mdDialog) {

    var domain = 'ctapp.io';

    $scope.brandName  = BrandName;
    $scope.commit     = COMMITHASH;
    $scope.ct_login   = CTLogin;

    function isOpen(section) {
      return (menu.isSectionSelected(section) && menu.isOpen());
    }

    $scope.toggle = function(section){
      $mdSidenav(section || 'left').toggle();
    };

    var toggleOpen = function(){
      if ($mdMedia('gt-sm')) {
        vm.menu.isOpenLeft = false;
        menu.isOpen = !menu.isOpen;
        vm._ctm = !vm._ctm;
        $cookies.put('_ctm', !menu.isOpen);
      } else {
        vm.menu.isOpenLeft = !vm.menu.isOpenLeft;
      }
      $(window).trigger('resize');
    };

    function toggle(section) {
      menu.toggleSelectSection(section);
    }

    var vm = this;

    vm._ctm = $cookies.get('_ctm');
    vm.menu = menu;

    vm.designer = designer;
    vm.toggle = toggle;

    if ($cookies.get('_ctm') === 'true') {
      vm.menu.isOpenLeft = false;
      vm.menu.isOpen = false;
    }

    vm.menu.main = [];
    // vm.menu.reports = [];
    vm.settingsMenu = [];
    vm.menuRight = [];

    // vm.menu.reports.push({
    //   title: gettextCatalog.getString('Reports'),
    //   type: 'link',
    //   link: '/#/reports',
    //   icon: 'timeline'
    // });

    // vm.menu.reports.push({
    //   title: gettextCatalog.getString('Audit'),
    //   type: 'link',
    //   link: '/#/audit',
    //   icon: 'assignment'
    // });

    vm.status = {
      isFirstOpen: true,
      isFirstDisabled: false
    };

    vm.menuRight.push({
      name: gettextCatalog.getString('Home'),
      link: '/#/',
      type: 'link',
      icon: 'home'
    });

    vm.menuRight.push({
      name: gettextCatalog.getString('Locations'),
      link: '/#/locations',
      type: 'link',
      icon: 'business'
    });

    vm.menuRight.push({
      name: gettextCatalog.getString('Events'),
      link: '/#/events',
      type: 'link',
      icon: 'warning'
    });

    vm.menuRight.push({
      name: gettextCatalog.getString('Reports'),
      link: '/#/reports',
      type: 'link',
      icon: 'timeline'
    });

    // vm.menuRight.push({
    //   name: gettextCatalog.getString('Audit'),
    //   link: '/#/audit',
    //   type: 'link',
    //   icon: 'assignment'
    // });

    vm.menuRight.push({
      type: 'divider',
    });

    vm.menuRight.push({
      name: gettextCatalog.getString('Developer'),
      link: '/#/apps',
      type: 'link',
      icon: 'android'
    });

    // Permissions //
    if ($localStorage.user && !$localStorage.user.custom) {
      vm.menuRight.push({
        name: gettextCatalog.getString('Documentation'),
        link: 'http://docs.cucumberwifi.io',
        type: 'link',
        target: '_blank',
        icon: 'account_balance'
      });

      vm.menuRight.push({
        name: gettextCatalog.getString('Discussions'),
        link: 'https://discuss.cucumberwifi.io',
        target: '_blank',
        type: 'link',
        icon: 'forum'
      });

      vm.menuRight.push({
        name: gettextCatalog.getString('Support'),
        icon: 'get_app',
        id: 'intercom'
      });
    }

    vm.menuRight.push({
      name: gettextCatalog.getString('Support'),
      icon: 'get_app',
      id: 'intercom'
    });

    vm.menuRight.push({
      name: gettextCatalog.getString('Downloads'),
      link: '/#/downloads',
      type: 'link',
      icon: 'get_app'
    });

    vm.menuRight.push({
      type: 'divider',
    });

    vm.showPromo = function(offer) {
      $mdDialog.show({
        controller: TrialController,
        templateUrl: 'components/views/main/promos.tmpl.html',
        parent: angular.element(document.body),
        clickOutsideToClose:true,
        locals: {
          offer: offer
        },
        fullscreen: $scope.customFullscreen // Only for -xs, -sm breakpoints.
      });
    };

    function TrialController($scope, $mdDialog, $sce, offer) {
      $scope.offer = $sce.trustAsHtml(offer);
      $scope.hide = function() {
        $mdDialog.hide();
      };

      $scope.upgrade = function() {
        $mdDialog.hide();
        $location.path('/users/' + Auth.currentUser().slug + '/billing');
        $location.search({trial: 'y'});
      };
    }

    vm.showUpgrade = function() {
      $mdDialog.show({
        controller: DialogController,
        templateUrl: 'components/views/main/upgrade.tmpl.html',
        parent: angular.element(document.body),
        clickOutsideToClose:true,
        fullscreen: $scope.customFullscreen // Only for -xs, -sm breakpoints.
      });
    };

    function DialogController($scope, $mdDialog) {
      $scope.hide = function() {
        $mdDialog.hide();
      };

      $scope.upgrade = function() {
        $mdDialog.hide();
        $location.path('/users/' + Auth.currentUser().slug + '/billing');
      };
    }

    $scope.toggleOpen = toggleOpen;

    $scope.$on('logout', function(args) {
      logout().then(function(response) {
        $route.reload();
        console.log('Refreshing Token.');
      }, function() {
        Auth.fullLogin();
      });
    });

    var logout = function(args) {
      var deferred = $q.defer();
      var user = $localStorage.user;
      var path = $location.path();
      AccessToken.del();
      if ( user && user.refresh ) {
        var host  = locationHelper.domain();
        $cookies.put('_ctp', JSON.stringify(path) );
        RefreshToken.refresh(user.refresh, path).then(function(response) {
          Auth.refresh(response).then(function(a){
            deferred.resolve();
          });
        }, function(er) {
          deferred.reject();
        });
      } else {
        deferred.reject();
      }
      return deferred.promise;
    };

    $scope.$on('login', function(args,event) {
      console.log('Logging in...');
      var cname = event.data.cname;
      if ((cname === null || cname === '') && event.data.url !== 'default') {
        var sub   = locationHelper.subdomain();
        var host  = locationHelper.domain();
        if (event.data.url && (sub !== event.data.url)) {
          var newUrl = locationHelper.reconstructed(event.data.url);
          var reconstructed = newUrl + '/#/';
          $cookies.put('event', JSON.stringify(event), {'domain': host});
          window.location = reconstructed;
        } else {
          doLogin(event);
        }
      } else {
        doLogin(event);
      }
    });

    function doLogin(event) {
      Auth.login(event.data).then(function(a) {
        var path;
        $scope.loggedIn = true;
        if (event.path) {
          path = event.path;
        } else {
          var raw = $cookies.get('_ctp');
          if (raw) {
            try{
              path = JSON.parse(raw);
            }catch(e){
              console.log('Couldn\'t parse JSON to redirect');
            }
          }
        }
        $location.path(path || '/').search(event.search || {});
        if (event !== undefined && event.rdir !== undefined) {
          $location.search({rdir: event.rdir});
        }
        $cookies.remove('_ctp');
        $scope.ct_login = undefined;
        // Translate.load();
      });
    }

    $scope.$on('intercom', function(args,event) {
      if (Auth.currentUser() && (Auth.currentUser().chat_enabled !== false && !Auth.currentUser().custom && Auth.currentUser().user_hash !== undefined)) {
        vm.menu.Intercom = true;
        var settings = {
            app_id: INTERCOM,
            user_id: Auth.currentUser().accountId,
            email: Auth.currentUser().email,
            name: Auth.currentUser().username,
            created_at: Auth.currentUser().created_at,
            user_hash: Auth.currentUser().user_hash,
            brand_name: Auth.currentUser().url,
            cname: Auth.currentUser().cname,
            sense_active: Auth.currentUser().sense_active,
            plan_name: Auth.currentUser().plan_name,
            paid_plan: Auth.currentUser().paid_plan,
            locs: Auth.currentUser().locs,
            version: '2'
        };
        settings.widget = {
          activator: '#intercom'
        };
        window.Intercom('boot', settings);
      }
    });

    function promos() {
      User.promos({}, {
        action: 'promos',
        id: Auth.currentUser().slug
      }).$promise.then(function(results) {
        vm.promos = results;
      }, function() {
        if (Auth.currentUser().paid_plan !== true) {
          vm.upgrade = true;
        }
      });
    }

    function menuPush() {
      if (vm.menu.main.length === 0) {
        vm.menu.main.push({
          title: gettextCatalog.getString('Locations'),
          type: 'link',
          link: '/#/locations',
          icon: 'business'
        });

        vm.menu.main.push({
          title: gettextCatalog.getString('Events'),
          type: 'link',
          link: '/#/events',
          icon: 'warning'
        });

        if ($localStorage.user && $localStorage.user.custom) {
          vm.menu.main.push({
            title: gettextCatalog.getString('Brands'),
            type: 'link',
            link: '/#/brands',
            icon: 'branding_watermark'
          });

          vm.menu.main.push({
            title: gettextCatalog.getString('Users'),
            type: 'link',
            link: '/#/users',
            icon: 'people'
          });

          vm.menuRight.push({
            name: gettextCatalog.getString('Brands'),
            type: 'link',
            link: '/#/brands',
            icon: 'branding_watermark'
          });

          vm.menuRight.push({
            name: gettextCatalog.getString('Users'),
            type: 'link',
            link: '/#/users',
            icon: 'people'
          });

          vm.menu.main.push({
            title: gettextCatalog.getString('Projects'),
            type: 'link',
            link: '/#/projects',
            icon: 'dns'
          });

          vm.menuRight.push({
            type: 'divider',
          });
        }

        vm.menuRight.push({
          name: gettextCatalog.getString('Profile'),
          link: '/#/me',
          type: 'link',
          icon: 'face'
        });

        vm.menuRight.push({
          type: 'divider',
        });
      }

      if (Auth.currentUser().promo !== '' && Auth.currentUser().promo !== null && Auth.currentUser().promo !== undefined) {
        promos();
      } else if (Auth.currentUser().paid_plan !== true) {
        vm.upgrade = true;
      }
    }

    var setDefaultImages = function(sub) {
      $scope.brandName.name = 'CT';
    };

    function getBrand(sub, cname) {
      if (Auth.currentUser() && Auth.currentUser().url !== null) {
        sub = Auth.currentUser().url;
      }

      Brand.query({}, {
        id: sub,
        cname: cname,
        type: 'showcase'
      }).$promise.then(function(results) {
        // Decide to switch the brand here
        // Can we turn CT into a variable so we don't just set
        // Maybe use the config files - Simon TBD //

        var t = $cookies.get('_ctt');
        // if (t !== results.theme_primary) {
        $cookies.put('_ctt', results.theme_primary + '.' + results.theme_accent);
        // }
        $scope.brandName.name  = results.brand_name || 'CT';
        // Maybe use the config files - Simon TBD //
        $scope.brandName.admin = results.admin;
        $scope.brandName.url   = results.url;
        $scope.brandName.id    = results.id;
        $scope.brandName.logo_url = results.logo_url;
      }, function() {
        setDefaultImages(sub);
      });
    }

    var removeCtCookie = function() {
      $cookies.remove('_ct', { domain: domain });
    };

    function getSubdomain () {
      var sub   = locationHelper.subdomain();
      var host  = locationHelper.domain();
      var parts = $location.host().split('.');
      var cname;
      if (host !== 'ctapp.io' && host !== 'ctapp.dev') {
        getBrand(host, true);
      }
      else if (parts.length === 3) {
        sub = parts[0];
        if (sub !== 'dashboard') {
          getBrand(sub);
          window.location.hostname = 'dashboard.ctapp.dev'
          return;
        }
        setDefaultImages();
      } else {
        console.log('Domain error occured');
      }
    }

    function getMe() {
      Me.get({}).$promise.then(function(res) {
        Auth.login(res).then(function(a) {
          $scope.user = Auth.currentUser();
          $scope.loggedIn = true;
          menuPush();
          if ($scope.user.promo !== '') {
            console.log('Getting promo...');
          }
        });
      });
    }

    function routeChangeStart() {
      var pusher;

      // If user logged in, load pusher
      if (Auth.currentUser() && Auth.currentUser().key !== null) {
        $scope.$broadcast('intercom', {hi: 'user'});
        window.client = new Pusher(PUSHER, {
          authEndpoint: API + '/pusherAuth?token=' + Auth.currentUser().key
        });
        pusher = $pusher(client);
      }

      var a = AccessToken.get();
      if ( (!Auth.currentUser() && a ) || Auth.currentUser() && (Auth.currentUser().url !== 'default' )) {
        getMe();
      }
      getSubdomain();

      // Translate.load();
    }

    var setLoggedIn = function(isLoggedIn) {
      $scope.loggedIn = isLoggedIn;
      return isLoggedIn;
    };

    setLoggedIn(AccessToken.get() !== undefined);

    $scope.logout = function() {
      Auth.logout();
    };

    // $scope.onlineStatus = onlineStatus;
    // if ( $scope.loggedIn ) {
      // $scope.$watch('onlineStatus.isOnline()', function(online) {
      //   $scope.online_status_string = online ? 'online' : 'offline';
      //   if ($scope.online_status_string === 'offline') {
      //     $scope.open('md');
      //   } else if ($scope.online_status_string === 'online' ){
      //     // if ($scope.modalInstance !== undefined) {
      //     //   $scope.modalInstance.close();
      //     // }
      //   }
      // });
    // }

    $rootScope.$on('$routeChangeStart', function (event, next, current) {
      routeChangeStart();
    });

}]);

app.controller( 'ParentCtrl', function ParentCtrl($scope, onlineStatus) {
});
<|endoftext|>


<commit_before>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

(function () {
    var pluginUtils = require('cordova/plugin/blackberry10/pluginUtils'),
        docAddEventListener = document.addEventListener,
        webworksReady = false,
        alreadyFired = false,
        listenerRegistered = false;

    //Only fire the webworks event when both webworks is ready and a listener is registered
    function fireWebworksReadyEvent() {
        var evt;
        if (listenerRegistered && webworksReady && !alreadyFired) {
            alreadyFired = true;
            evt = document.createEvent('Events');
            evt.initEvent('webworksready', true, true);
            document.dispatchEvent(evt);
        }
    }

    //Trapping when users add listeners to the webworks ready event
    //This way we can make sure not to fire the event before there is a listener
    document.addEventListener = function (event, callback, capture) {
        docAddEventListener.call(document, event, callback, capture);
        if (event.toLowerCase() === 'webworksready') {
            listenerRegistered = true;
            fireWebworksReadyEvent();
        }
    };

    function RemoteFunctionCall(functionUri) {
        var params = {};

        function composeUri() {
            return require("cordova/plugin/blackberry10/utils").getURIPrefix() + functionUri;
        }

        function createXhrRequest(uri, isAsync) {
            var request = new XMLHttpRequest();
            request.open("POST", uri, isAsync);
            request.setRequestHeader("Content-Type", "application/json");
            return request;
        }

        this.addParam = function (name, value) {
            params[name] = encodeURIComponent(JSON.stringify(value));
        };

        this.makeSyncCall = function (success, error) {
            var requestUri = composeUri(),
            request = createXhrRequest(requestUri, false),
            response,
            errored,
            cb,
            data;

            request.send(JSON.stringify(params));
            response = JSON.parse(decodeURIComponent(request.responseText) || "null");
            return response;
        };
    }

    window.webworks = {
        exec: function (success, fail, service, action, args) {
            var uri = service + "/" + action,
            request = new RemoteFunctionCall(uri),
            callbackId = service + cordova.callbackId++,
            response,
            name,
            didSucceed;

            for (name in args) {
                if (Object.hasOwnProperty.call(args, name)) {
                    request.addParam(name, args[name]);
                }
            }

            cordova.callbacks[callbackId] = {success:success, fail:fail};
            request.addParam("callbackId", callbackId);

            response = request.makeSyncCall();

            //Old WebWorks Extension success
            if (response.code === 42) {
                if (success) {
                    success(response.data, response);
                }
                delete cordova.callbacks[callbackId];
            } else if (response.code < 0) {
                if (fail) {
                    fail(response.msg, response);
                }
                delete cordova.callbacks[callbackId];
            } else {
                didSucceed = response.code === cordova.callbackStatus.OK || response.code === cordova.callbackStatus.NO_RESULT;
                cordova.callbackFromNative(callbackId, didSucceed, response.code, didSucceed ? response.data : response.msg, !!response.keepCallback);
            }
        },
        defineReadOnlyField: function (obj, field, value) {
            Object.defineProperty(obj, field, {
                "value": value,
                "writable": false
            });
        },
        event: require("cordova/plugin/blackberry10/event")
    };

    //Fire webworks ready once plugin javascript has been loaded
    pluginUtils.getPlugins(
        function (plugins) {
            pluginUtils.loadClientJs(plugins, function () {
                webworksReady = true;
                fireWebworksReadyEvent();
            });
        },
        function () {
            console.log('Unable to load plugins.json');
            webworksReady = true;
            fireWebworksReadyEvent();
        }
    );
}());

document.addEventListener("DOMContentLoaded", function () {
    document.addEventListener("webworksready", function () {
        require('cordova/channel').onNativeReady.fire();
    });
});
<commit_msg>[BlackBerry10] Update bootstrap to fix exec error caused by rebasing<commit_after>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

(function () {
    var pluginUtils = require('cordova/plugin/blackberry10/pluginUtils'),
        docAddEventListener = document.addEventListener,
        webworksReady = false,
        alreadyFired = false,
        listenerRegistered = false;

    //Only fire the webworks event when both webworks is ready and a listener is registered
    function fireWebworksReadyEvent() {
        var evt;
        if (listenerRegistered && webworksReady && !alreadyFired) {
            alreadyFired = true;
            evt = document.createEvent('Events');
            evt.initEvent('webworksready', true, true);
            document.dispatchEvent(evt);
        }
    }

    //Trapping when users add listeners to the webworks ready event
    //This way we can make sure not to fire the event before there is a listener
    document.addEventListener = function (event, callback, capture) {
        docAddEventListener.call(document, event, callback, capture);
        if (event.toLowerCase() === 'webworksready') {
            listenerRegistered = true;
            fireWebworksReadyEvent();
        }
    };

    function RemoteFunctionCall(functionUri) {
        var params = {};

        function composeUri() {
            return require("cordova/plugin/blackberry10/utils").getURIPrefix() + functionUri;
        }

        function createXhrRequest(uri, isAsync) {
            var request = new XMLHttpRequest();
            request.open("POST", uri, isAsync);
            request.setRequestHeader("Content-Type", "application/json");
            return request;
        }

        this.addParam = function (name, value) {
            params[name] = encodeURIComponent(JSON.stringify(value));
        };

        this.makeSyncCall = function (success, error) {
            var requestUri = composeUri(),
            request = createXhrRequest(requestUri, false),
            response,
            errored,
            cb,
            data;

            request.send(JSON.stringify(params));
            response = JSON.parse(decodeURIComponent(request.responseText) || "null");
            return response;
        };
    }

    window.webworks = {
        exec: function (success, fail, service, action, args) {
            var uri = service + "/" + action,
            request = new RemoteFunctionCall(uri),
            callbackId = service + cordova.callbackId++,
            response,
            name,
            didSucceed;

            for (name in args) {
                if (Object.hasOwnProperty.call(args, name)) {
                    request.addParam(name, args[name]);
                }
            }

            cordova.callbacks[callbackId] = {success:success, fail:fail};
            request.addParam("callbackId", callbackId);

            response = request.makeSyncCall();

            //Old WebWorks Extension success
            if (response.code === 42) {
                if (success) {
                    success(response.data, response);
                }
                delete cordova.callbacks[callbackId];
            } else if (response.code < 0) {
                if (fail) {
                    fail(response.msg, response);
                }
                delete cordova.callbacks[callbackId];
            } else {
                didSucceed = response.code === cordova.callbackStatus.OK || response.code === cordova.callbackStatus.NO_RESULT;
                cordova.callbackFromNative(callbackId, didSucceed, response.code, [ didSucceed ? response.data : response.msg ], !!response.keepCallback);
            }
        },
        defineReadOnlyField: function (obj, field, value) {
            Object.defineProperty(obj, field, {
                "value": value,
                "writable": false
            });
        },
        event: require("cordova/plugin/blackberry10/event")
    };

    //Fire webworks ready once plugin javascript has been loaded
    pluginUtils.getPlugins(
        function (plugins) {
            pluginUtils.loadClientJs(plugins, function () {
                webworksReady = true;
                fireWebworksReadyEvent();
            });
        },
        function () {
            console.log('Unable to load plugins.json');
            webworksReady = true;
            fireWebworksReadyEvent();
        }
    );
}());

document.addEventListener("DOMContentLoaded", function () {
    document.addEventListener("webworksready", function () {
        require('cordova/channel').onNativeReady.fire();
    });
});
<|endoftext|>


<commit_before>angular.module('roadmaps.ctrl', ['roadmaps.factory', 'services.server', 'services.user', 'scraper.ctrl'])

.controller('RoadMapsController', [ '$scope', '$http', '$stateParams', 'RoadMapsFactory', 'Server', 'User', '$timeout', '$state', function($scope, $http, $stateParams, RoadMapsFactory, Server, User, $timeout, $state){
  angular.extend($scope, RoadMapsFactory);

  var roadmapId = $stateParams.roadmapID;
  $scope.currentRoadMapData = {};
  $scope.renderedNodes = [];
  $('.tooltipped').tooltip({delay: 50});

  $scope.showComments = false;
  $scope.currentIndex = 0;

  $scope.toggleComments = function(){
    $scope.showComments = true;
  };

  $scope.isAuthor = function (){
    var username = localStorage.getItem('user.username');
    var roadmapAuthor = $scope.currentRoadMapData.author.username;
    if (username === roadmapAuthor){
      return true;
    } else {
      return false;
    }
  };

  $scope.resetCreationForm = function() {
    $scope.urlToScrape = "";
    $scope.currentCreationTitle = 'New node title';
    $scope.currentCreationDescription = 'New node description';
    $scope.currentCreationType = 'New node type';
    $scope.currentCreationLink = 'New node link (optional)';
    $scope.currentCreationImage = 'New node image (optional)';
  }

  $scope.resetCreationForm();

  $scope.urlToScrape = '';
  $scope.displayUrl = '';
  $scope.scrape = {};

  $scope.checkAndSubmit = function() {
    var url = $scope.urlToScrape;
    if (url.length < 4) return;
    if (url.substring(0, 4) !== 'http') url = 'http://' + url;

    $scope.displayUrl = url;

    Server.scrape(url)
    .then(function (data) {
      console.log('web scrape data is', data);
        $scope.currentCreationTitle = data.title;
        $scope.currentCreationDescription = data.description;
        $scope.currentCreationType = data.type;
        $scope.currentCreationLink = url;
        $scope.currentCreationImage = data.imageUrl;
    });
  };

  $scope.showNodeCreator = function($index, boolean){
    var username = localStorage.getItem('user.username');
    var roadmapAuthor = $scope.currentRoadMapData.author.username;
    console.log("'mini-circle-' + $index", 'mini-circle-' + $index);
    if( username !== roadmapAuthor ){
      $scope.nodeCreator = false;
      console.log("author fail");
    } else {

      $scope.displayNodeCreator = boolean;
    }
  }

  $scope.createNode = function($index) {
    console.log("* calling createNode *");
    console.log('roadmapID', roadmapId);
    $('#editor-placeholder').remove();
    return Server.createNode({
      title: $scope.currentCreationTitle,
      description: $scope.currentCreationDescription,
      resourceType: $scope.currentCreationType,
      resourceURL: $scope.currentCreationLink,
      imageUrl: $scope.currentCreationImage,
      parentRoadmap: roadmapId
    })
    .then(function(res){
      populateData();
      console.log("node created");
      $scope.displayNodeCreator = false;
      Materialize.toast('Node Added!', 4000, 'orangeToast');
      $scope.resetCreationForm();
    });
  };

  $scope.closeNodeCreator = function(){
    $scope.displayNodeCreator = false;
    $scope.resetCreationForm();
  }

  $scope.hideText = function ($index, field, idPrefix){
    $index = $index || 0;
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    var username = localStorage.getItem('user.username');
    var roadmapAuthor = $scope.currentRoadMapData.author.username;
    if( username !== roadmapAuthor ){
      return false;
    } else {
      if( !$scope[elementID] ){
        return  false;
      } else {
        return true;
      }
    }
  };

  $scope.showEditor = function ($index, field, boolean, idPrefix){
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    $scope.currentIndex = $index;
    var username = localStorage.getItem('user.username');
    var roadmapAuthor = $scope.currentRoadMapData.author.username;

    if( username !== roadmapAuthor ){
      $scope[elementID] = false;
      console.log("author fail");
    } else {
      if( field === 'circle' && idPrefix === 'mini'){
        $scope.resetCreationForm();
      }
      if( !$scope.currentResourceURL ) {
        $scope.currentResourceURL = $scope.currentLinks[0];
      }

      if(boolean === false && field !== 'circle'){
        $(elementID).val($scope.renderedNodes[$index][field]);
      }
      console.log("SHOW EDITOR");
      console.log('elementID', elementID);
      console.log('$scope[elementID]', $scope[elementID]);
      $scope[elementID] = boolean;
    }

  };

  $scope.getPlaceholder = function($index, field){
    var capitalizedField = field.substr(0, 1).toUpperCase() + field.substr(1);
    return $scope['current' + capitalizedField];
  };

  $scope.saveEdit = function($index, field, idPrefix){
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    var newProperty = $(elementID).val();
    var updateObj = {};
    updateObj['_id'] = $scope.renderedNodes[$index]._id;
    updateObj[field] = newProperty;
    Server.updateNode(updateObj)
      .then(function(node) {
      $scope.showEditor($index, field, false, idPrefix);
      $scope.renderedNodes[$index][field] = newProperty;
      var capitalizedField = field.substr(0, 1).toUpperCase() + field.substr(1);
      $scope['current' + capitalizedField] = newProperty;
      if( field === 'resourceURL' ){
        $scope.currentLinks[0] = newProperty;
      }
    })
      .catch(function(){
        console.log('problem updating node', err);
      });
  };

  //roadMapTitle

  $scope.hideTitle = false;

  $scope.showTitleEditor = function (boolean){
    var username = localStorage.getItem('user.username');
    var roadmapAuthor = $scope.currentRoadMapData.author.username;
    var storedTitle;

    if( username !== roadmapAuthor ){
      $scope.hideTitle = false;
    } else {
      $scope.hideTitle = boolean;
      return $scope.hideTitle;
    }

  };

  $scope.saveTitleEdit = function (){
    var newProperty = $('#main-title').val();
    var updateObj = {};
    updateObj['_id'] = roadmapId;
    updateObj['title'] = newProperty;
    Server.updateRoadmap(updateObj)
      .then(function(node) {
      $scope.hideTitle = false;
      $scope.roadMapTitle = newProperty;
    })
      .catch(function(){
        console.log('problem updating map title', err);
      });
  }

 // Get the current number of upvotes from current map
 $scope.getCountVotes = function(votes){
    $scope.votesCount = 0;
    for(var i = 0; i < votes.length; i++){
      $scope.votesCount++;
    }
    return $scope.votesCount;
 }

 // Renders the nodes for the current roadmap to the page
  $scope.renderNodes = function(){
    var title = $scope.currentRoadMapData.title || 'test title';
    var nodes = $scope.currentRoadMapData.nodes || ['testnode1', 'testnode2'];
    // Add an index to nodes to make ng-clicking easier
    nodes.map(function(node,index){
      node.index = index;
    });

    $scope.renderedNodes = nodes;
    $scope.roadMapTitle = title;

    // User Logged in Data in the future
    // Some variable that holds that the user is logged in
    $scope.currentNode = nodes[0];
    $scope.renderCurrentNode();
  };
  // Make a $scope.renderComments()
  $scope.renderComments = function(){
    var comments = $scope.currentRoadMapData.comments;
    console.log(comments);
    comments.map(function(comment,index){
      comment.index = index;
    })
    $scope.renderedComments = comments;
  }

  // When roadmap (identified by its id) data is fetched, set it
  function populateData (stop){
    stop = stop || false;
    Server.getRoadmapById(roadmapId).then(function (res){
      if( !res.nodes.length && stop === false){
        populateData(true);
      }
      $scope.currentRoadMapData = res;
      console.log($scope.currentRoadMapData,'I am the roadmap');
    }, function(err){
      if (err) return console.log(err);
    })
    .then(function(){
      $scope.renderNodes();
      $scope.renderComments();
      // Set the upvotes and downvotes
      var currentMapUpVotes = $scope.currentRoadMapData.upvotes;
      var currentMapDownVotes = $scope.currentRoadMapData.downvotes;
      $scope.upVoteCount = $scope.getCountVotes(currentMapUpVotes);
      $scope.downVoteCount = $scope.getCountVotes(currentMapDownVotes);

      // append Editor Mode message
      var username = localStorage.getItem('user.username');
      var roadmapAuthor = $scope.currentRoadMapData.author.username;

      if( username === roadmapAuthor ){
        $('#editor-placeholder').append(
        '
' +
          '
' +
            '' +
          '
' +
          '
' +
              'Since you created this roadmap, you can add or edit properties by clicking on them.' +
          '
' +
          '
' +
            '' +
          '
' +
        '
'
        );
      }
    });
  }

  populateData();

  // Render Title
  // Assumes title links and description properties from get method
  $scope.renderCurrentNode = function(){
    // For now lets make $scope.loggedIn be false, if logged in we can change it to true later.
    $scope.loggedin = false;
    if($scope.loggedIn) {
      // Get node index
      // set currentNode into node at that index;
    } else {
      //links from a node
      var links = $scope.renderedNodes[0].resourceURL;
      //description of a node
      var description = $scope.renderedNodes[0].description;
      var title = $scope.renderedNodes[0].title;
    }

    $scope.currentTitle = title;
    $scope.currentLinks = [links];
    $scope.currentDescription = description;
  }

  $scope.selectNode = function($index) {

    var links = $scope.renderedNodes[$index].resourceURL;
    var description = $scope.renderedNodes[$index].description;
    var title = $scope.renderedNodes[$index].title;

    $scope.currentIndex = $index;
    $scope.currentTitle = title;
    $scope.currentLinks = links;
    $scope.currentResourceURL = $scope.currentLinks[0];
    $scope.currentDescription = description;
    $scope.currentNode = $scope.renderedNodes[$index];

  };
  // Submits a node to the user's inProgress.nodes array.
  $scope.submitCompletedNode = function() {
    var nodeId = $scope.currentNode._id;
    User.completeNodeById(nodeId);
    Materialize.toast('Node Complete!', 4000, 'orangeToast');
  }

  // Submits a roadmap to the user's completedRoadmaps array.
  $scope.submitCompletedRoadmap = function() {
    Materialize.toast('Map Complete!', 4000, 'orangeToast');
    User.completeRoadmapById(roadmapId);
    $state.go('home.dashboard', {type: 'completed'});
  }

  // After upvote, submits vote update to the roadmap's upvotes and downvotes array
  $scope.upVoteMap = function () {
    User.upvoteMapById(roadmapId)
    .then(function(data){
      var dataUpVoteCount = data.upvotes;
      var dataDownVoteCount = data.downvotes;
      // Update the upvote count
      $scope.upVoteCount = $scope.getCountVotes(dataUpVoteCount);
      // Update the downvote count
      $scope.downVoteCount = $scope.getCountVotes(dataDownVoteCount);
    })
  }

  // After downvote, submits vote update to the roadmap's upvotes and downvotes array
  $scope.downVoteMap = function () {
    User.downvoteMapById(roadmapId)
    .then(function(data){
      var dataUpVoteCount = data.upvotes;
      var dataDownVoteCount = data.downvotes;
      // Update the upvote count
      $scope.upVoteCount = $scope.getCountVotes(dataUpVoteCount);
      // Update the downvote count
      $scope.downVoteCount = $scope.getCountVotes(dataDownVoteCount);
    });
  };

  $scope.connectLines = function(){
    $('.endPointForConnection').connections();
  };

  // We need async because ng-repeat creates the nodes before this function runs set timeout changes the loop.
  $scope.asyncConnectLines = function(cb){
    setTimeout($scope.connectLines,0);
  };

  $scope.subject = '';
  $scope.content = '';

  $scope.postComment = function(){
    // Will probably need to refactor
    $scope.currentRoadMapData.comments = $scope.currentRoadMapData.comments || [];

    Server.createComment({
      subject: $scope.subject,
      content: $scope.content,
      roadmap: $scope.currentRoadMapData._id
    });
  };

}]);
<commit_msg>(feat) Add default image for new roadmap-created nodes<commit_after>angular.module('roadmaps.ctrl', ['roadmaps.factory', 'services.server', 'services.user', 'scraper.ctrl'])

.controller('RoadMapsController', [ '$scope', '$http', '$stateParams', 'RoadMapsFactory', 'Server', 'User', '$timeout', '$state', function($scope, $http, $stateParams, RoadMapsFactory, Server, User, $timeout, $state){
  angular.extend($scope, RoadMapsFactory);

  var roadmapId = $stateParams.roadmapID;
  $scope.currentRoadMapData = {};
  $scope.renderedNodes = [];
  $('.tooltipped').tooltip({delay: 50});

  $scope.showComments = false;
  $scope.currentIndex = 0;

  $scope.toggleComments = function(){
    $scope.showComments = true;
  };

  $scope.isAuthor = function (){
    var username = localStorage.getItem('user.username');
    var roadmapAuthor = $scope.currentRoadMapData.author.username;
    if (username === roadmapAuthor){
      return true;
    } else {
      return false;
    }
  };

  $scope.resetCreationForm = function() {
    $scope.urlToScrape = "";
    $scope.currentCreationTitle = 'New node title';
    $scope.currentCreationDescription = 'New node description';
    $scope.currentCreationType = 'New node type';
    $scope.currentCreationLink = 'New node link (optional)';
    $scope.currentCreationImage = 'New node image (optional)';
  }

  $scope.resetCreationForm();

  $scope.urlToScrape = '';
  $scope.displayUrl = '';
  $scope.scrape = {};

  $scope.checkAndSubmit = function() {
    var url = $scope.urlToScrape;
    if (url.length < 4) return;
    if (url.substring(0, 4) !== 'http') url = 'http://' + url;

    $scope.displayUrl = url;

    Server.scrape(url)
    .then(function (data) {
      console.log('web scrape data is', data);
        $scope.currentCreationTitle = data.title;
        $scope.currentCreationDescription = data.description;
        $scope.currentCreationType = data.type;
        $scope.currentCreationLink = url;
        $scope.currentCreationImage = data.imageUrl;
    });
  };

  $scope.showNodeCreator = function($index, boolean){
    var username = localStorage.getItem('user.username');
    var roadmapAuthor = $scope.currentRoadMapData.author.username;
    console.log("'mini-circle-' + $index", 'mini-circle-' + $index);
    if( username !== roadmapAuthor ){
      $scope.nodeCreator = false;
      console.log("author fail");
    } else {

      $scope.displayNodeCreator = boolean;
    }
  }

  $scope.createNode = function($index) {
    if( $scope.currentCreationImage === 'New node image (optional)' ){
      $scope.currentCreationImage = 'https://openclipart.org/image/2400px/svg_to_png/103885/SimpleStar.png';
    }
    $('#editor-placeholder').remove();
    return Server.createNode({
      title: $scope.currentCreationTitle,
      description: $scope.currentCreationDescription,
      resourceType: $scope.currentCreationType,
      resourceURL: $scope.currentCreationLink,
      imageUrl: $scope.currentCreationImage,
      parentRoadmap: roadmapId
    })
    .then(function(res){
      populateData();
      console.log("node created");
      $scope.displayNodeCreator = false;
      Materialize.toast('Node Added!', 4000, 'orangeToast');
      $scope.resetCreationForm();
    });
  };

  $scope.closeNodeCreator = function(){
    $scope.displayNodeCreator = false;
    $scope.resetCreationForm();
  }

  $scope.hideText = function ($index, field, idPrefix){
    $index = $index || 0;
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    var username = localStorage.getItem('user.username');
    var roadmapAuthor = $scope.currentRoadMapData.author.username;
    if( username !== roadmapAuthor ){
      return false;
    } else {
      if( !$scope[elementID] ){
        return  false;
      } else {
        return true;
      }
    }
  };

  $scope.showEditor = function ($index, field, boolean, idPrefix){
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    $scope.currentIndex = $index;
    var username = localStorage.getItem('user.username');
    var roadmapAuthor = $scope.currentRoadMapData.author.username;

    if( username !== roadmapAuthor ){
      $scope[elementID] = false;
      console.log("author fail");
    } else {
      if( field === 'circle' && idPrefix === 'mini'){
        $scope.resetCreationForm();
      }
      if( !$scope.currentResourceURL ) {
        $scope.currentResourceURL = $scope.currentLinks[0];
      }

      if(boolean === false && field !== 'circle'){
        $(elementID).val($scope.renderedNodes[$index][field]);
      }
      console.log("SHOW EDITOR");
      console.log('elementID', elementID);
      console.log('$scope[elementID]', $scope[elementID]);
      $scope[elementID] = boolean;
    }

  };

  $scope.getPlaceholder = function($index, field){
    var capitalizedField = field.substr(0, 1).toUpperCase() + field.substr(1);
    return $scope['current' + capitalizedField];
  };

  $scope.saveEdit = function($index, field, idPrefix){
    var elementID = '#' + idPrefix + '-' + field + '-' + $index;
    var newProperty = $(elementID).val();
    var updateObj = {};
    updateObj['_id'] = $scope.renderedNodes[$index]._id;
    updateObj[field] = newProperty;
    Server.updateNode(updateObj)
      .then(function(node) {
      $scope.showEditor($index, field, false, idPrefix);
      $scope.renderedNodes[$index][field] = newProperty;
      var capitalizedField = field.substr(0, 1).toUpperCase() + field.substr(1);
      $scope['current' + capitalizedField] = newProperty;
      if( field === 'resourceURL' ){
        $scope.currentLinks[0] = newProperty;
      }
    })
      .catch(function(){
        console.log('problem updating node', err);
      });
  };

  //roadMapTitle

  $scope.hideTitle = false;

  $scope.showTitleEditor = function (boolean){
    var username = localStorage.getItem('user.username');
    var roadmapAuthor = $scope.currentRoadMapData.author.username;
    var storedTitle;

    if( username !== roadmapAuthor ){
      $scope.hideTitle = false;
    } else {
      $scope.hideTitle = boolean;
      return $scope.hideTitle;
    }

  };

  $scope.saveTitleEdit = function (){
    var newProperty = $('#main-title').val();
    var updateObj = {};
    updateObj['_id'] = roadmapId;
    updateObj['title'] = newProperty;
    Server.updateRoadmap(updateObj)
      .then(function(node) {
      $scope.hideTitle = false;
      $scope.roadMapTitle = newProperty;
    })
      .catch(function(){
        console.log('problem updating map title', err);
      });
  }

 // Get the current number of upvotes from current map
 $scope.getCountVotes = function(votes){
    $scope.votesCount = 0;
    for(var i = 0; i < votes.length; i++){
      $scope.votesCount++;
    }
    return $scope.votesCount;
 }

 // Renders the nodes for the current roadmap to the page
  $scope.renderNodes = function(){
    var title = $scope.currentRoadMapData.title || 'test title';
    var nodes = $scope.currentRoadMapData.nodes || ['testnode1', 'testnode2'];
    // Add an index to nodes to make ng-clicking easier
    nodes.map(function(node,index){
      node.index = index;
    });

    $scope.renderedNodes = nodes;
    $scope.roadMapTitle = title;

    // User Logged in Data in the future
    // Some variable that holds that the user is logged in
    $scope.currentNode = nodes[0];
    $scope.renderCurrentNode();
  };
  // Make a $scope.renderComments()
  $scope.renderComments = function(){
    var comments = $scope.currentRoadMapData.comments;
    console.log(comments);
    comments.map(function(comment,index){
      comment.index = index;
    })
    $scope.renderedComments = comments;
  }

  // When roadmap (identified by its id) data is fetched, set it
  function populateData (stop){
    stop = stop || false;
    Server.getRoadmapById(roadmapId).then(function (res){
      if( !res.nodes.length && stop === false){
        populateData(true);
      }
      $scope.currentRoadMapData = res;
      console.log($scope.currentRoadMapData,'I am the roadmap');
    }, function(err){
      if (err) return console.log(err);
    })
    .then(function(){
      $scope.renderNodes();
      $scope.renderComments();
      // Set the upvotes and downvotes
      var currentMapUpVotes = $scope.currentRoadMapData.upvotes;
      var currentMapDownVotes = $scope.currentRoadMapData.downvotes;
      $scope.upVoteCount = $scope.getCountVotes(currentMapUpVotes);
      $scope.downVoteCount = $scope.getCountVotes(currentMapDownVotes);

      // append Editor Mode message
      var username = localStorage.getItem('user.username');
      var roadmapAuthor = $scope.currentRoadMapData.author.username;

      if( username === roadmapAuthor ){
        $('#editor-placeholder').append(
        '
' +
          '
' +
            '' +
          '
' +
          '
' +
              'Since you created this roadmap, you can add or edit properties by clicking on them.' +
          '
' +
          '
' +
            '' +
          '
' +
        '
'
        );
      }
    });
  }

  populateData();

  // Render Title
  // Assumes title links and description properties from get method
  $scope.renderCurrentNode = function(){
    // For now lets make $scope.loggedIn be false, if logged in we can change it to true later.
    $scope.loggedin = false;
    if($scope.loggedIn) {
      // Get node index
      // set currentNode into node at that index;
    } else {
      //links from a node
      var links = $scope.renderedNodes[0].resourceURL;
      //description of a node
      var description = $scope.renderedNodes[0].description;
      var title = $scope.renderedNodes[0].title;
    }

    $scope.currentTitle = title;
    $scope.currentLinks = [links];
    $scope.currentDescription = description;
  }

  $scope.selectNode = function($index) {

    var links = $scope.renderedNodes[$index].resourceURL;
    var description = $scope.renderedNodes[$index].description;
    var title = $scope.renderedNodes[$index].title;

    $scope.currentIndex = $index;
    $scope.currentTitle = title;
    $scope.currentLinks = links;
    $scope.currentResourceURL = $scope.currentLinks[0];
    $scope.currentDescription = description;
    $scope.currentNode = $scope.renderedNodes[$index];

  };
  // Submits a node to the user's inProgress.nodes array.
  $scope.submitCompletedNode = function() {
    var nodeId = $scope.currentNode._id;
    User.completeNodeById(nodeId);
    Materialize.toast('Node Complete!', 4000, 'orangeToast');
  }

  // Submits a roadmap to the user's completedRoadmaps array.
  $scope.submitCompletedRoadmap = function() {
    Materialize.toast('Map Complete!', 4000, 'orangeToast');
    User.completeRoadmapById(roadmapId);
    $state.go('home.dashboard', {type: 'completed'});
  }

  // After upvote, submits vote update to the roadmap's upvotes and downvotes array
  $scope.upVoteMap = function () {
    User.upvoteMapById(roadmapId)
    .then(function(data){
      var dataUpVoteCount = data.upvotes;
      var dataDownVoteCount = data.downvotes;
      // Update the upvote count
      $scope.upVoteCount = $scope.getCountVotes(dataUpVoteCount);
      // Update the downvote count
      $scope.downVoteCount = $scope.getCountVotes(dataDownVoteCount);
    })
  }

  // After downvote, submits vote update to the roadmap's upvotes and downvotes array
  $scope.downVoteMap = function () {
    User.downvoteMapById(roadmapId)
    .then(function(data){
      var dataUpVoteCount = data.upvotes;
      var dataDownVoteCount = data.downvotes;
      // Update the upvote count
      $scope.upVoteCount = $scope.getCountVotes(dataUpVoteCount);
      // Update the downvote count
      $scope.downVoteCount = $scope.getCountVotes(dataDownVoteCount);
    });
  };

  $scope.connectLines = function(){
    $('.endPointForConnection').connections();
  };

  // We need async because ng-repeat creates the nodes before this function runs set timeout changes the loop.
  $scope.asyncConnectLines = function(cb){
    setTimeout($scope.connectLines,0);
  };

  $scope.subject = '';
  $scope.content = '';

  $scope.postComment = function(){
    // Will probably need to refactor
    $scope.currentRoadMapData.comments = $scope.currentRoadMapData.comments || [];

    Server.createComment({
      subject: $scope.subject,
      content: $scope.content,
      roadmap: $scope.currentRoadMapData._id
    });
  };

}]);
<|endoftext|>


<commit_before>'use strict';

const
  debug = require('debug')('kuzzle:broker:client'),
  path = require('path'),
  Promise = require('bluebird'),
  InternalError = require('kuzzle-common-objects').errors.InternalError;

let WS = require('ws'); // cannot be constant: stubbed in unit tests

  /**
 * Websocket client implementation for Kuzzle internal broker
 *
 * @param brokerType
 * @param options
 * @param pluginsManager
 * @param notifyOnListen
 * @constructor
 */
function WSBrokerClient (brokerType, options, pluginsManager, notifyOnListen) {
  this.pluginsManager = pluginsManager;
  this.eventName = brokerType;
  this.notifyOnListen = notifyOnListen;

  this._pingTimeout = options.pingTimeout || 50;
  this._pingInterval = options.pingInterval || 1000 * 60;
  this._pingRequestTimeoutId = null;
  this._pingRequestIntervalId = null;

  this.client = {
    socket: null,
    connected: null,
    state: 'disconnected',
    retryInterval: options.retryInterval || 1000
  };

  this.handlers = {};
  this.onConnectHandlers = [];
  this.onCloseHandlers = [];
  this.onErrorHandlers = [];
  this.server = {};

  if (options.host) {
    this.server.address = `ws://${options.host}:${options.port}`;
    this.server.transport = 'tcp';
  }
  else if (options.socket) {
    this.server.address = `ws+unix://${path.resolve(options.socket)}`;
    this.server.transport = 'unix';
    this.server.path = options.socket;
  }
  else {
    throw new InternalError('No endpoint configuration given to connect.');
  }

  this.ws = () => new WS(this.server.address, {perMessageDeflate: false});

  this.reconnect = true;
  this.retryTimer = null;
}

/**
 * Initializes the underlying Web socket connection
 *
 * @type {WSBrokerClient.client}
 */
WSBrokerClient.prototype.init = function wSBrokerClientInit () {
  if (this.client.connected) {
    return this.client.connected.promise;
  }

  this.client.state = 'pending';
  this.client.connected = getDeferredPromise();
  this._connect();

  return this.client.connected.promise;
};

/**
 * Attaches a callback to a given room.
 *
 * @param {string} room
 * @param {function} cb The callback
 */
WSBrokerClient.prototype.listen = function wSBrokerClientListen (room, cb) {
  if (!this.client.socket) {
    this.pluginsManager.trigger('log:error', `No socket for broker ${this.eventName}`);
    return false;
  }

  debug('[%s] broker client subscribed to room "%s"', this.eventName, room);

  if (this.handlers[room] === undefined) {
    this.handlers[room] = [];
  }

  this.handlers[room].push(cb);

  if (this.notifyOnListen !== false) {
    this.client.socket.send(JSON.stringify({
      action: 'listen',
      room: room
    }));
  }
};

/**
 * Stops listening to `room` notifications.
 *
 * @param {string} room
 */
WSBrokerClient.prototype.unsubscribe = function wSBrokerClientUnsubscribe (room) {
  if (!this.client.socket) {
    this.pluginsManager.trigger('log:error', `No socket for broker ${this.eventName}`);
    return false;
  }

  debug('[%s] broker client unsubscribed to room "%s"', this.eventName, room);

  if (this.handlers[room]) {
    delete this.handlers[room];
  }
  this.client.socket.send(JSON.stringify({
    action: 'unsubscribe',
    room: room
  }));
};

/**
 * Closes the underlying Websocket.
 */
WSBrokerClient.prototype.close = function wSBrokerClientClose () {
  if (!this.client.socket) {
    this.pluginsManager.trigger('log:error', `No socket for broker ${this.eventName}`);
    return false;
  }

  resetPing(this);

  if (this.client.state === 'connected') {
    this.client.state = 'disconnected';
    this.client.socket.close();
    this.client.socket = null;
    this.client.connected = getDeferredPromise();
  }
};

/**
 * Initiates the connection to the server.
 * Resolves the promise once connected.
 *
 * @private
 */
WSBrokerClient.prototype._connect = function wSBrokerClientConnect () {
  this.client.socket = this.ws();

  debug('[%s] initialize broker client connection on socket "%s"', this.eventName, this.server.address);

  this.client.socket.on('message', msg => {
    msg = JSON.parse(msg);

    debug('[%s] broker client received a message:\n%O', this.eventName, msg);

    if (msg.room && this.handlers[msg.room]) {
      this.handlers[msg.room].forEach(cb => cb(msg.data));
    }
  });

  this.client.socket.on('open', () => {
    debug('[%s] broker client connected', this.eventName);

    this.pluginsManager.trigger(this.eventName + ':connected', 'Connected to Kuzzle server');

    // if we were already listening to some rooms, subscribe again to the server
    Object.keys(this.handlers).forEach(room => {
      this.pluginsManager.trigger(this.eventName + ':reregistering', 'Re-registering room: ' + room);

      if (this.notifyOnListen !== false) {
        this.client.socket.send(JSON.stringify({
          action: 'listen',
          room: room
        }));
      }
    });

    this.onConnectHandlers.forEach(f => f());
    this.client.state = 'connected';

    resetPing(this);
    pingRequest(this);

    if (!this.client.connected.promise.isFulfilled()) {
      return this.client.connected.resolve(this.client.socket);
    }

    this.pluginsManager.trigger('log:warn', `[${this.eventName}] Node is connected while it was previously already.`);
  });

  this.client.socket.on('close', code => {
    debug('[%s] broker client received a exit code: %s', this.eventName, code);

    // Automatically reconnect except if this.close() was called
    if (this.client.state === 'disconnected') {
      return false;
    }
    this.close();

    this.onCloseHandlers.forEach(f => f());

    this.pluginsManager.trigger(this.eventName + ':socketClosed',
      `Socket closed with code ${code}
    ==> RECONNECTING IN ${this.client.retryInterval}ms`
    );

    this.client.state = 'retrying';

    if (this.retryTimer) {
      clearTimeout(this.retryTimer);
      this.retryTimer = null;
    }

    if (this.reconnect) {
      this.retryTimer = setTimeout(() => this._connect(), this.client.retryInterval);
    }
  });

  this.client.socket.on('error', err => {
    debug('[%s] broker client received an error: %s', this.eventName, err);

    this.close();

    this.onErrorHandlers.forEach(f => f());

    this.pluginsManager.trigger('log:error',
      `[${this.eventName}] Error while trying to connect to ${this.server.address} [${err.message}]
    ==> RECONNECTING IN ${this.client.retryInterval}ms`
    );
    this.pluginsManager.trigger(this.eventName + ':error', {
      server: this.server.address,
      message: err.message,
      retry: this.client.retryInterval
    });

    this.client.state = 'retrying';

    if (this.retryTimer) {
      clearTimeout(this.retryTimer);
      this.retryTimer = null;
    }

    if (this.reconnect) {
      this.retryTimer = setTimeout(() => this._connect(), this.client.retryInterval);
    }
  });
};

/**
 * Sends `data` to the server.
 *
 * @param {string} room
 * @param {object} data
 */
WSBrokerClient.prototype.broadcast = function wSBrokerClientBroadcast (room, data) {
  return emit(this, 'broadcast', room, data);
};

/**
 *
 * @param {string} room
 * @param {object} data
 */
WSBrokerClient.prototype.send = function wSBrokerClientSend (room, data) {
  return emit(this, 'send', room, data);
};

WSBrokerClient.prototype.waitForClients = function wSBrokerClientWaitForClients () {
  return Promise.reject(new InternalError('Not implemented for broker client'));
};

module.exports = WSBrokerClient;

/**
 * @param {WSBrokerClient} broker
 * @param {string} mode
 * @param {string} room
 * @param {object} data
 * @returns {*}
 */
function emit (broker, mode, room, data) {
  if (!broker.client.socket) {
    broker.pluginsManager.trigger('log:error', `No socket for broker ${broker.eventName}`);
    return false;
  }

  debug('[%s] broker client %s a message in room "%s":\n%O', broker.eventName, mode, room, data);

  return broker.client.socket.send(JSON.stringify({
    action: mode,
    room: room,
    data: data
  }));
}

function getDeferredPromise() {
  var
    resolve,
    reject,
    promise;

  promise = new Promise((res, rej) => {
    resolve = res;
    reject = rej;
  });

  return {resolve, reject, promise};
}

/**
 * Ensure that ping timeout, ping interval and pong listener are empty
 * @param {WSBrokerClient} broker
 */
function resetPing(broker) {
  debug('[%s] broker client reset ping requests status', broker.eventName);

  if (broker.client && broker.client.socket) {
    broker.client.socket.removeAllListeners('pong');
  }

  if (broker._pingRequestIntervalId) {
    clearTimeout(broker._pingRequestIntervalId);
    broker._pingRequestIntervalId = null;
  }

  if (broker._pingRequestTimeoutId) {
    clearTimeout(broker._pingRequestTimeoutId);
    broker._pingRequestTimeoutId = null;
  }
}

/**
 * Send a ping request to server
 * - register pong response handler
 * - handle the ping request timeout
 * @param {WSBrokerClient} broker
 */
function pingRequest(broker) {
  debug('[%s] broker client sending ping request to server', broker.eventName);

  broker.client.socket.once('pong', () => handlePongResponse(broker));
  broker.client.socket.ping();

  broker._pingRequestTimeoutId = setTimeout(() => {
    debug('[%s] ping timed out, disconnecting from server', broker.eventName);

    if (broker.client.socket) {
      broker.client.socket.emit('error', new Error('Connection to server timed out'));
    }

  }, broker._pingTimeout);
}

/**
 * Pong response handler
 * - remove ping timeout
 * - delay new ping request
 * @param {WSBrokerClient} broker
 */
function handlePongResponse(broker) {
  debug('[%s] broker client received pong from server', broker.eventName);

  if (broker._pingRequestTimeoutId) {
    clearTimeout(broker._pingRequestTimeoutId);
    broker._pingRequestTimeoutId = null;
  }

  broker._pingRequestIntervalId = setTimeout(() => {
    pingRequest(broker);
  }, broker._pingInterval);
}
<commit_msg>Fix - broker client - clear ping timer even if socket is down<commit_after>'use strict';

const
  debug = require('debug')('kuzzle:broker:client'),
  path = require('path'),
  Promise = require('bluebird'),
  InternalError = require('kuzzle-common-objects').errors.InternalError;

let WS = require('ws'); // cannot be constant: stubbed in unit tests

  /**
 * Websocket client implementation for Kuzzle internal broker
 *
 * @param brokerType
 * @param options
 * @param pluginsManager
 * @param notifyOnListen
 * @constructor
 */
function WSBrokerClient (brokerType, options, pluginsManager, notifyOnListen) {
  this.pluginsManager = pluginsManager;
  this.eventName = brokerType;
  this.notifyOnListen = notifyOnListen;

  this._pingTimeout = options.pingTimeout || 50;
  this._pingInterval = options.pingInterval || 1000 * 60;
  this._pingRequestTimeoutId = null;
  this._pingRequestIntervalId = null;

  this.client = {
    socket: null,
    connected: null,
    state: 'disconnected',
    retryInterval: options.retryInterval || 1000
  };

  this.handlers = {};
  this.onConnectHandlers = [];
  this.onCloseHandlers = [];
  this.onErrorHandlers = [];
  this.server = {};

  if (options.host) {
    this.server.address = `ws://${options.host}:${options.port}`;
    this.server.transport = 'tcp';
  }
  else if (options.socket) {
    this.server.address = `ws+unix://${path.resolve(options.socket)}`;
    this.server.transport = 'unix';
    this.server.path = options.socket;
  }
  else {
    throw new InternalError('No endpoint configuration given to connect.');
  }

  this.ws = () => new WS(this.server.address, {perMessageDeflate: false});

  this.reconnect = true;
  this.retryTimer = null;
}

/**
 * Initializes the underlying Web socket connection
 *
 * @type {WSBrokerClient.client}
 */
WSBrokerClient.prototype.init = function wSBrokerClientInit () {
  if (this.client.connected) {
    return this.client.connected.promise;
  }

  this.client.state = 'pending';
  this.client.connected = getDeferredPromise();
  this._connect();

  return this.client.connected.promise;
};

/**
 * Attaches a callback to a given room.
 *
 * @param {string} room
 * @param {function} cb The callback
 */
WSBrokerClient.prototype.listen = function wSBrokerClientListen (room, cb) {
  if (!this.client.socket) {
    this.pluginsManager.trigger('log:error', `No socket for broker ${this.eventName}`);
    return false;
  }

  debug('[%s] broker client subscribed to room "%s"', this.eventName, room);

  if (this.handlers[room] === undefined) {
    this.handlers[room] = [];
  }

  this.handlers[room].push(cb);

  if (this.notifyOnListen !== false) {
    this.client.socket.send(JSON.stringify({
      action: 'listen',
      room: room
    }));
  }
};

/**
 * Stops listening to `room` notifications.
 *
 * @param {string} room
 */
WSBrokerClient.prototype.unsubscribe = function wSBrokerClientUnsubscribe (room) {
  debug('[%s] broker client unsubscribed to room "%s"', this.eventName, room);

  if (this.handlers[room]) {
    delete this.handlers[room];
  }

  if (!this.client.socket) {
    this.pluginsManager.trigger('log:error', `No socket for broker ${this.eventName}`);
    return false;
  }

  if (this.client.state !== 'connected') {
    this.pluginsManager.trigger('log:error', `Socket not ready for broker ${this.eventName}`);
  }

  this.client.socket.send(JSON.stringify({
    action: 'unsubscribe',
    room: room
  }));
};

/**
 * Closes the underlying Websocket.
 */
WSBrokerClient.prototype.close = function wSBrokerClientClose () {
  resetPing(this);

  if (!this.client.socket) {
    this.pluginsManager.trigger('log:error', `No socket for broker ${this.eventName}`);
    return false;
  }

  if (this.client.state === 'connected') {
    this.client.state = 'disconnected';
    this.client.socket.close();
    this.client.socket = null;
    this.client.connected = getDeferredPromise();
  }
};

/**
 * Initiates the connection to the server.
 * Resolves the promise once connected.
 *
 * @private
 */
WSBrokerClient.prototype._connect = function wSBrokerClientConnect () {
  this.client.socket = this.ws();

  debug('[%s] initialize broker client connection on socket "%s"', this.eventName, this.server.address);

  this.client.socket.on('message', msg => {
    msg = JSON.parse(msg);

    debug('[%s] broker client received a message:\n%O', this.eventName, msg);

    if (msg.room && this.handlers[msg.room]) {
      this.handlers[msg.room].forEach(cb => cb(msg.data));
    }
  });

  this.client.socket.on('open', () => {
    debug('[%s] broker client connected', this.eventName);

    this.pluginsManager.trigger(this.eventName + ':connected', 'Connected to Kuzzle server');

    // if we were already listening to some rooms, subscribe again to the server
    Object.keys(this.handlers).forEach(room => {
      this.pluginsManager.trigger(this.eventName + ':reregistering', 'Re-registering room: ' + room);

      if (this.notifyOnListen !== false) {
        this.client.socket.send(JSON.stringify({
          action: 'listen',
          room: room
        }));
      }
    });

    this.onConnectHandlers.forEach(f => f());
    this.client.state = 'connected';

    resetPing(this);
    pingRequest(this);

    if (!this.client.connected.promise.isFulfilled()) {
      return this.client.connected.resolve(this.client.socket);
    }

    this.pluginsManager.trigger('log:warn', `[${this.eventName}] Node is connected while it was previously already.`);
  });

  this.client.socket.on('close', code => {
    debug('[%s] broker client received a exit code: %s', this.eventName, code);

    // Automatically reconnect except if this.close() was called
    if (this.client.state === 'disconnected') {
      return false;
    }
    this.close();

    this.onCloseHandlers.forEach(f => f());

    this.pluginsManager.trigger(this.eventName + ':socketClosed',
      `Socket closed with code ${code}
    ==> RECONNECTING IN ${this.client.retryInterval}ms`
    );

    this.client.state = 'retrying';

    if (this.retryTimer) {
      clearTimeout(this.retryTimer);
      this.retryTimer = null;
    }

    if (this.reconnect) {
      this.retryTimer = setTimeout(() => this._connect(), this.client.retryInterval);
    }
  });

  this.client.socket.on('error', err => {
    debug('[%s] broker client received an error: %s', this.eventName, err);

    this.close();

    this.onErrorHandlers.forEach(f => f());

    this.pluginsManager.trigger('log:error',
      `[${this.eventName}] Error while trying to connect to ${this.server.address} [${err.message}]
    ==> RECONNECTING IN ${this.client.retryInterval}ms`
    );
    this.pluginsManager.trigger(this.eventName + ':error', {
      server: this.server.address,
      message: err.message,
      retry: this.client.retryInterval
    });

    this.client.state = 'retrying';

    if (this.retryTimer) {
      clearTimeout(this.retryTimer);
      this.retryTimer = null;
    }

    if (this.reconnect) {
      this.retryTimer = setTimeout(() => this._connect(), this.client.retryInterval);
    }
  });
};

/**
 * Sends `data` to the server.
 *
 * @param {string} room
 * @param {object} data
 */
WSBrokerClient.prototype.broadcast = function wSBrokerClientBroadcast (room, data) {
  return emit(this, 'broadcast', room, data);
};

/**
 *
 * @param {string} room
 * @param {object} data
 */
WSBrokerClient.prototype.send = function wSBrokerClientSend (room, data) {
  return emit(this, 'send', room, data);
};

WSBrokerClient.prototype.waitForClients = function wSBrokerClientWaitForClients () {
  return Promise.reject(new InternalError('Not implemented for broker client'));
};

module.exports = WSBrokerClient;

/**
 * @param {WSBrokerClient} broker
 * @param {string} mode
 * @param {string} room
 * @param {object} data
 * @returns {*}
 */
function emit (broker, mode, room, data) {
  if (!broker.client.socket) {
    broker.pluginsManager.trigger('log:error', `No socket for broker ${broker.eventName}`);
    return false;
  }

  debug('[%s] broker client %s a message in room "%s":\n%O', broker.eventName, mode, room, data);

  return broker.client.socket.send(JSON.stringify({
    action: mode,
    room: room,
    data: data
  }));
}

function getDeferredPromise() {
  var
    resolve,
    reject,
    promise;

  promise = new Promise((res, rej) => {
    resolve = res;
    reject = rej;
  });

  return {resolve, reject, promise};
}

/**
 * Ensure that ping timeout, ping interval and pong listener are empty
 * @param {WSBrokerClient} broker
 */
function resetPing(broker) {
  debug('[%s] broker client reset ping requests status', broker.eventName);

  if (broker.client && broker.client.socket) {
    broker.client.socket.removeAllListeners('pong');
  }

  if (broker._pingRequestIntervalId) {
    clearTimeout(broker._pingRequestIntervalId);
    broker._pingRequestIntervalId = null;
  }

  if (broker._pingRequestTimeoutId) {
    clearTimeout(broker._pingRequestTimeoutId);
    broker._pingRequestTimeoutId = null;
  }
}

/**
 * Send a ping request to server
 * - register pong response handler
 * - handle the ping request timeout
 * @param {WSBrokerClient} broker
 */
function pingRequest(broker) {
  debug('[%s] broker client sending ping request to server', broker.eventName);

  broker.client.socket.once('pong', () => handlePongResponse(broker));
  broker.client.socket.ping();

  broker._pingRequestTimeoutId = setTimeout(() => {
    debug('[%s] ping timed out, disconnecting from server', broker.eventName);

    if (broker.client.socket) {
      broker.client.socket.emit('error', new Error('Connection to server timed out'));
    }

  }, broker._pingTimeout);
}

/**
 * Pong response handler
 * - remove ping timeout
 * - delay new ping request
 * @param {WSBrokerClient} broker
 */
function handlePongResponse(broker) {
  debug('[%s] broker client received pong from server', broker.eventName);

  if (broker._pingRequestTimeoutId) {
    clearTimeout(broker._pingRequestTimeoutId);
    broker._pingRequestTimeoutId = null;
  }

  broker._pingRequestIntervalId = setTimeout(() => {
    pingRequest(broker);
  }, broker._pingInterval);
}
<|endoftext|>


<commit_before>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

describe('Geolocation (navigator.geolocation)', function () {
    it("should exist", function() {
        expect(navigator.geolocation).toBeDefined();
    });

    it("should contain a getCurrentPosition function", function() {
        expect(typeof navigator.geolocation.getCurrentPosition).toBeDefined();
        expect(typeof navigator.geolocation.getCurrentPosition == 'function').toBe(true);
    });

    it("should contain a watchPosition function", function() {
        expect(typeof navigator.geolocation.watchPosition).toBeDefined();
        expect(typeof navigator.geolocation.watchPosition == 'function').toBe(true);
    });

    it("should contain a clearWatch function", function() {
        expect(typeof navigator.geolocation.clearWatch).toBeDefined();
        expect(typeof navigator.geolocation.clearWatch == 'function').toBe(true);
    });

    describe('getCurrentPosition method', function() {
        describe('error callback', function() {
            it("should be called if we set timeout to 0 and maximumAge to a very small number", function() {
                console.log("Here I am");
                var win = jasmine.createSpy(),
                    fail = jasmine.createSpy();

                runs(function () {
                    navigator.geolocation.getCurrentPosition(win, fail, {
                        maximumAge: 0,
                        timeout: 0
                    });
                });

                waitsFor(function () { return fail.wasCalled; }, "fail never called", 250); //small timeout as this should fire very fast

                runs(function () {
                    expect(win).not.toHaveBeenCalled();
                });
            });
        });

        describe('success callback', function() {
            it("should be called with a Position object", function() {
                var win = jasmine.createSpy().andCallFake(function(p) {
                          expect(p.coords).toBeDefined();
                          expect(p.timestamp).toBeDefined();
                          expect(p.timestamp instanceof Date).toBe(true);
                      }),
                      fail = jasmine.createSpy();

                runs(function () {
                    navigator.geolocation.getCurrentPosition(win, fail, {
                        maximumAge:300000 // 5 minutes maximum age of cached position
                    });
                });

                waitsFor(function () { return win.wasCalled; }, "win never called", 20000);

                runs(function () {
                    expect(fail).not.toHaveBeenCalled();
                });
            });
        });
    });

    describe('watchPosition method', function() {
        describe('error callback', function() {
            var errorWatch = null;

            afterEach(function() {
                navigator.geolocation.clearWatch(errorWatch);
            });
            it("should be called if we set timeout to 0 and maximumAge to a very small number", function() {
                var win = jasmine.createSpy(),
                    fail = jasmine.createSpy();

                runs(function () {
                    errorWatch = navigator.geolocation.watchPosition(win, fail, {
                        maximumAge: 0,
                        timeout: 0
                    });
                });

                waitsFor(function () { return fail.wasCalled; }, "fail never called", 250); // small timeout as this hsould fire very quickly

                runs(function () {
                    expect(win).not.toHaveBeenCalled();
                });
            });
        });

        describe('success callback', function() {
            var successWatch = null;

            afterEach(function() {
                navigator.geolocation.clearWatch(successWatch);
            });
            it("should be called with a Position object", function() {
                var win = jasmine.createSpy().andCallFake(function(p) {
                          expect(p.coords).toBeDefined();
                          expect(p.timestamp).toBeDefined();
                          expect(p.timestamp instanceof Date).toBe(true);
                      }),
                      fail = jasmine.createSpy();

                runs(function () {
                    successWatch = navigator.geolocation.watchPosition(win, fail, {
                        maximumAge:300000 // 5 minutes maximum age of cached position
                    });
                });

                waitsFor(function () { return win.wasCalled; }, "win never called", 20000);

                runs(function () {
                    expect(fail).not.toHaveBeenCalled();
                });
            });
        });
    });

    describe("Geolocation model", function () {
        it("should be able to define a Position object with coords and timestamp properties", function() {
            var pos = new Position({}, new Date());
            expect(pos).toBeDefined();
            expect(pos.coords).toBeDefined();
            expect(pos.timestamp).toBeDefined();
        });

        it("should be able to define a Coordinates object with latitude, longitude, accuracy, altitude, heading, speed and altitudeAccuracy properties", function() {
            var coords = new Coordinates(1,2,3,4,5,6,7);
            expect(coords).toBeDefined();
            expect(coords.latitude).toBeDefined();
            expect(coords.longitude).toBeDefined();
            expect(coords.accuracy).toBeDefined();
            expect(coords.altitude).toBeDefined();
            expect(coords.heading).toBeDefined();
            expect(coords.speed).toBeDefined();
            expect(coords.altitudeAccuracy).toBeDefined();
        });
    });
});
<commit_msg>[CB-1581, CB-1582] invalid tests<commit_after>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
*/

describe('Geolocation (navigator.geolocation)', function () {
    it("should exist", function() {
        expect(navigator.geolocation).toBeDefined();
    });

    it("should contain a getCurrentPosition function", function() {
        expect(typeof navigator.geolocation.getCurrentPosition).toBeDefined();
        expect(typeof navigator.geolocation.getCurrentPosition == 'function').toBe(true);
    });

    it("should contain a watchPosition function", function() {
        expect(typeof navigator.geolocation.watchPosition).toBeDefined();
        expect(typeof navigator.geolocation.watchPosition == 'function').toBe(true);
    });

    it("should contain a clearWatch function", function() {
        expect(typeof navigator.geolocation.clearWatch).toBeDefined();
        expect(typeof navigator.geolocation.clearWatch == 'function').toBe(true);
    });

    describe('getCurrentPosition method', function() {
        describe('error callback', function() {
            it("should be called if we set timeout to 0 and maximumAge to a very small number", function() {
                console.log("Here I am");
                var win = jasmine.createSpy(),
                    fail = jasmine.createSpy();

                runs(function () {
                    navigator.geolocation.getCurrentPosition(win, fail, {
                        maximumAge: 0,
                        timeout: 0
                    });
                });

                waitsFor(function () { return fail.wasCalled; }, "fail never called", 250); //small timeout as this should fire very fast

                runs(function () {
                    expect(win).not.toHaveBeenCalled();
                });
            });
        });

        describe('success callback', function() {
            it("should be called with a Position object", function() {
                var win = jasmine.createSpy().andCallFake(function(p) {
                          expect(p.coords).toBeDefined();
                          expect(p.timestamp).toBeDefined();
                      }),
                      fail = jasmine.createSpy();

                runs(function () {
                    navigator.geolocation.getCurrentPosition(win, fail, {
                        maximumAge:300000 // 5 minutes maximum age of cached position
                    });
                });

                waitsFor(function () { return win.wasCalled; }, "win never called", 20000);

                runs(function () {
                    expect(fail).not.toHaveBeenCalled();
                });
            });
        });
    });

    describe('watchPosition method', function() {
        describe('error callback', function() {
            var errorWatch = null;

            afterEach(function() {
                navigator.geolocation.clearWatch(errorWatch);
            });
            it("should be called if we set timeout to 0 and maximumAge to a very small number", function() {
                var win = jasmine.createSpy(),
                    fail = jasmine.createSpy();

                runs(function () {
                    errorWatch = navigator.geolocation.watchPosition(win, fail, {
                        maximumAge: 0,
                        timeout: 0
                    });
                });

                waitsFor(function () { return fail.wasCalled; }, "fail never called", 250); // small timeout as this hsould fire very quickly

                runs(function () {
                    expect(win).not.toHaveBeenCalled();
                });
            });
        });

        describe('success callback', function() {
            var successWatch = null;

            afterEach(function() {
                navigator.geolocation.clearWatch(successWatch);
            });
            it("should be called with a Position object", function() {
                var win = jasmine.createSpy().andCallFake(function(p) {
                          expect(p.coords).toBeDefined();
                          expect(p.timestamp).toBeDefined();
                      }),
                      fail = jasmine.createSpy();

                runs(function () {
                    successWatch = navigator.geolocation.watchPosition(win, fail, {
                        maximumAge:(5 * 60 * 1000) // 5 minutes maximum age of cached position
                    });
                });

                waitsFor(function () { return win.wasCalled; }, "win never called", 20000);

                runs(function () {
                    expect(fail).not.toHaveBeenCalled();
                });
            });
        });
    });
});
<|endoftext|>