<commit_before>/**
 * Controls the security of pad access
 */

/*
 * 2011 Peter 'Pita' Martischka (Primary Technology Ltd)
 *
 * Licensed 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 ERR = require("async-stacktrace");
var db = require("./DB").db;
var async = require("async");
var authorManager = require("./AuthorManager");
var padManager = require("./PadManager");
var sessionManager = require("./SessionManager");
var settings = require("../utils/Settings");
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;

/**
 * This function controlls the access to a pad, it checks if the user can access a pad.
 * @param padID the pad the user wants to access
 * @param sesssionID the session the user has (set via api)
 * @param token the token of the author (randomly generated at client side, used for public pads)
 * @param password the password the user has given to access this pad, can be null
 * @param callback will be called with (err, {accessStatus: grant|deny|wrongPassword|needPassword, authorID: a.xxxxxx})
 */
exports.checkAccess = function (padID, sessionCookie, token, password, callback)
{
  var statusObject;

  // a valid session is required (api-only mode)
  if(settings.requireSession)
  {
    // without sessionCookie, access is denied
    if(!sessionCookie)
    {
      callback(null, {accessStatus: "deny"});
      return;
    }
  }
  // a session is not required, so we'll check if it's a public pad
  else
  {
    // it's not a group pad, means we can grant access
    if(padID.indexOf("$") == -1)
    {
      //get author for this token
      authorManager.getAuthor4Token(token, function(err, author)
      {
        if(ERR(err, callback)) return;

        // assume user has access
        statusObject = {accessStatus: "grant", authorID: author};
        // user can't create pads
        if(settings.editOnly)
        {
          // check if pad exists
          padManager.doesPadExists(padID, function(err, exists)
          {
            if(ERR(err, callback)) return;

            // pad doesn't exist - user can't have access
            if(!exists) statusObject.accessStatus = "deny";
            // grant or deny access, with author of token
            callback(null, statusObject);
          });
        }
        // user may create new pads - no need to check anything
        else
        {
          // grant access, with author of token
          callback(null, statusObject);
        }
      });

      //don't continue
      return;
    }
  }

  var groupID = padID.split("$")[0];
  var padExists = false;
  var validSession = false;
  var sessionAuthor;
  var tokenAuthor;
  var isPublic;
  var isPasswordProtected;
  var passwordStatus = password == null ? "notGiven" : "wrong"; // notGiven, correct, wrong

  async.series([
    //get basic informations from the database
    function(callback)
    {
      async.parallel([
        //does pad exists
        function(callback)
        {
          padManager.doesPadExists(padID, function(err, exists)
          {
            if(ERR(err, callback)) return;
            padExists = exists;
            callback();
          });
        },
        //get information about all sessions contained in this cookie
        function(callback)
        {
          if (!sessionCookie) {
            callback();
            return;
          }

          var sessionIDs = sessionCookie.split(',');
          async.forEach(sessionIDs, function(sessionID, callback) {
            sessionManager.getSessionInfo(sessionID, function(err, sessionInfo) {
              //skip session if it doesn't exist
              if(err && err.message == "sessionID does not exist") return;

              if(ERR(err, callback)) return;

              var now = Math.floor(new Date().getTime()/1000);

              //is it for this group?
              if(sessionInfo.groupID != groupID) {
            	  callback();
            	  return;
              }

              //is validUntil still ok?
              if(sessionInfo.validUntil <= now){
            	  callback();
            	  return;
              }

              // There is a valid session
              validSession = true;
              sessionAuthor = sessionInfo.authorID;

              callback();
            });
          }, callback);
        },
        //get author for token
        function(callback)
        {
          //get author for this token
          authorManager.getAuthor4Token(token, function(err, author)
          {
            if(ERR(err, callback)) return;
            tokenAuthor = author;
            callback();
          });
        }
      ], callback);
    },
    //get more informations of this pad, if avaiable
    function(callback)
    {
      //skip this if the pad doesn't exists
      if(padExists == false)
      {
        callback();
        return;
      }

      padManager.getPad(padID, function(err, pad)
      {
        if(ERR(err, callback)) return;

        //is it a public pad?
        isPublic = pad.getPublicStatus();

        //is it password protected?
        isPasswordProtected = pad.isPasswordProtected();

        //is password correct?
        if(isPasswordProtected && password && pad.isCorrectPassword(password))
        {
          passwordStatus = "correct";
        }

        callback();
      });
    },
    function(callback)
    {
      //- a valid session for this group is avaible AND pad exists
      if(validSession && padExists)
      {
        //- the pad is not password protected
        if(!isPasswordProtected)
        {
          //--> grant access
          statusObject = {accessStatus: "grant", authorID: sessionAuthor};
        }
        //- the pad is password protected and password is correct
        else if(isPasswordProtected && passwordStatus == "correct")
        {
          //--> grant access
          statusObject = {accessStatus: "grant", authorID: sessionAuthor};
        }
        //- the pad is password protected but wrong password given
        else if(isPasswordProtected && passwordStatus == "wrong")
        {
          //--> deny access, ask for new password and tell them that the password is wrong
          statusObject = {accessStatus: "wrongPassword"};
        }
        //- the pad is password protected but no password given
        else if(isPasswordProtected && passwordStatus == "notGiven")
        {
          //--> ask for password
          statusObject = {accessStatus: "needPassword"};
        }
        else
        {
          throw new Error("Ops, something wrong happend");
        }
      }
      //- a valid session for this group avaible but pad doesn't exists
      else if(validSession && !padExists)
      {
        //--> grant access
        statusObject = {accessStatus: "grant", authorID: sessionAuthor};
        //--> deny access if user isn't allowed to create the pad
        if(settings.editOnly) statusObject.accessStatus = "deny";
      }
      // there is no valid session avaiable AND pad exists
      else if(!validSession && padExists)
      {
        //-- its public and not password protected
        if(isPublic && !isPasswordProtected)
        {
          //--> grant access, with author of token
          statusObject = {accessStatus: "grant", authorID: tokenAuthor};
        }
        //- its public and password protected and password is correct
        else if(isPublic && isPasswordProtected && passwordStatus == "correct")
        {
          //--> grant access, with author of token
          statusObject = {accessStatus: "grant", authorID: tokenAuthor};
        }
        //- its public and the pad is password protected but wrong password given
        else if(isPublic && isPasswordProtected && passwordStatus == "wrong")
        {
          //--> deny access, ask for new password and tell them that the password is wrong
          statusObject = {accessStatus: "wrongPassword"};
        }
        //- its public and the pad is password protected but no password given
        else if(isPublic && isPasswordProtected && passwordStatus == "notGiven")
        {
          //--> ask for password
          statusObject = {accessStatus: "needPassword"};
        }
        //- its not public
        else if(!isPublic)
        {
          //--> deny access
          statusObject = {accessStatus: "deny"};
        }
        else
        {
          throw new Error("Ops, something wrong happend");
        }
      }
      // there is no valid session avaiable AND pad doesn't exists
      else
      {
         //--> deny access
         statusObject = {accessStatus: "deny"};
      }

      callback();
    }
  ], function(err)
  {
    if(ERR(err, callback)) return;
    callback(null, statusObject);
  });
};
<commit_msg>Added debug-output to SecurityManager.checkAccess to indicate *why* an auth-try failed.<commit_after>/**
 * Controls the security of pad access
 */

/*
 * 2011 Peter 'Pita' Martischka (Primary Technology Ltd)
 *
 * Licensed 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 ERR = require("async-stacktrace");
var db = require("./DB").db;
var async = require("async");
var authorManager = require("./AuthorManager");
var padManager = require("./PadManager");
var sessionManager = require("./SessionManager");
var settings = require("../utils/Settings");
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;

/**
 * This function controlls the access to a pad, it checks if the user can access a pad.
 * @param padID the pad the user wants to access
 * @param sesssionID the session the user has (set via api)
 * @param token the token of the author (randomly generated at client side, used for public pads)
 * @param password the password the user has given to access this pad, can be null
 * @param callback will be called with (err, {accessStatus: grant|deny|wrongPassword|needPassword, authorID: a.xxxxxx})
 */
