<commit_before>function AdjacencyMatrix(matrix) {
  // You can create a new adjacency matrix without seeding it.
  matrix = matrix || [];

  // But if you try and seed it we're going to validate it to the Nth degree.
  if (!matrix instanceof Array) {
    throw new TypeError('AdjacencyMatrix expects an Array.');
  }

  // Guarantee we have a valid square matrix.
  var seenNumber = false;
  var seenTrue = false;
  var length = matrix.length;
  for (var v1 = 0; v1 < length; v1++) {
    if (!matrix[v1] instanceof Array) {
      throw new TypeError('AdjacencyMatrix expects an Array of Arrays.');
    }

    if (matrix[v1].length !== length) {
      throw new RangeError('AdjacencyMatrix expects a Square Matrix.');
    }

    for (var v2 = 0; v2 < length; v2++) {
      if (typeof matrix[v1][v2] !== "boolean" && typeof matrix[v1][v2] !== "number") {
        throw new TypeError('Edge weights must be either boolean or numeric.');
      }
      if (typeof matrix[v1][v2] === "number") { seenNumber = true; }
      if (matrix[v1][v2] === true) { seenTrue = true; }

      if (seenNumber && seenTrue) {
        throw new TypeError('Mixed weighted and unweighted edges.');
      }
    }
  }

  // You made it.
  this._weighted = seenNumber;
  this._unweighted = seenTrue;
  this._matrix = matrix;
  this._cardinality = matrix.length;
}

AdjacencyMatrix.prototype.isWeighted = function() {
  return this._weighted;
}

AdjacencyMatrix.prototype.isUnweighted = function() {
  return this._unweighted;
}

AdjacencyMatrix.prototype.getCardinality = function() {
  return this._cardinality;
}

AdjacencyMatrix.prototype.isValidEdge = function(v1, v2) {
  return (v1 < this.getCardinality() && v2 < this.getCardinality());
}

AdjacencyMatrix.prototype.getEdge = function(v1, v2) {
  return this.isValidEdge(v1, v2) ? this._matrix[v1][v2] : undefined;
}

AdjacencyMatrix.prototype.setEdge = function(v1, v2, weight) {
  if (!this.isValidEdge(v1, v2)) {
    throw new RangeError('The supplied vertices do not exist.');
  }
  if (typeof weight !== "boolean" && typeof weight !== "number") {
    throw new TypeError('Supplied weight must be either boolean or numeric.');
  }
  if (this.isWeighted() && (typeof weight !== "number" && weight !== false)) {
    throw new TypeError('Mixed weighted and unweighted edges.');
  }
  if (this.isUnweighted() && typeof weight !== "boolean") {
    throw new TypeError('Mixed weighted and unweighted edges.');
  }

  this._matrix[v1][v2] = weight;
  return true;
}

AdjacencyMatrix.prototype.removeEdge = function(v1, v2) {
  return this.setEdge(v1, v2, false);
}

AdjacencyMatrix.prototype.isConnected = function(v1, v2) {
  return !!this.getEdge(v1, v2);
}

/* Transformations return a new AdjacencyMatrix. */

AdjacencyMatrix.prototype.transform = function(callback) {
  var cardinality = this.getCardinality();
  var next = [];

  for (var v1 = 0; v1 < cardinality; v1++) {
    next.push([]);
    for (var v2 = 0; v2 < cardinality; v2++) {
      next[v1].push(callback.call(this, v1, v2));
    }
  }
  return new AdjacencyMatrix(next);
}

AdjacencyMatrix.prototype.unweighted = function() {
  return this.transform(function (v1, v2) {
    return this.isConnected(v1, v2);
  });
}

AdjacencyMatrix.prototype.undirected = function() {
  return this.transform(function (v1, v2) {
    return (this.isConnected(v1, v2) || this.isConnected(v2, v1));
  });
}

AdjacencyMatrix.prototype.toString = function() {
  var cardinality = this.getCardinality();
  var longest = 1;

  var v1, v2;
  var next = [];

  if (this.isUnweighted()) {
    for (v1 = 0; v1 < cardinality; v1++) {
      next.push([]);
      for (v2 = 0; v2 < cardinality; v2++) {
        next[v1].push(this.isConnected(v1, v2) ? "1" : "_");
      }
      next[v1] = "[" + next[v1].join(" ") + "]";
    }
  }

  if (this.isWeighted()) {
    // Loop once to identify max edge string length.
    var edgeWeight;
    for (v1 = 0; v1 < cardinality; v1++) {
      for (v2 = 0; v2 < cardinality; v2++) {
        edgeWeight = this.getEdge(v1, v2);
        if (typeof edgeWeight === "number") {
          longest = Math.max(longest, edgeWeight.toString().length);
        }
      }
    }

    var pad = new Array(longest + 1).join('_');
    for (v1 = 0; v1 < cardinality; v1++) {
      next.push([]);
      for (v2 = 0; v2 < cardinality; v2++) {
        edgeWeight = this.getEdge(v1, v2);
        if (edgeWeight !== false) {
          next[v1].push((pad + edgeWeight.toString()).slice(-longest));
        } else {
          next[v1].push(pad);
        }
      }
      next[v1] = "[" + next[v1].join(" ") + "]";
    }
  }

  return next.join("\n");
}
<commit_msg>Check for directedness, add a de-loop transform.<commit_after>function AdjacencyMatrix(matrix) {
  // You can create a new adjacency matrix without seeding it.
  matrix = matrix || [];
  this._edgeCardinality = 0;

  // But if you try and seed it we're going to validate it to the Nth degree.
  if (!matrix instanceof Array) {
    throw new TypeError('AdjacencyMatrix expects an Array.');
  }

  // Guarantee we have a valid square matrix.
  var seenNumber = false;
  var seenTrue = false;
  var length = matrix.length;
  for (var v1 = 0; v1 < length; v1++) {
    if (!matrix[v1] instanceof Array) {
      throw new TypeError('AdjacencyMatrix expects an Array of Arrays.');
    }

    if (matrix[v1].length !== length) {
      throw new RangeError('AdjacencyMatrix expects a Square Matrix.');
    }

    for (var v2 = 0; v2 < length; v2++) {
      if (typeof matrix[v1][v2] !== "boolean" && typeof matrix[v1][v2] !== "number") {
        throw new TypeError('Edge weights must be either boolean or numeric.');
      } else {
        this._edgeCardinality++;
      }

      if (typeof matrix[v1][v2] === "number") { seenNumber = true; }
      if (matrix[v1][v2] === true) { seenTrue = true; }

      if (seenNumber && seenTrue) {
        throw new TypeError('Mixed weighted and unweighted edges.');
      }
    }
  }

  // You made it.
  this._weighted = seenNumber;
  this._unweighted = seenTrue;
  this._matrix = matrix;
  this._cardinality = matrix.length;
}

AdjacencyMatrix.prototype.isWeighted = function() {
  return this._weighted;
}

AdjacencyMatrix.prototype.isUnweighted = function() {
  return this._unweighted;
}

AdjacencyMatrix.prototype.getCardinality = function() {
  return this._cardinality;
}

AdjacencyMatrix.prototype.isValidEdge = function(v1, v2) {
  return (v1 < this.getCardinality() && v2 < this.getCardinality());
}

AdjacencyMatrix.prototype.getEdge = function(v1, v2) {
  return this.isValidEdge(v1, v2) ? this._matrix[v1][v2] : undefined;
}

AdjacencyMatrix.prototype.setEdge = function(v1, v2, weight) {
  if (!this.isValidEdge(v1, v2)) {
    throw new RangeError('The supplied vertices do not exist.');
  }
  if (typeof weight !== "boolean" && typeof weight !== "number") {
    throw new TypeError('Supplied weight must be either boolean or numeric.');
  }
  if (this.isWeighted() && (typeof weight !== "number" && weight !== false)) {
    throw new TypeError('Mixed weighted and unweighted edges.');
  }
  if (this.isUnweighted() && typeof weight !== "boolean") {
    throw new TypeError('Mixed weighted and unweighted edges.');
  }

  this._matrix[v1][v2] = weight;
  return true;
}

AdjacencyMatrix.prototype.removeEdge = function(v1, v2) {
  return this.setEdge(v1, v2, false);
}

AdjacencyMatrix.prototype.isConnected = function(v1, v2) {
  return !!this.getEdge(v1, v2);
}

AdjacencyMatrix.prototype.isUndirected = function() {
  var cardinality = this.getCardinality();

  for (var v1 = 0; v1 < cardinality; v1++) {
    for (var v2 = 0; v2 < cardinality && v2 < v1; v2++) {
      if (this.getEdge(v1, v2) !== this.getEdge(v2, v1)) {
        return false;
      }
    }
  }
  return true;
}

AdjacencyMatrix.prototype.isDirected = function() {
  return !this.isUndirected();
}

/* Transformations return a new AdjacencyMatrix. */

AdjacencyMatrix.prototype.transform = function(callback) {
  var cardinality = this.getCardinality();
  var next = [];

  for (var v1 = 0; v1 < cardinality; v1++) {
    next.push([]);
    for (var v2 = 0; v2 < cardinality; v2++) {
      next[v1].push(callback.call(this, v1, v2));
    }
  }
  return new AdjacencyMatrix(next);
}

AdjacencyMatrix.prototype.unweighted = function() {
  return this.transform(function (v1, v2) {
    return this.isConnected(v1, v2);
  });
}

AdjacencyMatrix.prototype.undirected = function() {
  return this.transform(function (v1, v2) {
    return (this.isConnected(v1, v2) || this.isConnected(v2, v1));
  });
}

AdjacencyMatrix.prototype.deloop = function() {
  return this.transform(function (v1, v2) {
    return v1 === v2 ? false : this.getEdge(v1, v2);
  });
}

AdjacencyMatrix.prototype.toString = function() {
  var cardinality = this.getCardinality();
  var longest = 1;

  var v1, v2;
  var next = [];

  if (this.isUnweighted()) {
    for (v1 = 0; v1 < cardinality; v1++) {
      next.push([]);
      for (v2 = 0; v2 < cardinality; v2++) {
        next[v1].push(this.isConnected(v1, v2) ? "1" : "_");
      }
      next[v1] = "[" + next[v1].join(" ") + "]";
    }
  }

  if (this.isWeighted()) {
    // Loop once to identify max edge string length.
    var edgeWeight;
    for (v1 = 0; v1 < cardinality; v1++) {
      for (v2 = 0; v2 < cardinality; v2++) {
        edgeWeight = this.getEdge(v1, v2);
        if (typeof edgeWeight === "number") {
          longest = Math.max(longest, edgeWeight.toString().length);
        }
      }
    }

    var pad = new Array(longest + 1).join('_');
    for (v1 = 0; v1 < cardinality; v1++) {
      next.push([]);
      for (v2 = 0; v2 < cardinality; v2++) {
        edgeWeight = this.getEdge(v1, v2);
        if (edgeWeight !== false) {
          next[v1].push((pad + edgeWeight.toString()).slice(-longest));
        } else {
          next[v1].push(pad);
        }
      }
      next[v1] = "[" + next[v1].join(" ") + "]";
    }
  }

  return next.join("\n");
}
<|endoftext|>


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

