<commit_before>'use strict';

angular.module('mwListableBb', [])

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListable
 * @element table
 * @description
 *
 * Directive for table to add 'Select all' checkbox in header and content related displays like 'None found'
 * or pagination logic. Use this directive when you want to display items in a list without any hassle.
 *
 * @param {string} selectable Instance of selectable for this listable item
 * @param {string} filterable Instance of filterable for this listable item. Needed for pagination.
 * @example
 * <doc:example>
 *   <doc:source>
 *

 *

 *

 *          A column
 *

 *

 *

 *

 *          Column content
 *

 *

 *

 *   </doc:source>
 * </doc:example>
 */
    .directive('mwListableBb', function (Persistance) {

      return {
        restrict: 'A',
        scope: {
          collection: '='
        },
        compile: function  (elm) {
          elm.append('

');

          return function (scope, elm) {
            elm.addClass('table table-striped mw-listable');
          };
        },
        controller: function ($scope) {
          var columns = $scope.columns = [],
              self = this;

          this.actionColumns = [];

          this.sort = function (property, order) {
            var sortOrder = order + property;
            Persistance.saveSortOrder(sortOrder, $scope.collection);
            $scope.collection.filterable.setSortOrder(sortOrder);
            $scope.collection.fetch();
          };

          this.getSortOrder = function () {
            return $scope.collection.filterable.getSortOrder();
          };

          this.registerColumn = function (scope) {
            columns.push(scope);
          };

          this.unRegisterColumn = function (scope) {
            if(scope && scope.$id){
              var scopeInArray = _.findWhere(columns,{$id:scope.$id}),
                  indexOfScope = _.indexOf(columns,scopeInArray);

              if(indexOfScope>-1){
                columns.splice(indexOfScope,1);
              }
            }
          };

          this.getColumns = function() {
            return columns;
          };

          this.getCollection = function () {
            return $scope.collection;
          };

          this.isRadio = function(){
            if($scope.collection && $scope.collection.selectable){
              return $scope.collection.selectable.isRadio();
            }
            return false;
          };

          $scope.$on('$destroy', function(){
            self.actionColumns = [];
          });
        }
      };
    })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListableHead
 * @element thead
 * @description
 *
 * Displays amount of items from filterable and the amount of selected items of the selectable
 *
 */

  .directive('mwListableHeadBb', function($compile) {
    return {
      require: '^mwListableBb',
      scope:{
        title:'@mwListableHeadBb',
        noCounter: '='
      },
      link: function(scope,el,attr,mwListable){
        scope.collection = mwListable.getCollection();

        if(angular.isUndefined(scope.noCounter)) {
          var tmpl = '
' +
                  '0">' +
                  ' 0">{{collection.selectable.getSelectedModels().length}}/{{collection.filterable.getTotalAmount() || collection.length}} {{title}} {{ \'common.selected\' | i18n }}' +
                  '<span ng-if="!collection.selectable || collection.selectable.getSelectedModels().length<1">{{collection.filterable.getTotalAmount() || collection.length}} {{title}}' +
                  '	' +
                  '
',
              $tmpl = angular.element(tmpl),
              compiled = $compile($tmpl);

          el.prepend($tmpl);
          compiled(scope);
        }
      }
    };
  })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListableFooter
 * @element tfoot
 * @description
 *
 * Displays footer with:
 * * loading spinner if list is loading
 * * 'none found' message if filterable is empty
 * * 'load more' button for pagination
 *
 */

    .directive('mwListableFooterBb', function(Loading) {
      return {
        require: '^mwListableBb',
        templateUrl: 'modules/ui/templates/mwListableBb/mwListableFooter.html',
        link: function(scope, elm, attr, mwListableCtrl) {
          scope.Loading = Loading;
          scope.collection = mwListableCtrl.getCollection();
          scope.columns = mwListableCtrl.getColumns();
        }
      };
    })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListableHeader
 * @element th
 * @description
 *
 * Directive for table to add 'Select all' checkbox in header and content related displays like 'None found'
 * or pagination logic. Use this directive when you want to display items in a list without any hassle.
 *
 * @param {string} sort Property key of the model to sort by
 */
    .directive('mwListableHeaderBb', function () {
      return {
        restrict: 'A',
        require: '^mwListableBb',
        scope: {
          property: '@sort'
        },
        transclude: true,
        replace:true,
        templateUrl: 'modules/ui/templates/mwListableBb/mwListableHeader.html',
        link: function (scope, elm, attr, mwListableCtrl) {
          var ascending = '+',
              descending = '-';

          scope.toggleSortOrder = function () {
            if (scope.property) {
              var sortOrder = ascending; //default
              if (mwListableCtrl.getSortOrder() === ascending + scope.property) {
                sortOrder = descending;
              }
              mwListableCtrl.sort(scope.property, sortOrder);
            }
          };

          scope.isSelected = function (prefix) {
            if (prefix) {
              return mwListableCtrl.getSortOrder() === prefix + scope.property;
            } else {
              return (mwListableCtrl.getSortOrder() === '+' + scope.property || mwListableCtrl.getSortOrder() === '-' + scope.property);
            }
          };

          if(scope.property){
            elm.find('.title').on('click',scope.toggleSortOrder);
          }

          mwListableCtrl.registerColumn(scope);

          scope.$on('$destroy', function(){
            mwListableCtrl.unRegisterColumn(scope);
          });
        }
      };
    })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListableColumnCheckbox
 * @element th
 * @description
 *
 * Directive for table to add 'Select item' checkbox in content.
 *
 * Note: this directive has to be nested inside an `mwListable` table.
 */
    .directive('mwListableColumnCheckboxBb', function () {
      return {
        restrict: 'A',
        require: '^mwListableBb',
        scope: {
          item: '='
        },
        templateUrl: 'modules/ui/templates/mwListableBb/mwListableColumnCheckbox.html',
        link: function (scope, elm, attr, mwListableCtrl) {
          scope.radio = mwListableCtrl.isRadio();
          scope.click = function (item, $event) {
            $event.stopPropagation();
            if(item.selectable){
              item.selectable.toggleSelect();
            }
          };

          scope.$watch('item.selectable.isDisabled()', function(isDisabled){
            if(isDisabled){
              scope.item.selectable.unSelect();
            }
          });
        }
      };
    })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListableHeaderCheckbox
 * @element th
 * @description
 *
 * Directive for table to add 'Select all' checkbox in header.
 *
 * @scope
 *
 * Note: this directive has to be nested inside an `mwListable` table.
 */
    .directive('mwListableHeaderCheckboxBb', function () {
      return {
        restrict: 'A',
        require: '^mwListableBb',
        scope: true,
        templateUrl: 'modules/ui/templates/mwListableBb/mwListableHeaderCheckbox.html',
        link: function (scope, elm, attr, mwListableCtrl) {
          scope.radio = mwListableCtrl.isRadio();
          scope.collection = mwListableCtrl.getCollection();
        }
      };
    })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListableRow
 * @element tr
 * @description
 *
 * Directive for table row. Adds click actions. And class 'selected' if row is selected.
 *
 * Note: this directive has to be nested inside an `mwListable` table.
 */
    .directive('mwListableBodyRowBb', function ($timeout) {
      return {
        restrict: 'A',
        require: '^mwListableBb',
        compile: function (elm) {

          elm.prepend('	');

          return function (scope, elm, attr, ctrl) {
            var selectedClass = 'selected';

            scope.collection = ctrl.getCollection();

            if(!scope.item) {
              throw new Error('No item available in the list! Please make sure to use ng-repeat="item in collection"');
            }

            if(scope.item && scope.collection.selectable && !scope.item.selectable.isDisabled()){
              elm.addClass('selectable clickable');
            } else if (ctrl.actionColumns && ctrl.actionColumns.length>0) {
              elm.addClass('clickable');
            }

            elm.on('click', function () {
              if (scope.collection.selectable && scope.item.selectable && !scope.item.selectable.isDisabled()) {
                $timeout(function(){
                  scope.item.selectable.toggleSelect();
                });
              }
            });

            elm.on('dblclick', function(){
              if(ctrl.actionColumns && angular.isNumber(scope.$index) && ctrl.actionColumns[scope.$index]){
                document.location.href=ctrl.actionColumns[scope.$index];
              }
            });

            scope.$watch('item.selectable.isSelected()', function (value) {
              if(value) {
                elm.addClass(selectedClass);
              } else {
                elm.removeClass(selectedClass);
              }
            });
          };
        }
      };
    })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListableHeaderRow
 * @element tr
 * @description
 *
 * Directive for table header row. Adds mw-listable-header-checkbox if selectable is present and th tags for actionColumns.
 *
 * Note: this directive has to be nested inside an `mwListable` table.
 */
    .directive('mwListableHeaderRowBb', function () {
      return {
        restrict: 'A',
        require: '^mwListableBb',
        scope: true,
        compile: function (elm) {
          elm.prepend('	');
          elm.append(' 0" colspan="{{ actionColumns.length }}" width="1%" class="action-button">	');

          return function (scope, elm, attr, mwListableCtrl) {
            //empty collection is [] so ng-if would not work as expected
            //we also have to check if the collection has a selectable
            scope.hasCollection = false;
            var collection = mwListableCtrl.getCollection();
            if(collection){
              scope.hasCollection = angular.isDefined(collection.length) && collection.selectable;
            }
            scope.actionColumns = mwListableCtrl.actionColumns;
          };
        }
      };
    })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListableLinkShow
 * @element td
 * @description
 *
 * Directive to add a button link to show a dataset.
 *
 * @param {string} mwListableLinkShow URL as href
 *
 * Note: this directive has to be nested inside an `mwListable` table.
 */
    .directive('mwListableLinkShowBb', function () {
      return {
        restrict: 'A',
        require: '^mwListableBb',
        scope: {
          link: '@mwListableLinkShowBb'
        },
        template: '',
        link: function (scope, elm, attr, mwListableCtrl) {
          mwListableCtrl.actionColumns.push(scope.link);
        }
      };
    })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwRowIdentifier
 * @description
 *
 * Directive that adds title attribute to th and td elements. Used to hide columns in css for special branding
 *
 * @param {string} mwRowIdentifier the title to be used
 *
 */
    .directive('mwRowIdentifierBb', function () {
      return {
        restrict: 'A',
        link: function (scope, elm, attr) {
          if(attr.mwRowIdentifier){
            attr.$set('title', attr.mwRowIdentifier);
          }
        }
      };
    })
;<commit_msg>fixes bug when item has no selectable<commit_after>'use strict';

angular.module('mwListableBb', [])

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListable
 * @element table
 * @description
 *
 * Directive for table to add 'Select all' checkbox in header and content related displays like 'None found'
 * or pagination logic. Use this directive when you want to display items in a list without any hassle.
 *
 * @param {string} selectable Instance of selectable for this listable item
 * @param {string} filterable Instance of filterable for this listable item. Needed for pagination.
 * @example
 * <doc:example>
 *   <doc:source>
 *

 *

 *

 *          A column
 *

 *

 *

 *

 *          Column content
 *

 *

 *

 *   </doc:source>
 * </doc:example>
 */
  .directive('mwListableBb', function (Persistance) {

    return {
      restrict: 'A',
      scope: {
        collection: '='
      },
      compile: function (elm) {
        elm.append('

');

        return function (scope, elm) {
          elm.addClass('table table-striped mw-listable');
        };
      },
      controller: function ($scope) {
        var columns = $scope.columns = [],
          self = this;

        this.actionColumns = [];

        this.sort = function (property, order) {
          var sortOrder = order + property;
          Persistance.saveSortOrder(sortOrder, $scope.collection);
          $scope.collection.filterable.setSortOrder(sortOrder);
          $scope.collection.fetch();
        };

        this.getSortOrder = function () {
          return $scope.collection.filterable.getSortOrder();
        };

        this.registerColumn = function (scope) {
          columns.push(scope);
        };

        this.unRegisterColumn = function (scope) {
          if (scope && scope.$id) {
            var scopeInArray = _.findWhere(columns, {$id: scope.$id}),
              indexOfScope = _.indexOf(columns, scopeInArray);

            if (indexOfScope > -1) {
              columns.splice(indexOfScope, 1);
            }
          }
        };

        this.getColumns = function () {
          return columns;
        };

        this.getCollection = function () {
          return $scope.collection;
        };

        this.isRadio = function () {
          if ($scope.collection && $scope.collection.selectable) {
            return $scope.collection.selectable.isRadio();
          }
          return false;
        };

        $scope.$on('$destroy', function () {
          self.actionColumns = [];
        });
      }
    };
  })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListableHead
 * @element thead
 * @description
 *
 * Displays amount of items from filterable and the amount of selected items of the selectable
 *
 */

  .directive('mwListableHeadBb', function ($compile) {
    return {
      require: '^mwListableBb',
      scope: {
        title: '@mwListableHeadBb',
        noCounter: '='
      },
      link: function (scope, el, attr, mwListable) {
        scope.collection = mwListable.getCollection();

        if (angular.isUndefined(scope.noCounter)) {
          var tmpl = '
' +
              '0">' +
              ' 0">{{collection.selectable.getSelectedModels().length}}/{{collection.filterable.getTotalAmount() || collection.length}} {{title}} {{ \'common.selected\' | i18n }}' +
              '<span ng-if="!collection.selectable || collection.selectable.getSelectedModels().length<1">{{collection.filterable.getTotalAmount() || collection.length}} {{title}}' +
              '	' +
              '
',
            $tmpl = angular.element(tmpl),
            compiled = $compile($tmpl);

          el.prepend($tmpl);
          compiled(scope);
        }
      }
    };
  })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListableFooter
 * @element tfoot
 * @description
 *
 * Displays footer with:
 * * loading spinner if list is loading
 * * 'none found' message if filterable is empty
 * * 'load more' button for pagination
 *
 */

  .directive('mwListableFooterBb', function (Loading) {
    return {
      require: '^mwListableBb',
      templateUrl: 'modules/ui/templates/mwListableBb/mwListableFooter.html',
      link: function (scope, elm, attr, mwListableCtrl) {
        scope.Loading = Loading;
        scope.collection = mwListableCtrl.getCollection();
        scope.columns = mwListableCtrl.getColumns();
      }
    };
  })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListableHeader
 * @element th
 * @description
 *
 * Directive for table to add 'Select all' checkbox in header and content related displays like 'None found'
 * or pagination logic. Use this directive when you want to display items in a list without any hassle.
 *
 * @param {string} sort Property key of the model to sort by
 */
  .directive('mwListableHeaderBb', function () {
    return {
      restrict: 'A',
      require: '^mwListableBb',
      scope: {
        property: '@sort'
      },
      transclude: true,
      replace: true,
      templateUrl: 'modules/ui/templates/mwListableBb/mwListableHeader.html',
      link: function (scope, elm, attr, mwListableCtrl) {
        var ascending = '+',
          descending = '-';

        scope.toggleSortOrder = function () {
          if (scope.property) {
            var sortOrder = ascending; //default
            if (mwListableCtrl.getSortOrder() === ascending + scope.property) {
              sortOrder = descending;
            }
            mwListableCtrl.sort(scope.property, sortOrder);
          }
        };

        scope.isSelected = function (prefix) {
          if (prefix) {
            return mwListableCtrl.getSortOrder() === prefix + scope.property;
          } else {
            return (mwListableCtrl.getSortOrder() === '+' + scope.property || mwListableCtrl.getSortOrder() === '-' + scope.property);
          }
        };

        if (scope.property) {
          elm.find('.title').on('click', scope.toggleSortOrder);
        }

        mwListableCtrl.registerColumn(scope);

        scope.$on('$destroy', function () {
          mwListableCtrl.unRegisterColumn(scope);
        });
      }
    };
  })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListableColumnCheckbox
 * @element th
 * @description
 *
 * Directive for table to add 'Select item' checkbox in content.
 *
 * Note: this directive has to be nested inside an `mwListable` table.
 */
  .directive('mwListableColumnCheckboxBb', function () {
    return {
      restrict: 'A',
      require: '^mwListableBb',
      scope: {
        item: '='
      },
      templateUrl: 'modules/ui/templates/mwListableBb/mwListableColumnCheckbox.html',
      link: function (scope, elm, attr, mwListableCtrl) {
        scope.radio = mwListableCtrl.isRadio();
        scope.click = function (item, $event) {
          $event.stopPropagation();
          if (item.selectable) {
            item.selectable.toggleSelect();
          }
        };

        scope.$watch('item.selectable.isDisabled()', function (isDisabled) {
          if (isDisabled) {
            scope.item.selectable.unSelect();
          }
        });
      }
    };
  })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListableHeaderCheckbox
 * @element th
 * @description
 *
 * Directive for table to add 'Select all' checkbox in header.
 *
 * @scope
 *
 * Note: this directive has to be nested inside an `mwListable` table.
 */
  .directive('mwListableHeaderCheckboxBb', function () {
    return {
      restrict: 'A',
      require: '^mwListableBb',
      scope: true,
      templateUrl: 'modules/ui/templates/mwListableBb/mwListableHeaderCheckbox.html',
      link: function (scope, elm, attr, mwListableCtrl) {
        scope.radio = mwListableCtrl.isRadio();
        scope.collection = mwListableCtrl.getCollection();
      }
    };
  })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListableRow
 * @element tr
 * @description
 *
 * Directive for table row. Adds click actions. And class 'selected' if row is selected.
 *
 * Note: this directive has to be nested inside an `mwListable` table.
 */
  .directive('mwListableBodyRowBb', function ($timeout) {
    return {
      restrict: 'A',
      require: '^mwListableBb',
      compile: function (elm) {

        elm.prepend('	');

        return function (scope, elm, attr, ctrl) {
          var selectedClass = 'selected';

          scope.collection = ctrl.getCollection();

          if (!scope.item) {
            throw new Error('No item available in the list! Please make sure to use ng-repeat="item in collection"');
          }

          if (scope.item && scope.item.selectable && !scope.item.selectable.isDisabled()) {
            elm.addClass('selectable clickable');
          } else if (ctrl.actionColumns && ctrl.actionColumns.length > 0) {
            elm.addClass('clickable');
          }

          elm.on('click', function () {
            if (scope.item && scope.item.selectable && !scope.item.selectable.isDisabled()) {
              $timeout(function () {
                scope.item.selectable.toggleSelect();
              });
            }
          });

          elm.on('dblclick', function () {
            if (ctrl.actionColumns && angular.isNumber(scope.$index) && ctrl.actionColumns[scope.$index]) {
              document.location.href = ctrl.actionColumns[scope.$index];
            }
          });

          scope.$watch('item.selectable.isSelected()', function (value) {
            if (value) {
              elm.addClass(selectedClass);
            } else {
              elm.removeClass(selectedClass);
            }
          });
        };
      }
    };
  })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListableHeaderRow
 * @element tr
 * @description
 *
 * Directive for table header row. Adds mw-listable-header-checkbox if selectable is present and th tags for actionColumns.
 *
 * Note: this directive has to be nested inside an `mwListable` table.
 */
  .directive('mwListableHeaderRowBb', function () {
    return {
      restrict: 'A',
      require: '^mwListableBb',
      scope: true,
      compile: function (elm) {
        elm.prepend('	');
        elm.append(' 0" colspan="{{ actionColumns.length }}" width="1%" class="action-button">	');

        return function (scope, elm, attr, mwListableCtrl) {
          //empty collection is [] so ng-if would not work as expected
          //we also have to check if the collection has a selectable
          scope.hasCollection = false;
          var collection = mwListableCtrl.getCollection();
          if (collection) {
            scope.hasCollection = angular.isDefined(collection.length) && collection.selectable;
          }
          scope.actionColumns = mwListableCtrl.actionColumns;
        };
      }
    };
  })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwListableLinkShow
 * @element td
 * @description
 *
 * Directive to add a button link to show a dataset.
 *
 * @param {string} mwListableLinkShow URL as href
 *
 * Note: this directive has to be nested inside an `mwListable` table.
 */
  .directive('mwListableLinkShowBb', function () {
    return {
      restrict: 'A',
      require: '^mwListableBb',
      scope: {
        link: '@mwListableLinkShowBb'
      },
      template: '',
      link: function (scope, elm, attr, mwListableCtrl) {
        mwListableCtrl.actionColumns.push(scope.link);
      }
    };
  })

/**
 * @ngdoc directive
 * @name mwListable.directive:mwRowIdentifier
 * @description
 *
 * Directive that adds title attribute to th and td elements. Used to hide columns in css for special branding
 *
 * @param {string} mwRowIdentifier the title to be used
 *
 */
  .directive('mwRowIdentifierBb', function () {
    return {
      restrict: 'A',
      link: function (scope, elm, attr) {
        if (attr.mwRowIdentifier) {
          attr.$set('title', attr.mwRowIdentifier);
        }
      }
    };
  })
;<|endoftext|>


<commit_before>/* File: userProfil.js
 *
 * Copyright (c) 2014
 * Centre National d’Enseignement à Distance (Cned), Boulevard Nicephore Niepce, 86360 CHASSENEUIL-DU-POITOU, France
 * (direction-innovation@cned.fr)
 *
 * GNU Affero General Public License (AGPL) version 3.0 or later version
 *
 * This file is part of a program which is free software: you can
 * redistribute it and/or modify it under the terms of the
 * GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 *
 */

'use strict';
/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
  UserProfil = mongoose.model('UserProfil');

exports.createUserProfil = function(req, res) {

  var userProfil = new UserProfil(req.body);

  UserProfil.findOne({
    userID: userProfil.userID,
    actuel: true
  }, function(err, item) {
    if (err) {
      res.send({
        'result': 'error'
      });
    } else {
      if (item) {
        item.actuel = false;
        item.save(function(err) {
          if (err) {
            res.send({
              'result': 'error'
            });
          } else {
            UserProfil.findOne({
              userID: userProfil.userID,
              profilID: userProfil.profilID
            }, function(err, item) {
              if (err) {
                res.send({
                  'result': 'error'
                });
              } else {
                if (item) {
                  item.actuel = true;

                  item.save(function(err) {
                    if (err) {
                      res.send({
                        'result': 'error'
                      });
                    } else {
                      res.send(200, item);
                    }
                  });
                } else {
                  res.send({
                    'result': 'error'
                  });

                }
              }
            });
          }
        });

      } else {

        UserProfil.findOne({
          userID: userProfil.userID,
          profilID: userProfil.profilID
        }, function(err, item) {
          if (err) {
            res.send({
              'result': 'error'
            });
          } else {
            if (item) {
              item.actuel = true;
              item.save(function(err) {
                if (err) {
                  res.send({
                    'result': 'error'
                  });
                } else {
                  res.send(200, item);
                }
              });
            } else {
              res.send({
                'result': 'error'
              });

            }
          }
        });

      }
    }
  });
};

exports.addUserProfil = function(req, res) {
  var userProfil = new UserProfil(req.body);

  userProfil.save(function(err) {
    if (err) {
      res.send({
        'result': 'error'
      });
    } else {
      res.jsonp(200, userProfil);
    }
  });

};

exports.removeUserProfile = function(req, res) {
  UserProfil.findOne({
    profilID: req.body.profilID,
    userID: req.body.userID
  }, function(err, item) {
    if (err) {
      res.send({
        'result': 'error'
      });
    } else {

      item.remove(function(err) {
        if (err) {
          res.send({
            'result': 'error'
          });
        } else {
          res.jsonp(200);
        }
      });
    }
  });

};

exports.setDefaultProfile = function(req, res) {

  var userProfil = new UserProfil(req.body);

  UserProfil.findOne({
    userID: userProfil.userID,
    default: true
  }, function(err, item) {
    if (err) {
      res.send({
        'result': 'error'
      });
    } else {
      if (item) {
        item.
        default = false;
        item.save(function(err) {
          if (err) {
            res.send({
              'result': 'error'
            });
          } else {
            UserProfil.findOne({
              userID: userProfil.userID,
              profilID: userProfil.profilID
            }, function(err, item) {
              if (err) {
                res.send({
                  'result': 'error'
                });
              } else {
                if (item) {
                  item.
                  default = true;
                  item.save(function(err) {
                    if (err) {
                      res.send({
                        'result': 'error'
                      });
                    } else {
                      res.send(200, item);
                    }
                  });
                } else {
                  res.send({
                    'result': 'error'
                  });

                }
              }
            });
          }
        });

      } else {

        UserProfil.findOne({
          userID: userProfil.userID,
          profilID: userProfil.profilID
        }, function(err, item) {
          if (err) {
            res.send({
              'result': 'error'
            });
          } else {
            if (item) {
              item.
              default = true;

              item.save(function(err) {
                if (err) {
                  res.send({
                    'result': 'error'
                  });
                } else {
                  res.send(200, item);
                }
              });
            } else {
              res.send({
                'result': 'error'
              });

            }
          }
        });

      }
    }
  });
};

exports.chercherProfilParDefaut = function(req, res) {
  UserProfil.findOne({
    default: true
  }, function(err, item) {
    if (err) {
      res.send({
        'result': 'error'
      });
    } else {
      if (item) {
        res.send(item);
      }

    }
  });

};

exports.chercherProfilActuel = function(req, res) {
  var userProfil = new UserProfil(req.body);

  UserProfil.findOne({
    userID: userProfil.userID,
    actuel: true
  }, function(err, item) {
    if (err) {
      res.send({
        'result': 'error'
      });
    } else {
      if (item) {
        res.send(item);
      }

    }
  });

};

exports.defaultByUserProfilId = function(req, res) {
  var userProfil = new UserProfil(req.body);
  var result = [];
  var flag = false;
  var k = 0;
  for (var i = req.body.profilID.length - 1; i >= 0; i--) {

    UserProfil.findOne({
      profilID: req.body.profilID[i]._id,
      userID: req.body.userID
    }, function(err, item) {
      if (err) {
        res.send({
          'result': 'error'
        });
      } else {
        if (item) {
          result.push(item);
          k++;

          if (k == req.body.profilID.length) {
            flag = true;

            res.send(result);

          }

        }

      }
    });

  };

};<commit_msg>Jshint userProfil dao<commit_after>/* File: userProfil.js
 *
 * Copyright (c) 2014
 * Centre National d’Enseignement à Distance (Cned), Boulevard Nicephore Niepce, 86360 CHASSENEUIL-DU-POITOU, France
 * (direction-innovation@cned.fr)
 *
 * GNU Affero General Public License (AGPL) version 3.0 or later version
 *
 * This file is part of a program which is free software: you can
 * redistribute it and/or modify it under the terms of the
 * GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program.
 * If not, see <http://www.gnu.org/licenses/>.
 *
 */

'use strict';
/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
  UserProfil = mongoose.model('UserProfil');
/*jshint loopfunc: true */

exports.createUserProfil = function(req, res) {

  var userProfil = new UserProfil(req.body);

  UserProfil.findOne({
    userID: userProfil.userID,
    actuel: true
  }, function(err, item) {
    if (err) {
      res.send({
        'result': 'error'
      });
    } else {
      if (item) {
        item.actuel = false;
        item.save(function(err) {
          if (err) {
            res.send({
              'result': 'error'
            });
          } else {
            UserProfil.findOne({
              userID: userProfil.userID,
              profilID: userProfil.profilID
            }, function(err, item) {
              if (err) {
                res.send({
                  'result': 'error'
                });
              } else {
                if (item) {
                  item.actuel = true;

                  item.save(function(err) {
                    if (err) {
                      res.send({
                        'result': 'error'
                      });
                    } else {
                      res.send(200, item);
                    }
                  });
                } else {
                  res.send({
                    'result': 'error'
                  });

                }
              }
            });
          }
        });

      } else {

        UserProfil.findOne({
          userID: userProfil.userID,
          profilID: userProfil.profilID
        }, function(err, item) {
          if (err) {
            res.send({
              'result': 'error'
            });
          } else {
            if (item) {
              item.actuel = true;
              item.save(function(err) {
                if (err) {
                  res.send({
                    'result': 'error'
                  });
                } else {
                  res.send(200, item);
                }
              });
            } else {
              res.send({
                'result': 'error'
              });

            }
          }
        });

      }
    }
  });
};

exports.addUserProfil = function(req, res) {
  var userProfil = new UserProfil(req.body);

  userProfil.save(function(err) {
    if (err) {
      res.send({
        'result': 'error'
      });
    } else {
      res.jsonp(200, userProfil);
    }
  });

};

exports.removeUserProfile = function(req, res) {
  UserProfil.findOne({
    profilID: req.body.profilID,
    userID: req.body.userID
  }, function(err, item) {
    if (err) {
      res.send({
        'result': 'error'
      });
    } else {

      item.remove(function(err) {
        if (err) {
          res.send({
            'result': 'error'
          });
        } else {
          res.jsonp(200);
        }
      });
    }
  });

};

exports.setDefaultProfile = function(req, res) {

  var userProfil = new UserProfil(req.body);

  UserProfil.findOne({
    userID: userProfil.userID,
    default: true
  }, function(err, item) {
    if (err) {
      res.send({
        'result': 'error'
      });
    } else {
      if (item) {
        item.
        default = false;
        item.save(function(err) {
          if (err) {
            res.send({
              'result': 'error'
            });
          } else {
            UserProfil.findOne({
              userID: userProfil.userID,
              profilID: userProfil.profilID
            }, function(err, item) {
              if (err) {
                res.send({
                  'result': 'error'
                });
              } else {
                if (item) {
                  item.
                  default = true;
                  item.save(function(err) {
                    if (err) {
                      res.send({
                        'result': 'error'
                      });
                    } else {
                      res.send(200, item);
                    }
                  });
                } else {
                  res.send({
                    'result': 'error'
                  });

                }
              }
            });
          }
        });

      } else {

        UserProfil.findOne({
          userID: userProfil.userID,
          profilID: userProfil.profilID
        }, function(err, item) {
          if (err) {
            res.send({
              'result': 'error'
            });
          } else {
            if (item) {
              item.
              default = true;

              item.save(function(err) {
                if (err) {
                  res.send({
                    'result': 'error'
                  });
                } else {
                  res.send(200, item);
                }
              });
            } else {
              res.send({
                'result': 'error'
              });

            }
          }
        });

      }
    }
  });
};

exports.chercherProfilParDefaut = function(req, res) {
  UserProfil.findOne({
    default: true
  }, function(err, item) {
    if (err) {
      res.send({
        'result': 'error'
      });
    } else {
      if (item) {
        res.send(item);
      }

    }
  });

};

exports.chercherProfilActuel = function(req, res) {
  var userProfil = new UserProfil(req.body);

  UserProfil.findOne({
    userID: userProfil.userID,
    actuel: true
  }, function(err, item) {
    if (err) {
      res.send({
        'result': 'error'
      });
    } else {
      if (item) {
        res.send(item);
      }

    }
  });

};

exports.defaultByUserProfilId = function(req, res) {
  var result = [];
  var flag = false;
  var k = 0;
  for (var i = req.body.profilID.length - 1; i >= 0; i--) {

    UserProfil.findOne({
      profilID: req.body.profilID[i]._id,
      userID: req.body.userID
    }, function(err, item) {
      if (err) {
        res.send({
          'result': 'error'
        });
      } else {
        if (item) {
          result.push(item);
          k++;

          if (k === req.body.profilID.length) {
            flag = true;

            res.send(result);

          }

        }

      }
    });

  }

};<|endoftext|>


<commit_before>import config from '../../src/config'

const Wreck = require('wreck')
const jwt = require('jsonwebtoken')
const jwtKey = config.tasks.key
const tasksUrl = config.tasks.url
const logger = require('../../src/lib/logger')

export function getTasks (request) {
  return new Promise((resolve, reject) => {
    const user = request.auth.credentials.userId
    const name = request.auth.credentials.cn
    const url = tasksUrl + '/' + user
    const tokenOptions = {
      expiresIn: '1h',
      issuer: 'https://auth.t-fk.no'
    }
    const data = {
      user: user,
      name: name,
      system: 'portalen-forside'
    }
    const token = jwt.sign(data, jwtKey, tokenOptions)
    const options = {
      json: true,
      timeout: 1000,
      headers: {
        Authorization: token
      }
    }

    logger('info', ['tasks', 'getTasks', 'user', user])
    Wreck.get(url, options, (error, response, payload) => {
      if (error) {
        logger('error', ['tasks', 'getTasks', 'user', user, error])
        reject(error.message || error)
      } else {
        logger('info', ['tasks', 'getTasks', 'user', user, 'success'])
        resolve(payload)
      }
    })
  })
}
<commit_msg>Change wreck to promise<commit_after>import config from '../../src/config'

const Wreck = require('wreck')
const jwt = require('jsonwebtoken')
const jwtKey = config.tasks.key
const tasksUrl = config.tasks.url
const logger = require('../../src/lib/logger')

export function getTasks (request) {
  return new Promise(async (resolve, reject) => {
    const user = request.auth.credentials.userId
    const name = request.auth.credentials.cn
    const url = tasksUrl + '/' + user
    const tokenOptions = {
      expiresIn: '1h',
      issuer: 'https://auth.t-fk.no'
    }
    const data = {
      user: user,
      name: name,
      system: 'portalen-forside'
    }
    const token = jwt.sign(data, jwtKey, tokenOptions)
    const options = {
      json: true,
      timeout: 1000,
      headers: {
        Authorization: token
      }
    }

    logger('info', ['tasks', 'getTasks', 'user', user])
    try {
      const { payload } = await Wreck.get(url, options)
      logger('info', ['tasks', 'getTasks', 'user', user, 'success'])
      resolve(payload)
    } catch (error) {
      logger('error', ['tasks', 'getTasks', 'user', user, error])
      reject(error)
    }
  })
}
<|endoftext|>


<commit_before>/**
 * Project
 *
 * @module      ::  Model
 * @description ::  This model represents project on taskboard.
 * @docs        ::  http://sailsjs.org/#!documentation/models
 */
"use strict";

module.exports = {
    schema: true,
    attributes: {
        // Relation to User model
        managerId: {
            type:       "integer",
            required:   true
        },
        title: {
            type:       "string",
            required:   true,
            minLength:  5
        },
        description: {
            type:       "text",
            required:   true,
            defaultsTo: ""
        },
        dateStart: {
            type:       "date",
            required:   true
        },
        dateEnd: {
            type:       "date",
            required:   true
        },
        createdUserId: {
            type:       "integer",
            required:   true
        },
        updatedUserId: {
            type:       "integer",
            required:   true
        },

        // Dynamic data attributes

        objectTitle: function() {
            return this.title;
        },
        dateStartObject: function() {
            return (this.dateStart && this.dateStart != "0000-00-00")
                ? DateService.convertDateObjectToUtc(this.dateStart) : null;
        },
        dateEndObject: function() {
            return (this.dateEnd && this.dateEnd != "0000-00-00")
                ? DateService.convertDateObjectToUtc(this.dateEnd) : null;
        },
        createdAtObject: function () {
            return (this.createdAt && this.createdAt != "0000-00-00 00:00:00")
                ? DateService.convertDateObjectToUtc(this.createdAt) : null;
        },
        updatedAtObject: function () {
            return (this.updatedAt && this.updatedAt != "0000-00-00 00:00:00")
                ? DateService.convertDateObjectToUtc(this.updatedAt) : null;
        }
    },

    // Life cycle callbacks

    /**
     * After create callback.
     *
     * @param   {sails.model.project}   values
     * @param   {Function}              cb
     */
    afterCreate: function(values, cb) {
        HistoryService.write("Project", values);

        cb();
    },

    /**
     * After update callback.
     *
     * @param   {sails.model.project}   values
     * @param   {Function}              cb
     */
    afterUpdate: function(values, cb) {
        HistoryService.write("Project", values);

        cb();
    },

    /**
     * Before destroy callback.
     *
     * @param   {Object}    terms
     * @param   {Function}  cb
     */
    beforeDestroy: function(terms, cb) {
        Project
            .findOne(terms)
            .done(function(error, project) {
                if (error) {
                    sails.log.error(error);
                } else {
                    HistoryService.remove("Project", project.id);
                }

                cb();
            });
    }
};
<commit_msg>Changed project model to support default behavior for sprints weekend handling.<commit_after>/**
 * Project
 *
 * @module      ::  Model
 * @description ::  This model represents project on taskboard.
 * @docs        ::  http://sailsjs.org/#!documentation/models
 */
"use strict";

module.exports = {
    schema: true,
    attributes: {
        // Relation to User model
        managerId: {
            type:       "integer",
            required:   true
        },
        title: {
            type:       "string",
            required:   true,
            minLength:  5
        },
        description: {
            type:       "text",
            required:   true,
            defaultsTo: ""
        },
        dateStart: {
            type:       "date",
            required:   true
        },
        dateEnd: {
            type:       "date",
            required:   true
        },
        ignoreWeekends: {
            type:       "boolean",
            defaultsTo: false
        },
        createdUserId: {
            type:       "integer",
            required:   true
        },
        updatedUserId: {
            type:       "integer",
            required:   true
        },

        // Dynamic data attributes

        objectTitle: function() {
            return this.title;
        },
        dateStartObject: function() {
            return (this.dateStart && this.dateStart != "0000-00-00")
                ? DateService.convertDateObjectToUtc(this.dateStart) : null;
        },
        dateEndObject: function() {
            return (this.dateEnd && this.dateEnd != "0000-00-00")
                ? DateService.convertDateObjectToUtc(this.dateEnd) : null;
        },
        createdAtObject: function () {
            return (this.createdAt && this.createdAt != "0000-00-00 00:00:00")
                ? DateService.convertDateObjectToUtc(this.createdAt) : null;
        },
        updatedAtObject: function () {
            return (this.updatedAt && this.updatedAt != "0000-00-00 00:00:00")
                ? DateService.convertDateObjectToUtc(this.updatedAt) : null;
        }
    },

    // Life cycle callbacks

    /**
     * After create callback.
     *
     * @param   {sails.model.project}   values
     * @param   {Function}              cb
     */
    afterCreate: function(values, cb) {
        HistoryService.write("Project", values);

        cb();
    },

    /**
     * After update callback.
     *
     * @param   {sails.model.project}   values
     * @param   {Function}              cb
     */
    afterUpdate: function(values, cb) {
        HistoryService.write("Project", values);

        cb();
    },

    /**
     * Before destroy callback.
     *
     * @param   {Object}    terms
     * @param   {Function}  cb
     */
    beforeDestroy: function(terms, cb) {
        Project
            .findOne(terms)
            .done(function(error, project) {
                if (error) {
                    sails.log.error(error);
                } else {
                    HistoryService.remove("Project", project.id);
                }

                cb();
            });
    }
};
<|endoftext|>


<commit_before>var util = require('../../../util');

import Label              from './shared/Label'
import BezierEdgeDynamic  from './edges/BezierEdgeDynamic'
import BezierEdgeStatic   from './edges/BezierEdgeStatic'
import StraightEdge       from './edges/StraightEdge'

/**
 * @class Edge
 *
 * A edge connects two nodes
 * @param {Object} properties     Object with options. Must contain
 *                                At least options from and to.
 *                                Available options: from (number),
 *                                to (number), label (string, color (string),
 *                                width (number), style (string),
 *                                length (number), title (string)
 * @param {Network} network       A Network object, used to find and edge to
 *                                nodes.
 * @param {Object} constants      An object with default values for
 *                                example for the color
 */
class Edge {
  constructor(options, body, globalOptions) {
    if (body === undefined) {
      throw "No body provided";
    }
    this.options = util.bridgeObject(globalOptions);
    this.body = body;

    // initialize variables
    this.id = undefined;
    this.fromId = undefined;
    this.toId = undefined;
    this.selected = false;
    this.hover = false;
    this.labelDirty = true;
    this.colorDirty = true;

    this.baseWidth = this.options.width;
    this.baseFontSize = this.options.font.size;

    this.from = undefined; // a node
    this.to   = undefined; // a node

    this.edgeType = undefined;

    this.connected = false;

    this.labelModule = new Label(this.body, this.options);

    this.setOptions(options);
  }

  /**
   * Set or overwrite options for the edge
   * @param {Object} options  an object with options
   * @param doNotEmit
   */
  setOptions(options) {
    if (!options) {
      return;
    }
    this.colorDirty = true;

    Edge.parseOptions(this.options, options, true);

    if (options.id !== undefined)   {this.id = options.id;}
    if (options.from !== undefined) {this.fromId = options.from;}
    if (options.to !== undefined)   {this.toId = options.to;}
    if (options.title !== undefined) {this.title = options.title;}
    if (options.value !== undefined)  {options.value = parseInt(options.value);}

    // update label Module
    this.updateLabelModule();

    let dataChanged = this.updateEdgeType();

    // if anything has been updates, reset the selection width and the hover width
    this._setInteractionWidths();

    // A node is connected when it has a from and to node that both exist in the network.body.nodes.
    this.connect();

    if (options.hidden !== undefined || options.physics !== undefined) {
      dataChanged = true;
    }

    return dataChanged;
  }

  static parseOptions(parentOptions, newOptions, allowDeletion = false) {
    var fields = [
      'id',
      'from',
      'hidden',
      'hoverWidth',
      'label',
      'length',
      'line',
      'opacity',
      'physics',
      'selectionWidth',
      'selfReferenceSize',
      'to',
      'title',
      'value',
      'width'
    ];

    // only deep extend the items in the field array. These do not have shorthand.
    util.selectiveDeepExtend(fields, parentOptions, newOptions, allowDeletion);

    util.mergeOptions(parentOptions, newOptions, 'smooth');
    util.mergeOptions(parentOptions, newOptions, 'shadow');

    if (newOptions.dashes !== undefined && newOptions.dashes !== null) {
      parentOptions.dashes = newOptions.dashes;
    }
    else if (allowDeletion === true && newOptions.dashes === null) {
      parentOptions.dashes = undefined;
      delete parentOptions.dashes;
    }

    // set the scaling newOptions
    if (newOptions.scaling !== undefined && newOptions.scaling !== null) {
      if (newOptions.scaling.min !== undefined) {parentOptions.scaling.min = newOptions.scaling.min;}
      if (newOptions.scaling.max !== undefined) {parentOptions.scaling.max = newOptions.scaling.max;}
      util.mergeOptions(parentOptions.scaling, newOptions.scaling, 'label');
    }
    else if (allowDeletion === true && newOptions.scaling === null) {
      parentOptions.scaling = undefined;
      delete parentOptions.scaling;
    }

    // hanlde multiple input cases for arrows
    if (newOptions.arrows !== undefined && newOptions.arrows !== null) {
      if (typeof newOptions.arrows === 'string') {
        let arrows = newOptions.arrows.toLowerCase();
        if (arrows.indexOf("to")     != -1) {parentOptions.arrows.to.enabled     = true;}
        if (arrows.indexOf("middle") != -1) {parentOptions.arrows.middle.enabled = true;}
        if (arrows.indexOf("from")   != -1) {parentOptions.arrows.from.enabled   = true;}
      }
      else if (typeof newOptions.arrows === 'object') {
        util.mergeOptions(parentOptions.arrows, newOptions.arrows, 'to');
        util.mergeOptions(parentOptions.arrows, newOptions.arrows, 'middle');
        util.mergeOptions(parentOptions.arrows, newOptions.arrows, 'from');
      }
      else {
        throw new Error("The arrow newOptions can only be an object or a string. Refer to the documentation. You used:" + JSON.stringify(newOptions.arrows));
      }
    }
    else if (allowDeletion === true && newOptions.arrows === null) {
      parentOptions.arrows = undefined;
      delete parentOptions.arrows;
    }

    // hanlde multiple input cases for color
    if (newOptions.color !== undefined && newOptions.color !== null) {
      if (util.isString(newOptions.color)) {
        parentOptions.color.color     = newOptions.color;
        parentOptions.color.highlight = newOptions.color;
        parentOptions.color.hover     = newOptions.color;
        parentOptions.color.inherit   = false;
      }
      else {
        let colorsDefined = false;
        if (newOptions.color.color     !== undefined) {parentOptions.color.color     = newOptions.color.color;     colorsDefined = true;}
        if (newOptions.color.highlight !== undefined) {parentOptions.color.highlight = newOptions.color.highlight; colorsDefined = true;}
        if (newOptions.color.hover     !== undefined) {parentOptions.color.hover     = newOptions.color.hover;     colorsDefined = true;}
        if (newOptions.color.inherit   !== undefined) {parentOptions.color.inherit   = newOptions.color.inherit;}
        if (newOptions.color.opacity   !== undefined) {parentOptions.color.opacity   = Math.min(1,Math.max(0,newOptions.color.opacity));}

        if (newOptions.color.inherit === undefined && colorsDefined === true) {
          parentOptions.color.inherit = false;
        }
      }
    }
    else if (allowDeletion === true && newOptions.color === null) {
      parentOptions.color = undefined;
      delete parentOptions.color;
    }

    // handle the font settings
    if (newOptions.font !== undefined) {
      Label.parseOptions(parentOptions.font, newOptions);
    }
  }

  /**
   * update the options in the label module
   */
  updateLabelModule() {
    this.labelModule.setOptions(this.options, true);
    if (this.labelModule.baseSize !== undefined) {
      this.baseFontSize = this.labelModule.baseSize;
    }
  }

  /**
   * update the edge type, set the options
   * @returns {boolean}
   */
  updateEdgeType() {
    let dataChanged = false;
    let changeInType = true;
    if (this.edgeType !== undefined) {
      if (this.edgeType instanceof BezierEdgeDynamic && this.options.smooth.enabled === true && this.options.smooth.type === 'dynamic') {changeInType = false;}
      if (this.edgeType instanceof BezierEdgeStatic  && this.options.smooth.enabled === true && this.options.smooth.type !== 'dynamic') {changeInType = false;}
      if (this.edgeType instanceof StraightEdge      && this.options.smooth.enabled === false)                                          {changeInType = false;}

      if (changeInType === true) {
        dataChanged = this.edgeType.cleanup();
      }
    }

    if (changeInType === true) {
      if (this.options.smooth.enabled === true) {
        if (this.options.smooth.type === 'dynamic') {
          dataChanged = true;
          this.edgeType = new BezierEdgeDynamic(this.options, this.body, this.labelModule);
        }
        else {
          this.edgeType = new BezierEdgeStatic(this.options, this.body, this.labelModule);
        }
      }
      else {
        this.edgeType = new StraightEdge(this.options, this.body, this.labelModule);
      }
    }
    else {
      // if nothing changes, we just set the options.
      this.edgeType.setOptions(this.options);
    }

    return dataChanged;
  }

  /**
   * Enable or disable the physics.
   * @param status
   */
  togglePhysics(status) {
    this.options.physics = status;
    this.edgeType.togglePhysics(status);
  }

  /**
   * Connect an edge to its nodes
   */
  connect() {
    this.disconnect();

    this.from = this.body.nodes[this.fromId] || undefined;
    this.to = this.body.nodes[this.toId] || undefined;
    this.connected = (this.from !== undefined && this.to !== undefined);

    if (this.connected === true) {
      this.from.attachEdge(this);
      this.to.attachEdge(this);
    }
    else {
      if (this.from) {
        this.from.detachEdge(this);
      }
      if (this.to) {
        this.to.detachEdge(this);
      }
    }

    this.edgeType.connect();
  }

  /**
   * Disconnect an edge from its nodes
   */
  disconnect() {
    if (this.from) {
      this.from.detachEdge(this);
      this.from = undefined;
    }
    if (this.to) {
      this.to.detachEdge(this);
      this.to = undefined;
    }

    this.connected = false;
  }

  /**
   * get the title of this edge.
   * @return {string} title    The title of the edge, or undefined when no title
   *                           has been set.
   */
  getTitle() {
    return this.title;
  }

  /**
   * check if this node is selecte
   * @return {boolean} selected   True if node is selected, else false
   */
  isSelected() {
    return this.selected;
  }

  /**
   * Retrieve the value of the edge. Can be undefined
   * @return {Number} value
   */
  getValue() {
    return this.options.value;
  }

  /**
   * Adjust the value range of the edge. The edge will adjust it's width
   * based on its value.
   * @param {Number} min
   * @param {Number} max
   * @param total
   */
  setValueRange(min, max, total) {
    if (this.options.value !== undefined) {
      var scale = this.options.scaling.customScalingFunction(min, max, total, this.options.value);
      var widthDiff = this.options.scaling.max - this.options.scaling.min;
      if (this.options.scaling.label.enabled === true) {
        var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
        this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
      }
      this.options.width = this.options.scaling.min + scale * widthDiff;
    }
    else {
      this.options.width = this.baseWidth;
      this.options.font.size = this.baseFontSize;
    }

    this._setInteractionWidths();
  }

   _setInteractionWidths() {
     if (typeof this.options.hoverWidth === 'function') {
        this.edgeType.hoverWidth = this.options.hoverWidth(this.options.width);
     }
     else {
       this.edgeType.hoverWidth = this.options.hoverWidth + this.options.width;
     }

     if (typeof this.options.selectionWidth === 'function') {
       this.edgeType.selectionWidth = this.options.selectionWidth(this.options.width);
     }
     else {
       this.edgeType.selectionWidth = this.options.selectionWidth + this.options.width;
     }
   }

  /**
   * Redraw a edge
   * Draw this edge in the given canvas
   * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
   * @param {CanvasRenderingContext2D}   ctx
   */
  draw(ctx) {
    let via = this.edgeType.drawLine(ctx, this.selected, this.hover);
    this.drawArrows(ctx, via);
    this.drawLabel (ctx, via);
  }

  drawArrows(ctx, viaNode) {
    if (this.options.arrows.from.enabled   === true) {this.edgeType.drawArrowHead(ctx,'from',   viaNode, this.selected, this.hover);}
    if (this.options.arrows.middle.enabled === true) {this.edgeType.drawArrowHead(ctx,'middle', viaNode, this.selected, this.hover);}
    if (this.options.arrows.to.enabled     === true) {this.edgeType.drawArrowHead(ctx,'to',     viaNode, this.selected, this.hover);}
  }

  drawLabel(ctx, viaNode) {
    if (this.options.label !== undefined) {
      // set style
      var node1 = this.from;
      var node2 = this.to;
      var selected = (this.from.selected || this.to.selected || this.selected);
      if (node1.id != node2.id) {
        this.labelModule.pointToSelf = false;
        var point = this.edgeType.getPoint(0.5, viaNode);
        ctx.save();

        // if the label has to be rotated:
        if (this.options.font.align !== "horizontal") {
          this.labelModule.calculateLabelSize(ctx,selected,point.x,point.y);
          ctx.translate(point.x, this.labelModule.size.yLine);
          this._rotateForLabelAlignment(ctx);
        }

        // draw the label
        this.labelModule.draw(ctx, point.x, point.y, selected);
        ctx.restore();
      }
      else {
        // Ignore the orientations.
        this.labelModule.pointToSelf = true;
        var x, y;
        var radius = this.options.selfReferenceSize;
        if (node1.shape.width > node1.shape.height) {
          x = node1.x + node1.shape.width * 0.5;
          y = node1.y - radius;
        }
        else {
          x = node1.x + radius;
          y = node1.y - node1.shape.height * 0.5;
        }
        point = this._pointOnCircle(x, y, radius, 0.125);
        this.labelModule.draw(ctx, point.x, point.y, selected);
      }
    }
  }

  /**
   * Check if this object is overlapping with the provided object
   * @param {Object} obj   an object with parameters left, top
   * @return {boolean}     True if location is located on the edge
   */
  isOverlappingWith(obj) {
    if (this.connected) {
      var distMax = 10;
      var xFrom = this.from.x;
      var yFrom = this.from.y;
      var xTo = this.to.x;
      var yTo = this.to.y;
      var xObj = obj.left;
      var yObj = obj.top;

      var dist = this.edgeType.getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj);

      return (dist < distMax);
    }
    else {
      return false
    }
  }

  /**
   * Rotates the canvas so the text is most readable
   * @param {CanvasRenderingContext2D} ctx
   * @private
   */
  _rotateForLabelAlignment(ctx) {
    var dy = this.from.y - this.to.y;
    var dx = this.from.x - this.to.x;
    var angleInDegrees = Math.atan2(dy, dx);

    // rotate so label it is readable
    if ((angleInDegrees < -1 && dx < 0) || (angleInDegrees > 0 && dx < 0)) {
      angleInDegrees = angleInDegrees + Math.PI;
    }

    ctx.rotate(angleInDegrees);
  }

  /**
   * Get a point on a circle
   * @param {Number} x
   * @param {Number} y
   * @param {Number} radius
   * @param {Number} percentage. Value between 0 (line start) and 1 (line end)
   * @return {Object} point
   * @private
   */
  _pointOnCircle(x, y, radius, percentage) {
    var angle = percentage * 2 * Math.PI;
    return {
      x: x + radius * Math.cos(angle),
      y: y - radius * Math.sin(angle)
    }
  }

  select() {
    this.selected = true;
  }

  unselect() {
    this.selected = false;
  }
}

export default Edge;<commit_msg>parseFloat of edges<commit_after>var util = require('../../../util');

import Label              from './shared/Label'
import BezierEdgeDynamic  from './edges/BezierEdgeDynamic'
import BezierEdgeStatic   from './edges/BezierEdgeStatic'
import StraightEdge       from './edges/StraightEdge'

/**
 * @class Edge
 *
 * A edge connects two nodes
 * @param {Object} properties     Object with options. Must contain
 *                                At least options from and to.
 *                                Available options: from (number),
 *                                to (number), label (string, color (string),
 *                                width (number), style (string),
 *                                length (number), title (string)
 * @param {Network} network       A Network object, used to find and edge to
 *                                nodes.
 * @param {Object} constants      An object with default values for
 *                                example for the color
 */
class Edge {
  constructor(options, body, globalOptions) {
    if (body === undefined) {
      throw "No body provided";
    }
    this.options = util.bridgeObject(globalOptions);
    this.body = body;

    // initialize variables
    this.id = undefined;
    this.fromId = undefined;
    this.toId = undefined;
    this.selected = false;
    this.hover = false;
    this.labelDirty = true;
    this.colorDirty = true;

    this.baseWidth = this.options.width;
    this.baseFontSize = this.options.font.size;

    this.from = undefined; // a node
    this.to   = undefined; // a node

    this.edgeType = undefined;

    this.connected = false;

    this.labelModule = new Label(this.body, this.options);

    this.setOptions(options);
  }

  /**
   * Set or overwrite options for the edge
   * @param {Object} options  an object with options
   * @param doNotEmit
   */
  setOptions(options) {
    if (!options) {
      return;
    }
    this.colorDirty = true;

    Edge.parseOptions(this.options, options, true);

    if (options.id !== undefined)   {this.id = options.id;}
    if (options.from !== undefined) {this.fromId = options.from;}
    if (options.to !== undefined)   {this.toId = options.to;}
    if (options.title !== undefined) {this.title = options.title;}
    if (options.value !== undefined)  {options.value = parseFloat(options.value);}

    // update label Module
    this.updateLabelModule();

    let dataChanged = this.updateEdgeType();

    // if anything has been updates, reset the selection width and the hover width
    this._setInteractionWidths();

    // A node is connected when it has a from and to node that both exist in the network.body.nodes.
    this.connect();

    if (options.hidden !== undefined || options.physics !== undefined) {
      dataChanged = true;
    }

    return dataChanged;
  }

  static parseOptions(parentOptions, newOptions, allowDeletion = false) {
    var fields = [
      'id',
      'from',
      'hidden',
      'hoverWidth',
      'label',
      'length',
      'line',
      'opacity',
      'physics',
      'selectionWidth',
      'selfReferenceSize',
      'to',
      'title',
      'value',
      'width'
    ];

    // only deep extend the items in the field array. These do not have shorthand.
    util.selectiveDeepExtend(fields, parentOptions, newOptions, allowDeletion);

    util.mergeOptions(parentOptions, newOptions, 'smooth');
    util.mergeOptions(parentOptions, newOptions, 'shadow');

    if (newOptions.dashes !== undefined && newOptions.dashes !== null) {
      parentOptions.dashes = newOptions.dashes;
    }
    else if (allowDeletion === true && newOptions.dashes === null) {
      parentOptions.dashes = undefined;
      delete parentOptions.dashes;
    }

    // set the scaling newOptions
    if (newOptions.scaling !== undefined && newOptions.scaling !== null) {
      if (newOptions.scaling.min !== undefined) {parentOptions.scaling.min = newOptions.scaling.min;}
      if (newOptions.scaling.max !== undefined) {parentOptions.scaling.max = newOptions.scaling.max;}
      util.mergeOptions(parentOptions.scaling, newOptions.scaling, 'label');
    }
    else if (allowDeletion === true && newOptions.scaling === null) {
      parentOptions.scaling = undefined;
      delete parentOptions.scaling;
    }

    // hanlde multiple input cases for arrows
    if (newOptions.arrows !== undefined && newOptions.arrows !== null) {
      if (typeof newOptions.arrows === 'string') {
        let arrows = newOptions.arrows.toLowerCase();
        if (arrows.indexOf("to")     != -1) {parentOptions.arrows.to.enabled     = true;}
        if (arrows.indexOf("middle") != -1) {parentOptions.arrows.middle.enabled = true;}
        if (arrows.indexOf("from")   != -1) {parentOptions.arrows.from.enabled   = true;}
      }
      else if (typeof newOptions.arrows === 'object') {
        util.mergeOptions(parentOptions.arrows, newOptions.arrows, 'to');
        util.mergeOptions(parentOptions.arrows, newOptions.arrows, 'middle');
        util.mergeOptions(parentOptions.arrows, newOptions.arrows, 'from');
      }
      else {
        throw new Error("The arrow newOptions can only be an object or a string. Refer to the documentation. You used:" + JSON.stringify(newOptions.arrows));
      }
    }
    else if (allowDeletion === true && newOptions.arrows === null) {
      parentOptions.arrows = undefined;
      delete parentOptions.arrows;
    }

    // hanlde multiple input cases for color
    if (newOptions.color !== undefined && newOptions.color !== null) {
      if (util.isString(newOptions.color)) {
        parentOptions.color.color     = newOptions.color;
        parentOptions.color.highlight = newOptions.color;
        parentOptions.color.hover     = newOptions.color;
        parentOptions.color.inherit   = false;
      }
      else {
        let colorsDefined = false;
        if (newOptions.color.color     !== undefined) {parentOptions.color.color     = newOptions.color.color;     colorsDefined = true;}
        if (newOptions.color.highlight !== undefined) {parentOptions.color.highlight = newOptions.color.highlight; colorsDefined = true;}
        if (newOptions.color.hover     !== undefined) {parentOptions.color.hover     = newOptions.color.hover;     colorsDefined = true;}
        if (newOptions.color.inherit   !== undefined) {parentOptions.color.inherit   = newOptions.color.inherit;}
        if (newOptions.color.opacity   !== undefined) {parentOptions.color.opacity   = Math.min(1,Math.max(0,newOptions.color.opacity));}

        if (newOptions.color.inherit === undefined && colorsDefined === true) {
          parentOptions.color.inherit = false;
        }
      }
    }
    else if (allowDeletion === true && newOptions.color === null) {
      parentOptions.color = undefined;
      delete parentOptions.color;
    }

    // handle the font settings
    if (newOptions.font !== undefined) {
      Label.parseOptions(parentOptions.font, newOptions);
    }
  }

  /**
   * update the options in the label module
   */
  updateLabelModule() {
    this.labelModule.setOptions(this.options, true);
    if (this.labelModule.baseSize !== undefined) {
      this.baseFontSize = this.labelModule.baseSize;
    }
  }

  /**
   * update the edge type, set the options
   * @returns {boolean}
   */
  updateEdgeType() {
    let dataChanged = false;
    let changeInType = true;
    if (this.edgeType !== undefined) {
      if (this.edgeType instanceof BezierEdgeDynamic && this.options.smooth.enabled === true && this.options.smooth.type === 'dynamic') {changeInType = false;}
      if (this.edgeType instanceof BezierEdgeStatic  && this.options.smooth.enabled === true && this.options.smooth.type !== 'dynamic') {changeInType = false;}
      if (this.edgeType instanceof StraightEdge      && this.options.smooth.enabled === false)                                          {changeInType = false;}

      if (changeInType === true) {
        dataChanged = this.edgeType.cleanup();
      }
    }

    if (changeInType === true) {
      if (this.options.smooth.enabled === true) {
        if (this.options.smooth.type === 'dynamic') {
          dataChanged = true;
          this.edgeType = new BezierEdgeDynamic(this.options, this.body, this.labelModule);
        }
        else {
          this.edgeType = new BezierEdgeStatic(this.options, this.body, this.labelModule);
        }
      }
      else {
        this.edgeType = new StraightEdge(this.options, this.body, this.labelModule);
      }
    }
    else {
      // if nothing changes, we just set the options.
      this.edgeType.setOptions(this.options);
    }

    return dataChanged;
  }

  /**
   * Enable or disable the physics.
   * @param status
   */
  togglePhysics(status) {
    this.options.physics = status;
    this.edgeType.togglePhysics(status);
  }

  /**
   * Connect an edge to its nodes
   */
  connect() {
    this.disconnect();

    this.from = this.body.nodes[this.fromId] || undefined;
    this.to = this.body.nodes[this.toId] || undefined;
    this.connected = (this.from !== undefined && this.to !== undefined);

    if (this.connected === true) {
      this.from.attachEdge(this);
      this.to.attachEdge(this);
    }
    else {
      if (this.from) {
        this.from.detachEdge(this);
      }
      if (this.to) {
        this.to.detachEdge(this);
      }
    }

    this.edgeType.connect();
  }

  /**
   * Disconnect an edge from its nodes
   */
  disconnect() {
    if (this.from) {
      this.from.detachEdge(this);
      this.from = undefined;
    }
    if (this.to) {
      this.to.detachEdge(this);
      this.to = undefined;
    }

    this.connected = false;
  }

  /**
   * get the title of this edge.
   * @return {string} title    The title of the edge, or undefined when no title
   *                           has been set.
   */
  getTitle() {
    return this.title;
  }

  /**
   * check if this node is selecte
   * @return {boolean} selected   True if node is selected, else false
   */
  isSelected() {
    return this.selected;
  }

  /**
   * Retrieve the value of the edge. Can be undefined
   * @return {Number} value
   */
  getValue() {
    return this.options.value;
  }

  /**
   * Adjust the value range of the edge. The edge will adjust it's width
   * based on its value.
   * @param {Number} min
   * @param {Number} max
   * @param total
   */
  setValueRange(min, max, total) {
    if (this.options.value !== undefined) {
      var scale = this.options.scaling.customScalingFunction(min, max, total, this.options.value);
      var widthDiff = this.options.scaling.max - this.options.scaling.min;
      if (this.options.scaling.label.enabled === true) {
        var fontDiff = this.options.scaling.label.max - this.options.scaling.label.min;
        this.options.font.size = this.options.scaling.label.min + scale * fontDiff;
      }
      this.options.width = this.options.scaling.min + scale * widthDiff;
    }
    else {
      this.options.width = this.baseWidth;
      this.options.font.size = this.baseFontSize;
    }

    this._setInteractionWidths();
  }

   _setInteractionWidths() {
     if (typeof this.options.hoverWidth === 'function') {
        this.edgeType.hoverWidth = this.options.hoverWidth(this.options.width);
     }
     else {
       this.edgeType.hoverWidth = this.options.hoverWidth + this.options.width;
     }

     if (typeof this.options.selectionWidth === 'function') {
       this.edgeType.selectionWidth = this.options.selectionWidth(this.options.width);
     }
     else {
       this.edgeType.selectionWidth = this.options.selectionWidth + this.options.width;
     }
   }

  /**
   * Redraw a edge
   * Draw this edge in the given canvas
   * The 2d context of a HTML canvas can be retrieved by canvas.getContext("2d");
   * @param {CanvasRenderingContext2D}   ctx
   */
  draw(ctx) {
    let via = this.edgeType.drawLine(ctx, this.selected, this.hover);
    this.drawArrows(ctx, via);
    this.drawLabel (ctx, via);
  }

  drawArrows(ctx, viaNode) {
    if (this.options.arrows.from.enabled   === true) {this.edgeType.drawArrowHead(ctx,'from',   viaNode, this.selected, this.hover);}
    if (this.options.arrows.middle.enabled === true) {this.edgeType.drawArrowHead(ctx,'middle', viaNode, this.selected, this.hover);}
    if (this.options.arrows.to.enabled     === true) {this.edgeType.drawArrowHead(ctx,'to',     viaNode, this.selected, this.hover);}
  }

  drawLabel(ctx, viaNode) {
    if (this.options.label !== undefined) {
      // set style
      var node1 = this.from;
      var node2 = this.to;
      var selected = (this.from.selected || this.to.selected || this.selected);
      if (node1.id != node2.id) {
        this.labelModule.pointToSelf = false;
        var point = this.edgeType.getPoint(0.5, viaNode);
        ctx.save();

        // if the label has to be rotated:
        if (this.options.font.align !== "horizontal") {
          this.labelModule.calculateLabelSize(ctx,selected,point.x,point.y);
          ctx.translate(point.x, this.labelModule.size.yLine);
          this._rotateForLabelAlignment(ctx);
        }

        // draw the label
        this.labelModule.draw(ctx, point.x, point.y, selected);
        ctx.restore();
      }
      else {
        // Ignore the orientations.
        this.labelModule.pointToSelf = true;
        var x, y;
        var radius = this.options.selfReferenceSize;
        if (node1.shape.width > node1.shape.height) {
          x = node1.x + node1.shape.width * 0.5;
          y = node1.y - radius;
        }
        else {
          x = node1.x + radius;
          y = node1.y - node1.shape.height * 0.5;
        }
        point = this._pointOnCircle(x, y, radius, 0.125);
        this.labelModule.draw(ctx, point.x, point.y, selected);
      }
    }
  }

  /**
   * Check if this object is overlapping with the provided object
   * @param {Object} obj   an object with parameters left, top
   * @return {boolean}     True if location is located on the edge
   */
  isOverlappingWith(obj) {
    if (this.connected) {
      var distMax = 10;
      var xFrom = this.from.x;
      var yFrom = this.from.y;
      var xTo = this.to.x;
      var yTo = this.to.y;
      var xObj = obj.left;
      var yObj = obj.top;

      var dist = this.edgeType.getDistanceToEdge(xFrom, yFrom, xTo, yTo, xObj, yObj);

      return (dist < distMax);
    }
    else {
      return false
    }
  }

  /**
   * Rotates the canvas so the text is most readable
   * @param {CanvasRenderingContext2D} ctx
   * @private
   */
  _rotateForLabelAlignment(ctx) {
    var dy = this.from.y - this.to.y;
    var dx = this.from.x - this.to.x;
    var angleInDegrees = Math.atan2(dy, dx);

    // rotate so label it is readable
    if ((angleInDegrees < -1 && dx < 0) || (angleInDegrees > 0 && dx < 0)) {
      angleInDegrees = angleInDegrees + Math.PI;
    }

    ctx.rotate(angleInDegrees);
  }

  /**
   * Get a point on a circle
   * @param {Number} x
   * @param {Number} y
   * @param {Number} radius
   * @param {Number} percentage. Value between 0 (line start) and 1 (line end)
   * @return {Object} point
   * @private
   */
  _pointOnCircle(x, y, radius, percentage) {
    var angle = percentage * 2 * Math.PI;
    return {
      x: x + radius * Math.cos(angle),
      y: y - radius * Math.sin(angle)
    }
  }

  select() {
    this.selected = true;
  }

  unselect() {
    this.selected = false;
  }
}

export default Edge;<|endoftext|>


<commit_before>var fs = require('fs');
var util = require('util');
var soap = require('soap');

var stations = getStations('resources/station_codes.csv');
var apiKey = process.env.APIKEY;
var soapUrl = 'https://lite.realtime.nationalrail.co.uk/OpenLDBWS/wsdl.aspx?ver=2014-02-20';
var soapHeader = util.format('<AccessToken><TokenValue>%s</TokenValue></AccessToken>', apiKey);

exports.findStation = findStation; // function findStation()
exports.getDepartures = getDepartures; // function getDepartures(response, fromStation, toStation)

/**
 * Returns an array of station objects, each with stationName and stationCode
 */
function getStations(stationCsv) {
    var i;
    var result = fs.readFileSync(stationCsv, 'utf8').split('\n');
    result = result.slice(1, result.length);
    var output = [];
    for (i = 0; i < result.length; i += 1) {
        if (result[i].split(',').length === 2) output.push({stationName: result[i].split(',')[0].trim(), stationCode: result[i].split(',')[1].trim()});
    }
    return output;
}

function findStation(input) {
    var i;
    var bestMatch = {
        stationNumber: -1,
        matchIndex: -1
    }
    var position;

    console.log("Finding station for input " + input);
    if (input.length == 3) {
        console.log("Checking station codes");
        for(i = 0; i < stations.length; i++) {
            if (stations[i].stationCode.toUpperCase() === input.toUpperCase()) {
                console.log(util.format("Found station %d: %s (%s)", i, stations[i].stationName, stations[i].stationCode));
                return stations[i];
            }
        }
    }

    console.log("Checking station name equality");
    for(i = 0; i < stations.length; i++) {
        if (stations[i].stationName.replace(' ','').toUpperCase() === input.toUpperCase()) {
            console.log(util.format("Found station %d: %s (%s)", i, stations[i].stationName, stations[i].stationCode));
            return stations[i];
        }
    }

    console.log("Checking station name matches");
    for(i = 0; i < stations.length; i++) {
        position = stations[i].stationName.replace(' ','').toUpperCase().indexOf(input.toUpperCase());
        if (position != -1) {
            console.log(util.format("Found station %d: %s (%s) at position %d", i, stations[i].stationName, stations[i].stationCode, position));
            if (bestMatch.stationNumber === -1 || bestMatch.matchIndex > position) {
                console.log('new best match!');
                bestMatch.stationNumber = i;
                bestMatch.matchIndex = position;
            }
        }
    }
    if (bestMatch.stationNumber !== -1) return stations[bestMatch.stationNumber];

    console.log("No match found");
    return errorStation;
}

function getDepartures(response, fromStation, toStation) {
    var options = {
        numRows: 10,
        crs: fromStation.stationCode
    }
    var output = util.format('Departure board for %s (%s)', fromStation.stationName, fromStation.stationCode);
    if (toStation !== undefined) {
        options.filterCrs = toStation.stationCode;
        output += util.format(' calling at %s (%s)', toStation.stationName, toStation.stationCode);
    }

    soap.createClient(soapUrl, function(err, client) {
        client.addSoapHeader(soapHeader);
        return client.GetDepartureBoard(options, function(err, result) {
            console.log(JSON.stringify(result));
            fs.writeFile('public/lastrequest.txt', JSON.stringify(result), function(err) {
                if (err) {
                    return console.log(err);
                }
            })
            var formattedData = '';
            try {
                formattedData = formatStationData(result);
            } catch (err) {
                formattedData = 'There was an error processing your request: ' + err.message;
                console.log(err.stack);
            }
            response.send(util.format('%s

%s
%s', output, formattedData, footer()));
        });
    });
}

function formatStationData(oStationBoard) {
    var oTrainServices = oStationBoard.GetStationBoardResult.trainServices;
    var aServices = oTrainServices === undefined ? [] : oTrainServices.service;
    var i;
    var output = '';
    if (aServices.length === 0) {
        output += 'No services found.'
    }
    for (i = 0; i < aServices.length; i += 1) {
        output += '----

';
        output += aServices[i].origin.location[0].locationName + ' --> ' + aServices[i].destination.location[0].locationName + '
';
        if (aServices[i].etd !== 'On time') output += '';
        output += aServices[i].std;
        if (aServices[i].etd !== 'On time') output += '';
        output += ' (' + aServices[i].etd + ')
';
        if (aServices[i].platform !== undefined) {
            output += 'Platform ' + aServices[i].platform + '
';
        } else {
            output += 'No platform information available
';
        }
        output += '
';
    }
    return output;
}

function footer() {
    var d = new Date();
    return '
----
Page loaded at ' + d.getHours() + ':' + d.getMinutes() + '

'
        + 'About trntxt

Powered by National Rail Enquiries.
';
}
<commit_msg>Added API key check<commit_after>var fs = require('fs');
var util = require('util');
var soap = require('soap');

var stations = getStations('resources/station_codes.csv');
var apiKey = process.env.APIKEY;
if (apiKey === undefined) {
    console.log('process.env.APIKEY not set!');
    process.exit(0);
}
var soapUrl = 'https://lite.realtime.nationalrail.co.uk/OpenLDBWS/wsdl.aspx?ver=2014-02-20';
var soapHeader = util.format('<AccessToken><TokenValue>%s</TokenValue></AccessToken>', apiKey);

exports.findStation = findStation; // function findStation()
exports.getDepartures = getDepartures; // function getDepartures(response, fromStation, toStation)

/**
 * Returns an array of station objects, each with stationName and stationCode
 */
function getStations(stationCsv) {
    var i;
    var result = fs.readFileSync(stationCsv, 'utf8').split('\n');
    result = result.slice(1, result.length);
    var output = [];
    for (i = 0; i < result.length; i += 1) {
        if (result[i].split(',').length === 2) output.push({stationName: result[i].split(',')[0].trim(), stationCode: result[i].split(',')[1].trim()});
    }
    return output;
}

function findStation(input) {
    var i;
    var bestMatch = {
        stationNumber: -1,
        matchIndex: -1
    }
    var position;

    console.log("Finding station for input " + input);
    if (input.length == 3) {
        console.log("Checking station codes");
        for(i = 0; i < stations.length; i++) {
            if (stations[i].stationCode.toUpperCase() === input.toUpperCase()) {
                console.log(util.format("Found station %d: %s (%s)", i, stations[i].stationName, stations[i].stationCode));
                return stations[i];
            }
        }
    }

    console.log("Checking station name equality");
    for(i = 0; i < stations.length; i++) {
        if (stations[i].stationName.replace(' ','').toUpperCase() === input.toUpperCase()) {
            console.log(util.format("Found station %d: %s (%s)", i, stations[i].stationName, stations[i].stationCode));
            return stations[i];
        }
    }

    console.log("Checking station name matches");
    for(i = 0; i < stations.length; i++) {
        position = stations[i].stationName.replace(' ','').toUpperCase().indexOf(input.toUpperCase());
        if (position != -1) {
            console.log(util.format("Found station %d: %s (%s) at position %d", i, stations[i].stationName, stations[i].stationCode, position));
            if (bestMatch.stationNumber === -1 || bestMatch.matchIndex > position) {
                console.log('new best match!');
                bestMatch.stationNumber = i;
                bestMatch.matchIndex = position;
            }
        }
    }
    if (bestMatch.stationNumber !== -1) return stations[bestMatch.stationNumber];

    console.log("No match found");
    return errorStation;
}

function getDepartures(response, fromStation, toStation) {
    var options = {
        numRows: 10,
        crs: fromStation.stationCode
    }
    var output = util.format('Departure board for %s (%s)', fromStation.stationName, fromStation.stationCode);
    if (toStation !== undefined) {
        options.filterCrs = toStation.stationCode;
        output += util.format(' calling at %s (%s)', toStation.stationName, toStation.stationCode);
    }

    soap.createClient(soapUrl, function(err, client) {
        client.addSoapHeader(soapHeader);
        return client.GetDepartureBoard(options, function(err, result) {
            console.log(JSON.stringify(result));
            fs.writeFile('public/lastrequest.txt', JSON.stringify(result), function(err) {
                if (err) {
                    return console.log(err);
                }
            })
            var formattedData = '';
            try {
                formattedData = formatStationData(result);
            } catch (err) {
                formattedData = 'There was an error processing your request: ' + err.message;
                console.log(err.stack);
            }
            response.send(util.format('%s

%s
%s', output, formattedData, footer()));
        });
    });
}

function formatStationData(oStationBoard) {
    var oTrainServices = oStationBoard.GetStationBoardResult.trainServices;
    var aServices = oTrainServices === undefined ? [] : oTrainServices.service;
    var i;
    var output = '';
    if (aServices.length === 0) {
        output += 'No services found.'
    }
    for (i = 0; i < aServices.length; i += 1) {
        output += '----

';
        output += aServices[i].origin.location[0].locationName + ' --> ' + aServices[i].destination.location[0].locationName + '
';
        if (aServices[i].etd !== 'On time') output += '';
        output += aServices[i].std;
        if (aServices[i].etd !== 'On time') output += '';
        output += ' (' + aServices[i].etd + ')
';
        if (aServices[i].platform !== undefined) {
            output += 'Platform ' + aServices[i].platform + '
';
        } else {
            output += 'No platform information available
';
        }
        output += '
';
    }
    return output;
}

function footer() {
    var d = new Date();
    return '
----
Page loaded at ' + d.getHours() + ':' + d.getMinutes() + '

'
        + 'About trntxt

Powered by National Rail Enquiries.
';
}
<|endoftext|>


<commit_before>module.exports = {
  'rules': {
    // enforces getter/setter pairs in objects
    'accessor-pairs': 0,
    // treat var statements as if they were block scoped
    'block-scoped-var': 2,
    // specify the maximum cyclomatic complexity allowed in a program
    'complexity': [0, 11],
    // require return statements to either always or never specify values
    'consistent-return': 2,
    // specify curly brace conventions for all control statements
    'curly': [2, 'multi-line'],
    // require default case in switch statements
    'default-case': 2,
    // encourages use of dot notation whenever possible
    'dot-notation': [2, { 'allowKeywords': true }],
    // enforces consistent newlines before or after dots
    'dot-location': 0,
    // require the use of === and !==
    'eqeqeq': 2,
    // make sure for-in loops have an if statement
    'guard-for-in': 2,
    // disallow the use of alert, confirm, and prompt
    'no-alert': 1,
    // disallow use of arguments.caller or arguments.callee
    'no-caller': 2,
    // disallow lexical declarations in case/default clauses
    'no-case-declaration': 2,
    // disallow division operators explicitly at beginning of regular expression
    'no-div-regex': 0,
    // disallow else after a return in an if
    'no-else-return': 2,
    // disallow use of labels for anything other then loops and switches
    'no-empty-label': 2,
    // disallow comparisons to null without a type-checking operator
    'no-eq-null': 0,
    // disallow use of eval()
    'no-eval': 2,
    // disallow adding to native types
    'no-extend-native': 2,
    // disallow unnecessary function binding
    'no-extra-bind': 2,
    // disallow fallthrough of case statements
    'no-fallthrough': 2,
    // disallow the use of leading or trailing decimal points in numeric literals
    'no-floating-decimal': 2,
    // disallow the type conversions with shorter notations
    'no-implicit-coercion': 0,
    // disallow use of eval()-like methods
    'no-implied-eval': 2,
    // disallow this keywords outside of classes or class-like objects
    'no-invalid-this': 0,
    // disallow usage of __iterator__ property
    'no-iterator': 2,
    // disallow use of labeled statements
    'no-labels': 2,
    // disallow unnecessary nested blocks
    'no-lone-blocks': 2,
    // disallow creation of functions within loops
    'no-loop-func': 2,
    // disallow use of multiple spaces
    'no-multi-spaces': 2,
    // disallow use of multiline strings
    'no-multi-str': 2,
    // disallow reassignments of native objects
    'no-native-reassign': 2,
    // disallow use of new operator when not part of the assignment or comparison
    'no-new': 2,
    // disallow use of new operator for Function object
    'no-new-func': 2,
    // disallows creating new instances of String,Number, and Boolean
    'no-new-wrappers': 2,
    // disallow use of (old style) octal literals
    'no-octal': 2,
    // disallow use of octal escape sequences in string literals, such as
    // var foo = 'Copyright \251';
    'no-octal-escape': 2,
    // disallow reassignment of function parameters
    // disallow parameter object manipulation
    // rule: http://eslint.org/docs/rules/no-param-reassign.html
    'no-param-reassign': [2, { 'props': true }],
    // disallow use of process.env
    'no-process-env': 0,
    // disallow usage of __proto__ property
    'no-proto': 2,
    // disallow declaring the same variable more then once
    'no-redeclare': 2,
    // disallow use of assignment in return statement
    'no-return-assign': 2,
    // disallow use of `javascript:` urls.
    'no-script-url': 2,
    // disallow comparisons where both sides are exactly the same
    'no-self-compare': 2,
    // disallow use of comma operator
    'no-sequences': 2,
    // restrict what can be thrown as an exception
    'no-throw-literal': 2,
    // disallow usage of expressions in statement position
    'no-unused-expressions': 2,
    // disallow unnecessary .call() and .apply()
    'no-useless-call': 0,
    // disallow use of void operator
    'no-void': 0,
    // disallow usage of configurable warning terms in comments: e.g. todo
    'no-warning-comments': [0, { 'terms': ['todo', 'fixme', 'xxx'], 'location': 'start' }],
    // disallow use of the with statement
    'no-with': 2,
    // require use of the second argument for parseInt()
    'radix': 2,
    // requires to declare all vars on top of their containing scope
    'vars-on-top': 2,
    // require immediate function invocation to be wrapped in parentheses
    // http://eslint.org/docs/rules/wrap-iife.html
    'wrap-iife': [2, 'outside'],
    // require or disallow Yoda conditions
    'yoda': 2
  }
};
<commit_msg>[eslint config] [fix] `s/no-case-declaration/no-case-declarations/g` (from #712)<commit_after>module.exports = {
  'rules': {
    // enforces getter/setter pairs in objects
    'accessor-pairs': 0,
    // treat var statements as if they were block scoped
    'block-scoped-var': 2,
    // specify the maximum cyclomatic complexity allowed in a program
    'complexity': [0, 11],
    // require return statements to either always or never specify values
    'consistent-return': 2,
    // specify curly brace conventions for all control statements
    'curly': [2, 'multi-line'],
    // require default case in switch statements
    'default-case': 2,
    // encourages use of dot notation whenever possible
    'dot-notation': [2, { 'allowKeywords': true }],
    // enforces consistent newlines before or after dots
    'dot-location': 0,
    // require the use of === and !==
    'eqeqeq': 2,
    // make sure for-in loops have an if statement
    'guard-for-in': 2,
    // disallow the use of alert, confirm, and prompt
    'no-alert': 1,
    // disallow use of arguments.caller or arguments.callee
    'no-caller': 2,
    // disallow lexical declarations in case/default clauses
    // http://eslint.org/docs/rules/no-case-declarations.html
    'no-case-declarations': 2,
    // disallow division operators explicitly at beginning of regular expression
    'no-div-regex': 0,
    // disallow else after a return in an if
    'no-else-return': 2,
    // disallow use of labels for anything other then loops and switches
    'no-empty-label': 2,
    // disallow comparisons to null without a type-checking operator
    'no-eq-null': 0,
    // disallow use of eval()
    'no-eval': 2,
    // disallow adding to native types
    'no-extend-native': 2,
    // disallow unnecessary function binding
    'no-extra-bind': 2,
    // disallow fallthrough of case statements
    'no-fallthrough': 2,
    // disallow the use of leading or trailing decimal points in numeric literals
    'no-floating-decimal': 2,
    // disallow the type conversions with shorter notations
    'no-implicit-coercion': 0,
    // disallow use of eval()-like methods
    'no-implied-eval': 2,
    // disallow this keywords outside of classes or class-like objects
    'no-invalid-this': 0,
    // disallow usage of __iterator__ property
    'no-iterator': 2,
    // disallow use of labeled statements
    'no-labels': 2,
    // disallow unnecessary nested blocks
    'no-lone-blocks': 2,
    // disallow creation of functions within loops
    'no-loop-func': 2,
    // disallow use of multiple spaces
    'no-multi-spaces': 2,
    // disallow use of multiline strings
    'no-multi-str': 2,
    // disallow reassignments of native objects
    'no-native-reassign': 2,
    // disallow use of new operator when not part of the assignment or comparison
    'no-new': 2,
    // disallow use of new operator for Function object
    'no-new-func': 2,
    // disallows creating new instances of String,Number, and Boolean
    'no-new-wrappers': 2,
    // disallow use of (old style) octal literals
    'no-octal': 2,
    // disallow use of octal escape sequences in string literals, such as
    // var foo = 'Copyright \251';
    'no-octal-escape': 2,
    // disallow reassignment of function parameters
    // disallow parameter object manipulation
    // rule: http://eslint.org/docs/rules/no-param-reassign.html
    'no-param-reassign': [2, { 'props': true }],
    // disallow use of process.env
    'no-process-env': 0,
    // disallow usage of __proto__ property
    'no-proto': 2,
    // disallow declaring the same variable more then once
    'no-redeclare': 2,
    // disallow use of assignment in return statement
    'no-return-assign': 2,
    // disallow use of `javascript:` urls.
    'no-script-url': 2,
    // disallow comparisons where both sides are exactly the same
    'no-self-compare': 2,
    // disallow use of comma operator
    'no-sequences': 2,
    // restrict what can be thrown as an exception
    'no-throw-literal': 2,
    // disallow usage of expressions in statement position
    'no-unused-expressions': 2,
    // disallow unnecessary .call() and .apply()
    'no-useless-call': 0,
    // disallow use of void operator
    'no-void': 0,
    // disallow usage of configurable warning terms in comments: e.g. todo
    'no-warning-comments': [0, { 'terms': ['todo', 'fixme', 'xxx'], 'location': 'start' }],
    // disallow use of the with statement
    'no-with': 2,
    // require use of the second argument for parseInt()
    'radix': 2,
    // requires to declare all vars on top of their containing scope
    'vars-on-top': 2,
    // require immediate function invocation to be wrapped in parentheses
    // http://eslint.org/docs/rules/wrap-iife.html
    'wrap-iife': [2, 'outside'],
    // require or disallow Yoda conditions
    'yoda': 2
  }
};
<|endoftext|>