exports.checkAccess = function (padID, sessionCookie, token, password, callback)
{
  var statusObject;

  // a valid session is required (api-only mode)
  if(settings.requireSession)
  {
    // without sessionCookie, access is denied
    if(!sessionCookie)
    {
      callback(null, {accessStatus: "deny"});
      return;
    }
  }
  // a session is not required, so we'll check if it's a public pad
  else
  {
    // it's not a group pad, means we can grant access
    if(padID.indexOf("$") == -1)
    {
      //get author for this token
      authorManager.getAuthor4Token(token, function(err, author)
      {
        if(ERR(err, callback)) return;

        // assume user has access
        statusObject = {accessStatus: "grant", authorID: author};
        // user can't create pads
        if(settings.editOnly)
        {
          // check if pad exists
          padManager.doesPadExists(padID, function(err, exists)
          {
            if(ERR(err, callback)) return;

            // pad doesn't exist - user can't have access
            if(!exists) statusObject.accessStatus = "deny";
            // grant or deny access, with author of token
            callback(null, statusObject);
          });
        }
        // user may create new pads - no need to check anything
        else
        {
          // grant access, with author of token
          callback(null, statusObject);
        }
      });

      //don't continue
      return;
    }
  }

  var groupID = padID.split("$")[0];
  var padExists = false;
  var validSession = false;
  var sessionAuthor;
  var tokenAuthor;
  var isPublic;
  var isPasswordProtected;
  var passwordStatus = password == null ? "notGiven" : "wrong"; // notGiven, correct, wrong

  async.series([
    //get basic informations from the database
    function(callback)
    {
      async.parallel([
        //does pad exists
        function(callback)
        {
          padManager.doesPadExists(padID, function(err, exists)
          {
            if(ERR(err, callback)) return;
            padExists = exists;
            callback();
          });
        },
        //get information about all sessions contained in this cookie
        function(callback)
        {
          if (!sessionCookie) {
            callback();
            return;
          }

          var sessionIDs = sessionCookie.split(',');
          async.forEach(sessionIDs, function(sessionID, callback) {
            sessionManager.getSessionInfo(sessionID, function(err, sessionInfo) {
              //skip session if it doesn't exist
              if(err && err.message == "sessionID does not exist") return;

              if(ERR(err, callback)) return;

              var now = Math.floor(new Date().getTime()/1000);

              //is it for this group?
              if(sessionInfo.groupID != groupID) {
                console.debug("Auth failed: wrong group");
            	  callback();
            	  return;
              }

              //is validUntil still ok?
              if(sessionInfo.validUntil <= now){
                console.debug("Auth failed: validUntil");
            	  callback();
            	  return;
              }

              // There is a valid session
              validSession = true;
              sessionAuthor = sessionInfo.authorID;

              callback();
            });
          }, callback);
        },
        //get author for token
        function(callback)
        {
          //get author for this token
          authorManager.getAuthor4Token(token, function(err, author)
          {
            if(ERR(err, callback)) return;
            tokenAuthor = author;
            callback();
          });
        }
      ], callback);
    },
    //get more informations of this pad, if avaiable
    function(callback)
    {
      //skip this if the pad doesn't exists
      if(padExists == false)
      {
        callback();
        return;
      }

      padManager.getPad(padID, function(err, pad)
      {
        if(ERR(err, callback)) return;

        //is it a public pad?
        isPublic = pad.getPublicStatus();

        //is it password protected?
        isPasswordProtected = pad.isPasswordProtected();

        //is password correct?
        if(isPasswordProtected && password && pad.isCorrectPassword(password))
        {
          passwordStatus = "correct";
        }

        callback();
      });
    },
    function(callback)
    {
      //- a valid session for this group is avaible AND pad exists
      if(validSession && padExists)
      {
        //- the pad is not password protected
        if(!isPasswordProtected)
        {
          //--> grant access
          statusObject = {accessStatus: "grant", authorID: sessionAuthor};
        }
        //- the pad is password protected and password is correct
        else if(isPasswordProtected && passwordStatus == "correct")
        {
          //--> grant access
          statusObject = {accessStatus: "grant", authorID: sessionAuthor};
        }
        //- the pad is password protected but wrong password given
        else if(isPasswordProtected && passwordStatus == "wrong")
        {
          //--> deny access, ask for new password and tell them that the password is wrong
          statusObject = {accessStatus: "wrongPassword"};
        }
        //- the pad is password protected but no password given
        else if(isPasswordProtected && passwordStatus == "notGiven")
        {
          //--> ask for password
          statusObject = {accessStatus: "needPassword"};
        }
        else
        {
          throw new Error("Ops, something wrong happend");
        }
      }
      //- a valid session for this group avaible but pad doesn't exists
      else if(validSession && !padExists)
      {
        //--> grant access
        statusObject = {accessStatus: "grant", authorID: sessionAuthor};
        //--> deny access if user isn't allowed to create the pad
        if(settings.editOnly)
        {
          console.debug("Auth failed: valid session & pad does not exist");
          statusObject.accessStatus = "deny";
        }
      }
      // there is no valid session avaiable AND pad exists
      else if(!validSession && padExists)
      {
        //-- its public and not password protected
        if(isPublic && !isPasswordProtected)
        {
          //--> grant access, with author of token
          statusObject = {accessStatus: "grant", authorID: tokenAuthor};
        }
        //- its public and password protected and password is correct
        else if(isPublic && isPasswordProtected && passwordStatus == "correct")
        {
          //--> grant access, with author of token
          statusObject = {accessStatus: "grant", authorID: tokenAuthor};
        }
        //- its public and the pad is password protected but wrong password given
        else if(isPublic && isPasswordProtected && passwordStatus == "wrong")
        {
          //--> deny access, ask for new password and tell them that the password is wrong
          statusObject = {accessStatus: "wrongPassword"};
        }
        //- its public and the pad is password protected but no password given
        else if(isPublic && isPasswordProtected && passwordStatus == "notGiven")
        {
          //--> ask for password
          statusObject = {accessStatus: "needPassword"};
        }
        //- its not public
        else if(!isPublic)
        {
          console.debug("Auth failed: invalid session & pad is not public");
          //--> deny access
          statusObject = {accessStatus: "deny"};
        }
        else
        {
          throw new Error("Ops, something wrong happend");
        }
      }
      // there is no valid session avaiable AND pad doesn't exists
      else
      {
         console.debug("Auth failed: invalid session & pad does not exist");
         //--> deny access
         statusObject = {accessStatus: "deny"};
      }

      callback();
    }
  ], function(err)
  {
    if(ERR(err, callback)) return;
    callback(null, statusObject);
  });
};
<|endoftext|>


<commit_before>/**
 * The API Handler handles all API http requests
 */

/*
 * 2011 Peter 'Pita' Martischka (Primary Technology Ltd)
 *
 * Licensed 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 ERR = require("async-stacktrace");
var fs = require("fs");
var api = require("../db/API");
var padManager = require("../db/PadManager");
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;

//ensure we have an apikey
var apikey = null;
try
{
  apikey = fs.readFileSync("./APIKEY.txt","utf8");
}
catch(e)
{
  apikey = randomString(32);
  fs.writeFileSync("./APIKEY.txt",apikey,"utf8");
}

//a list of all functions
var version =
{ "1":
  { "createGroup"               : []
  , "createGroupIfNotExistsFor" : ["groupMapper"]
  , "deleteGroup"               : ["groupID"]
  , "listPads"                  : ["groupID"]
  , "createPad"                 : ["padID", "text"]
  , "createGroupPad"            : ["groupID", "padName", "text"]
  , "createAuthor"              : ["name"]
  , "createAuthorIfNotExistsFor": ["authorMapper" , "name"]
  , "listPadsOfAuthor"          : ["authorID"]
  , "createSession"             : ["groupID", "authorID", "validUntil"]
  , "deleteSession"             : ["sessionID"]
  , "getSessionInfo"            : ["sessionID"]
  , "listSessionsOfGroup"       : ["groupID"]
  , "listSessionsOfAuthor"      : ["authorID"]
  , "getText"                   : ["padID", "rev"]
  , "setText"                   : ["padID", "text"]
  , "getHTML"                   : ["padID", "rev"]
  , "setHTML"                   : ["padID", "html"]
  , "getRevisionsCount"         : ["padID"]
  , "getLastEdited"             : ["padID"]
  , "deletePad"                 : ["padID"]
  , "getReadOnlyID"             : ["padID"]
  , "setPublicStatus"           : ["padID", "publicStatus"]
  , "getPublicStatus"           : ["padID"]
  , "setPassword"               : ["padID", "password"]
  , "isPasswordProtected"       : ["padID"]
  , "listAuthorsOfPad"          : ["padID"]
  , "padUsersCount"             : ["padID"]
  , "getAuthorName"             : ["authorID"]
  , "padUsers"                  : ["padID"]
  , "sendClientsMessage"        : ["padID", "msg"]
  }
};

/**
 * Handles a HTTP API call
 * @param functionName the name of the called function
 * @param fields the params of the called function
 * @req express request object
 * @res express response object
 */
exports.handle = function(apiVersion, functionName, fields, req, res)
{
  //check if this is a valid apiversion
  var isKnownApiVersion = false;
  for(var knownApiVersion in version)
  {
    if(knownApiVersion == apiVersion)
    {
      isKnownApiVersion = true;
      break;
    }
  }

  //say goodbye if this is an unkown API version
  if(!isKnownApiVersion)
  {
    res.statusCode = 404;
    res.send({code: 3, message: "no such api version", data: null});
    return;
  }

  //check if this is a valid function name
  var isKnownFunctionname = false;
  for(var knownFunctionname in version[apiVersion])
  {
    if(knownFunctionname == functionName)
    {
      isKnownFunctionname = true;
      break;
    }
  }

  //say goodbye if this is a unkown function
  if(!isKnownFunctionname)
  {
    res.send({code: 3, message: "no such function", data: null});
    return;
  }

  //check the api key!
  if(fields["apikey"] != apikey.trim())
  {
    res.send({code: 4, message: "no or wrong API Key", data: null});
    return;
  }

  //sanitize any pad id's before continuing
  if(fields["padID"])
  {
    padManager.sanitizePadId(fields["padID"], function(padId)
    {
      fields["padID"] = padId;
      callAPI(apiVersion, functionName, fields, req, res);
    });
  }
  else if(fields["padName"])
  {
    padManager.sanitizePadId(fields["padName"], function(padId)
    {
      fields["padName"] = padId;
      callAPI(apiVersion, functionName, fields, req, res);
    });
  }
  else
  {
    callAPI(apiVersion, functionName, fields, req, res);
  }
}

//calls the api function
function callAPI(apiVersion, functionName, fields, req, res)
{
  //put the function parameters in an array
  var functionParams = [];
  for(var i=0;i<version[apiVersion][functionName].length;i++)
  {
    functionParams.push(fields[ version[apiVersion][functionName][i] ]);
  }

  //add a callback function to handle the response
  functionParams.push(function(err, data)
  {
    // no error happend, everything is fine
    if(err == null)
    {
      if(!data)
        data = null;

      res.send({code: 0, message: "ok", data: data});
    }
    // parameters were wrong and the api stopped execution, pass the error
    else if(err.name == "apierror")
    {
      res.send({code: 1, message: err.message, data: null});
    }
    //an unkown error happend
    else
    {
      res.send({code: 2, message: "internal error", data: null});
      ERR(err);
    }
  });

  //call the api function
  api[functionName](functionParams[0],functionParams[1],functionParams[2],functionParams[3],functionParams[4]);
}
<commit_msg>Bump API version to v1.1<commit_after>/**
 * The API Handler handles all API http requests
 */

/*
 * 2011 Peter 'Pita' Martischka (Primary Technology Ltd)
 *
 * Licensed 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 ERR = require("async-stacktrace");
var fs = require("fs");
var api = require("../db/API");
var padManager = require("../db/PadManager");
var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString;

//ensure we have an apikey
var apikey = null;
try
{
  apikey = fs.readFileSync("./APIKEY.txt","utf8");
}
catch(e)
{
  apikey = randomString(32);
  fs.writeFileSync("./APIKEY.txt",apikey,"utf8");
}

//a list of all functions
var version =
{ "1":
  { "createGroup"               : []
  , "createGroupIfNotExistsFor" : ["groupMapper"]
  , "deleteGroup"               : ["groupID"]
  , "listPads"                  : ["groupID"]
  , "createPad"                 : ["padID", "text"]
  , "createGroupPad"            : ["groupID", "padName", "text"]
  , "createAuthor"              : ["name"]
  , "createAuthorIfNotExistsFor": ["authorMapper" , "name"]
  , "listPadsOfAuthor"          : ["authorID"]
  , "createSession"             : ["groupID", "authorID", "validUntil"]
  , "deleteSession"             : ["sessionID"]
  , "getSessionInfo"            : ["sessionID"]
  , "listSessionsOfGroup"       : ["groupID"]
  , "listSessionsOfAuthor"      : ["authorID"]
  , "getText"                   : ["padID", "rev"]
  , "setText"                   : ["padID", "text"]
  , "getHTML"                   : ["padID", "rev"]
  , "setHTML"                   : ["padID", "html"]
  , "getRevisionsCount"         : ["padID"]
  , "getLastEdited"             : ["padID"]
  , "deletePad"                 : ["padID"]
  , "getReadOnlyID"             : ["padID"]
  , "setPublicStatus"           : ["padID", "publicStatus"]
  , "getPublicStatus"           : ["padID"]
  , "setPassword"               : ["padID", "password"]
  , "isPasswordProtected"       : ["padID"]
  , "listAuthorsOfPad"          : ["padID"]
  , "padUsersCount"             : ["padID"]
  }
, "1.1":
  { "getAuthorName"             : ["authorID"]
  , "padUsers"                  : ["padID"]
  , "sendClientsMessage"        : ["padID", "msg"]
  }
};

/**
 * Handles a HTTP API call
 * @param functionName the name of the called function
 * @param fields the params of the called function
 * @req express request object
 * @res express response object
 */