var App = require('app');

App.version = ''; // filled out by set-ambari-version.sh script
App.testMode = (location.port == '3333'); // test mode is automatically enabled if running on brunch server
App.testModeDelayForActions = 10000;
App.skipBootstrap = false;
App.alwaysGoToInstaller = false;
App.testEnableSecurity = true; // By default enable security is tested; turning it false tests disable security
App.testNameNodeHA = true;
App.apiPrefix = '/api/v1';
App.defaultStackVersion = 'HDP-2.2';
App.defaultWindowsStackVersion = 'HDPWIN-2.1';

App.defaultJavaHome = '/usr/jdk/jdk1.6.0_31';
App.timeout = 180000; // default AJAX timeout
App.maxRetries = 3; // max number of retries for certain AJAX calls
App.sessionKeepAliveInterval  = 60000;
App.bgOperationsUpdateInterval = 6000;
App.componentsUpdateInterval = 6000;
App.contentUpdateInterval = 15000;
App.hostStatusCountersUpdateInterval = 10000;
App.alertDefinitionsUpdateInterval = 10000;
App.alertInstancesUpdateInterval = 10000;
App.alertGroupsUpdateInterval = 10000;
App.pageReloadTime=3600000;
App.singleNodeInstall = false;
App.singleNodeAlias = document.location.hostname;
App.minDiskSpace = 2.0; // minimum disk space required for '/' for each host before install, unit GB
App.minDiskSpaceUsrLib = 1.0; // minimum disk space for '/usr/lib' for each host before install, unit GB
App.healthIconClassGreen = 'icon-ok-sign'; // bootstrap icon class for healthy/started service/host/host-component
App.healthIconClassRed = 'icon-warning-sign'; // bootstrap icon class for master down/stopped service/host/host-component
App.healthIconClassOrange = 'icon-minus-sign'; // bootstrap icon class for slave down/decommissioned host/host-component
App.healthIconClassYellow = 'icon-question-sign'; // bootstrap icon class for heartbeat lost service/host/host-component
App.isManagedMySQLForHiveEnabled = false;
App.isStormMetricsSupported = true;
App.healthStatusRed = '#ff0000';
App.healthStatusGreen = '#5AB400';
App.healthStatusOrange = '#FF8E00';

App.stackVersionsAvailable = true;

// experimental features are automatically enabled if running on brunch server
App.enableExperimental = false;

App.supports = {
  preUpgradeCheck: true,
  stackUpgrade: true,
  displayOlderVersions: false,
  autoRollbackHA: false,
  alwaysEnableManagedMySQLForHive: false,
  preKerberizeCheck: false,
  customizeAgentUserAccount: false,
  installGanglia: false,
  opsDuringRollingUpgrade: false,
  customizedWidgets: true,
  customizedWidgetLayout: false,
  enhancedConfigs: false
};

if (App.enableExperimental) {
  for (var support in App.supports) {
    App.supports[support] = true;
  }
}

// this is to make sure that IE does not cache data when making AJAX calls to the server
if (!$.mocho) {
  $.ajaxSetup({
    cache: false,
    headers: {"X-Requested-By": "X-Requested-By"}
  });
}

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

var App = require('app');

App.version = ''; // filled out by set-ambari-version.sh script
App.testMode = (location.port == '3333'); // test mode is automatically enabled if running on brunch server
App.testModeDelayForActions = 10000;
App.skipBootstrap = false;
App.alwaysGoToInstaller = false;
App.testEnableSecurity = true; // By default enable security is tested; turning it false tests disable security
App.testNameNodeHA = true;
App.apiPrefix = '/api/v1';
App.defaultStackVersion = 'HDP-2.2';
App.defaultWindowsStackVersion = 'HDPWIN-2.1';

App.defaultJavaHome = '/usr/jdk/jdk1.6.0_31';
App.timeout = 180000; // default AJAX timeout
App.maxRetries = 3; // max number of retries for certain AJAX calls
App.sessionKeepAliveInterval  = 60000;
App.bgOperationsUpdateInterval = 6000;
App.componentsUpdateInterval = 6000;
App.contentUpdateInterval = 15000;
App.hostStatusCountersUpdateInterval = 10000;
App.alertDefinitionsUpdateInterval = 10000;
App.alertInstancesUpdateInterval = 10000;
App.alertGroupsUpdateInterval = 10000;
App.pageReloadTime=3600000;
App.singleNodeInstall = false;
App.singleNodeAlias = document.location.hostname;
App.minDiskSpace = 2.0; // minimum disk space required for '/' for each host before install, unit GB
App.minDiskSpaceUsrLib = 1.0; // minimum disk space for '/usr/lib' for each host before install, unit GB
App.healthIconClassGreen = 'icon-ok-sign'; // bootstrap icon class for healthy/started service/host/host-component
App.healthIconClassRed = 'icon-warning-sign'; // bootstrap icon class for master down/stopped service/host/host-component
App.healthIconClassOrange = 'icon-minus-sign'; // bootstrap icon class for slave down/decommissioned host/host-component
App.healthIconClassYellow = 'icon-question-sign'; // bootstrap icon class for heartbeat lost service/host/host-component
App.isManagedMySQLForHiveEnabled = false;
App.isStormMetricsSupported = true;
App.healthStatusRed = '#ff0000';
App.healthStatusGreen = '#5AB400';
App.healthStatusOrange = '#FF8E00';

App.stackVersionsAvailable = true;

// experimental features are automatically enabled if running on brunch server
App.enableExperimental = false;

App.supports = {
  preUpgradeCheck: true,
  stackUpgrade: true,
  displayOlderVersions: false,
  autoRollbackHA: false,
  alwaysEnableManagedMySQLForHive: false,
  preKerberizeCheck: false,
  customizeAgentUserAccount: false,
  installGanglia: false,
  opsDuringRollingUpgrade: false,
  customizedWidgets: true,
  customizedWidgetLayout: false,
  enhancedConfigs: true
};

if (App.enableExperimental) {
  for (var support in App.supports) {
    App.supports[support] = true;
  }
}

// this is to make sure that IE does not cache data when making AJAX calls to the server
if (!$.mocho) {
  $.ajaxSetup({
    cache: false,
    headers: {"X-Requested-By": "X-Requested-By"}
  });
}

/**
 * Test Mode values
 */
App.test_hostname = 'hostname';
<|endoftext|>


<commit_before>'use strict';

angular.module('anvil', [])

  .provider('Anvil', function AnvilProvider () {

    /**
     * Private state
     */

    var issuer, params, encodedParams, display, urls = {}, session = {};

    /**
     * Provider configuration
     */

    this.configure = function (iss, options) {

      issuer = iss;

      params = {
        response_type:  options.response_type || 'id_token token',
        client_id:      options.client_id,
        redirect_uri:   options.redirect_uri,
        scope:          ['openid', 'profile'].concat(options.scope || []).join(' '),
        // other
      };

      encodedParams = toFormUrlEncoded(params),

      urls = {
        authorize:  issuer + '/authorize?' + encodedParams,
        signin:     issuer + '/signin?'    + encodedParams,
        signup:     issuer + '/signup?'    + encodedParams,
        userinfo:   issuer + '/userinfo',
        connect: function (provider) {
          return issuer + '/connect/' + provider + '?' + encodedParams;
        }
      };

      display        = options.display || 'page';

      this.issuer    = issuer;
      this.params    = params;
      this.urls      = urls;
      this.display   = display;

    };

    /**
     * Form Urlencode an object
     */

    function toFormUrlEncoded (obj) {
      var pairs = [];

      Object.keys(obj).forEach(function (key) {
        pairs.push(key + '=' + obj[key]);
      });

      return pairs.join('&');
    }

    /**
     * Parse Form Urlencoded data
     */

    function parseFormUrlEncoded (str) {
      var obj = {};

      str.split('&').forEach(function (property) {
        var pair = property.split('=')
          , key  = pair[0]
          , val  = pair[1]
          ;

        obj[key] = val;
      });

      return obj;
    }

    /**
     * Deserialize session
     */

    //function deserializeSession () {
    //  var re, secret, json, session
    //  try {
    //    re      = new RegExp('[; ]anvil.connect=([^\\s;]*)');
    //    secret  = document.cookie.match(re).pop();
    //    json    = sjcl.decrypt(secret, localStorage['anvil.connect']);
    //    session = JSON.parse(json);
    //  } catch (e) {}
    //  return session;
    //}

    this.$get = [
      '$q',
      '$http',
      '$location',
      '$document',
      '$window', function ($q, $http, $location, $document, $window) {

      var Anvil = {};

      /**
       * Session object
       */

      Anvil.session = session;

      /**
       * Serialize session
       */

      Anvil.serialize = function () {
        var now = new Date()
          , time = now.getTime()
          , exp = time + (Anvil.session.expires_in || 3600) * 1000
          , secret = sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(Math.random().toString(36).substr(2, 10)))
          ;

        now.setTime(exp);
        document.cookie = 'anvil.connect=' + secret + '; expires=' + now.toUTCString();
        var encrypted = sjcl.encrypt(secret, JSON.stringify(Anvil.session));
        localStorage['anvil.connect'] = encrypted;
        console.log('SERIALIZED', encrypted);
      };

      /**
       * Deserialize session
       */

      Anvil.deserialize = function () {
        var re, secret, json, parsed;

        try {
          // Use the cookie value to decrypt the session in localStorage
          re      = new RegExp('[; ]anvil.connect=([^\\s;]*)');
          secret  = document.cookie.match(re).pop();
          json    = sjcl.decrypt(secret, localStorage['anvil.connect']);
          parsed  = JSON.parse(json);

        } catch (e) {
          console.log('Cannot deserialize session data');
        }

        Anvil.session = session = parsed;
        console.log('DESERIALIZED', session);
      };

      /**
       * Urls
       */

      Anvil.urls = urls;

      /**
       * Quick and dirty uri method with nonce
       */

      Anvil.uri = function (endpoint) {
        return issuer + '/'
             + (endpoint || 'authorize') + '?'
             + encodedParams
             + '&nonce=' + this.nonce()
             ;
      };

      /**
       * Create or verify a nonce
       */

      Anvil.nonce = function (nonce) {
        if (nonce) {
          return (this.sha256url(localStorage['nonce']) === nonce);
        } else {
          localStorage['nonce'] = Math.random().toString(36).substr(2, 10);
          return this.sha256url(localStorage['nonce']);
        }
      };

      /**
       * Base64url encode a SHA256 hash of the input string
       */

      Anvil.sha256url = function (str) {
        return sjcl.codec.base64url.fromBits(sjcl.hash.sha256.hash(str));
      };

      /**
       * Parse uri fragment response from Anvil Connect
       */

      Anvil.response = function () {
        return parseFormUrlEncoded($location.hash());
      };

      /**
       * Headers
       */

      Anvil.headers = function (headers) {
        if (this.session.access_token) {
          return angular.extend(headers || {}, {
            'Authorization': 'Bearer ' + this.session.access_token
          });
        } else {
          return headers;
        }
      };

      /**
       * Request
       */

      Anvil.request = function (config) {
        var deferred = $q.defer();

        config.headers = this.headers(config.headers);

        function success (response) {
          deferred.resolve(response.data);
        }

        function failure (fault) {
          deferred.reject(fault);
        }

        $http(config).then(success, failure);

        return deferred.promise;
      };

      /**
       * UserInfo
       */

      Anvil.userInfo = function () {
        return this.request({
          method: 'GET',
          url: this.urls.userinfo
        });
      };

      /**
       * Authorize
       */

      Anvil.authorize = function (authorization) {
        // handle the auth response
        if (authorization) {
          var deferred = $q.defer()
            , response = parseFormUrlEncoded($location.hash())
            ;

          // handle authorization error
          if (response.error) {
            deferred.reject(response);
            console.log('ERROR', response)
            // clear localStorage/cookie?
          }

          // handle successful authorization
          else {
            // TODO:
            // - verify id token
            // - verify nonce
            // - verify access token (athash claim)
            // - expose userinfo as a property of the service

            Anvil.session = session = response;

            Anvil.userInfo().then(

              function userInfoSuccess (userInfo) {
                Anvil.session.userInfo = userInfo;
                Anvil.serialize();
                deferred.resolve(session);
              },

              function userInfoFailure () {

              }

            );
          }

          return deferred.promise;
        }

        // initiate the auth flow
        else {
          // open the signin page in a popup window
          if (display === 'popup') {
            $window.open(this.uri(), 'authorize', 'width=500, height=600');
          }

          // navigate the current window to the provider
          else {
            $window.location = this.uri();
          }
        }
      };

      /**
       * Reinstate an existing session
       */

      Anvil.deserialize();

      /**
       * Service
       */

      return Anvil;

    }];
  })

<commit_msg>signout method<commit_after>'use strict';

angular.module('anvil', [])

  .provider('Anvil', function AnvilProvider () {

    /**
     * Private state
     */

    var issuer, params, encodedParams, display, urls = {}, session = {};

    /**
     * Provider configuration
     */

    this.configure = function (iss, options) {

      issuer = iss;

      params = {
        response_type:  options.response_type || 'id_token token',
        client_id:      options.client_id,
        redirect_uri:   options.redirect_uri,
        scope:          ['openid', 'profile'].concat(options.scope || []).join(' '),
        // other
      };

      encodedParams = toFormUrlEncoded(params),

      urls = {
        authorize:  issuer + '/authorize?' + encodedParams,
        signin:     issuer + '/signin?'    + encodedParams,
        signup:     issuer + '/signup?'    + encodedParams,
        userinfo:   issuer + '/userinfo',
        connect: function (provider) {
          return issuer + '/connect/' + provider + '?' + encodedParams;
        }
      };

      display        = options.display || 'page';

      this.issuer    = issuer;
      this.params    = params;
      this.urls      = urls;
      this.display   = display;

    };

    /**
     * Form Urlencode an object
     */

    function toFormUrlEncoded (obj) {
      var pairs = [];

      Object.keys(obj).forEach(function (key) {
        pairs.push(key + '=' + obj[key]);
      });

      return pairs.join('&');
    }

    /**
     * Parse Form Urlencoded data
     */

    function parseFormUrlEncoded (str) {
      var obj = {};

      str.split('&').forEach(function (property) {
        var pair = property.split('=')
          , key  = pair[0]
          , val  = pair[1]
          ;

        obj[key] = val;
      });

      return obj;
    }

    /**
     * Factory
     */

    this.$get = [
      '$q',
      '$http',
      '$location',
      '$document',
      '$window', function ($q, $http, $location, $document, $window) {

      var Anvil = {};

      /**
       * Session object
       */

      Anvil.session = session;

      /**
       * Serialize session
       */

      Anvil.serialize = function () {
        var now = new Date()
          , time = now.getTime()
          , exp = time + (Anvil.session.expires_in || 3600) * 1000
          , secret = sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(Math.random().toString(36).substr(2, 10)))
          ;

        now.setTime(exp);
        document.cookie = 'anvil.connect=' + secret + '; expires=' + now.toUTCString();
        var encrypted = sjcl.encrypt(secret, JSON.stringify(Anvil.session));
        localStorage['anvil.connect'] = encrypted;
        console.log('SERIALIZED', encrypted);
      };

      /**
       * Deserialize session
       */

      Anvil.deserialize = function () {
        var re, secret, json, parsed;

        try {
          // Use the cookie value to decrypt the session in localStorage
          re      = new RegExp('[; ]anvil.connect=([^\\s;]*)');
          secret  = document.cookie.match(re).pop();
          json    = sjcl.decrypt(secret, localStorage['anvil.connect']);
          parsed  = JSON.parse(json);

        } catch (e) {
          console.log('Cannot deserialize session data');
        }

        Anvil.session = session = parsed;
        console.log('DESERIALIZED', session);
      };

      /**
       * Urls
       */

      Anvil.urls = urls;

      /**
       * Quick and dirty uri method with nonce
       */

      Anvil.uri = function (endpoint) {
        return issuer + '/'
             + (endpoint || 'authorize') + '?'
             + encodedParams
             + '&nonce=' + this.nonce()
             ;
      };

      /**
       * Create or verify a nonce
       */

      Anvil.nonce = function (nonce) {
        if (nonce) {
          return (this.sha256url(localStorage['nonce']) === nonce);
        } else {
          localStorage['nonce'] = Math.random().toString(36).substr(2, 10);
          return this.sha256url(localStorage['nonce']);
        }
      };

      /**
       * Base64url encode a SHA256 hash of the input string
       */

      Anvil.sha256url = function (str) {
        return sjcl.codec.base64url.fromBits(sjcl.hash.sha256.hash(str));
      };

      /**
       * Parse uri fragment response from Anvil Connect
       */

      Anvil.response = function () {
        return parseFormUrlEncoded($location.hash());
      };

      /**
       * Headers
       */

      Anvil.headers = function (headers) {
        if (this.session.access_token) {
          return angular.extend(headers || {}, {
            'Authorization': 'Bearer ' + this.session.access_token
          });
        } else {
          return headers;
        }
      };

      /**
       * Request
       */

      Anvil.request = function (config) {
        var deferred = $q.defer();

        config.headers = this.headers(config.headers);

        function success (response) {
          deferred.resolve(response.data);
        }

        function failure (fault) {
          deferred.reject(fault);
        }

        $http(config).then(success, failure);

        return deferred.promise;
      };

      /**
       * UserInfo
       */

      Anvil.userInfo = function () {
        return this.request({
          method: 'GET',
          url: this.urls.userinfo
        });
      };

      /**
       * Authorize
       */

      Anvil.authorize = function (authorization) {
        // handle the auth response
        if (authorization) {
          var deferred = $q.defer()
            , response = parseFormUrlEncoded($location.hash())
            ;

          // handle authorization error
          if (response.error) {
            deferred.reject(response);
            console.log('ERROR', response)
            // clear localStorage/cookie?
          }

          // handle successful authorization
          else {
            // TODO:
            // - verify id token
            // - verify nonce
            // - verify access token (athash claim)
            // - expose userinfo as a property of the service

            Anvil.session = session = response;

            Anvil.userInfo().then(

              function userInfoSuccess (userInfo) {
                Anvil.session.userInfo = userInfo;
                Anvil.serialize();
                deferred.resolve(session);
              },

              function userInfoFailure () {

              }

            );
          }

          return deferred.promise;
        }

        // initiate the auth flow
        else {
          // open the signin page in a popup window
          if (display === 'popup') {
            $window.open(this.uri(), 'authorize', 'width=500, height=600');
          }

          // navigate the current window to the provider
          else {
            $window.location = this.uri();
          }
        }
      };

      /**
       * Signout
       */

      Anvil.signout = function () {
        Anvil.session = session = {};
        document.cookie = 'anvil.connect=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
        delete localStorage['anvil.connect'];
        // what about signing out of the auth server?
      };

      /**
       * Reinstate an existing session
       */

      Anvil.deserialize();

      /**
       * Service
       */

      return Anvil;

    }];
  })

<|endoftext|>


<commit_before>'use strict'
const Rat = require('./../db').Rat
const Epic = require('./../db').Epic
const Query = require('./index')

/**
 * A class representing a rescue query
 */
class RescueQuery extends Query {
  /**
   * Create a sequelize rescue query from a set of parameters
   * @constructor
   * @param params
   * @param connection
   */
  constructor (params, connection) {
    super(params, connection)

    this._query.attributes = {
      exclude: [
        'deletedAt'
      ]
    }

    let rats = {}
    if (this._params.rats) {
      rats = this.subQuery(this._params.rats)
      delete this._params.rats
    }

    let firstLimpet = {}
    if (this._params.firstLimpet) {
      firstLimpet = this.subQuery(this._params.firstLimpet)
      delete this._params.firstLimpet
    }

    let epics = {}
    if (this._params.epics) {
      epics = this.subQuery(this._params.epics)
      delete this._params.epics
    }

    this._query.where = this._params

    this._query.include = [
      {
        where: rats,
        model: Rat,
        as: 'rats',
        require: false,
        through: {
          attributes: []
        }
      },
      {
        where: firstLimpet,
        model: Rat,
        as: 'firstLimpet',
        require: false
      },
      {
        model: Epic,
        as: 'epics',
        require: false
      }
    ]
  }
}

module.exports = RescueQuery<commit_msg>Make result counts distinct so Clapton will be happy<commit_after>'use strict'
const Rat = require('./../db').Rat
const Epic = require('./../db').Epic
const Query = require('./index')

/**
 * A class representing a rescue query
 */
class RescueQuery extends Query {
  /**
   * Create a sequelize rescue query from a set of parameters
   * @constructor
   * @param params
   * @param connection
   */
  constructor (params, connection) {
    super(params, connection)

    this._query.distinct = true

    this._query.attributes = {
      exclude: [
        'deletedAt'
      ]
    }

    let rats = {}
    if (this._params.rats) {
      rats = this.subQuery(this._params.rats)
      delete this._params.rats
    }

    let firstLimpet = {}
    if (this._params.firstLimpet) {
      firstLimpet = this.subQuery(this._params.firstLimpet)
      delete this._params.firstLimpet
    }

    let epics = {}
    if (this._params.epics) {
      epics = this.subQuery(this._params.epics)
      delete this._params.epics
    }

    this._query.where = this._params

    this._query.include = [
      {
        where: rats,
        model: Rat,
        as: 'rats',
        require: false,
        through: {
          attributes: []
        }
      },
      {
        where: firstLimpet,
        model: Rat,
        as: 'firstLimpet',
        require: false
      },
      {
        model: Epic,
        as: 'epics',
        require: false
      }
    ]
  }
}

module.exports = RescueQuery<|endoftext|>


<commit_before>var Promise = require('bluebird');
var mime = require('mime');
var Path = require('path');