exports.handle = function(apiVersion, functionName, fields, req, res)
{
  //check if this is a valid apiversion
  var isKnownApiVersion = false;
  for(var knownApiVersion in version)
  {
    if(knownApiVersion == apiVersion)
    {
      isKnownApiVersion = true;
      break;
    }
  }

  //say goodbye if this is an unkown API version
  if(!isKnownApiVersion)
  {
    res.statusCode = 404;
    res.send({code: 3, message: "no such api version", data: null});
    return;
  }

  //check if this is a valid function name
  var isKnownFunctionname = false;
  for(var knownFunctionname in version[apiVersion])
  {
    if(knownFunctionname == functionName)
    {
      isKnownFunctionname = true;
      break;
    }
  }

  //say goodbye if this is a unkown function
  if(!isKnownFunctionname)
  {
    res.send({code: 3, message: "no such function", data: null});
    return;
  }

  //check the api key!
  if(fields["apikey"] != apikey.trim())
  {
    res.send({code: 4, message: "no or wrong API Key", data: null});
    return;
  }

  //sanitize any pad id's before continuing
  if(fields["padID"])
  {
    padManager.sanitizePadId(fields["padID"], function(padId)
    {
      fields["padID"] = padId;
      callAPI(apiVersion, functionName, fields, req, res);
    });
  }
  else if(fields["padName"])
  {
    padManager.sanitizePadId(fields["padName"], function(padId)
    {
      fields["padName"] = padId;
      callAPI(apiVersion, functionName, fields, req, res);
    });
  }
  else
  {
    callAPI(apiVersion, functionName, fields, req, res);
  }
}

//calls the api function
function callAPI(apiVersion, functionName, fields, req, res)
{
  //put the function parameters in an array
  var functionParams = [];
  for(var i=0;i<version[apiVersion][functionName].length;i++)
  {
    functionParams.push(fields[ version[apiVersion][functionName][i] ]);
  }

  //add a callback function to handle the response
  functionParams.push(function(err, data)
  {
    // no error happend, everything is fine
    if(err == null)
    {
      if(!data)
        data = null;

      res.send({code: 0, message: "ok", data: data});
    }
    // parameters were wrong and the api stopped execution, pass the error
    else if(err.name == "apierror")
    {
      res.send({code: 1, message: err.message, data: null});
    }
    //an unkown error happend
    else
    {
      res.send({code: 2, message: "internal error", data: null});
      ERR(err);
    }
  });

  //call the api function
  api[functionName](functionParams[0],functionParams[1],functionParams[2],functionParams[3],functionParams[4]);
}
<|endoftext|>


<commit_before>var config = require('uiconfig');
var Base = require('ampersand-model');
var debug = require('debug')("craftodex:base:model");
var urlRe = require('url-regex')({ exact: true });

var registry = require('registry');

module.exports = Base.extend({

  typeAttribute: "modelType",
  idAttribute: "@id",
  namespaceAttribute: "@graph",

  extraProperties: 'ignore',

  initialize: function () {
    debug("adding", this.getId(), "to registry");
    registry.set(this.getId(), this);
    this.on('destroy', function() {
      debug("deleting", this.getId(), "from registry");
      registry['delete'](this.getId());
    }, this);
  },

  props: {
    "@id": "string",
    "@type": "string",
    "@context": "object",
  },

  dataTypes: {
    link: {
      set: function (newVal) {
        debug("dataTypes.link.set", newVal);
        var isInstance = newVal instanceof Base || (newVal && newVal.isState);
        if (isInstance) {
          newVal = newVal.getId();
        }
        var isUrl = urlRe.test(newVal);
        return {
          val: newVal,
          type: isUrl ? 'link' : typeof newVal,
        };
      },
      get: function (val) {
        debug("dataTypes.link.get(", val, ")");
        var ret = registry.get(val);
        debug("dataTypes.link.get() ->", ret);
        return ret;
      },
      compare: function (currentVal, newVal, attributeName) {
        debug("dataTypes.link.compare", currentVal, newVal, attributeName);
        return currentVal === newVal;
      },
    },
  },

  derived: {
    id: {
      deps: ["@id"],
      fn: function () {
        var id = this.getId();
        var api = config.api;

        if (!id) {
          return null;
        }

        var subId = id.substring(0, api.length);
        if (id.substring(0, api.length) === api) {
          return id.substring(api.length);
        } else {
          return id;
        }
      },
    },
  },

  url: function () {
    var id = this.getId();
    var api = config.api;

    var url = null;
    if (urlRe.test(id)) {
      url = id;
    } else if (id) {
      url = api + "/" + id
      ;
    }

    debug("url() ->", url, this);
    return url;
  },
});
<commit_msg>update base model so when '@id' changes, the model is moved in the registry<commit_after>var config = require('uiconfig');
var Base = require('ampersand-model');
var debug = require('debug')("craftodex:base:model");
var urlRe = require('url-regex')({ exact: true });

var registry = require('registry');

module.exports = Base.extend({

  typeAttribute: "modelType",
  idAttribute: "@id",
  namespaceAttribute: "@graph",

  extraProperties: 'ignore',

  initialize: function () {
    debug("adding", this.getId(), "to registry");
    registry.set(this.getId(), this);
    this.on('destroy', function() {
      debug("deleting", this.getId(), "from registry");
      registry['delete'](this.getId());
    }, this);
    this.on('change:@id', function (oldId, newId) {
      var oldId = this.previousAttributes()['@id'];
      var newId = this.attributes['@id'];
      debug("moving", oldId, "to", newId);
      registry['delete'](oldId);
      registry.set(newId, this);
    });
  },

  props: {
    "@id": "string",
    "@type": "string",
    "@context": "object",
  },

  dataTypes: {
    link: {
      set: function (newVal) {
        debug("dataTypes.link.set", newVal);
        var isInstance = newVal instanceof Base || (newVal && newVal.isState);
        if (isInstance) {
          newVal = newVal.getId();
        }
        var isUrl = urlRe.test(newVal);
        return {
          val: newVal,
          type: isUrl ? 'link' : typeof newVal,
        };
      },
      get: function (val) {
        debug("dataTypes.link.get(", val, ")");
        var ret = registry.get(val);
        debug("dataTypes.link.get() ->", ret);
        return ret;
      },
      compare: function (currentVal, newVal, attributeName) {
        debug("dataTypes.link.compare", currentVal, newVal, attributeName);
        return currentVal === newVal;
      },
    },
  },

  derived: {
    id: {
      deps: ["@id"],
      fn: function () {
        var id = this.getId();
        var api = config.api;

        if (!id) {
          return null;
        }

        var subId = id.substring(0, api.length);
        if (id.substring(0, api.length) === api) {
          return id.substring(api.length);
        } else {
          return id;
        }
      },
    },
  },

  url: function () {
    var id = this.getId();
    var api = config.api;

    var url = null;
    if (urlRe.test(id)) {
      url = id;
    } else if (id) {
      url = api + "/" + id
      ;
    }

    debug("url() ->", url, this);
    return url;
  },
});
<|endoftext|>


<commit_before>import React from 'react';
import TestRenderer from 'react-test-renderer';
import ObjectValue from './ObjectValue';

describe('ObjectValue', () => {
  it('should render', () => {
    const tree = TestRenderer.create(<ObjectValue object={0} />);
    expect(tree).toMatchSnapshot();
  });

  it('should render bigint', () => {
    const tree = TestRenderer.create(<ObjectValue object={9007199254740993n} />).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['9007199254740993n']);
  });

  it('should render number', () => {
    const tree = TestRenderer.create(<ObjectValue object={0} />).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['0']);
  });

  it('should render string with quotes', () => {
    const tree = TestRenderer.create(
      <ObjectValue object={'octocat'} />
    ).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['"', 'octocat', '"']);
  });

  it('should render boolean', () => {
    const tree = TestRenderer.create(<ObjectValue object={true} />).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['true']);
  });

  it('should render undefined', () => {
    const tree = TestRenderer.create(
      <ObjectValue object={undefined} />
    ).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['undefined']);
  });

  it('should render null', () => {
    const tree = TestRenderer.create(<ObjectValue object={null} />).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['null']);
  });

  it('should display date correctly', () => {
    const dateString = 'December 17, 1995 03:24:00';
    const date = new Date(dateString);
    const tree = TestRenderer.create(<ObjectValue object={date} />).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual([date.toString()]);
  });

  it('should render array with length information', () => {
    const tree = TestRenderer.create(
      <ObjectValue object={[1, 2, 3, 4, 5]} />
    ).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['Array(5)']);
  });

  it('should render an empty object', () => {
    const tree = TestRenderer.create(<ObjectValue object={{}} />).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['Object']);
  });

  it('should render a simple object', () => {
    const tree = TestRenderer.create(
      <ObjectValue object={{ k: 'v' }} />
    ).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['Object']);
  });

  it('should render a null prototyped object', () => {
    const tree = TestRenderer.create(
      <ObjectValue object={Object.create(null)} />
    ).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['Object']);
  });

  /*
  it('should render an anonymous function', () => {
    renderer.render(<ObjectValue object={function(){}} />)
    const tree = renderer.getRenderOutput()
    expect(tree.type).toBe('span')
    // const n = tree.children[1].props.children[1]
    // console.log(JSON.stringify(n, null, 2))
    // console.log(typeof n)
    // console.log(tree.children[1].props.children)
    expect(tree.children[0]).toEqual(function)
    expect(tree.children[1]).toEqual({[ '\xa0', 'object', '()' ]})
  });
  */

  /*
  it('should render a named function', () => {
    renderer.render(<ObjectValue object={function id(a){return a;}} />)
    const tree = renderer.getRenderOutput()
    expect(tree.type).toBe('span')
    expect(tree.children).toEqual([
                                          function,
                                          {[ '\xa0', 'id', '()' ]}
                                        ])
  });
  */

  it('should render a symbol', () => {
    const tree = TestRenderer.create(
      <ObjectValue object={Symbol()} />
    ).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['Symbol()']);
  });

  it('should render a symbol foo', () => {
    const tree = TestRenderer.create(
      <ObjectValue object={Symbol('foo')} />
    ).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['Symbol(foo)']);
  });

  it('accepts and applies style from `styles` prop', () => {
    // Custom `styles` prop gets applied to the element
    const style = { color: 'blue' };
    const tree = TestRenderer.create(
      <ObjectValue styles={style} object={''} />
    ).toJSON();
    expect(tree.props.style.color).toEqual('blue');
  });
});
<commit_msg>Fix BigInt test<commit_after>import React from 'react';
import TestRenderer from 'react-test-renderer';
import ObjectValue from './ObjectValue';