var client = require('../../lib/amazon-client').create();

var log = require('../../lib/logger.js');
var Remix = require('../../lib/remix');

var File = require('../modules/files/model');
var PublishedFiles = require('../modules/publishedFiles/model');
var PublishedProject = require('../modules/publishedProjects/model');

/**
 * Utility functions
 */
function reject(e) {
  return Promise.reject(e);
}

function buildUrl(project, user) {
  var url = process.env.PUBLIC_PROJECT_ENDPOINT + '/' +
            user.get('name') + '/' +
            project.get('id');
  return url;
}

/**
 * Model retrieval functions
 */
function getUserForProject(project) {
  return project.user().query({}).fetch();
}

function getPublishedProject(project) {
  return PublishedProject.query({
    where: {
      id: project.get('published_id')
    }
  }).fetch();
}

function getPublishedFiles(publishedProject) {
  return PublishedFiles.query({
    where: {
      published_id: publishedProject.get('id')
    }
  }).fetchAll();
}

// Takes an absolute path and uri-encodes each component
// of the path to return a fully uri safe path
function uriSafe(path) {
  if (path === '/') {
    return '/';
  }

  var uriSafePath = '';

  while (path !== '/') {
    uriSafePath = Path.join('/', encodeURIComponent(Path.basename(path)), uriSafePath);
    path = Path.dirname(path);
  }

  return uriSafePath;
}

/**
 * Publish helpers
 */
function upload(path, buffer, mimeType) {
  var headers = {
    'Cache-Control': 'max-age=0',
    'Content-Type': mimeType,
    'Content-Length': buffer.length
  };

  var request = client.put(uriSafe(path), headers);

  return new Promise(function(resolve, reject) {
    request.on('error', function(err) {
      reject(err);
    });
    request.on('continue', function() {
      request.end(buffer);
    });
    request.on('response', function(res) {
      if (res.statusCode === 200) {
        log.info('Successfully uploaded ' + path);
        resolve();
      } else {
        reject('S3 upload returned ' + res.statusCode);
      }
    });
  });
}

function uploadFile(file, root, remixMetadata) {
  var buffer = file.get('buffer');
  var path = root + file.get('path');
  var mimeType = mime.lookup(path);

  if (mimeType === 'text/html') {
    buffer = new Buffer(Remix.inject(buffer.toString(), remixMetadata));
  }

  return upload(path, buffer, mimeType);
}

function deleteFileRemotely(file, root) {
  var path = root + file.get('path');

  return new Promise(function(resolve, reject) {
    var request = client.del(uriSafe(path));
    request.on('error', function(err) {
      reject(err);
    });
    request.on('response', function(res) {
      if (res.statusCode === 204) {
        log.info('Successfully deleted ' + path);
        resolve();
      } else {
        reject('S3 delete returned ' + res.statusCode);
      }
    });
    request.end();
  });
}

function modifyPublishedFiles(action, project, user, files, remixMetadata) {
  return Promise.resolve()
  .then(function() {
    if (files.length) {
      return files.mapThen(function(file) {
        return action(file, '/' + user.get('name') + '/' + project.get('id'), remixMetadata);
      });
    }
    return action(files, '/' + user.get('name') + '/' + project.get('id'), remixMetadata);
  });
}

/**
 * Exports
 */
exports.publish = function publish(project) {
  var user;
  var files;

  var publishedFiles;
  var publishedProject;
  var remixMetadata;

  var projectFiles = {};
  var publishedProjectFiles = {};
  var toBeCreated = [];
  var toBeDeleted = [];
  var toBeUpdated = [];

  return Promise.resolve()
  // First, collect the related user
  .then(function() {
    return getUserForProject(project)
    .then(function(u) {
      user = u;
    });
  })
  // Then, collect or create the current project's publishedProject
  .then(function() {
    return getPublishedProject(project)
    .then(function(oldPublishedProject) {
      if (oldPublishedProject) {
        return oldPublishedProject.set({
          title: project.get('title'),
          tags: project.get('tags'),
          description: project.get('description')
        }).save();
      }
      return PublishedProject.forge({
        title: project.get('title'),
        tags: project.get('tags'),
        description: project.get('description')
      }).save();
    })
    .then(function(p) {
      publishedProject = p;
      remixMetadata = {
        projectId: publishedProject.get('id'),
        projectTitle: publishedProject.get('title'),
        projectAuthor: user.get('name'),
        dateUpdated: project.get('date_updated'),
        host: Remix.resourceHost
      };
    });
  })
  // Then, fetch all the project's files
  .then(function() {
    return File.query({
      where: {
        project_id: project.get('id')
      }
    }).fetchAll()
    .then(function(f) {
      if (f.length === 0) {
        throw 'No files to be published!';
      }

      files = f;
    });
  })
  // Then, fetch all the publishedProject's files (if any)
  .then(function() {
    return PublishedFiles.query({
      where: {
        published_id: publishedProject.get('id')
      }
    }).fetchAll()
    .then(function(f) {
      if (f.length === 0) {
        return;
      }
      publishedFiles = f;
    });
  })
  // Then, identify which files need to be remotely republished,
  // deleted or created
  .then(function() {
    // We organize the project's 'file' objects by id
    files.forEach(function(file) {
      projectFiles[file.get('id')] = file;
    });
    var filePrimaryKeys = Object.keys(projectFiles);

    // Nothing published yet?
    if (!publishedFiles) {
      return filePrimaryKeys.forEach(function(id) {
        toBeCreated.push(projectFiles[id]);
      });
    }

    // In this step we:
    //   1) Organize our 'publishedFile' collection to be keyed on
    //      their foreign key reference to the related 'file'
    //   2) Collect an array of 'publishedFile' objects whose related
    //      'file' object has been deleted. These must be unpublished later
    publishedFiles.forEach(function(publishedFile) {
      if (publishedFile.get('file_id') === null) {
        toBeDeleted.push(publishedFile);
        return;
      }
      publishedProjectFiles[publishedFile.get('file_id')] = publishedFile;
    });
    var publishedFileForeignKeys = Object.keys(publishedProjectFiles);

    // Next, we identify which 'files' are new since this project was last
    // published.
    filePrimaryKeys.forEach(function(primaryKey) {
      if (publishedFileForeignKeys.indexOf(primaryKey) === -1) {
        toBeCreated.push(projectFiles[primaryKey]);
      }
    });

    // The last step identifies which 'files' have already been published
    // and don't require deletion
    publishedFileForeignKeys.forEach(function(foreignKey) {
      if (filePrimaryKeys.indexOf(foreignKey) !== -1) {
        toBeUpdated.push(publishedProjectFiles[foreignKey]);
      }
    });
  })
  // Then, we create 'publishedFile' objects for all new 'files' since last publish
  .then(function() {
    if (toBeCreated.length === 0) {
      return;
    }

    return Promise.map(toBeCreated, function(file) {
      return PublishedFiles.forge({
        file_id: file.get('id'),
        published_id: publishedProject.get('id'),
        path: file.get('path'),
        buffer: file.get('buffer')
      }).save();
    })
    .then(function(f) {
      return Promise.map(f, function(toBePublished) {
        return modifyPublishedFiles(uploadFile, project, user, toBePublished, remixMetadata);
      });
    });
  })
  // Then, we unpublish and delete 'publishedFile' objects for all newly deleted 'files'
  .then(function() {
    if (toBeDeleted.length === 0) {
      return;
    }

    return Promise.map(toBeDeleted, function(model) {
      return modifyPublishedFiles(deleteFileRemotely, project, user, model)
      .then(function() {
        return model.destroy();
      });
    });
  })
  // Then, we unpublish and republish all remaining 'files' in case the path or
  // data has changed
  .then(function() {
    if (toBeUpdated.length === 0) {
      return;
    }

    return Promise.map(toBeUpdated, function(model) {
      return modifyPublishedFiles(deleteFileRemotely, project, user, model)
      .then(function() {
        var originalFile = projectFiles[model.get('file_id')];

        return model.set({
          path: originalFile.get('path'),
          buffer: originalFile.get('buffer')
        }).save()
        .then(function() {
          return modifyPublishedFiles(uploadFile, project, user, model, remixMetadata);
        });
      });
    });
  })
  // Then, we make sure the project has up-to-date references
  .then(function() {
    return project.set({
      publish_url: buildUrl(project, user),
      published_id: publishedProject.get('id')
    }).save();
  })
  // And finally...
  .then(function() {
    log.info(
      'Successfully published ' +
      project.get('title') +
      ' to ' + project.get('publish_url')
    );
  })
  .catch(reject);
};

exports.unpublish = function unpublish(project) {
  function getUserAndPublishedProject(callback) {
    var user = getUserForProject(project);
    var publishedProject = getPublishedProject(project);

    return Promise.join(user, publishedProject, callback);
  }

  function destroyPublishedFiles(user, publishedProject) {
    function deleteFilesFromS3(files) {
      return modifyPublishedFiles(deleteFileRemotely, project, user, files);
    }

    function unsetProjectReferences() {
      return project.set({
        published_id: null,
        publish_url: null
      }).save();
    }

    function destroyPublishedProject() {
      return publishedProject.destroy();
    }

    return getPublishedFiles(publishedProject)
      .then(deleteFilesFromS3)
      .then(unsetProjectReferences)
      .then(destroyPublishedProject);
  }

  return getUserAndPublishedProject(function(user, publishedProject) {
    return destroyPublishedFiles(user, publishedProject);
  })
  .then(function() {
    return project.set({ publish_url: null }).save();
  })
  .then(function() {
    log.info(
      'Successfully unpublished ' +
      project.get('title')
    );
  })
  .catch(reject);
};

module.exports = exports;
<commit_msg>only add the remix script to html files if 'readonly' isn't set<commit_after>var Promise = require('bluebird');
var mime = require('mime');
var Path = require('path');

var client = require('../../lib/amazon-client').create();

var log = require('../../lib/logger.js');
var Remix = require('../../lib/remix');

var File = require('../modules/files/model');
var PublishedFiles = require('../modules/publishedFiles/model');
var PublishedProject = require('../modules/publishedProjects/model');

/**
 * Utility functions
 */
function reject(e) {
  return Promise.reject(e);
}

function buildUrl(project, user) {
  var url = process.env.PUBLIC_PROJECT_ENDPOINT + '/' +
            user.get('name') + '/' +
            project.get('id');
  return url;
}

/**
 * Model retrieval functions
 */
function getUserForProject(project) {
  return project.user().query({}).fetch();
}

function getPublishedProject(project) {
  return PublishedProject.query({
    where: {
      id: project.get('published_id')
    }
  }).fetch();
}

function getPublishedFiles(publishedProject) {
  return PublishedFiles.query({
    where: {
      published_id: publishedProject.get('id')
    }
  }).fetchAll();
}

// Takes an absolute path and uri-encodes each component
// of the path to return a fully uri safe path
function uriSafe(path) {
  if (path === '/') {
    return '/';
  }

  var uriSafePath = '';

  while (path !== '/') {
    uriSafePath = Path.join('/', encodeURIComponent(Path.basename(path)), uriSafePath);
    path = Path.dirname(path);
  }

  return uriSafePath;
}

/**
 * Publish helpers
 */
function upload(path, buffer, mimeType) {
  var headers = {
    'Cache-Control': 'max-age=0',
    'Content-Type': mimeType,
    'Content-Length': buffer.length
  };

  var request = client.put(uriSafe(path), headers);

  return new Promise(function(resolve, reject) {
    request.on('error', function(err) {
      reject(err);
    });
    request.on('continue', function() {
      request.end(buffer);
    });
    request.on('response', function(res) {
      if (res.statusCode === 200) {
        log.info('Successfully uploaded ' + path);
        resolve();
      } else {
        reject('S3 upload returned ' + res.statusCode);
      }
    });
  });
}

function uploadFile(file, root, remixMetadata) {
  var buffer = file.get('buffer');
  var path = root + file.get('path');
  var mimeType = mime.lookup(path);

  if (mimeType === 'text/html' && !remixMetadata.readonly) {
    buffer = new Buffer(Remix.inject(buffer.toString(), remixMetadata));
  }

  return upload(path, buffer, mimeType);
}

function deleteFileRemotely(file, root) {
  var path = root + file.get('path');

  return new Promise(function(resolve, reject) {
    var request = client.del(uriSafe(path));
    request.on('error', function(err) {
      reject(err);
    });
    request.on('response', function(res) {
      if (res.statusCode === 204) {
        log.info('Successfully deleted ' + path);
        resolve();
      } else {
        reject('S3 delete returned ' + res.statusCode);
      }
    });
    request.end();
  });
}

function modifyPublishedFiles(action, project, user, files, remixMetadata) {
  return Promise.resolve()
  .then(function() {
    if (files.length) {
      return files.mapThen(function(file) {
        return action(file, '/' + user.get('name') + '/' + project.get('id'), remixMetadata);
      });
    }
    return action(files, '/' + user.get('name') + '/' + project.get('id'), remixMetadata);
  });
}

/**
 * Exports
 */
exports.publish = function publish(project) {
  var user;
  var files;

  var publishedFiles;
  var publishedProject;
  var remixMetadata;

  var projectFiles = {};
  var publishedProjectFiles = {};
  var toBeCreated = [];
  var toBeDeleted = [];
  var toBeUpdated = [];

  return Promise.resolve()
  // First, collect the related user
  .then(function() {
    return getUserForProject(project)
    .then(function(u) {
      user = u;
    });
  })
  // Then, collect or create the current project's publishedProject
  .then(function() {
    return getPublishedProject(project)
    .then(function(oldPublishedProject) {
      if (oldPublishedProject) {
        return oldPublishedProject.set({
          title: project.get('title'),
          tags: project.get('tags'),
          description: project.get('description')
        }).save();
      }
      return PublishedProject.forge({
        title: project.get('title'),
        tags: project.get('tags'),
        description: project.get('description')
      }).save();
    })
    .then(function(p) {
      publishedProject = p;
      remixMetadata = {
        projectId: publishedProject.get('id'),
        projectTitle: publishedProject.get('title'),
        projectAuthor: user.get('name'),
        dateUpdated: project.get('date_updated'),
        host: Remix.resourceHost,
        readonly: project.get('readonly')
      };
    });
  })
  // Then, fetch all the project's files
  .then(function() {
    return File.query({
      where: {
        project_id: project.get('id')
      }
    }).fetchAll()
    .then(function(f) {
      if (f.length === 0) {
        throw 'No files to be published!';
      }

      files = f;
    });
  })
  // Then, fetch all the publishedProject's files (if any)
  .then(function() {
    return PublishedFiles.query({
      where: {
        published_id: publishedProject.get('id')
      }
    }).fetchAll()
    .then(function(f) {
      if (f.length === 0) {
        return;
      }
      publishedFiles = f;
    });
  })
  // Then, identify which files need to be remotely republished,
  // deleted or created
  .then(function() {
    // We organize the project's 'file' objects by id
    files.forEach(function(file) {
      projectFiles[file.get('id')] = file;
    });
    var filePrimaryKeys = Object.keys(projectFiles);

    // Nothing published yet?
    if (!publishedFiles) {
      return filePrimaryKeys.forEach(function(id) {
        toBeCreated.push(projectFiles[id]);
      });
    }

    // In this step we:
    //   1) Organize our 'publishedFile' collection to be keyed on
    //      their foreign key reference to the related 'file'
    //   2) Collect an array of 'publishedFile' objects whose related
    //      'file' object has been deleted. These must be unpublished later
    publishedFiles.forEach(function(publishedFile) {
      if (publishedFile.get('file_id') === null) {
        toBeDeleted.push(publishedFile);
        return;
      }
      publishedProjectFiles[publishedFile.get('file_id')] = publishedFile;
    });
    var publishedFileForeignKeys = Object.keys(publishedProjectFiles);

    // Next, we identify which 'files' are new since this project was last
    // published.
    filePrimaryKeys.forEach(function(primaryKey) {
      if (publishedFileForeignKeys.indexOf(primaryKey) === -1) {
        toBeCreated.push(projectFiles[primaryKey]);
      }
    });

    // The last step identifies which 'files' have already been published
    // and don't require deletion
    publishedFileForeignKeys.forEach(function(foreignKey) {
      if (filePrimaryKeys.indexOf(foreignKey) !== -1) {
        toBeUpdated.push(publishedProjectFiles[foreignKey]);
      }
    });
  })
  // Then, we create 'publishedFile' objects for all new 'files' since last publish
  .then(function() {
    if (toBeCreated.length === 0) {
      return;
    }

    return Promise.map(toBeCreated, function(file) {
      return PublishedFiles.forge({
        file_id: file.get('id'),
        published_id: publishedProject.get('id'),
        path: file.get('path'),
        buffer: file.get('buffer')
      }).save();
    })
    .then(function(f) {
      return Promise.map(f, function(toBePublished) {
        return modifyPublishedFiles(uploadFile, project, user, toBePublished, remixMetadata);
      });
    });
  })
  // Then, we unpublish and delete 'publishedFile' objects for all newly deleted 'files'
  .then(function() {
    if (toBeDeleted.length === 0) {
      return;
    }

    return Promise.map(toBeDeleted, function(model) {
      return modifyPublishedFiles(deleteFileRemotely, project, user, model)
      .then(function() {
        return model.destroy();
      });
    });
  })
  // Then, we unpublish and republish all remaining 'files' in case the path or
  // data has changed
  .then(function() {
    if (toBeUpdated.length === 0) {
      return;
    }

    return Promise.map(toBeUpdated, function(model) {
      return modifyPublishedFiles(deleteFileRemotely, project, user, model)
      .then(function() {
        var originalFile = projectFiles[model.get('file_id')];

        return model.set({
          path: originalFile.get('path'),
          buffer: originalFile.get('buffer')
        }).save()
        .then(function() {
          return modifyPublishedFiles(uploadFile, project, user, model, remixMetadata);
        });
      });
    });
  })
  // Then, we make sure the project has up-to-date references
  .then(function() {
    return project.set({
      publish_url: buildUrl(project, user),
      published_id: publishedProject.get('id')
    }).save();
  })
  // And finally...
  .then(function() {
    log.info(
      'Successfully published ' +
      project.get('title') +
      ' to ' + project.get('publish_url')
    );
  })
  .catch(reject);
};

exports.unpublish = function unpublish(project) {
  function getUserAndPublishedProject(callback) {
    var user = getUserForProject(project);
    var publishedProject = getPublishedProject(project);

    return Promise.join(user, publishedProject, callback);
  }

  function destroyPublishedFiles(user, publishedProject) {
    function deleteFilesFromS3(files) {
      return modifyPublishedFiles(deleteFileRemotely, project, user, files);
    }

    function unsetProjectReferences() {
      return project.set({
        published_id: null,
        publish_url: null
      }).save();
    }

    function destroyPublishedProject() {
      return publishedProject.destroy();
    }

    return getPublishedFiles(publishedProject)
      .then(deleteFilesFromS3)
      .then(unsetProjectReferences)
      .then(destroyPublishedProject);
  }

  return getUserAndPublishedProject(function(user, publishedProject) {
    return destroyPublishedFiles(user, publishedProject);
  })
  .then(function() {
    return project.set({ publish_url: null }).save();
  })
  .then(function() {
    log.info(
      'Successfully unpublished ' +
      project.get('title')
    );
  })
  .catch(reject);
};

module.exports = exports;
<|endoftext|>


<commit_before>/* global Source, User, Group, SourceMetric, SourceTypes, Attribute, GroupAttribute, PrincipalInvestigator, MembershipGroup, GroupTypes*/
// Importer.js - in api/services

"use strict";

const xlsx = require('xlsx');
const _ = require('lodash');
const fs = require('fs');
const request = require('request-promise');
const moment = require('moment');

module.exports = {
    importSources,
    importPeople,
    importGroups,
    importSourceMetrics
};

async function importSources() {

    function readWorksheet(worksheet, mappingsTable, mapFn = _.identity, filterFn = _.stubTrue) {
        function readSourceRow(r) {
            const sourceData = {};
            _.forEach(mappingsTable, (col, field) => {
                const cell = col + r;
                if (!_.isUndefined(worksheet[cell]))
                    sourceData[field] = worksheet[cell]['v'];
            });
            return sourceData;
        }

        const sources = [];
        for (let r = 2; ; r++) {
            const sourceData = readSourceRow(r);
            if (_.isEmpty(sourceData))
                break;
            const mappedSourceData = mapFn(sourceData);
            if (filterFn(mappedSourceData))
                sources.push(mappedSourceData);
        }
        return sources;
    }

    const scopusSourcesFileName = 'config/init/scopus_sources.xlsx';
    let journalsAndBookSeries = [], newConferences = [], oldConferences = [];
    if (fs.existsSync(scopusSourcesFileName)) {
        const workbook = xlsx.readFile(scopusSourcesFileName);
        const sheetNameList = workbook.SheetNames;

        const journalWorksheet = workbook.Sheets[sheetNameList[0]];
        const journalMappingsTable = {
            "title": 'B',
            "scopusId": 'A',
            "issn": 'C',
            "eissn": 'D',
            "type": 'T',
            "publisher": 'Z'
        };

        const mapJournal = (s) => {
            const sourceMappingTable = {
                'Book Series': SourceTypes.BOOKSERIES,
                'Journal': SourceTypes.JOURNAL
            };
            s.type = sourceMappingTable[s.type];
            return s;
        };

        const filterJournals = (s) => s.type;

        journalsAndBookSeries = readWorksheet(journalWorksheet, journalMappingsTable, mapJournal, filterJournals);

        const newConferencesWorksheet = workbook.Sheets[sheetNameList[1]];
        const newConferencesMappingsTable = {
            "title": 'B',
            "scopusId": 'A',
            "issn": 'D'
        };
        const mapConference = s => {
            s.type = SourceTypes.CONFERENCE;
            return s;
        };
        newConferences = readWorksheet(newConferencesWorksheet, newConferencesMappingsTable, mapConference);

        const oldConferencesWorksheet = workbook.Sheets[sheetNameList[2]];
        const oldConferencesMappingsTable = newConferencesMappingsTable;
        oldConferences = readWorksheet(oldConferencesWorksheet, oldConferencesMappingsTable, mapConference);
    }

    let books = [];
    const scopusSourcesFileName2 = 'config/init/scopus_book_sources.xlsx';
    if (fs.existsSync(scopusSourcesFileName2)) {
        const workbook2 = xlsx.readFile(scopusSourcesFileName2);
        const sheetNameList2 = workbook2.SheetNames;

        const bookWorksheet = workbook2.Sheets[sheetNameList2[0]];
        const bookMappingsTable = {
            "title": 'A',
            "isbn": 'C',
            "publisher": 'D',
            "year": 'E'
        };

        const mapBook = (s) => {
            s.type = 'book';
            return s;
        };

        books = readWorksheet(bookWorksheet, bookMappingsTable, mapBook);
    }

    const sources = _.union(journalsAndBookSeries, newConferences, oldConferences, books);

    sails.log.info('Inserting ' + sources.length + ' new sources');
    await Source.create(sources);
}