describe('ObjectValue', () => {
  it('should render', () => {
    const tree = TestRenderer.create(<ObjectValue object={0} />);
    expect(tree).toMatchSnapshot();
  });

  it('should render bigint', () => {
    const tree = TestRenderer.create(<ObjectValue object={9007199254740993n} />).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['9007199254740993', 'n']);
  });

  it('should render number', () => {
    const tree = TestRenderer.create(<ObjectValue object={0} />).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['0']);
  });

  it('should render string with quotes', () => {
    const tree = TestRenderer.create(
      <ObjectValue object={'octocat'} />
    ).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['"', 'octocat', '"']);
  });

  it('should render boolean', () => {
    const tree = TestRenderer.create(<ObjectValue object={true} />).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['true']);
  });

  it('should render undefined', () => {
    const tree = TestRenderer.create(
      <ObjectValue object={undefined} />
    ).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['undefined']);
  });

  it('should render null', () => {
    const tree = TestRenderer.create(<ObjectValue object={null} />).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['null']);
  });

  it('should display date correctly', () => {
    const dateString = 'December 17, 1995 03:24:00';
    const date = new Date(dateString);
    const tree = TestRenderer.create(<ObjectValue object={date} />).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual([date.toString()]);
  });

  it('should render array with length information', () => {
    const tree = TestRenderer.create(
      <ObjectValue object={[1, 2, 3, 4, 5]} />
    ).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['Array(5)']);
  });

  it('should render an empty object', () => {
    const tree = TestRenderer.create(<ObjectValue object={{}} />).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['Object']);
  });

  it('should render a simple object', () => {
    const tree = TestRenderer.create(
      <ObjectValue object={{ k: 'v' }} />
    ).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['Object']);
  });

  it('should render a null prototyped object', () => {
    const tree = TestRenderer.create(
      <ObjectValue object={Object.create(null)} />
    ).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['Object']);
  });

  /*
  it('should render an anonymous function', () => {
    renderer.render(<ObjectValue object={function(){}} />)
    const tree = renderer.getRenderOutput()
    expect(tree.type).toBe('span')
    // const n = tree.children[1].props.children[1]
    // console.log(JSON.stringify(n, null, 2))
    // console.log(typeof n)
    // console.log(tree.children[1].props.children)
    expect(tree.children[0]).toEqual(function)
    expect(tree.children[1]).toEqual({[ '\xa0', 'object', '()' ]})
  });
  */

  /*
  it('should render a named function', () => {
    renderer.render(<ObjectValue object={function id(a){return a;}} />)
    const tree = renderer.getRenderOutput()
    expect(tree.type).toBe('span')
    expect(tree.children).toEqual([
                                          function,
                                          {[ '\xa0', 'id', '()' ]}
                                        ])
  });
  */

  it('should render a symbol', () => {
    const tree = TestRenderer.create(
      <ObjectValue object={Symbol()} />
    ).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['Symbol()']);
  });

  it('should render a symbol foo', () => {
    const tree = TestRenderer.create(
      <ObjectValue object={Symbol('foo')} />
    ).toJSON();
    expect(tree.type).toBe('span');
    expect(tree.children).toEqual(['Symbol(foo)']);
  });

  it('accepts and applies style from `styles` prop', () => {
    // Custom `styles` prop gets applied to the element
    const style = { color: 'blue' };
    const tree = TestRenderer.create(
      <ObjectValue styles={style} object={''} />
    ).toJSON();
    expect(tree.props.style.color).toEqual('blue');
  });
});
<|endoftext|>


<commit_before>/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
 * full list of contributors). Published under the Clear BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/Layer/XYZ.js
 */

/**
 * Class: OpenLayers.Layer.OSM
 * This layer allows accessing OpenStreetMap tiles. By default the OpenStreetMap
 *    hosted tile.openstreetmap.org Mapnik tileset is used. If you wish to use
 *    tiles@home / osmarender layer instead, you need to provide a different
 *    URL to the constructor. Here's an example for tiles@home:
 *
 * (code)
 *     new OpenLayers.Layer.OSM("t@h",
 *       "http://tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png");
 * (end)
 *
 * Inherits from:
 *  - <OpenLayers.Layer.XYZ>
 */
OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {

    /**
     * APIProperty: name
     * {String} The layer name. Defaults to "OpenStreetMap" if the first
     * argument to the constructor is null or undefined.
     */
    name: "OpenStreetMap",

    /**
     * APIProperty: url
     * {String} The tileset URL scheme. Defaults to
     * : http://tile.openstreetmap.org/${z}/${x}/${y}.png
     * (the official OSM tileset) if the second argument to the constructor
     * is null or undefined. To use another tileset you can have something
     * like this:
     * (start code)
     *     new OpenLayers.Layer.OSM("t@h",
     *       "http://tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png");
     * (end)
     */
    url: 'http://tile.openstreetmap.org/${z}/${x}/${y}.png',

    /**
     * Property: attribution
     * {String} The layer attribution.
     */
    attribution: "Data CC-By-SA by OpenStreetMap",

    /**
     * Property: sphericalMercator
     * {Boolean}
     */
    sphericalMercator: true,

    /**
     * Property: wrapDateLine
     * {Boolean}
     */
    wrapDateLine: true,

    /** APIProperty: tileOptions
     *  {Object} optional configuration options for <OpenLayers.Tile> instances
     *  created by this Layer. Default is
     *
     *  (code)
     *  {crossOriginKeyword: 'anonymous'}
     *  (end)
     *
     *  When using OSM tilesets other than the default ones, it may be
     *  necessary to set this to
     *
     *  (code)
     *  {crossOriginKeyword: null}
     *  (end)
     *
     *  if the server does not send Access-Control-Allow-Origin headers.
     */
    tileOptions: null,

    /**
     * Constructor: OpenLayers.Layer.OSM
     *
     * Parameters:
     * name - {String} The layer name.
     * url - {String} The tileset URL scheme.
     * options - {Object} Configuration options for the layer. Any inherited
     *     layer option can be set in this object (e.g.
     *     <OpenLayers.Layer.Grid.buffer>).
     */
    initialize: function(name, url, options) {
        OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments);
        this.tileOptions = OpenLayers.Util.extend({
            crossOriginKeyword: 'anonymous'
        }, this.options && this.options.tileOptions);
    },

    /**
     * Method: clone
     */
    clone: function(obj) {
        if (obj == null) {
            obj = new OpenLayers.Layer.OSM(
                this.name, this.url, this.getOptions());
        }
        obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]);
        return obj;
    },

    CLASS_NAME: "OpenLayers.Layer.OSM"
});
<commit_msg>Use the 3 available sub-domains for OSM by default<commit_after>/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
 * full list of contributors). Published under the Clear BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/Layer/XYZ.js
 */

/**
 * Class: OpenLayers.Layer.OSM
 * This layer allows accessing OpenStreetMap tiles. By default the OpenStreetMap
 *    hosted tile.openstreetmap.org Mapnik tileset is used. If you wish to use
 *    tiles@home / osmarender layer instead, you need to provide a different
 *    URL to the constructor. Here's an example for tiles@home:
 *
 * (code)
 *     new OpenLayers.Layer.OSM("t@h",
 *       "http://tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png");
 * (end)
 *
 * Inherits from:
 *  - <OpenLayers.Layer.XYZ>
 */
OpenLayers.Layer.OSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {

    /**
     * APIProperty: name
     * {String} The layer name. Defaults to "OpenStreetMap" if the first
     * argument to the constructor is null or undefined.
     */
    name: "OpenStreetMap",

    /**
     * APIProperty: url
     * {String} The tileset URL scheme. Defaults to
     * : http://[a|b|c].tile.openstreetmap.org/${z}/${x}/${y}.png
     * (the official OSM tileset) if the second argument to the constructor
     * is null or undefined. To use another tileset you can have something
     * like this:
     * (start code)
     *     new OpenLayers.Layer.OSM("t@h",
     *       "http://tah.openstreetmap.org/Tiles/tile/${z}/${x}/${y}.png");
     * (end)
     */
    url: [
        'http://a.tile.openstreetmap.org/${z}/${x}/${y}.png',
        'http://b.tile.openstreetmap.org/${z}/${x}/${y}.png',
        'http://c.tile.openstreetmap.org/${z}/${x}/${y}.png'
    ],

    /**
     * Property: attribution
     * {String} The layer attribution.
     */
    attribution: "Data CC-By-SA by OpenStreetMap",

    /**
     * Property: sphericalMercator
     * {Boolean}
     */
    sphericalMercator: true,

    /**
     * Property: wrapDateLine
     * {Boolean}
     */
    wrapDateLine: true,

    /** APIProperty: tileOptions
     *  {Object} optional configuration options for <OpenLayers.Tile> instances
     *  created by this Layer. Default is
     *
     *  (code)
     *  {crossOriginKeyword: 'anonymous'}
     *  (end)
     *
     *  When using OSM tilesets other than the default ones, it may be
     *  necessary to set this to
     *
     *  (code)
     *  {crossOriginKeyword: null}
     *  (end)
     *
     *  if the server does not send Access-Control-Allow-Origin headers.
     */
    tileOptions: null,

    /**
     * Constructor: OpenLayers.Layer.OSM
     *
     * Parameters:
     * name - {String} The layer name.
     * url - {String} The tileset URL scheme.
     * options - {Object} Configuration options for the layer. Any inherited
     *     layer option can be set in this object (e.g.
     *     <OpenLayers.Layer.Grid.buffer>).
     */
    initialize: function(name, url, options) {
        OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments);
        this.tileOptions = OpenLayers.Util.extend({
            crossOriginKeyword: 'anonymous'
        }, this.options && this.options.tileOptions);
    },

    /**
     * Method: clone
     */
    clone: function(obj) {
        if (obj == null) {
            obj = new OpenLayers.Layer.OSM(
                this.name, this.url, this.getOptions());
        }
        obj = OpenLayers.Layer.XYZ.prototype.clone.apply(this, [obj]);
        return obj;
    },

    CLASS_NAME: "OpenLayers.Layer.OSM"
});
<|endoftext|>


<commit_before>goog.provide('ol.tilegrid.XYZ');

goog.require('ol.Coordinate');
goog.require('ol.Projection');
goog.require('ol.Size');
goog.require('ol.TileRange');
goog.require('ol.tilegrid.TileGrid');

/**
 * @constructor
 * @extends {ol.tilegrid.TileGrid}
 * @param {ol.tilegrid.XYZOptions} xyzOptions XYZ options.
 */
ol.tilegrid.XYZ = function(xyzOptions) {

  var resolutions = new Array(xyzOptions.maxZoom + 1);
  var z;
  for (z = 0; z <= xyzOptions.maxZoom; ++z) {
    resolutions[z] =
        2 * ol.Projection.EPSG_3857_HALF_SIZE / (ol.DEFAULT_TILE_SIZE << z);
  }

  goog.base(this, {
    extent: ol.Projection.EPSG_3857_EXTENT,
    origin: new ol.Coordinate(-ol.Projection.EPSG_3857_HALF_SIZE,
                              ol.Projection.EPSG_3857_HALF_SIZE),
    resolutions: resolutions,
    tileSize: new ol.Size(ol.DEFAULT_TILE_SIZE, ol.DEFAULT_TILE_SIZE)
  });

};
goog.inherits(ol.tilegrid.XYZ, ol.tilegrid.TileGrid);

/**
 * @inheritDoc
 */