async function importPeople() {
    function userShouldBeUpdated(user, values) {
        const userFieldsToUpdate = [
            'jobTitle',
            'name',
            'surname'
        ];
        const toUpdate = userFieldsToUpdate.some(f => values[f] !== user[f]);
        return toUpdate;
    }

    const usersCreationCondition = sails.config.scientilla.mainInstituteImport.usersCreationCondition;
    const groupInsertionEnabled = false;
    sails.log.info('Import started');
    const url = sails.config.scientilla.mainInstituteImport.userImportUrl;
    const reqOptions = {
        uri: url,
        json: true
    };

    let people;
    try {
        people = await request(reqOptions);
        sails.log.info(people.length + ' entries found');
        const importTime = moment.utc().format();
        //groups are loaded in memory because waterline doesn't allow case-insensitive queries with postegres
        let allGroups = await Group.find();
        let numUsersInserted = 0, numUsersUpdated = 0, numGroupsInserted = 0;
        for (let [i, p] of people.entries()) {
            p.username = _.toLower(p.username);
            const groupsToSearch = allGroups.filter(g => p.groups.some(g2 => _.toLower(g2) == _.toLower(g.name))).map(g => g.name);
            if (groupInsertionEnabled) {
                const groupsToBeInserted = p.groups.filter(g => !allGroups.some(g2 => _.toLower(g2.name) == _.toLower(g)));
                if (groupsToBeInserted.length) {
                    const groupObjs = groupsToBeInserted.map(g => ({name: g}));
                    sails.log.info('inserting groups: ' + groupsToBeInserted.join(', '));
                    const newGroups = await Group.create(groupObjs);
                    numGroupsInserted++;
                    const newGroupsName = newGroups.map(g => g.name);
                    groupsToSearch.push(...newGroupsName);
                    allGroups = await Group.find();
                }
            }
            const groupSearchCriteria = {or: groupsToSearch.map(g => ({name: g}))};
            const groups = await Group.find(groupSearchCriteria).populate('members').populate('administrators');
            const criteria = {username: p.username};
            let user = await User.findOne(criteria);
            if (!user) {
                const auth = await Auth.findOne({dn: p.dn}).populate('user');
                if (auth) user = auth.user;
            }
            p.lastsynch = moment().utc().format();
            p.synchronized = true;
            const activeMembership = p.active;
            p.active = true;
            if (user) {
                const u = await User.update({id: user.id}, p);
                if (userShouldBeUpdated(user, p)) {
                    sails.log.info(`Updating user ${p.username}`);
                    numUsersUpdated++;
                }
            }
            else {
                if (!usersCreationCondition || p[usersCreationCondition.attribute] === usersCreationCondition.value) {
                    sails.log.info(`Inserting user ${p.username}`);
                    user = await User.createCompleteUser(p);
                    numUsersInserted++;
                }
            }
            if (!user)
                continue;

            for (let g of groups) {
                const membershipCriteria = {user: user.id, group: g.id};
                let membership = await Membership.findOne(membershipCriteria);
                if (!membership) {
                    membership = await Group.addMember(g, user);
                }
                if (membership) {
                    membership.lastsynch = moment.utc().format();
                    membership.synchronized = true;
                    membership.active = activeMembership;
                    const m = await Membership.update(membershipCriteria, membership);
                }
            }
            //reenable membership to main group if a user is back
            if (User.isInternalUser(user)) {
                const m = await Membership.findOne({group: 1, user: user.id});
                if (m && !m.active && activeMembership)
                    await Membership.update({id: m.id}, {active: true});
            }
        }
        const membershipUpdateCriteria = {lastsynch: {'<': importTime}, synchronized: true, active: true};
        const membershipDisabled = await Membership.update(membershipUpdateCriteria, {active: false});
        const userUpdateCriteria = {lastsynch: {'<': importTime}, synchronized: true, active: true};
        const usersDisabled = await User.update(userUpdateCriteria, {active: false});
        const collaborationUpdateCriteria = {synchronized: false, user: usersDisabled.map(u => u.id), active: true};
        const collaborationDisabled = await Membership.update(collaborationUpdateCriteria, {active: false});
        const numUsersDisabled = usersDisabled.length;
        const numMembershipDisabled = membershipDisabled.length + collaborationDisabled.length;
        await Membership.update({user: usersDisabled.map(u => u.id), active: true, group: 1}, {active: false});
        sails.log.info('Import finished');
        sails.log.info(`${numUsersInserted} users inserted`);
        sails.log.info(`${numUsersUpdated} users updated`);
        sails.log.info(`${numUsersDisabled} users disabled`);
        sails.log.info(`${numGroupsInserted} groups inserted`);
        sails.log.info(`${numMembershipDisabled} membership disabled`);
    } catch (e) {
        sails.log.error('importPeople error');
        sails.log.error(e);
    }
}

async function importGroups() {
    sails.log.info('Group import started');

    const researchDomains = [];
    const url = sails.config.scientilla.mainInstituteImport.officialGroupsImportUrl;
    const reqOptions = {
        uri: url,
        json: true
    };

    let res;
    try {
        res = await request(reqOptions);
    } catch (e) {
        sails.log.debug('importGroups');
        sails.log.debug(e);
    }
    const {
        research_domains: researchDomainsData,
        research_structures: researchStructuresData
    } = res;

    await Attribute.destroy({
        key: {'!': researchDomainsData.map(rd => rd.code)},
        category: 'research_domain'
    });
    for (const rdData of researchDomainsData) {
        let researchDomain = await Attribute.findOrCreate({
            key: rdData.code,
            category: 'research_domain'
        });
        researchDomain = await Attribute.update({id: researchDomain.id}, {value: rdData});
        researchDomains.push(researchDomain[0]);
    }

    for (const rsData of researchStructuresData) {
        const group = await Group.findOrCreate({code: rsData.cdr});
        await Group.update({id: group.id}, {
            name: rsData.description,
            type: rsData.type,
            starting_date: rsData.start_date,
            active: true
        });

        //PI
        if (Array.isArray(rsData.pis) && rsData.pis.length > 0) {
            const pis = await User.find({username: rsData.pis.map(p => p.email)});

            if (pis && pis.length) {
                await PrincipalInvestigator.destroy({
                    group: group.id,
                    pi: {'!': pis.map(p => p.id)}
                });

                for (const pi of pis) {
                    await GroupAdministrator.findOrCreate({
                        administrator: pi.id,
                        group: group.id
                    });

                    await PrincipalInvestigator.findOrCreate({
                        pi: pi.id,
                        group: group.id
                    });
                }
            }
            else
                await PrincipalInvestigator.destroy({group: group.id});
        }
        else
            await PrincipalInvestigator.destroy({group: group.id});

        //center
        const membershipGroups = await MembershipGroup.find({child_group: group.id}).populate('parent_group');
        const oldCentersMG = membershipGroups.filter(mg => mg.parent_group.type === GroupTypes.CENTER);

        if (rsData.center && rsData.center.code) {
            const center = await Group.findOrCreate({code: rsData.center.code});
            await Group.update({id: center.id}, {
                name: rsData.center.name,
                type: GroupTypes.CENTER
            });

            const toDeleteIds = oldCentersMG.filter(mg => mg.parent_group.id !== center.id).map(mg => mg.id);
            if (toDeleteIds.length > 0)
                await MembershipGroup.destroy({id: toDeleteIds});

            if (!oldCentersMG.find(mg => mg.parent_group.id === center.id))
                await MembershipGroup.create({
                    parent_group: center.id,
                    child_group: group.id
                });
        }
        else
            await MembershipGroup.destroy({child_group: oldCentersMG.map(mg => mg.id)});

        //research domains and interactions
        if (rsData.main_research_domain) {
            await clearResearchDomains([rsData.main_research_domain.code], group, 'main');
            await addResearchDomain(rsData.main_research_domain.code, group, 'main');
        }
        else
            await clearResearchDomains([], group, 'main');

        await clearResearchDomains(rsData.interactions.map(i => i.code), group, 'interaction');
        for (const ird of rsData.interactions)
            await addResearchDomain(ird.code, group, 'interaction');
    }

    async function clearResearchDomains(correctRdCodes, group, type) {
        let res;
        if (!correctRdCodes.length)
            res = await GroupAttribute.find({
                researchEntity: group.id
            });
        else
            res = await GroupAttribute.find({
                attribute: {
                    '!': researchDomains.filter(rd => correctRdCodes.includes(rd.key)).map(rd => rd.id),
                },
                researchEntity: group.id
            });

        //query language does not support JSON
        const toDeleteIds = res.filter(ga => !ga.extra || ga.extra.type === type).map(ga => ga.id);
        if (toDeleteIds.length)
            await GroupAttribute.destroy({id: toDeleteIds});
    }

    async function addResearchDomain(rdCode, group, type) {
        const rd = researchDomains.find(rd => rd.key === rdCode);
        if (rd) {
            const res = await GroupAttribute.find({attribute: rd.id, researchEntity: group.id});
            if (!res.filter(ga => ga.extra && ga.extra.type === type).length)
                await GroupAttribute.create({attribute: rd.id, researchEntity: group.id, extra: {type}});
        }
    }

    sails.log.info('Group import finished');
}