ol.tilegrid.XYZ.prototype.forEachTileCoordParentTileRange =
    function(tileCoord, callback, opt_obj) {
  var x = tileCoord.x;
  var y = tileCoord.y;
  var z = tileCoord.z;
  var tileRange;
  while (true) {
    z -= 1;
    if (z < 0) {
      break;
    }
    x = Math.floor(x / 2);
    y = Math.floor(y / 2);
    tileRange = new ol.TileRange(x, y, x, y);
    if (callback.call(opt_obj, z, tileRange)) {
      break;
    }
  }
};
<commit_msg>Use shifts rather than floor<commit_after>goog.provide('ol.tilegrid.XYZ');

goog.require('ol.Coordinate');
goog.require('ol.Projection');
goog.require('ol.Size');
goog.require('ol.TileRange');
goog.require('ol.tilegrid.TileGrid');

/**
 * @constructor
 * @extends {ol.tilegrid.TileGrid}
 * @param {ol.tilegrid.XYZOptions} xyzOptions XYZ options.
 */
ol.tilegrid.XYZ = function(xyzOptions) {

  var resolutions = new Array(xyzOptions.maxZoom + 1);
  var z;
  for (z = 0; z <= xyzOptions.maxZoom; ++z) {
    resolutions[z] =
        2 * ol.Projection.EPSG_3857_HALF_SIZE / (ol.DEFAULT_TILE_SIZE << z);
  }

  goog.base(this, {
    extent: ol.Projection.EPSG_3857_EXTENT,
    origin: new ol.Coordinate(-ol.Projection.EPSG_3857_HALF_SIZE,
                              ol.Projection.EPSG_3857_HALF_SIZE),
    resolutions: resolutions,
    tileSize: new ol.Size(ol.DEFAULT_TILE_SIZE, ol.DEFAULT_TILE_SIZE)
  });

};
goog.inherits(ol.tilegrid.XYZ, ol.tilegrid.TileGrid);

/**
 * @inheritDoc
 */
ol.tilegrid.XYZ.prototype.forEachTileCoordParentTileRange =
    function(tileCoord, callback, opt_obj) {
  var x = tileCoord.x;
  var y = tileCoord.y;
  var z = tileCoord.z;
  var tileRange;
  while (true) {
    z -= 1;
    if (z < 0) {
      break;
    }
    x >>= 1;
    y >>= 1;
    tileRange = new ol.TileRange(x, y, x, y);
    if (callback.call(opt_obj, z, tileRange)) {
      break;
    }
  }
};
<|endoftext|>


<commit_before>/* jslint node: true, esnext: true */
"use strict";

/**
 * assign services based on a configuration
 */

module.exports.defineServiceConsumerProperties = function (object, config, provider, waitUntilFactoryPresent) {
	const promises = [];

	Object.keys(config).forEach(name => {
		let entry = config[name];

		if (typeof entry === 'string') {
			entry = {
				name: name,
				type: entry
			};
		}

		promises.push(provider.declareService(entry, waitUntilFactoryPresent).then(service =>
			Object.defineProperty(object, name, {
				value: service
			})
		));
	});

	return Promise.all(promises);
};
<commit_msg>fix(ServiceConsumer): also start service<commit_after>/* jslint node: true, esnext: true */
"use strict";

/**
 * assign services based on a configuration
 */

module.exports.defineServiceConsumerProperties = function (object, config, provider, waitUntilFactoryPresent) {
	const promises = [];

	Object.keys(config).forEach(name => {
		let entry = config[name];

		if (typeof entry === 'string') {
			entry = {
				name: name,
				type: entry
			};
		}

		promises.push(provider.declareService(entry, waitUntilFactoryPresent).then(service => {
			Object.defineProperty(object, name, {
				value: service
			});
			return service.start();
		}));
	});

	return Promise.all(promises);
};
<|endoftext|>


<commit_before>/*jslint node:true*/
'use strict';
var when = require('when'),
    ffs = require('final-fs'),
    path = require('path'),
    finders = require('../finders.js'),
    extend = require('extend'),
    mapper = require('../mapper.js'),
    sequence = require('when/sequence'),
    generateUniqueId = require('../generateUniqueId.js');

module.exports = function (entity, fdbCollection) {
    this.entity = extend({}, entity);
    this.fdbCollection = fdbCollection;

    entity.rev = generateUniqueId();
};

module.exports.prototype = Object.create(null, {
    execute: {
        value: function () {
            var dir = this.fdbCollection.dirName,
                maps = this.fdbCollection.maps,
                entity = this.entity,
                oldEntity,
                filePath = dir + '/' + entity.id + '.json',
                backupFilePath = path.resolve(dir, entity.id, entity.rev + '.json'),
                dirName = path.resolve(dir, entity.id);

            return finders.byId(dir, entity.id) //find old
                .then(function (result) {
                    oldEntity = result;
                    return ffs.mkdir(dirName);
                })
                .then(function () {
                    return ffs.rename(filePath, backupFilePath);
                })
                .then(function () {
                    return ffs.writeJSON(filePath, entity);
                })
                .then(function () { //find old
                    return finders.byId(dir, entity.id);
                })
                .then(function () {
                    return sequence([
                        function () {
                            return mapper.removeObjectFromMaps(dir, maps, oldEntity);
                        },
                        function () {
                            return mapper.insertObjectToMaps(dir, maps, entity);
                        }
                    ]);
                });
        }
    }
});<commit_msg>set new revision on update<commit_after>/*jslint node:true*/
'use strict';
var when = require('when'),
    ffs = require('final-fs'),
    path = require('path'),
    finders = require('../finders.js'),
    extend = require('extend'),
    mapper = require('../mapper.js'),
    sequence = require('when/sequence'),
    generateUniqueId = require('../generateUniqueId.js');

module.exports = function (entity, fdbCollection) {
    entity.rev = generateUniqueId();
    this.entity = extend({}, entity);
    this.fdbCollection = fdbCollection;
};

module.exports.prototype = Object.create(null, {
    execute: {
        value: function () {
            var dir = this.fdbCollection.dirName,
                maps = this.fdbCollection.maps,
                entity = this.entity,
                oldEntity,
                filePath = dir + '/' + entity.id + '.json',
                dirName = path.resolve(dir, entity.id);

            return finders.byId(dir, entity.id) //find old
                .then(function (result) {
                    oldEntity = result;
                    return ffs.mkdir(dirName);
                })
                .then(function () {
                    var backupFilePath = path.resolve(dir, entity.id, oldEntity.rev + '.json');

                    return ffs.rename(filePath, backupFilePath);
                })
                .then(function () {
                    return ffs.writeJSON(filePath, entity);
                })
                .then(function () { //find old
                    return finders.byId(dir, entity.id);
                })
                .then(function () {
                    return sequence([
                        function () {
                            return mapper.removeObjectFromMaps(dir, maps, oldEntity);
                        },
                        function () {
                            return mapper.insertObjectToMaps(dir, maps, entity);
                        }
                    ]);
                });
        }
    }
});<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */

var form = require('./form-template');
var clause = require('./form-clause');
var serialize = require('serialize');
var classes = require('classes');
var Emitter = require('emitter');
var request = require('request');
var regexps = require('regexps');
var events = require('events');
var render = require('render');
var empty = require('empty');
var tags = require('tags');
var o = require('query');
var t = require('t');
var log = require('debug')('democracyos:settings-password');

/**
 * Expose LawForm
 */

module.exports = LawForm;

/**
 * Creates a password edit view
 */

function LawForm(law) {
  if (!(this instanceof LawForm)) {
    return new LawForm(law);
  };

  if (law) {
    this.action = '/law/' + law.id;
    this.title = 'Edit law';
  } else {
    this.action = '/law/create';
    this.title = 'Create law';
  }

  this.law = law;

  this.formsubmit = this.formsubmit.bind(this);
  this.onsuccess = this.onsuccess.bind(this);
  this.onerror = this.onerror.bind(this);

  this.build();
  this.switchOn();
}

/**
 * Mixin with `Emitter`
 */

Emitter(LawForm.prototype);

/**
 * Build view's `this.el`
 */

LawForm.prototype.build = function() {
  this.el = render.dom(form, {
    form: { title: this.title, action: this.action },
    law: this.law || { clauses: [] },
    tags: tags.get()
  });
}

/**
 * Turn on event bindings
 */

LawForm.prototype.switchOn = function() {
  this.events = events(this.el, this);
  this.events.bind('submit form');
  this.events.bind('click a.add-clause', 'onaddclauseclick');
  this.on('submit', this.formsubmit);
  this.on('success', this.onsuccess);
  this.on('error', this.onerror);
}

/**
 * Turn off event bindings
 */

LawForm.prototype.switchOff = function() {
  this.events.unbind();
  this.off();
}

/**
 * Handle `onsubmit` form event
 *
 * @param {Event} ev
 * @api private
 */

LawForm.prototype.onsubmit = function(ev) {
  ev.preventDefault();

  // Clean errors list
  this.messages();

  // Serialize form
  var form = o('form', this.el);
  var data = serialize.object(form);

  // Check for errors in data
  var errors = this.validate(data);

  // If errors, show and exit
  if (errors.length) {
    return this.messages(errors);
  };

  // Deliver form submit
  this.emit('submit', data);
}

/**
 * Handle `submit` event to
 * perform POST request with
 * data
 *
 * @param {Event} ev
 * @api private
 */

LawForm.prototype.formsubmit = function(data) {
  var view = this;

  request
  .post('/api' + this.action)
  .send(data)
  .end(function(err, res) {
    if (err || !res.ok) {
      return log('Fetch error: %o', err || res.error), view.emit('error', res.body || res.text);
    };
    if (res.body && res.body.error) {
      return view.emit('error', res.body.error);
    };

    view.emit('success', res.body);
  });
}

/**
 * Handle `error` event with
 * logging and display
 *
 * @param {String} error
 * @api private
 */

LawForm.prototype.onerror = function(error) {
  log('Error: %o', error);
  this.messages([error]);
}

/**
 * Handle `error` event with
 * logging and display
 *
 * @param {String} error
 * @api private
 */

LawForm.prototype.onsuccess = function() {
  log('Law create successful');
  this.messages([t('Law successfuly saved')]);
}

/**
 * Validate form's fields
 *
 * @param {Object} data
 * @return {Array} of Errors
 * @api public
 */

LawForm.prototype.validate = function(data) {
  var errors = [];
  if (!data.lawId.length) {
    errors.push(t('Official Id required'));
  };
  if (!data.mediaTitle.length) {
    errors.push(t('Media title required'));
  };
  if (!data.source.length) {
    errors.push(t('Source required'));
  } else if (!regexps.url.test(data.source)) {
    errors.push(t('Source must be a valid url'));
  };
  return errors;
}

/**
 * Fill messages list
 *
 * @param {Array} msgs
 * @param {string} type
 * @api public
 */

LawForm.prototype.messages = function(msgs, type) {
  var ul = o('ul.form-messages', this.el);

  if (!arguments.length) return empty(ul), this;

  msgs.forEach(function(m) {
    if (!m) return;
    var li = document.createElement('li');
    li.innerHTML = m.message || m;
    classes(li).add(type || 'error');
    ul.appendChild(li);
  });
}

/**
 * Renders to provided `el`
 * or delivers view's `el`
 *
 * @param {Element} el
 * @return {LawForm|Element}
 * @api public
 */

LawForm.prototype.render = function(el) {
  if (1 === arguments.length) {

    // if string, then query element
    if ('string' === typeof el) {
      el = o(el);
    };

    // if it's not currently inserted
    // at `el`, then append to `el`
    if (el !== this.el.parentNode) {
      el.appendChild(this.el);
    };

    return this;
  };

  return this.el;
}

LawForm.prototype.onaddclauseclick = function(ev) {
  ev.preventDefault();

  var id = this.law ? this.law.id : null;
  if (id != null) return this.addClause();

  // if no law, reveal message forbidden
  classes(o('.add-clause-forbidden', this.el)).remove('hide');
}

LawForm.prototype.addClause = function() {
  var clauses = o('.law-clauses', this.el);

  request
  .post('/api' + this.action + '/clause')
  .end(function (err, res) {
    if (err || !res.ok) return log('Found error %o', err || res.error);
    clauses.appendChild(render.dom(clause, {
      clause: res.body
    }));
  });
}<commit_msg>[admin-laws:law-form] - Parse clauses input names before sending on POST request<commit_after>/**
 * Module dependencies.
 */

var form = require('./form-template');
var clause = require('./form-clause');
var serialize = require('serialize');
var classes = require('classes');
var Emitter = require('emitter');
var request = require('request');
var regexps = require('regexps');
var events = require('events');
var render = require('render');
var empty = require('empty');
var tags = require('tags');
var o = require('query');
var t = require('t');
var log = require('debug')('democracyos:settings-password');

/**
 * Expose LawForm
 */

module.exports = LawForm;

/**
 * Creates a password edit view
 */

function LawForm(law) {
  if (!(this instanceof LawForm)) {
    return new LawForm(law);
  };

  if (law) {
    this.action = '/law/' + law.id;
    this.title = 'Edit law';
  } else {
    this.action = '/law/create';
    this.title = 'Create law';
  }

  this.law = law;

  this.formsubmit = this.formsubmit.bind(this);
  this.onsuccess = this.onsuccess.bind(this);
  this.onerror = this.onerror.bind(this);

  this.build();
  this.switchOn();
}

/**
 * Mixin with `Emitter`
 */

Emitter(LawForm.prototype);

/**
 * Build view's `this.el`
 */

LawForm.prototype.build = function() {
  this.el = render.dom(form, {
    form: { title: this.title, action: this.action },
    law: this.law || { clauses: [] },
    tags: tags.get()
  });
}

/**
 * Turn on event bindings
 */

LawForm.prototype.switchOn = function() {
  this.events = events(this.el, this);
  this.events.bind('submit form');
  this.events.bind('click a.add-clause', 'onaddclauseclick');
  this.on('submit', this.formsubmit);
  this.on('success', this.onsuccess);
  this.on('error', this.onerror);
}

/**
 * Turn off event bindings
 */

LawForm.prototype.switchOff = function() {
  this.events.unbind();
  this.off();
}

/**
 * Handle `onsubmit` form event
 *
 * @param {Event} ev
 * @api private
 */

LawForm.prototype.onsubmit = function(ev) {
  ev.preventDefault();

  // Clean errors list
  this.messages();

  // Serialize form
  var form = o('form', this.el);
  var data = serialize.object(form);

  this.parseClauses(data);

  // Check for errors in data
  var errors = this.validate(data);

  // If errors, show and exit
  if (errors.length) {
    return this.messages(errors);
  };

  // Deliver form submit
  this.emit('submit', data);
}

/**
 * Handle `submit` event to
 * perform POST request with
 * data
 *
 * @param {Event} ev
 * @api private
 */

LawForm.prototype.formsubmit = function(data) {
  var view = this;

  request
  .post('/api' + this.action)
  .send(data)
  .end(function(err, res) {
    if (err || !res.ok) {
      return log('Fetch error: %o', err || res.error), view.emit('error', res.body || res.text);
    };
    if (res.body && res.body.error) {
      return view.emit('error', res.body.error);
    };

    view.emit('success', res.body);
  });
}

/**
 * Handle `error` event with
 * logging and display
 *
 * @param {String} error
 * @api private
 */

LawForm.prototype.onerror = function(error) {
  log('Error: %o', error);
  this.messages([error]);
}

/**
 * Handle `error` event with
 * logging and display
 *
 * @param {String} error
 * @api private
 */

LawForm.prototype.onsuccess = function() {
  log('Law create successful');
  this.messages([t('Law successfuly saved')]);
}

/**
 * Validate form's fields
 *
 * @param {Object} data
 * @return {Array} of Errors
 * @api public
 */

LawForm.prototype.validate = function(data) {
  var errors = [];
  if (!data.lawId.length) {
    errors.push(t('Official Id required'));
  };
  if (!data.mediaTitle.length) {
    errors.push(t('Media title required'));
  };
  if (!data.source.length) {
    errors.push(t('Source required'));
  } else if (!regexps.url.test(data.source)) {
    errors.push(t('Source must be a valid url'));
  };
  return errors;
}

/**
 * Fill messages list
 *
 * @param {Array} msgs
 * @param {string} type
 * @api public
 */

LawForm.prototype.messages = function(msgs, type) {
  var ul = o('ul.form-messages', this.el);

  if (!arguments.length) return empty(ul), this;

  msgs.forEach(function(m) {
    if (!m) return;
    var li = document.createElement('li');
    li.innerHTML = m.message || m;
    classes(li).add(type || 'error');
    ul.appendChild(li);
  });
}

/**
 * Renders to provided `el`
 * or delivers view's `el`
 *
 * @param {Element} el
 * @return {LawForm|Element}
 * @api public
 */

LawForm.prototype.render = function(el) {
  if (1 === arguments.length) {

    // if string, then query element
    if ('string' === typeof el) {
      el = o(el);
    };

    // if it's not currently inserted
    // at `el`, then append to `el`
    if (el !== this.el.parentNode) {
      el.appendChild(this.el);
    };

    return this;
  };

  return this.el;
}

LawForm.prototype.onaddclauseclick = function(ev) {
  ev.preventDefault();

  var id = this.law ? this.law.id : null;
  if (id != null) return this.addClause();

  // if no law, reveal message forbidden
  classes(o('.add-clause-forbidden', this.el)).remove('hide');
}

LawForm.prototype.addClause = function() {
  var clauses = o('.law-clauses', this.el);

  request
  .post('/api' + this.action + '/clause')
  .end(function (err, res) {
    if (err || !res.ok) return log('Found error %o', err || res.error);
    clauses.appendChild(render.dom(clause, {
      clause: res.body
    }));
  });
}

LawForm.prototype.parseClauses = function(data) {
  data = data || {};
  var clauses = {};
  var regexp = /^clauses\[([a-z0-9]*)\]\[([^\]]*)\]/;

  for (var key in data) {
    var isClause = regexp.test(key)
      && data.hasOwnProperty(key);

    if (isClause) {
      var parsed = regexp.exec(key);
      var id = parsed[1];
      var prop = parsed[2];
      var value = data[key];
      clauses[id] = clauses[id] || {};
      clauses[id][prop] = value;
      delete data[key];
    }
  }

  var ids = Object.keys(clauses);
  var ret = [];

  ids.forEach(function(id) {
    clauses[id].id = id;
    ret.push(clauses[id]);
  });

  data.clauses = ret;
  return data;
}<|endoftext|>


<commit_before>var debug = require('debug')('rascal:SubscriberError')
var format = require('util').format
var _ = require('lodash').mixin({ 'defaultsDeep': require('merge-defaults') })
var async = require('async')

module.exports = function SubscriptionRecovery(broker, vhost) {

    this.handle = function(session, message, recoveryProcess, next) {

        debug('Handling subscriber error for message: %s', message.properties.messageId)

        async.eachSeries([].concat(recoveryProcess), function(recoveryConfig, cb) {
            debug('Attempting to recover message: %s using strategy: %s', message.properties.messageId, recoveryConfig.strategy)

            var once = _.once(cb)

            setTimeout(function() {
                getStrategy(recoveryConfig).execute(session, message, _.omit(recoveryConfig, 'defer'), function(err, handled) {
                    if (err) setImmediate(function() {
                        session.emit('error', err)
                    })
                    if (handled) {
                        debug('Message %s: was recovered using stagegy: %s', message.properties.messageId, recoveryConfig.strategy)
                        return next()
                    }
                    once()
                })
            }, recoveryConfig.defer)
        }, next)
    }

    function getStrategy(recoveryConfig) {
        return recoveryStrategies[recoveryConfig.strategy] || recoveryStrategies.unknown
    }

    var recoveryStrategies = _.indexBy([
        {
            name: 'ack',
            execute: function(session, message, strategyConfig, next) {
                session._ack(message)
                next(null, true)
            }
        },
        {
            name: 'nack',
            execute: function(session, message, strategyConfig, next) {
                session._nack(message, { requeue: strategyConfig.requeue })
                next(null, true)
            }
        },
        {
            name: 'republish',
            execute: function(session, message, strategyConfig, next) {
                debug('Republishing message: %s', message.properties.messageId)

                var republished = message.properties.headers.rascal && message.properties.headers.rascal.republished || 0

                if (strategyConfig.attempts && strategyConfig.attempts <= republished) {
                    debug('Skipping recovery - message: %s has already been republished %d times.', message.properties.messageId, republished)
                    return next(null, false)
                }

                var publishOptions = _.defaultsDeep(message.properties, { headers: { rascal: {} } })
                publishOptions.headers.rascal.republished = republished + 1
                publishOptions.headers.rascal.originalExchange = message.fields.exchange
                publishOptions.headers.rascal.originalRoutingKey = message.fields.routingKey

                vhost.getConfirmChannel(function(err, publisherChannel) {

                    publisherChannel.on('error', next)

                    publisherChannel.publish(undefined, message.properties.headers.rascal.originalQueue, message.content, publishOptions, function(err) {
                        if (err) return next(err)
                        debug('Message: %s was republished to queue: %s %d times', message.properties.messageId, message.properties.headers.rascal.originalQueue, publishOptions.headers.rascal.republished)
                        session._ack(message)
                        next(null, true)
                    })
                })
            }
        },
        {
            name: 'forward',
            execute: function(session, message, strategyConfig, next) {
                debug('Forwarding message: %s', message.properties.messageId)

                var forwarded = message.properties.headers.rascal && message.properties.headers.rascal.forwarded || 0

                if (strategyConfig.attempts && strategyConfig.attempts <= forwarded) {
                    debug('Skipping recovery - message: %s has already been forwarded %d times.', message.properties.messageId, forwarded)
                    return next(null, false)
                }

                // See https://github.com/rabbitmq/rabbitmq-server/issues/161
                if (strategyConfig.xDeathFix) delete message.properties.headers['x-death']

                broker.forward(strategyConfig.publication, message, strategyConfig.options || {}, function(err, publication) {
                    if (err) return next(err)
                    publication.on('success', function() {
                        debug('Message: %s was forwarded to publicaiton: %s %d times', message.properties.messageId, strategyConfig.publication, forwarded + 1)
                        session._ack(message)
                        next(null, true)
                    })
                    .on('error', next)
                    .on('return', function() {
                        next(new Error(format('Message: %s was forwared to publication: %s, but was returned', message.properties.messageId, strategyConfig.publication)))
                    })
                })
            }
        },
        {
            name: 'fallback',
            execute: function(session, message, strategyConfig, next) {
                session._nack(message, {})
                next(null, true)
            }
        },
        {
            name: 'unknown',
            execute: function(session, message, strategyConfig, next) {
                session.emit('error', new Error(format('Error recovering message: %s. No such strategy: %s.', message.properties.messageId, strategyConfig.strategy)))
                next()
            }
        }
    ], 'name')
}