async function importSourceMetrics(filename) {
    sails.log.info('Source metrics import started');

    const sourceIdentifiers = SourceMetric.sourceIdentifiers;

    const originCellCoord = 'B1';
    const yearCellCoord = 'D1';

    let recordsCount = 0;

    const cols = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
    const filePath = 'config/init/' + filename;
    if (fs.existsSync(filePath)) {
        const workbook = xlsx.readFile(filePath);
        const sheetNameList = workbook.SheetNames;

        const workSheet = workbook.Sheets[sheetNameList[0]];

        if (!workSheet[originCellCoord] || !workSheet[yearCellCoord])
            throw 'Invalid file format';

        const origin = workSheet[originCellCoord].v;
        const year = workSheet[yearCellCoord].v;

        const columnsMapping = {};

        for (const c of cols) {
            const colNameCell = workSheet[c + '2'];
            if (!colNameCell)
                break;

            columnsMapping[colNameCell.v] = c;
        }

        const keyColumns = Object.keys(columnsMapping).filter(c => sourceIdentifiers.includes(c));
        const valueColumns = Object.keys(columnsMapping).filter(c => !sourceIdentifiers.includes(c));

        let i = 3;
        while (true) {
            const workSheetRow = {};

            for (const colName in columnsMapping) {
                const col = columnsMapping[colName];
                const cellCoord = col + i;
                if (workSheet[cellCoord])
                    workSheetRow[colName] = workSheet[cellCoord].v;
            }

            if (workSheetRow.issn) {
                workSheetRow.issn = workSheetRow.issn + '';
                workSheetRow.issn = workSheetRow.issn.replace(/-/g, '');
            }
            if (workSheetRow.eissn) {
                workSheetRow.eissn = workSheetRow.eissn + '';
                workSheetRow.eissn = workSheetRow.eissn.replace(/-/g, '');
            }

            if (_.isEmpty(workSheetRow))
                break;

            i++;

            const baseRecord = {};

            for (const kc of keyColumns)
                if (workSheetRow[kc])
                    baseRecord[kc] = workSheetRow[kc];

            if (_.isEmpty(baseRecord))
                continue;

            baseRecord.year = year;
            baseRecord.origin = origin;

            for (const vc of valueColumns) {
                if (!workSheetRow[vc])
                    continue;

                const criteria = _.clone(baseRecord);
                criteria.name = vc;
                const record = _.clone(baseRecord);
                record.name = vc;
                record.value = workSheetRow[vc];
                await SourceMetric.createOrUpdate(criteria, record);
                recordsCount++;
            }
        }
    }

    sails.log.info('imported ' + recordsCount + ' records');
    sails.log.info('Source metrics import finished');
}<commit_msg>Added logging status<commit_after>/* global Source, User, Group, SourceMetric, SourceTypes, Attribute, GroupAttribute, PrincipalInvestigator, MembershipGroup, GroupTypes*/
// Importer.js - in api/services

"use strict";

const xlsx = require('xlsx');
const _ = require('lodash');
const fs = require('fs');
const request = require('request-promise');
const moment = require('moment');

module.exports = {
    importSources,
    importPeople,
    importGroups,
    importSourceMetrics
};

async function importSources() {

    function readWorksheet(worksheet, mappingsTable, mapFn = _.identity, filterFn = _.stubTrue) {
        function readSourceRow(r) {
            const sourceData = {};
            _.forEach(mappingsTable, (col, field) => {
                const cell = col + r;
                if (!_.isUndefined(worksheet[cell]))
                    sourceData[field] = worksheet[cell]['v'];
            });
            return sourceData;
        }

        const sources = [];
        for (let r = 2; ; r++) {
            const sourceData = readSourceRow(r);
            if (_.isEmpty(sourceData))
                break;
            const mappedSourceData = mapFn(sourceData);
            if (filterFn(mappedSourceData))
                sources.push(mappedSourceData);
        }
        return sources;
    }

    const scopusSourcesFileName = 'config/init/scopus_sources.xlsx';
    let journalsAndBookSeries = [], newConferences = [], oldConferences = [];
    if (fs.existsSync(scopusSourcesFileName)) {
        const workbook = xlsx.readFile(scopusSourcesFileName);
        const sheetNameList = workbook.SheetNames;

        const journalWorksheet = workbook.Sheets[sheetNameList[0]];
        const journalMappingsTable = {
            "title": 'B',
            "scopusId": 'A',
            "issn": 'C',
            "eissn": 'D',
            "type": 'T',
            "publisher": 'Z'
        };

        const mapJournal = (s) => {
            const sourceMappingTable = {
                'Book Series': SourceTypes.BOOKSERIES,
                'Journal': SourceTypes.JOURNAL
            };
            s.type = sourceMappingTable[s.type];
            return s;
        };

        const filterJournals = (s) => s.type;

        journalsAndBookSeries = readWorksheet(journalWorksheet, journalMappingsTable, mapJournal, filterJournals);

        const newConferencesWorksheet = workbook.Sheets[sheetNameList[1]];
        const newConferencesMappingsTable = {
            "title": 'B',
            "scopusId": 'A',
            "issn": 'D'
        };
        const mapConference = s => {
            s.type = SourceTypes.CONFERENCE;
            return s;
        };
        newConferences = readWorksheet(newConferencesWorksheet, newConferencesMappingsTable, mapConference);

        const oldConferencesWorksheet = workbook.Sheets[sheetNameList[2]];
        const oldConferencesMappingsTable = newConferencesMappingsTable;
        oldConferences = readWorksheet(oldConferencesWorksheet, oldConferencesMappingsTable, mapConference);
    }

    let books = [];
    const scopusSourcesFileName2 = 'config/init/scopus_book_sources.xlsx';
    if (fs.existsSync(scopusSourcesFileName2)) {
        const workbook2 = xlsx.readFile(scopusSourcesFileName2);
        const sheetNameList2 = workbook2.SheetNames;

        const bookWorksheet = workbook2.Sheets[sheetNameList2[0]];
        const bookMappingsTable = {
            "title": 'A',
            "isbn": 'C',
            "publisher": 'D',
            "year": 'E'
        };

        const mapBook = (s) => {
            s.type = 'book';
            return s;
        };

        books = readWorksheet(bookWorksheet, bookMappingsTable, mapBook);
    }

    const sources = _.union(journalsAndBookSeries, newConferences, oldConferences, books);

    sails.log.info('Inserting ' + sources.length + ' new sources');
    await Source.create(sources);
}

async function importPeople() {
    function userShouldBeUpdated(user, values) {
        const userFieldsToUpdate = [
            'jobTitle',
            'name',
            'surname'
        ];
        const toUpdate = userFieldsToUpdate.some(f => values[f] !== user[f]);
        return toUpdate;
    }

    const usersCreationCondition = sails.config.scientilla.mainInstituteImport.usersCreationCondition;
    const groupInsertionEnabled = false;
    sails.log.info('Import started');
    const url = sails.config.scientilla.mainInstituteImport.userImportUrl;
    const reqOptions = {
        uri: url,
        json: true
    };

    let people;
    try {
        people = await request(reqOptions);
        sails.log.info(people.length + ' entries found');
        const importTime = moment.utc().format();
        //groups are loaded in memory because waterline doesn't allow case-insensitive queries with postegres
        let allGroups = await Group.find();
        let numUsersInserted = 0, numUsersUpdated = 0, numGroupsInserted = 0;
        for (let [i, p] of people.entries()) {
            p.username = _.toLower(p.username);
            const groupsToSearch = allGroups.filter(g => p.groups.some(g2 => _.toLower(g2) == _.toLower(g.name))).map(g => g.name);
            if (groupInsertionEnabled) {
                const groupsToBeInserted = p.groups.filter(g => !allGroups.some(g2 => _.toLower(g2.name) == _.toLower(g)));
                if (groupsToBeInserted.length) {
                    const groupObjs = groupsToBeInserted.map(g => ({name: g}));
                    sails.log.info('inserting groups: ' + groupsToBeInserted.join(', '));
                    const newGroups = await Group.create(groupObjs);
                    numGroupsInserted++;
                    const newGroupsName = newGroups.map(g => g.name);
                    groupsToSearch.push(...newGroupsName);
                    allGroups = await Group.find();
                }
            }
            const groupSearchCriteria = {or: groupsToSearch.map(g => ({name: g}))};
            const groups = await Group.find(groupSearchCriteria).populate('members').populate('administrators');
            const criteria = {username: p.username};
            let user = await User.findOne(criteria);
            if (!user) {
                const auth = await Auth.findOne({dn: p.dn}).populate('user');
                if (auth) user = auth.user;
            }
            p.lastsynch = moment().utc().format();
            p.synchronized = true;
            const activeMembership = p.active;
            p.active = true;
            if (user) {
                const u = await User.update({id: user.id}, p);
                if (userShouldBeUpdated(user, p)) {
                    sails.log.info(`Updating user ${p.username}`);
                    numUsersUpdated++;
                }
            }
            else {
                if (!usersCreationCondition || p[usersCreationCondition.attribute] === usersCreationCondition.value) {
                    sails.log.info(`Inserting user ${p.username}`);
                    user = await User.createCompleteUser(p);
                    numUsersInserted++;
                }
            }
            if (!user)
                continue;

            for (let g of groups) {
                const membershipCriteria = {user: user.id, group: g.id};
                let membership = await Membership.findOne(membershipCriteria);
                if (!membership) {
                    membership = await Group.addMember(g, user);
                }
                if (membership) {
                    membership.lastsynch = moment.utc().format();
                    membership.synchronized = true;
                    membership.active = activeMembership;
                    const m = await Membership.update(membershipCriteria, membership);
                }
            }
            //reenable membership to main group if a user is back
            if (User.isInternalUser(user)) {
                const m = await Membership.findOne({group: 1, user: user.id});
                if (m && !m.active && activeMembership)
                    await Membership.update({id: m.id}, {active: true});
            }
        }
        const membershipUpdateCriteria = {lastsynch: {'<': importTime}, synchronized: true, active: true};
        const membershipDisabled = await Membership.update(membershipUpdateCriteria, {active: false});
        const userUpdateCriteria = {lastsynch: {'<': importTime}, synchronized: true, active: true};
        const usersDisabled = await User.update(userUpdateCriteria, {active: false});
        const collaborationUpdateCriteria = {synchronized: false, user: usersDisabled.map(u => u.id), active: true};
        const collaborationDisabled = await Membership.update(collaborationUpdateCriteria, {active: false});
        const numUsersDisabled = usersDisabled.length;
        const numMembershipDisabled = membershipDisabled.length + collaborationDisabled.length;
        await Membership.update({user: usersDisabled.map(u => u.id), active: true, group: 1}, {active: false});
        sails.log.info('Import finished');
        sails.log.info(`${numUsersInserted} users inserted`);
        sails.log.info(`${numUsersUpdated} users updated`);
        sails.log.info(`${numUsersDisabled} users disabled`);
        sails.log.info(`${numGroupsInserted} groups inserted`);
        sails.log.info(`${numMembershipDisabled} membership disabled`);
    } catch (e) {
        sails.log.error('importPeople error');
        sails.log.error(e);
    }
}