<commit_msg>Fixing minor bug where channel handler was catching subscriber errors during recovery<commit_after>var debug = require('debug')('rascal:SubscriberError')
var format = require('util').format
var _ = require('lodash').mixin({ 'defaultsDeep': require('merge-defaults') })
var async = require('async')

module.exports = function SubscriptionRecovery(broker, vhost) {

    this.handle = function(session, message, recoveryProcess, next) {

        debug('Handling subscriber error for message: %s', message.properties.messageId)

        async.eachSeries([].concat(recoveryProcess), function(recoveryConfig, cb) {
            debug('Attempting to recover message: %s using strategy: %s', message.properties.messageId, recoveryConfig.strategy)

            var once = _.once(cb)

            setTimeout(function() {
                getStrategy(recoveryConfig).execute(session, message, _.omit(recoveryConfig, 'defer'), function(err, handled) {
                    if (err) setImmediate(function() {
                        session.emit('error', err)
                    })
                    if (handled) {
                        debug('Message %s: was recovered using stagegy: %s', message.properties.messageId, recoveryConfig.strategy)
                        return next()
                    }
                    once()
                })
            }, recoveryConfig.defer)
        }, next)
    }

    function getStrategy(recoveryConfig) {
        return recoveryStrategies[recoveryConfig.strategy] || recoveryStrategies.unknown
    }

    var recoveryStrategies = _.indexBy([
        {
            name: 'ack',
            execute: function(session, message, strategyConfig, next) {
                session._ack(message)
                next(null, true)
            }
        },
        {
            name: 'nack',
            execute: function(session, message, strategyConfig, next) {
                session._nack(message, { requeue: strategyConfig.requeue })
                next(null, true)
            }
        },
        {
            name: 'republish',
            execute: function(session, message, strategyConfig, next) {
                debug('Republishing message: %s', message.properties.messageId)

                var republished = message.properties.headers.rascal && message.properties.headers.rascal.republished || 0

                if (strategyConfig.attempts && strategyConfig.attempts <= republished) {
                    debug('Skipping recovery - message: %s has already been republished %d times.', message.properties.messageId, republished)
                    return next(null, false)
                }

                var publishOptions = _.defaultsDeep(message.properties, { headers: { rascal: {} } })
                publishOptions.headers.rascal.republished = republished + 1
                publishOptions.headers.rascal.originalExchange = message.fields.exchange
                publishOptions.headers.rascal.originalRoutingKey = message.fields.routingKey

                vhost.getConfirmChannel(function(err, publisherChannel) {

                    publisherChannel.on('error', next)

                    publisherChannel.publish(undefined, message.properties.headers.rascal.originalQueue, message.content, publishOptions, function(err) {
                        if (err) return next(err)
                        debug('Message: %s was republished to queue: %s %d times', message.properties.messageId, message.properties.headers.rascal.originalQueue, publishOptions.headers.rascal.republished)
                        session._ack(message)
                        next(null, true)
                    })
                })
            }
        },
        {
            name: 'forward',
            execute: function(session, message, strategyConfig, next) {
                debug('Forwarding message: %s', message.properties.messageId)

                var forwarded = message.properties.headers.rascal && message.properties.headers.rascal.forwarded || 0

                if (strategyConfig.attempts && strategyConfig.attempts <= forwarded) {
                    debug('Skipping recovery - message: %s has already been forwarded %d times.', message.properties.messageId, forwarded)
                    return next(null, false)
                }

                // See https://github.com/rabbitmq/rabbitmq-server/issues/161
                if (strategyConfig.xDeathFix) delete message.properties.headers['x-death']

                broker.forward(strategyConfig.publication, message, strategyConfig.options || {}, function(err, publication) {
                    if (err) return next(err)
                    publication.on('success', function() {
                        debug('Message: %s was forwarded to publicaiton: %s %d times', message.properties.messageId, strategyConfig.publication, forwarded + 1)
                        session._ack(message)
                        next(null, true)
                    })
                    .on('error', next)
                    .on('return', function() {
                        next(new Error(format('Message: %s was forwared to publication: %s, but was returned', message.properties.messageId, strategyConfig.publication)))
                    })
                })
            }
        },
        {
            name: 'fallback',
            execute: function(session, message, strategyConfig, next) {
                session._nack(message, {})
                next(null, true)
            }
        },
        {
            name: 'unknown',
            execute: function(session, message, strategyConfig, next) {
                next(new Error(format('Error recovering message: %s. No such strategy: %s.', message.properties.messageId, strategyConfig.strategy)))
            }
        }
    ], 'name')
}

<|endoftext|>


<commit_before>/**
 * Module dependencies
 */

var rc = require('rc');

/**
 * Locate and load a .sailsrc file if one exists.
 *
 * NOTE: this occurs almost immediately when sails is required,
 * and since `rc` is synchronous, the examination of env variables,
 * cmdline opts, and .sailsrc files is immediate, and happens only once.
 *
 * @type {Object}
 */
module.exports = rc('sails');
<commit_msg>Humanize config vars that are loaded from the environment.<commit_after>/**
 * Module dependencies
 */
var _ = require('lodash');
var rc = require('rc');
var rttc = require('rttc');

/**
 * Locate and load .sailsrc files if they exist.
 *
 * NOTE: this occurs almost immediately when sails is required,
 * and since `rc` is synchronous, the examination of env variables,
 * cmdline opts, and .sailsrc files is immediate, and happens only once.
 *
 * @type {Object}
 */
var conf = rc('sails');

// Load in overrides from the environment, using `rttc.parseHuman` to
// guesstimate the types.
// NOTE -- the code below is lifted from the `rc` module, and modified to:
//  1. Pass JSHint
//  2. Run parseHuman on values
// If at some point `rc` exposes metadata about which configs came from
// the environment, we can simplify our code by just running `parseHuman`
// on those values instead of doing the work to pluck them from the env.
var env = (function () {
  var env = process.env;
  var prefix = 'sails_';
  var obj = {};
  var l = prefix.length;
  _.each(_.keys(env), function(k) {
    if((k.indexOf(prefix)) === 0) {

      var keypath = k.substring(l).split('__');

      // Trim empty strings from keypath array
      var _emptyStringIndex;
      while ((_emptyStringIndex=keypath.indexOf('')) > -1) {
        keypath.splice(_emptyStringIndex, 1);
      }

      var cursor = obj;
      _.each(keypath, function _buildSubObj(_subkey,i){

        // (check for _subkey first so we ignore empty strings)
        if (!_subkey) {
          return;
        }

        // If this is the last key, just stuff the value in there
        // Assigns actual value from env variable to final key
        // (unless it's just an empty string- in that case use the last valid key)
        if (i === keypath.length-1){
          try {
            cursor[_subkey] = rttc.parseHuman(env[k], 'json');
          } catch(e) {
            cursor[_subkey] = rttc.parseHuman(env[k]);
          }
        }

        // Build sub-object if nothing already exists at the keypath
        if (cursor[_subkey] === undefined){
          cursor[_subkey] = {};
        }

        // Increment cursor used to track the object at the current depth
        cursor = cursor[_subkey];

      });

    }

  });
  return obj;
})();

// Merge the humanized environment vars into the config we loaded via `rc`.
conf = _.merge(conf, env);

// Expose the final conf object to the world.
module.exports = conf;
<|endoftext|>


<commit_before>import React from 'react'
import moment from 'moment'
import Helmet from 'react-helmet'

import FlightTracker from 'src/lib/FlightTracker'
import People        from 'src/lib/People'

import { getFirebase } from 'src/lib/firebaseAdapter'

import {
  DatePicker,
  FlightsForm,
  OldLeaderboard,
  UserPicker,
} from 'src/components'

export class FlightTrackerPage extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      entryDate: moment(),
      person: People.get(0),
    }
  }

  componentDidMount() {
    getFirebase().auth().onAuthStateChanged(user => {
      if (user) {
        getFirebase().database()
          .ref(`users/${user.uid}`)
          .on('value', snapshot => {
            this.setState({ user: snapshot.val() })
          })
      }
    })
  }

  onEntryDateChanged = (entryDate) => {
    this.setState({ entryDate })
  }

  onFlightsChanged = (flights) => {
    this.state.person.flightsClimbed.set(this.state.entryDate, flights)
    this.setState({
      person: this.state.person,
    })
  }

  onPersonChanged = (person) => {
    this.setState({ person })
  }

  render() {
    return (

        {<Helmet title="Home" />}

StepUp

        {this.state.user &&
Hello {this.state.user.name}!
}
        <UserPicker user={this.state.person} onChange={this.onPersonChanged} />

        <DatePicker
          selected={this.state.entryDate}
          onChange={this.onEntryDateChanged}
        />
        <FlightsForm
          homeFloor={this.state.person.homeFloor}
          value={this.state.person.flightsClimbed.get(this.state.entryDate)}
          onChange={this.onFlightsChanged}
        />

        <OldLeaderboard people={People} flightTracker={FlightTracker} />

    )
  }
}
<commit_msg>Use firebase to get/set flights<commit_after>import React from 'react'
import moment from 'moment'
import Helmet from 'react-helmet'

import FlightTracker from 'src/lib/FlightTracker'
import People        from 'src/lib/People'

import { getFirebase } from 'src/lib/firebaseAdapter'

import {
  DatePicker,
  FlightsForm,
  /* OldLeaderboard,
   * UserPicker,*/
} from 'src/components'

export class FlightTrackerPage extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      entryDate: moment(),
      person: People.get(0),
    }
  }

  componentDidMount() {
    getFirebase().auth().onAuthStateChanged(user => {
      if (user) {
        getFirebase().database()
          .ref(`users/${user.uid}`)
          .on('value', snapshot => {
            this.setState({ user: Object.assign({}, snapshot.val(), { uid: user.uid }) })
            this.getFlightsClimbed(this.state.user.uid, this.state.entryDate.format('YYYY-MM-DD'))
          })
      }
    })
  }

  onEntryDateChanged = (entryDate) => {
    this.setState({ entryDate })
  }

  onFlightsChanged = (flights) => {
    this.state.person.flightsClimbed.set(this.state.entryDate, flights)
    this.setState({
      person: this.state.person,
    })
    this.setFlightsClimbed(flights, this.state.user.uid, this.state.entryDate.format('YYYY-MM-DD'))
  }

  onPersonChanged = (person) => {
    this.setState({ person })
  }

  getFlightsClimbed = (uid, date) => {
    getFirebase().database()
                 .ref(`flights/${uid}/${date}`)
                 .once('value')
                 .then(snapshot => {
                   const data = snapshot.val()
                   console.log('Getting:', `flights/${uid}/${date}`, data)
                   this.state.person.flightsClimbed.set(this.state.entryDate, data.flights_climbed)
                   this.setState({
                     person: this.state.person,
                   })
                 })
  }

  setFlightsClimbed = (flights, uid, date) => {
    console.log('Storing:', `flights/${uid}/${date}`, flights)
    getFirebase().database()
           .ref(`flights/${uid}/${date}`)
           .update({ flights_climbed: flights })
  }

  render() {
    return (

        {<Helmet title="Home" />}

StepUp

        {this.state.user &&
Hello {this.state.user.name}!
}

        <DatePicker
          selected={this.state.entryDate}
          onChange={this.onEntryDateChanged}
        />
        <FlightsForm
          homeFloor={this.state.person.homeFloor}
          value={this.state.person.flightsClimbed.get(this.state.entryDate)}
          onChange={this.onFlightsChanged}
        />

    )
  }
}
<|endoftext|>


<commit_before>var md5                    = require('MD5'),
    _                      = require('lodash'),
    AuthenticationAbstract = require('./authentication-abstract.js');

/**
 * use oauth for authentication
 * @param {Object}  options
 * @param {String}  options.clientId
 * @param {String}  options.clientSecret
 * @param {String} [options.grantType]
 * @param {String} [options.scope]
 * @constructor
 */
function AuthenticationOAuth(options){
    AuthenticationAbstract.call(this, options);
    options            = options || {};
    this._clientId     = options.clientId;
    this._clientSecret = options.clientSecret;
    this._grantType    = options.grantType || 'password';
    this._scope        = options.scope || 'send sender receive phonebook statistic wallet.credits subuser hlr';
    this._token        = null;
}

AuthenticationOAuth.prototype = Object.create(AuthenticationAbstract.prototype);

/**
 * @param  {String} username
 * @param  {String} password
 * @return {Promise}
 */
AuthenticationOAuth.prototype.login = function(username, password){
    return this.loginHashed(username, md5(password));
};

/**
 * @param  {String} username
 * @param  {String} hashedPassword
 * @return {Promise}
 */
AuthenticationOAuth.prototype.loginHashed = function(username, hashedPassword){
    var that = this;

    var data = {
        username:      username,
        password:      hashedPassword,
        client_id:     this._clientId,
        client_secret: this._clientSecret,
        grant_type:    this._grantType,
        scope:         this._scope
    };

    var promise = this.proxy().request()
        .path('oauth/token')
        .data(data)
        .json()
        .execute();

    promise.then(function(result){
        that.setToken({
            access: result.access_token,
            refresh: result.refresh_token,
            expires: result.expires
        });
    });

    return promise;
};

/**
 * @return {Promise}
 */
AuthenticationOAuth.prototype.refreshToken = function(){
    var that = this;

    var data = {
        client_id:      this._clientId,
        client_secret:  this._clientSecret,
        grant_type:     'refresh_token',
        refresh_token:  this.getRefreshToken()
    };

    var promise = this.proxy().request()
        .path('oauth/token')
        .data(data)
        .json()
        .execute();

    promise.then(function(result){
        that.setToken({
            access: result.access_token,
            refresh: result.refresh_token,
            expires: result.expires
        });
    });

    return promise;
};

/**
 *
 * @param {String} token
 * @returns {AuthenticationOAuth}
 */
AuthenticationOAuth.prototype.setToken = function(token){
    this._token = token;
    return this;
};

/**
 *
 * @returns {null|String}
 */
AuthenticationOAuth.prototype.getToken = function(){
    return this._token;
};

/**
 *
 * @returns {null|String}
 */
AuthenticationOAuth.prototype.getAccessToken = function(){
    return this._token ? this._token.access : null;
};

/**
 *
 * @returns {null|String}
 */
AuthenticationOAuth.prototype.getRefreshToken = function(){
    return this._token ? this._token.refresh : null;
};

/**
 *
 * @returns {boolean}
 */
AuthenticationOAuth.prototype.isAuthorized = function(){
    if (this._token)
        return this._token.expires > (new Date()).getTime() / 1000;
    else
        return false;
};

/**
 *
 * @returns {{access_token: (null|String)}}
 */
AuthenticationOAuth.prototype.getPOSTParams = function(){
    return {
        access_token: this.getAccessToken()
    };
};

/**
 *
 * @returns {{Authorization: String}|{}}
 */
AuthenticationOAuth.prototype.getHeaders = function(){
    return this.getAccessToken() ? {
        Authorization: 'Bearer ' + this.getAccessToken()
    } : {};
};

/**
 *
 * @returns {AuthenticationOAuth}
 */
AuthenticationOAuth.prototype.logout = function(){
    this._token = null;
    return this;
};

module.exports = AuthenticationOAuth;
<commit_msg>Fix md5 lib name (use lowercase)<commit_after>var md5                    = require('md5'),
    _                      = require('lodash'),
    AuthenticationAbstract = require('./authentication-abstract.js');

/**
 * use oauth for authentication
 * @param {Object}  options
 * @param {String}  options.clientId
 * @param {String}  options.clientSecret
 * @param {String} [options.grantType]
 * @param {String} [options.scope]
 * @constructor
 */
function AuthenticationOAuth(options){
    AuthenticationAbstract.call(this, options);
    options            = options || {};
    this._clientId     = options.clientId;
    this._clientSecret = options.clientSecret;
    this._grantType    = options.grantType || 'password';
    this._scope        = options.scope || 'send sender receive phonebook statistic wallet.credits subuser hlr';
    this._token        = null;
}

AuthenticationOAuth.prototype = Object.create(AuthenticationAbstract.prototype);

/**
 * @param  {String} username
 * @param  {String} password
 * @return {Promise}
 */
AuthenticationOAuth.prototype.login = function(username, password){
    return this.loginHashed(username, md5(password));
};

/**
 * @param  {String} username
 * @param  {String} hashedPassword
 * @return {Promise}
 */
AuthenticationOAuth.prototype.loginHashed = function(username, hashedPassword){
    var that = this;

    var data = {
        username:      username,
        password:      hashedPassword,
        client_id:     this._clientId,
        client_secret: this._clientSecret,
        grant_type:    this._grantType,
        scope:         this._scope
    };

    var promise = this.proxy().request()
        .path('oauth/token')
        .data(data)
        .json()
        .execute();

    promise.then(function(result){
        that.setToken({
            access: result.access_token,
            refresh: result.refresh_token,
            expires: result.expires
        });
    });

    return promise;
};

/**
 * @return {Promise}
 */
AuthenticationOAuth.prototype.refreshToken = function(){
    var that = this;

    var data = {
        client_id:      this._clientId,
        client_secret:  this._clientSecret,
        grant_type:     'refresh_token',
        refresh_token:  this.getRefreshToken()
    };

    var promise = this.proxy().request()
        .path('oauth/token')
        .data(data)
        .json()
        .execute();

    promise.then(function(result){
        that.setToken({
            access: result.access_token,
            refresh: result.refresh_token,
            expires: result.expires
        });
    });

    return promise;
};

/**
 *
 * @param {String} token
 * @returns {AuthenticationOAuth}
 */
AuthenticationOAuth.prototype.setToken = function(token){
    this._token = token;
    return this;
};

/**
 *
 * @returns {null|String}
 */
AuthenticationOAuth.prototype.getToken = function(){
    return this._token;
};

/**
 *
 * @returns {null|String}
 */
AuthenticationOAuth.prototype.getAccessToken = function(){
    return this._token ? this._token.access : null;
};

/**
 *
 * @returns {null|String}
 */
AuthenticationOAuth.prototype.getRefreshToken = function(){
    return this._token ? this._token.refresh : null;
};

/**
 *
 * @returns {boolean}
 */
AuthenticationOAuth.prototype.isAuthorized = function(){
    if (this._token)
        return this._token.expires > (new Date()).getTime() / 1000;
    else
        return false;
};

/**
 *
 * @returns {{access_token: (null|String)}}
 */
AuthenticationOAuth.prototype.getPOSTParams = function(){
    return {
        access_token: this.getAccessToken()
    };
};

/**
 *
 * @returns {{Authorization: String}|{}}
 */
AuthenticationOAuth.prototype.getHeaders = function(){
    return this.getAccessToken() ? {
        Authorization: 'Bearer ' + this.getAccessToken()
    } : {};
};

/**
 *
 * @returns {AuthenticationOAuth}
 */
AuthenticationOAuth.prototype.logout = function(){
    this._token = null;
    return this;
};

module.exports = AuthenticationOAuth;
<|endoftext|>


<commit_before>const SekshiModule = require('../Module')
const debug = require('debug')('sekshi:stuck-skip')

export default class StuckSkip extends SekshiModule {

  constructor(sekshi, options) {
    super(sekshi, options)

    this.author = 'ReAnna'
    this.version = '1.0.0'
    this.description = 'Skips songs when plug.dj forgets to push advance messages.'

    this.onAdvance = this.onAdvance.bind(this)
    this._skip = this._skip.bind(this)
  }

  defaultOptions() {
    return {
      delay: 3.0
    }
  }

  init() {
    this.sekshi.on(this.sekshi.ADVANCE, this.onAdvance)
  }

  destroy() {
    clearTimeout(this._timer)
    this.sekshi.removeListener(this.sekshi.ADVANCE, this.onAdvance)
  }

  onAdvance(booth, { media }, previous) {
    clearTimeout(this._timer)
    if (media) {
      let delay = parseFloat(this.options.delay)
      this._timer = setTimeout(this._skip, (media.duration + delay) * 1000)
    }
  }

  _skip() {
    this.sekshi.sendChat('/me Song stuck, skipping...')
    this.sekshi.skipDJ(this.sekshi.getCurrentDJ().id)
  }

}<commit_msg>stuckskip: auto-delete stuck skip message<commit_after>const SekshiModule = require('../Module')
const debug = require('debug')('sekshi:stuck-skip')

export default class StuckSkip extends SekshiModule {

  constructor(sekshi, options) {
    super(sekshi, options)

    this.author = 'ReAnna'
    this.version = '1.0.0'
    this.description = 'Skips songs when plug.dj forgets to push advance messages.'

    this.onAdvance = this.onAdvance.bind(this)
    this._skip = this._skip.bind(this)
  }

  defaultOptions() {
    return {
      delay: 3.0
    }
  }

  init() {
    this.sekshi.on(this.sekshi.ADVANCE, this.onAdvance)
  }

  destroy() {
    clearTimeout(this._timer)
    this.sekshi.removeListener(this.sekshi.ADVANCE, this.onAdvance)
  }

  onAdvance(booth, { media }, previous) {
    clearTimeout(this._timer)
    if (media) {
      let delay = parseFloat(this.options.delay)
      this._timer = setTimeout(this._skip, (media.duration + delay) * 1000)
    }
  }

  _skip() {
    this.sekshi.sendChat('/me Song stuck, skipping...', 5000)
    this.sekshi.skipDJ(this.sekshi.getCurrentDJ().id)
  }

}<|endoftext|>