async function importGroups() {
    sails.log.info('Group import started');

    const researchDomains = [];
    const url = sails.config.scientilla.mainInstituteImport.officialGroupsImportUrl;
    const reqOptions = {
        uri: url,
        json: true
    };

    let res;
    try {
        res = await request(reqOptions);
    } catch (e) {
        sails.log.debug('importGroups');
        sails.log.debug(e);
    }
    const {
        research_domains: researchDomainsData,
        research_structures: researchStructuresData
    } = res;

    await Attribute.destroy({
        key: {'!': researchDomainsData.map(rd => rd.code)},
        category: 'research_domain'
    });
    for (const rdData of researchDomainsData) {
        let researchDomain = await Attribute.findOrCreate({
            key: rdData.code,
            category: 'research_domain'
        });
        researchDomain = await Attribute.update({id: researchDomain.id}, {value: rdData});
        researchDomains.push(researchDomain[0]);
    }

    for (const rsData of researchStructuresData) {
        const group = await Group.findOrCreate({code: rsData.cdr});
        await Group.update({id: group.id}, {
            name: rsData.description,
            type: rsData.type,
            starting_date: rsData.start_date,
            active: true
        });

        //PI
        if (Array.isArray(rsData.pis) && rsData.pis.length > 0) {
            const pis = await User.find({username: rsData.pis.map(p => p.email)});

            if (pis && pis.length) {
                await PrincipalInvestigator.destroy({
                    group: group.id,
                    pi: {'!': pis.map(p => p.id)}
                });

                for (const pi of pis) {
                    await GroupAdministrator.findOrCreate({
                        administrator: pi.id,
                        group: group.id
                    });

                    await PrincipalInvestigator.findOrCreate({
                        pi: pi.id,
                        group: group.id
                    });
                }
            }
            else
                await PrincipalInvestigator.destroy({group: group.id});
        }
        else
            await PrincipalInvestigator.destroy({group: group.id});

        //center
        const membershipGroups = await MembershipGroup.find({child_group: group.id}).populate('parent_group');
        const oldCentersMG = membershipGroups.filter(mg => mg.parent_group.type === GroupTypes.CENTER);

        if (rsData.center && rsData.center.code) {
            const center = await Group.findOrCreate({code: rsData.center.code});
            await Group.update({id: center.id}, {
                name: rsData.center.name,
                type: GroupTypes.CENTER
            });

            const toDeleteIds = oldCentersMG.filter(mg => mg.parent_group.id !== center.id).map(mg => mg.id);
            if (toDeleteIds.length > 0)
                await MembershipGroup.destroy({id: toDeleteIds});

            if (!oldCentersMG.find(mg => mg.parent_group.id === center.id))
                await MembershipGroup.create({
                    parent_group: center.id,
                    child_group: group.id
                });
        }
        else
            await MembershipGroup.destroy({child_group: oldCentersMG.map(mg => mg.id)});

        //research domains and interactions
        if (rsData.main_research_domain) {
            await clearResearchDomains([rsData.main_research_domain.code], group, 'main');
            await addResearchDomain(rsData.main_research_domain.code, group, 'main');
        }
        else
            await clearResearchDomains([], group, 'main');

        await clearResearchDomains(rsData.interactions.map(i => i.code), group, 'interaction');
        for (const ird of rsData.interactions)
            await addResearchDomain(ird.code, group, 'interaction');
    }

    async function clearResearchDomains(correctRdCodes, group, type) {
        let res;
        if (!correctRdCodes.length)
            res = await GroupAttribute.find({
                researchEntity: group.id
            });
        else
            res = await GroupAttribute.find({
                attribute: {
                    '!': researchDomains.filter(rd => correctRdCodes.includes(rd.key)).map(rd => rd.id),
                },
                researchEntity: group.id
            });

        //query language does not support JSON
        const toDeleteIds = res.filter(ga => !ga.extra || ga.extra.type === type).map(ga => ga.id);
        if (toDeleteIds.length)
            await GroupAttribute.destroy({id: toDeleteIds});
    }

    async function addResearchDomain(rdCode, group, type) {
        const rd = researchDomains.find(rd => rd.key === rdCode);
        if (rd) {
            const res = await GroupAttribute.find({attribute: rd.id, researchEntity: group.id});
            if (!res.filter(ga => ga.extra && ga.extra.type === type).length)
                await GroupAttribute.create({attribute: rd.id, researchEntity: group.id, extra: {type}});
        }
    }

    sails.log.info('Group import finished');
}

async function importSourceMetrics(filename) {
    sails.log.info('Source metrics import started');

    const sourceIdentifiers = SourceMetric.sourceIdentifiers;

    const originCellCoord = 'B1';
    const yearCellCoord = 'D1';

    let recordsCount = 0;

    const cols = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
    const filePath = 'config/init/' + filename;
    if (fs.existsSync(filePath)) {
        const workbook = xlsx.readFile(filePath);
        const sheetNameList = workbook.SheetNames;

        const workSheet = workbook.Sheets[sheetNameList[0]];

        if (!workSheet[originCellCoord] || !workSheet[yearCellCoord])
            throw 'Invalid file format';

        const origin = workSheet[originCellCoord].v;
        const year = workSheet[yearCellCoord].v;

        const columnsMapping = {};

        for (const c of cols) {
            const colNameCell = workSheet[c + '2'];
            if (!colNameCell)
                break;

            columnsMapping[colNameCell.v] = c;
        }

        const keyColumns = Object.keys(columnsMapping).filter(c => sourceIdentifiers.includes(c));
        const valueColumns = Object.keys(columnsMapping).filter(c => !sourceIdentifiers.includes(c));

        let i = 3;
        while (true) {
            const workSheetRow = {};

            for (const colName in columnsMapping) {
                const col = columnsMapping[colName];
                const cellCoord = col + i;
                if (workSheet[cellCoord])
                    workSheetRow[colName] = workSheet[cellCoord].v;
            }

            if (workSheetRow.issn) {
                workSheetRow.issn = workSheetRow.issn + '';
                workSheetRow.issn = workSheetRow.issn.replace(/-/g, '');
            }
            if (workSheetRow.eissn) {
                workSheetRow.eissn = workSheetRow.eissn + '';
                workSheetRow.eissn = workSheetRow.eissn.replace(/-/g, '');
            }

            if (_.isEmpty(workSheetRow))
                break;

            i++;

            const baseRecord = {};

            for (const kc of keyColumns)
                if (workSheetRow[kc])
                    baseRecord[kc] = workSheetRow[kc];

            if (_.isEmpty(baseRecord))
                continue;

            baseRecord.year = year;
            baseRecord.origin = origin;

            for (const vc of valueColumns) {
                if (!workSheetRow[vc])
                    continue;

                const criteria = _.clone(baseRecord);
                criteria.name = vc;
                const record = _.clone(baseRecord);
                record.name = vc;
                record.value = workSheetRow[vc];
                await SourceMetric.createOrUpdate(criteria, record);
                recordsCount++;

                if (recordsCount % 1000 === 0)
                    sails.log.debug('source metrics inserted/updated: ' + recordsCount);
            }
        }
    }

    sails.log.info('imported ' + recordsCount + ' records');
    sails.log.info('Source metrics import finished');
}<|endoftext|>


<commit_before>'use strict';

angular.module('myApp.FindGame', ['ngCordova','ngResource'])

.controller('FindGameCtrl', function($scope, $location, $cordovaGeolocation, MyGamesFactory, MyGroundsFactory, OrganizeGameFactory) {
    var
    listGrounds = MyGroundsFactory.query();
console.log(listGrounds);
        var
    listGames = MyGamesFactory.query();
    console.log(listGames);

    $scope.events = listGames;
    $scope.grounds = listGrounds;
    console.log($scope.events);
    console.log(listGames);
angular.module('myApp.FindGame', ['ngCordova','ngResource'])

.controller('FindGameCtrl', function($scope, $cordovaGeolocation, GamesFactory, GroundsFactoryy) {
    var
    listGrounds = GroundsFactoryy.query();
console.log(listGrounds);
        var
    listGames = GamesFactory.query();
    console.log(listGames);

    //for(var i=0; i<listGames.length; i++){
    //    for(var j=0; j<listGrounds.length; j++) {
    //
    //       if ( listGames[i].d.groundID == listGrounds[j].d._id){
    //           listGames[i].location = listGrounds[j].name;
    //           console.log(listGames[i].groundID);
    //       }
    //    }
    //}

    $scope.games = listGames;
    console.log($scope.games);
    console.log(listGames);
     /////////////////////MAP//////////////////////
   // $scope.map = { center: { latitude: 45, longitude: -73 }, zoom: 8 };
    var options = {timeout: 10000, enableHighAccuracy: true};
    $cordovaGeolocation.getCurrentPosition(options).then(function(position){
    var latLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
        var mapOptions = {
      center: latLng,
      zoom: 15,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    $scope.map = new google.maps.Map(document.getElementById("map"), mapOptions);
  }, function(error){
    console.log("Could not get location");
  });
    //////////////////////////////////////////////////

    $scope.game=new OrganizeGameFactory();
    $scope.organizeGame=function(){

        $scope.game.$save();
        $location.path("/waiting");
    }
})

    .factory('OrganizeGameFactory', function($resource){
        //Resource
        return $resource('http://localhost:3000/games/store');

    })

    .factory('MyGamesFactory', function($resource){
        //Resource
        return $resource('http://localhost:3000/events');

    })

    .factory('MyGroundsFactory', function($resource){
        //Resource
        return $resource('http://localhost:3000/grounds/grounds');

    })

})

    .factory('GamesFactory', function($resource){
        //Resource
        return $resource('http://localhost:3000/events');

    })
    .factory('GameDetailsFactory', function($resource){
        //Resource
        return $resource('http://localhost:3000/events/:id');

    })

    .factory('GroundsFactoryy', function($resource){
        //Resource
        return $resource('http://localhost:3000/grounds/grounds');

    })
;
<commit_msg>fixed find games<commit_after>'use strict';

angular.module('myApp.FindGame', ['ngCordova','ngResource'])

    .controller('FindGameCtrl', function($scope, $location, $cordovaGeolocation, MyGamesFactory, MyGroundsFactory, OrganizeGameFactory) {
        var
            listGrounds = MyGroundsFactory.query();
        console.log(listGrounds);
        var
            listGames = MyGamesFactory.query();
        console.log(listGames);

        $scope.events = listGames;
        $scope.grounds = listGrounds;
        console.log($scope.events);
        console.log(listGames);
        /////////////////////MAP//////////////////////
        // $scope.map = { center: { latitude: 45, longitude: -73 }, zoom: 8 };
        var options = {timeout: 10000, enableHighAccuracy: true};
        $cordovaGeolocation.getCurrentPosition(options).then(function(position){
            var latLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
            var mapOptions = {
                center: latLng,
                zoom: 15,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            };
            $scope.map = new google.maps.Map(document.getElementById("map"), mapOptions);
        }, function(error){
            console.log("Could not get location");
        });
        //////////////////////////////////////////////////

        $scope.game=new OrganizeGameFactory();
        $scope.organizeGame=function(){

            $scope.game.$save();
            $location.path("/waiting");
        }
    })

    .factory('OrganizeGameFactory', function($resource){
        //Resource
        return $resource('http://localhost:3000/games/store');

    })

    .factory('MyGamesFactory', function($resource){
        //Resource
        return $resource('http://localhost:3000/events');

    })

    .factory('MyGroundsFactory', function($resource){
        //Resource
        return $resource('http://localhost:3000/grounds/grounds');

    })
;<|endoftext|>