<commit_before>
function createTransactionFactory() {

    const _createTransaction = function(transactionId, type, transactionHandler) {

        let _ready = false;

        let _processing = false;

        let _failed = false;

        let _errors = [];

        let _validationErrors = null;

        const _handleTransactionReady = function() {
            _ready = true;
            _processing = false;
            _failed = false;
            _errors = [];
            _validationErrors = null;
        },

        const _handleTransactionCanceled = function() {
            _ready = false;
            _processing = false;
            _failed = false;
        },

        const _handleTransactionFailed = function(errors, meta) {
            _ready = true;
            _processing = false;
            _failed = true;
            _errors = errors.slice(0);
            _validationErrors = {};
            if (meta.hasOwnProperty('validationErrors')) {
                for (var key in meta.validationErrors) {
                    _validationErrors[key] = meta.validationErrors[key];
                }
            }
        },

        return {

            transactionId: function() {
                return transactionId;
            },

            type: function() {
                return type;
            },

            start: function() {
                if (!this.processing()) {
                    _ready = false;
                    _processing = true;
                    _errors = [];
                    _validationErrors = {};
                    transactionHandler.start({
                        onReady: _handleTransactionReady,
                        onFailed: _handleTransactionFailed
                    });
                }
            },

            cancel: function() {
                if (this.processing()) {
                    transactionHandler.cancel({
                        onCanceled: _handleTransactionCanceled
                    });
                }
            },

            ready: function() {
                return _ready;
            },

            processing: function() {
                return _processing;
            },

            failed: function() {
                return _failed;
            },

            hasErrors: function() {
                return (_errors.length > 0);
            },

            errors: function() {
                return _errors;
            },

            hasValidationErrors: function() {
                return (Object.keys(_validationErrors).length > 0);
            },

            validationErrors: function() {
                return _validationErrors;
            }
        }
    }

    return {

        createTransaction: _createTransaction,

    };

}

export default createTransactionFactory;
<commit_msg>reset failed before on start<commit_after>
function createTransactionFactory() {

    const _createTransaction = function(transactionId, type, transactionHandler) {

        let _ready = false;

        let _processing = false;

        let _failed = false;

        let _errors = [];

        let _validationErrors = null;

        const _handleTransactionReady = function() {
            _ready = true;
            _processing = false;
            _failed = false;
            _errors = [];
            _validationErrors = null;
        },

        const _handleTransactionCanceled = function() {
            _ready = false;
            _processing = false;
            _failed = false;
        },

        const _handleTransactionFailed = function(errors, meta) {
            _ready = true;
            _processing = false;
            _failed = true;
            _errors = errors.slice(0);
            _validationErrors = {};
            if (meta.hasOwnProperty('validationErrors')) {
                for (var key in meta.validationErrors) {
                    _validationErrors[key] = meta.validationErrors[key];
                }
            }
        },

        return {

            transactionId: function() {
                return transactionId;
            },

            type: function() {
                return type;
            },

            start: function() {
                if (!this.processing()) {
                    _ready = false;
                    _processing = true;
                    _failed = false;
                    _errors = [];
                    _validationErrors = {};
                    transactionHandler.start({
                        onReady: _handleTransactionReady,
                        onFailed: _handleTransactionFailed
                    });
                }
            },

            cancel: function() {
                if (this.processing()) {
                    transactionHandler.cancel({
                        onCanceled: _handleTransactionCanceled
                    });
                }
            },

            ready: function() {
                return _ready;
            },

            processing: function() {
                return _processing;
            },

            failed: function() {
                return _failed;
            },

            hasErrors: function() {
                return (_errors.length > 0);
            },

            errors: function() {
                return _errors;
            },

            hasValidationErrors: function() {
                return (Object.keys(_validationErrors).length > 0);
            },

            validationErrors: function() {
                return _validationErrors;
            }
        }
    }

    return {

        createTransaction: _createTransaction,

    };

}

export default createTransactionFactory;
<|endoftext|>


<commit_before>"use strict";
define(['./Element'],function(element){
	return element.extend({
		getConfig:function(obj,column,recordActions){
			var self = this;
			var field = openbiz.Element.prototype.getConfig.call(this,obj,column);
			{
				if(recordActions.length > 0){
					field.cell = openbiz.Grid.UriCell.extend({
						render:function(){
							this.$el.empty();
							var model = this.model;
							var value = model.get("_id");
							var html = "
";
							for (var i in recordActions){
								var recordAction = recordActions[i];
								var displayName = 'recordAction'+recordAction.name.charAt(0).toUpperCase() + recordAction.name.slice(1);
								if(self._hasPermission(recordAction.permission))
								{
									var isEnabled = self._getEnableText(recordAction["name"],obj.model!=null?obj.model:model,obj.model!=null?true:false);
									var label = obj.locale[displayName]?obj.locale[displayName]: recordAction.displayName;
									switch(recordAction.type.toLowerCase()){
										case "link":
										{
											var url = recordAction.url.replace(":id","{{ id }}");
											var className;
											if(typeof recordAction.className!='undefined' && recordAction.className!=""){
												className = recordAction.className;
												if(className.indexOf("btn-")==-1)className += " btn-default";
											}else{
												className = "btn-default";
											}
											url = "#!/backend/"+obj.app.name+url
											html = html + ""+label+""+"&nbsp";
											break;
										}
										case "button":
										{
											var className = "rec-act-"+recordAction.name.toLowerCase();
											if(typeof recordAction.className!='undefined' && recordAction.className!="" ){
												className += " "+recordAction.className;
												if(className.indexOf("btn-")==-1)className += " btn-default";
											}else{
												className += " btn-default";
											}
											html = html + ""+label+""+"&nbsp";
											break;
										}
										default:
										{
											break;
										}
									}
								}
							}
							html = html + "
";
							this.$el.html( _.template(
								html,
								{id:value},
								{interpolate: /\{\{(.+?)\}\}/g}) );
							this.delegateEvents();
							return this;
						}
					});
				}
			}
			return field;
		},
		_getEnableText:function(action,model,isSubDoc){
			if(_.isUndefined(model.get("_metadata")))
				return "";
			var state = model.get("_metadata").state
			var text = "";

			if(action == "edit"){
				if(state.writable == false){
					text = " disabled='disabled'";
				}
			}else if(action == "delete"){
				if(state.deletable==false){
					text = " disabled='disabled'";
				}
				if(isSubDoc){
					if(state.writable == false){
						text = " disabled='disabled'";
					}
				}
			}
			return text;
		},
		_hasPermission:function(permission){
			if(typeof permission != 'undefined' && permission){
				return openbiz.session.me.hasPermission(permission);
			}
			return true;
		}
	});
});<commit_msg>update invitations and members<commit_after>"use strict";
define(['./Element'],function(element){
	return element.extend({
		getConfig:function(obj,column,recordActions){
			var self = this;
			var field = openbiz.Element.prototype.getConfig.call(this,obj,column);
			{
				if(recordActions.length > 0){
					field.cell = openbiz.Grid.UriCell.extend({
						render:function(){
							this.$el.empty();
							var model = this.model;
							var value = model.get("_id");
							var html = "
";
							for (var i in recordActions){
								var recordAction = recordActions[i];
								var displayName = 'recordAction'+recordAction.name.charAt(0).toUpperCase() + recordAction.name.slice(1);
								if(self._hasPermission(recordAction.permission))
								{
									var isEnabled = self._getEnableText(recordAction["name"],obj.model!=null?obj.model:model,obj.model!=null?true:false);
									var label = obj.locale[displayName]?obj.locale[displayName]: recordAction.displayName;
									switch(recordAction.type.toLowerCase()){
										case "link":
										{
											var url = recordAction.url.replace(":id","{{ id }}");
											var className;
											if(typeof recordAction.className!='undefined' && recordAction.className!=""){
												className = recordAction.className;
												if(className.indexOf("btn-")==-1)className += " btn-default";
											}else{
												className = "btn-default";
											}
											url = "#!/backend"+ (obj.app.name=='cubi'?'':'/'+obj.app.name)+url;
											html = html + ""+label+""+"&nbsp";
											break;
										}
										case "button":
										{
											var className = "rec-act-"+recordAction.name.toLowerCase();
											if(typeof recordAction.className!='undefined' && recordAction.className!="" ){
												className += " "+recordAction.className;
												if(className.indexOf("btn-")==-1)className += " btn-default";
											}else{
												className += " btn-default";
											}
											html = html + ""+label+""+"&nbsp";
											break;
										}
										default:
										{
											break;
										}
									}
								}
							}
							html = html + "
";
							this.$el.html( _.template(
								html,
								{id:value},
								{interpolate: /\{\{(.+?)\}\}/g}) );
							this.delegateEvents();
							return this;
						}
					});
				}
			}
			return field;
		},
		_getEnableText:function(action,model,isSubDoc){
			if(_.isUndefined(model.get("_metadata")))
				return "";
			var state = model.get("_metadata").state
			var text = "";

			if(action == "edit"){
				if(state.writable == false){
					text = " disabled='disabled'";
				}
			}else if(action == "delete"){
				if(state.deletable==false){
					text = " disabled='disabled'";
				}
				if(isSubDoc){
					if(state.writable == false){
						text = " disabled='disabled'";
					}
				}
			}
			return text;
		},
		_hasPermission:function(permission){
			if(typeof permission != 'undefined' && permission){
				return openbiz.session.me.hasPermission(permission);
			}
			return true;
		}
	});
});<|endoftext|>


<commit_before>/*jshint strict: false */
/*global require */

////////////////////////////////////////////////////////////////////////////////
/// @brief user management
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var arangodb = require("org/arangodb");
var actions = require("org/arangodb/actions");
var users = require("org/arangodb/users");

// -----------------------------------------------------------------------------
// --SECTION--                                                 private functions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief fetches a user
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @COMMENT{######################################################################}
/// @anchor HttpUserDocument
/// @startDocuBlock JSF_api_user_fetch
///
/// @RESTHEADER{GET /_api/user/{user}, Fetch User}
///
/// @RESTDESCRIPTION
///
/// Fetches data about the specified user.
///
/// The call will return a JSON document with at least the following attributes on success:
///
/// * *user*: The name of the user as a string.
/// * *active*: An optional flag that specifies whether the user is active.
/// * *extra*: An optional JSON object with arbitrary extra data about the user.
/// * *changePassword*: An optional flag that specifies whether the user must
///   change the password or not.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{200}
/// The user was found
///
/// @RESTRETURNCODE{404}
/// The user with user does not exist
///
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////

function get_api_user (req, res) {
  if (req.suffix.length === 0) {
    actions.resultOk(req, res, actions.HTTP_OK, { result: users.all() });
    return;
  }

  if (req.suffix.length !== 1) {
    actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
    return;
  }

  var user = decodeURIComponent(req.suffix[0]);

  try {
    actions.resultOk(req, res, actions.HTTP_OK, users.document(user));
  }
  catch (err) {
    if (err.errorNum === arangodb.errors.ERROR_USER_NOT_FOUND.code) {
      actions.resultNotFound(req, res, arangodb.errors.ERROR_USER_NOT_FOUND.code);
    }
    else {
      throw err;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief creates a new user
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @COMMENT{######################################################################}
/// @anchor HttpUserSave
/// @startDocuBlock JSF_api_user_create
///
/// @RESTHEADER{POST /_api/user, Create User}
///
/// @RESTDESCRIPTION
///
/// The following data need to be passed in a JSON representation in the body
/// of the POST request:
///
/// * *user*: The name of the user as a string. This is mandatory
/// * *passwd*: The user password as a string. If no password is specified,
///   the empty string will be used
/// * *active*: An optional flag that specifies whether the user is active.
///   If not specified, this will default to true
/// * *extra*: An optional JSON object with arbitrary extra data about the user
/// * *changePassword*: An optional flag that specifies whethers the user must
///   change the password or not. If not specified, this will default to false
///
/// If set to true, the only operations allowed are PUT /_api/user or PATCH /_api/user.
/// All other operations will result in a HTTP 403.
/// If the user can be added by the server, the server will respond with HTTP 201.
/// In case of success, the returned JSON object has the following properties:
///
/// * *error*: Boolean flag to indicate that an error occurred (false in this case)
/// * *code*: The HTTP status code
///
/// If the JSON representation is malformed or mandatory data is missing from the request,
/// the server will respond with HTTP 400.
///
/// The body of the response will contain a JSON object with additional error details.
/// The object has the following attributes:
///
/// * *error*: Boolean flag to indicate that an error occurred (true in this case)
/// * *code*: The HTTP status code
/// * *errorNum*: The server error number
/// * *errorMessage*: A descriptive error message
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{201}
/// Returned if the user can be added by the server
///
/// @RESTRETURNCODE{400}
/// If the JSON representation is malformed or mandatory data is missing from the request.
///
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////

function post_api_user (req, res) {
  var json = actions.getJsonBody(req, res, actions.HTTP_BAD);

  if (json === undefined) {
    return;
  }

  var user;

  if (req.suffix.length === 1) {
    // validate if a combination or username / password is valid
    user = decodeURIComponent(req.suffix[0]);
    var result = users.isValid(user, json.passwd);

    if (result) {
      actions.resultOk(req, res, actions.HTTP_OK, { result: true });
    }
    else {
      actions.resultNotFound(req, res, arangodb.errors.ERROR_USER_NOT_FOUND.code);
    }
    return;
  }

  if (req.suffix.length !== 0) {
    // unexpected URL
    actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
    return;
  }

  user = json.user;

  if (user === undefined && json.hasOwnProperty("username")) {
    // deprecated usage
    user = json.username;
  }

  var doc = users.save(user, json.passwd, json.active, json.extra, json.changePassword);

  if (json.passwordToken) {
    users.setPasswordToken(user, json.passwordToken);
  }
  users.reload();

  actions.resultOk(req, res, actions.HTTP_CREATED, doc);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief replaces an existing user
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_api_user_replace
///
/// @RESTHEADER{PUT /_api/user/{user}, Replace User}
///
/// @RESTDESCRIPTION
///
/// Replaces the data of an existing user. The name of an existing user must be specified in user.
///
/// The following data can to be passed in a JSON representation in the body of the POST request:
///
/// * *passwd*: The user password as a string. Specifying a password is mandatory,
///   but the empty string is allowed for passwords
/// * *active*: An optional flag that specifies whether the user is active.
///   If not specified, this will default to true
/// * *extra*: An optional JSON object with arbitrary extra data about the user
/// * *changePassword*: An optional flag that specifies whether the user must change
///   the password or not. If not specified, this will default to false
///
/// If the user can be replaced by the server, the server will respond with HTTP 200.
///
/// In case of success, the returned JSON object has the following properties:
///
/// * *error*: Boolean flag to indicate that an error occurred (false in this case)
/// * *code*: The HTTP status code
///
/// If the JSON representation is malformed or mandatory data is missing from the request,
/// the server will respond with HTTP 400. If the specified user does not exist,
/// the server will respond with HTTP 404.
///
/// The body of the response will contain a JSON object with additional
/// error details. The object has the following attributes:
///
/// * *error*: Boolean flag to indicate that an error occurred (true in this case)
/// * *code*: The HTTP status code
/// * *errorNum*: The server error number
/// * *errorMessage*: A descriptive error message
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{200}
/// Is returned if the user data can be replaced by the server
///
/// @RESTRETURNCODE{400}
/// The JSON representation is malformed or mandatory data is missing from the request
///
/// @RESTRETURNCODE{404}
/// The specified user does not exist
///
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////

function put_api_user (req, res) {
  if (req.suffix.length !== 1) {
    actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
    return;
  }

  var user = decodeURIComponent(req.suffix[0]);

  var json = actions.getJsonBody(req, res, actions.HTTP_BAD);

  if (json === undefined) {
    return;
  }

  try {
    var doc = users.replace(user, json.passwd, json.active, json.extra, json.changePassword);
    users.reload();

    actions.resultOk(req, res, actions.HTTP_OK, doc);
  }
  catch (err) {
    if (err.errorNum === arangodb.errors.ERROR_USER_NOT_FOUND.code) {
      actions.resultNotFound(req, res, arangodb.errors.ERROR_USER_NOT_FOUND.code);
    }
    else {
      throw err;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief partially updates an existing user
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @COMMENT{######################################################################}
/// @anchor HttpUserUpdate
/// @startDocuBlock JSF_api_user_update
///
/// @RESTHEADER{PATCH /_api/user/{user}, Update User}
///
/// @RESTDESCRIPTION
///
/// Partially updates the data of an existing user. The name of an existing
/// user must be specified in user.
///
/// The following data can be passed in a JSON representation in the body of the
/// POST request:
///
/// * *passwd*: The user password as a string. Specifying a password is optional.
///   If not specified, the previously existing value will not be modified.
/// * *active*: An optional flag that specifies whether the user is active.
///   If not specified, the previously existing value will not be modified.
/// * *extra*: An optional JSON object with arbitrary extra data about the user.
///   If not specified, the previously existing value will not be modified.
/// * *changePassword*: An optional flag that specifies whether the user must change
///   the password or not. If not specified, the previously existing value will not be modified.
///
/// If the user can be updated by the server, the server will respond with HTTP 200.
///
/// In case of success, the returned JSON object has the following properties:
///
/// * *error*: Boolean flag to indicate that an error occurred (false in this case)
/// * *code*: The HTTP status code
///
/// If the JSON representation is malformed or mandatory data is missing from the request,
/// the server will respond with HTTP 400. If the specified user does not exist,
/// the server will respond with HTTP 404.
///
/// The body of the response will contain a JSON object with additional error details.
/// The object has the following attributes:
///
/// * *error*: Boolean flag to indicate that an error occurred (true in this case)
/// * *code*: The HTTP status code
/// * *errorNum*: The server error number
/// * *errorMessage*: A descriptive error message
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{200}
/// Is returned if the user data can be replaced by the server
///
/// @RESTRETURNCODE{400}
/// The JSON representation is malformed or mandatory data is missing from the request
///
/// @RESTRETURNCODE{404}
/// The specified user does not exist
///
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////

function patch_api_user (req, res) {
  if (req.suffix.length !== 1) {
    actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
    return;
  }

  var user = decodeURIComponent(req.suffix[0]);
  var json = actions.getJsonBody(req, res, actions.HTTP_BAD);

  if (json === undefined) {
    return;
  }

  try {
    var doc = users.update(user, json.passwd, json.active, json.extra, json.changePassword);
    users.reload();

    actions.resultOk(req, res, actions.HTTP_OK, doc);
  }
  catch (err) {
    if (err.errorNum === arangodb.errors.ERROR_USER_NOT_FOUND.code) {
      actions.resultNotFound(req, res, arangodb.errors.ERROR_USER_NOT_FOUND.code);
    }
    else {
      throw err;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief removes an existing user
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_api_user_delete
///
/// @RESTHEADER{DELETE /_api/user/{user}, Remove User}
///
/// @RESTDESCRIPTION
///
/// Removes an existing user, identified by user.
///
/// If the user can be removed, the server will respond with HTTP 202.
/// In case of success, the returned JSON object has the following properties:
///
/// * *error*: Boolean flag to indicate that an error occurred (false in this case)
/// * *code*: The HTTP status code
///
/// If the specified user does not exist, the server will respond with HTTP 404.
///
/// The body of the response will contain a JSON object with additional error details.
/// The object has the following attributes:
///
/// * *error*: Boolean flag to indicate that an error occurred (true in this case)
/// * *code*: The HTTP status code
/// * *errorNum*: The server error number
/// * *errorMessage*: A descriptive error message
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{202}
/// Is returned if the user was removed by the server
///
/// @RESTRETURNCODE{404}
/// The specified user does not exist
///
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////

function delete_api_user (req, res) {
  if (req.suffix.length !== 1) {
    actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
    return;
  }

  var user = decodeURIComponent(req.suffix[0]);
  try {
    users.remove(user);
    users.reload();

    actions.resultOk(req, res, actions.HTTP_ACCEPTED, {});
  }
  catch (err) {
    if (err.errorNum === arangodb.errors.ERROR_USER_NOT_FOUND.code) {
      actions.resultNotFound(req, res, arangodb.errors.ERROR_USER_NOT_FOUND.code);
    }
    else {
      throw err;
    }
  }
}

// -----------------------------------------------------------------------------
// --SECTION--                                                           actions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief user actions gateway
////////////////////////////////////////////////////////////////////////////////

actions.defineHttp({
  url : "_api/user",

  callback : function (req, res) {
    try {
      switch (req.requestType) {
        case actions.GET:
          get_api_user(req, res);
          break;

        case actions.POST:
          post_api_user(req, res);
          break;

        case actions.PUT:
          put_api_user(req, res);
          break;

        case actions.PATCH:
          patch_api_user(req, res);
          break;

        case actions.DELETE:
          delete_api_user(req, res);
          break;

        default:
          actions.resultUnsupported(req, res);
      }
    }
    catch (err) {
      actions.resultException(req, res, err, undefined, false);
    }
  }
});

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<commit_msg>fixed API description<commit_after>/*jshint strict: false */
/*global require */

////////////////////////////////////////////////////////////////////////////////
/// @brief user management
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

var arangodb = require("org/arangodb");
var actions = require("org/arangodb/actions");
var users = require("org/arangodb/users");

// -----------------------------------------------------------------------------
// --SECTION--                                                 private functions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief fetches a user
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @COMMENT{######################################################################}
/// @anchor HttpUserDocument
/// @startDocuBlock JSF_api_user_fetch
///
/// @RESTHEADER{GET /_api/user/{user}, Fetch User}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{user,string,optional}
/// The name of the user
///
/// @RESTDESCRIPTION
///
/// Fetches data about the specified user.
///
/// The call will return a JSON document with at least the following attributes on success:
///
/// * *user*: The name of the user as a string.
/// * *active*: An optional flag that specifies whether the user is active.
/// * *extra*: An optional JSON object with arbitrary extra data about the user.
/// * *changePassword*: An optional flag that specifies whether the user must
///   change the password or not.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{200}
/// The user was found
///
/// @RESTRETURNCODE{404}
/// The user with the specified name does not exist
///
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////

function get_api_user (req, res) {
  if (req.suffix.length === 0) {
    actions.resultOk(req, res, actions.HTTP_OK, { result: users.all() });
    return;
  }

  if (req.suffix.length !== 1) {
    actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
    return;
  }

  var user = decodeURIComponent(req.suffix[0]);

  try {
    actions.resultOk(req, res, actions.HTTP_OK, users.document(user));
  }
  catch (err) {
    if (err.errorNum === arangodb.errors.ERROR_USER_NOT_FOUND.code) {
      actions.resultNotFound(req, res, arangodb.errors.ERROR_USER_NOT_FOUND.code);
    }
    else {
      throw err;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief creates a new user
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @COMMENT{######################################################################}
/// @anchor HttpUserSave
/// @startDocuBlock JSF_api_user_create
///
/// @RESTHEADER{POST /_api/user, Create User}
///
/// @RESTDESCRIPTION
///
/// The following data need to be passed in a JSON representation in the body
/// of the POST request:
///
/// * *user*: The name of the user as a string. This is mandatory
/// * *passwd*: The user password as a string. If no password is specified,
///   the empty string will be used
/// * *active*: An optional flag that specifies whether the user is active.
///   If not specified, this will default to true
/// * *extra*: An optional JSON object with arbitrary extra data about the user
/// * *changePassword*: An optional flag that specifies whethers the user must
///   change the password or not. If not specified, this will default to false
///
/// If set to true, the only operations allowed are PUT /_api/user or PATCH /_api/user.
/// All other operations will result in a HTTP 403.
/// If the user can be added by the server, the server will respond with HTTP 201.
/// In case of success, the returned JSON object has the following properties:
///
/// * *error*: Boolean flag to indicate that an error occurred (false in this case)
/// * *code*: The HTTP status code
///
/// If the JSON representation is malformed or mandatory data is missing from the request,
/// the server will respond with HTTP 400.
///
/// The body of the response will contain a JSON object with additional error details.
/// The object has the following attributes:
///
/// * *error*: Boolean flag to indicate that an error occurred (true in this case)
/// * *code*: The HTTP status code
/// * *errorNum*: The server error number
/// * *errorMessage*: A descriptive error message
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{201}
/// Returned if the user can be added by the server
///
/// @RESTRETURNCODE{400}
/// If the JSON representation is malformed or mandatory data is missing from the request.
///
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////

function post_api_user (req, res) {
  var json = actions.getJsonBody(req, res, actions.HTTP_BAD);

  if (json === undefined) {
    return;
  }

  var user;

  if (req.suffix.length === 1) {
    // validate if a combination or username / password is valid
    user = decodeURIComponent(req.suffix[0]);
    var result = users.isValid(user, json.passwd);

    if (result) {
      actions.resultOk(req, res, actions.HTTP_OK, { result: true });
    }
    else {
      actions.resultNotFound(req, res, arangodb.errors.ERROR_USER_NOT_FOUND.code);
    }
    return;
  }

  if (req.suffix.length !== 0) {
    // unexpected URL
    actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
    return;
  }

  user = json.user;

  if (user === undefined && json.hasOwnProperty("username")) {
    // deprecated usage
    user = json.username;
  }

  var doc = users.save(user, json.passwd, json.active, json.extra, json.changePassword);

  if (json.passwordToken) {
    users.setPasswordToken(user, json.passwordToken);
  }
  users.reload();

  actions.resultOk(req, res, actions.HTTP_CREATED, doc);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief replaces an existing user
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_api_user_replace
///
/// @RESTHEADER{PUT /_api/user/{user}, Replace User}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{user,string,optional}
/// The name of the user
///
/// @RESTDESCRIPTION
///
/// Replaces the data of an existing user. The name of an existing user must be specified in user.
///
/// The following data can to be passed in a JSON representation in the body of the POST request:
///
/// * *passwd*: The user password as a string. Specifying a password is mandatory,
///   but the empty string is allowed for passwords
/// * *active*: An optional flag that specifies whether the user is active.
///   If not specified, this will default to true
/// * *extra*: An optional JSON object with arbitrary extra data about the user
/// * *changePassword*: An optional flag that specifies whether the user must change
///   the password or not. If not specified, this will default to false
///
/// If the user can be replaced by the server, the server will respond with HTTP 200.
///
/// In case of success, the returned JSON object has the following properties:
///
/// * *error*: Boolean flag to indicate that an error occurred (false in this case)
/// * *code*: The HTTP status code
///
/// If the JSON representation is malformed or mandatory data is missing from the request,
/// the server will respond with HTTP 400. If the specified user does not exist,
/// the server will respond with HTTP 404.
///
/// The body of the response will contain a JSON object with additional
/// error details. The object has the following attributes:
///
/// * *error*: Boolean flag to indicate that an error occurred (true in this case)
/// * *code*: The HTTP status code
/// * *errorNum*: The server error number
/// * *errorMessage*: A descriptive error message
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{200}
/// Is returned if the user data can be replaced by the server
///
/// @RESTRETURNCODE{400}
/// The JSON representation is malformed or mandatory data is missing from the request
///
/// @RESTRETURNCODE{404}
/// The specified user does not exist
///
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////

function put_api_user (req, res) {
  if (req.suffix.length !== 1) {
    actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
    return;
  }

  var user = decodeURIComponent(req.suffix[0]);

  var json = actions.getJsonBody(req, res, actions.HTTP_BAD);

  if (json === undefined) {
    return;
  }

  try {
    var doc = users.replace(user, json.passwd, json.active, json.extra, json.changePassword);
    users.reload();

    actions.resultOk(req, res, actions.HTTP_OK, doc);
  }
  catch (err) {
    if (err.errorNum === arangodb.errors.ERROR_USER_NOT_FOUND.code) {
      actions.resultNotFound(req, res, arangodb.errors.ERROR_USER_NOT_FOUND.code);
    }
    else {
      throw err;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief partially updates an existing user
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @COMMENT{######################################################################}
/// @anchor HttpUserUpdate
/// @startDocuBlock JSF_api_user_update
///
/// @RESTHEADER{PATCH /_api/user/{user}, Update User}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{user,string,optional}
/// The name of the user
///
/// @RESTDESCRIPTION
///
/// Partially updates the data of an existing user. The name of an existing
/// user must be specified in user.
///
/// The following data can be passed in a JSON representation in the body of the
/// POST request:
///
/// * *passwd*: The user password as a string. Specifying a password is optional.
///   If not specified, the previously existing value will not be modified.
/// * *active*: An optional flag that specifies whether the user is active.
///   If not specified, the previously existing value will not be modified.
/// * *extra*: An optional JSON object with arbitrary extra data about the user.
///   If not specified, the previously existing value will not be modified.
/// * *changePassword*: An optional flag that specifies whether the user must change
///   the password or not. If not specified, the previously existing value will not be modified.
///
/// If the user can be updated by the server, the server will respond with HTTP 200.
///
/// In case of success, the returned JSON object has the following properties:
///
/// * *error*: Boolean flag to indicate that an error occurred (false in this case)
/// * *code*: The HTTP status code
///
/// If the JSON representation is malformed or mandatory data is missing from the request,
/// the server will respond with HTTP 400. If the specified user does not exist,
/// the server will respond with HTTP 404.
///
/// The body of the response will contain a JSON object with additional error details.
/// The object has the following attributes:
///
/// * *error*: Boolean flag to indicate that an error occurred (true in this case)
/// * *code*: The HTTP status code
/// * *errorNum*: The server error number
/// * *errorMessage*: A descriptive error message
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{200}
/// Is returned if the user data can be replaced by the server
///
/// @RESTRETURNCODE{400}
/// The JSON representation is malformed or mandatory data is missing from the request
///
/// @RESTRETURNCODE{404}
/// The specified user does not exist
///
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////

function patch_api_user (req, res) {
  if (req.suffix.length !== 1) {
    actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
    return;
  }

  var user = decodeURIComponent(req.suffix[0]);
  var json = actions.getJsonBody(req, res, actions.HTTP_BAD);

  if (json === undefined) {
    return;
  }

  try {
    var doc = users.update(user, json.passwd, json.active, json.extra, json.changePassword);
    users.reload();

    actions.resultOk(req, res, actions.HTTP_OK, doc);
  }
  catch (err) {
    if (err.errorNum === arangodb.errors.ERROR_USER_NOT_FOUND.code) {
      actions.resultNotFound(req, res, arangodb.errors.ERROR_USER_NOT_FOUND.code);
    }
    else {
      throw err;
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief removes an existing user
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_api_user_delete
///
/// @RESTHEADER{DELETE /_api/user/{user}, Remove User}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{user,string,optional}
/// The name of the user
///
/// @RESTDESCRIPTION
///
/// Removes an existing user, identified by user.
///
/// If the user can be removed, the server will respond with HTTP 202.
/// In case of success, the returned JSON object has the following properties:
///
/// * *error*: Boolean flag to indicate that an error occurred (false in this case)
/// * *code*: The HTTP status code
///
/// If the specified user does not exist, the server will respond with HTTP 404.
///
/// The body of the response will contain a JSON object with additional error details.
/// The object has the following attributes:
///
/// * *error*: Boolean flag to indicate that an error occurred (true in this case)
/// * *code*: The HTTP status code
/// * *errorNum*: The server error number
/// * *errorMessage*: A descriptive error message
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{202}
/// Is returned if the user was removed by the server
///
/// @RESTRETURNCODE{404}
/// The specified user does not exist
///
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////

function delete_api_user (req, res) {
  if (req.suffix.length !== 1) {
    actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
    return;
  }

  var user = decodeURIComponent(req.suffix[0]);
  try {
    users.remove(user);
    users.reload();

    actions.resultOk(req, res, actions.HTTP_ACCEPTED, {});
  }
  catch (err) {
    if (err.errorNum === arangodb.errors.ERROR_USER_NOT_FOUND.code) {
      actions.resultNotFound(req, res, arangodb.errors.ERROR_USER_NOT_FOUND.code);
    }
    else {
      throw err;
    }
  }
}

// -----------------------------------------------------------------------------
// --SECTION--                                                           actions
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief user actions gateway
////////////////////////////////////////////////////////////////////////////////

actions.defineHttp({
  url : "_api/user",

  callback : function (req, res) {
    try {
      switch (req.requestType) {
        case actions.GET:
          get_api_user(req, res);
          break;

        case actions.POST:
          post_api_user(req, res);
          break;

        case actions.PUT:
          put_api_user(req, res);
          break;

        case actions.PATCH:
          patch_api_user(req, res);
          break;

        case actions.DELETE:
          delete_api_user(req, res);
          break;

        default:
          actions.resultUnsupported(req, res);
      }
    }
    catch (err) {
      actions.resultException(req, res, err, undefined, false);
    }
  }
});

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<|endoftext|>


<commit_before>"use strict";

// Define our default color generator controller!
mcgApp.controller('ColorGeneratorCtrl',
function ($scope, $mdDialog, ColourLovers, $rootScope, $mdColorPalette )
{
	// Init function.
	// This is placed into a function
	// for ease-of-use in the future.
	// Often times an app needs to be
	// "Restarted" without a reload.
	$scope.init = function ()
	{
		// Reset palette to default color
		$scope.setDefaultPalette();

		// Define palettes
		$scope.palettes = [];
		$scope.colourlovers = [];

		// Toolbar is hidden by default.
		$scope.initSpeedDial();

		// Add a default palette
		$scope.addPaletteFromObject( $mdColorPalette.indigo );

		// Define theme defaults
		$scope.theme = {
			name: '',
            palettes: $scope.palettes
		};
	};

	$scope.initSpeedDial = function(){
		$scope.dialOpen = false;
	};

	// Function to replace all current palettes with an array of hex values.
	$rootScope.setPalettesByColors = function(colors){
		$scope.palettes = [];
		angular.forEach(colors, function( value ){
			$scope.palette.base = '#'+ value;
			$scope.addBasePalette();
		});
		$scope.setDefaultPalette();
	};

	// Function to add a palette from import code
	$scope.addPaletteFromJSON = function ( code )
	{
		// Break code into chunks to find JSON
		var chunks = code.split( /[{}]/ );
		var colorsObj = JSON.parse( '{' + chunks[ 1 ] + '}' );

		// Add this palette!
		$scope.addPaletteFromObject(colorsObj);
	};

	// Function to add a palette from
	// a JSON object (angularjs material
	// design format)
	$scope.addPaletteFromObject = function ( objectRef )
	{
		// First, clone object to clean it.
		var paletteObj = angular.copy( objectRef );

		// Init our customized palette values.
		var colors = [];
		var base = $scope.palette.base;

		// Build palette color json format
		angular.forEach( paletteObj, function ( value, key )
		{
			// If this is an object with RGB/Contrast values (Default angularjs palettes)
			if(typeof value == "object")
			{
				// Format it for tinycolor
				value = "rgb(" + value.value[ 0 ] + ", " + value.value[ 1 ] + ", " + value.value[ 2 ] + ")";
			}

			// Regardless, push this color to the colors using tinycolor!
			colors.push( { hex: tinycolor( value ).toHexString(), name: key } );

			// If this key is the base (500), set as base
			if ( key == 500 || key == "500" ) {
				base = value;
			}
		} );

		// Copy the base palette & add our customizations
		var palette = angular.copy( $scope.palette );
		palette.colors = colors;
		palette.base = base;

		// Push to the palette repository.
		$scope.palettes.push( palette );
	};

	// Function to add a palette to palettes.
	$scope.addBasePalette = function()
	{
		// Push on the default and then calculate it's values from it's base.
		$scope.palettes.push(angular.copy($scope.palette));
		$scope.calcPalette($scope.palettes.length-1);

		// Google Analytics Event Track
		ga('send', 'event', 'mcg', 'add_palette');
	};

	// Function to reset palette back to default.
	$scope.setDefaultPalette = function () {
		// Define base palette
		$scope.palette = {
			colors: [],
			orig:   [],
			base:   '#26a69a',
			json:   '',
			name:   ''
		};
	};

	// Function to calculate all colors for all palettes
	$scope.calcPalettes = function(){
		for(var i = 0; i < $scope.palettes.length; i++){
			$scope.calcPalette(i);
		}
	};

	// Function to delete a palette when passed it's key.
	$scope.deletePalette = function(key){
		$scope.palettes.remove(key);
		// Google Analytics Event Track
		ga('send', 'event', 'mcg', 'remove_palette');
	};

	// Function to assign watchers to all bases
	$scope.calcPalette = function(key){
		$scope.palettes[key].orig = $scope.computeColors($scope.palettes[key].base);
		$scope.palettes[key].colors = $scope.palettes[key].orig;
	};

	// Function to make the definePalette code for a palette.
	$scope.createDefinePalette = function(palette){
		return '$mdThemingProvider.definePalette(\'' + palette.name + '\', ' + $scope.makeColorsJson(palette.colors) + ');';
	};

	// Function to make an exportable json array for themes.
	$scope.makeColorsJson = function(colors){
		var exportable = {};
		angular.forEach(colors, function(value, key){
			exportable[value.name] = value.hex;
		});
		return angular.toJson(exportable, null, 4);
	};

	// Function to calculate all colors from base
	$scope.computeColors = function(hex)
	{
		// Return array of color objects.
		return [
			{ hex : tinycolor( hex ).lighten( 52 ).toHexString(), name : '50' },
			{ hex : tinycolor( hex ).lighten( 37 ).toHexString(), name : '100' },
			{ hex : tinycolor( hex ).lighten( 26 ).toHexString(), name : '200' },
			{ hex : tinycolor( hex ).lighten( 12 ).toHexString(), name : '300' },
			{ hex : tinycolor( hex ).lighten( 6 ).toHexString(), name : '400' },
			{ hex : hex, name : '500' },
			{ hex : tinycolor( hex ).darken( 6 ).toHexString(), name: '600' },
			{ hex : tinycolor( hex ).darken( 12 ).toHexString(), name: '700' },
			{ hex : tinycolor( hex ).darken( 18 ).toHexString(), name: '800' },
			{ hex : tinycolor( hex ).darken( 24 ).toHexString(), name: '900' },
			{ hex : tinycolor( hex ).lighten( 52 ).toHexString(), name: 'A100' },
			{ hex : tinycolor( hex ).lighten( 37 ).toHexString(), name: 'A200' },
			{ hex : tinycolor( hex ).lighten( 6 ).toHexString(), name: 'A400' },
			{ hex : tinycolor( hex ).darken( 12 ).toHexString(), name: 'A700' }
		];
	};

    // Function to show theme's full code
    $scope.showThemeCode = function()
    {
	    // Check to see that a theme name and palette names are set.
	    if(
		    typeof $scope.theme.name === 'undefined' || $scope.theme.name.length < 1 ||
		    typeof $scope.palettes[0] === 'undefined' || typeof $scope.palettes[0].name === 'undefined' || $scope.palettes[0].name.length < 1 ||
		    typeof $scope.palettes[1] === 'undefined' || typeof $scope.palettes[1].name === 'undefined' || $scope.palettes[1].name.length < 1
	    ){
		    alert('To generate the code for a theme you must provide a theme name and at least two palettes with names.');
		    return false;
	    }

        // Init return string
        var themeCodeString = '';

        // For each palette, add it's declaration
        for(var i = 0; i < $scope.palettes.length; i++){
            themeCodeString = themeCodeString+$scope.createDefinePalette($scope.palettes[i])+'\n\r';
        }

        // Add theme configuration
        themeCodeString = themeCodeString +
        '$mdThemingProvider.theme(\'' + $scope.theme.name + '\')\n\r\t'+
        '.primaryPalette(\''+$scope.palettes[0].name+'\')\n\r\t'+
        '.accentPalette(\''+$scope.palettes[1].name+'\');'
        +'\n\r';

        // Show clipboard with theme code
        $scope.showClipboard(themeCodeString);

	    // Google Analytics Event Track
	    ga('send', 'event', 'mcg', 'copy_code_theme');
    };

	// Function to regenerate json and show dialog for palette.
	$scope.showPaletteCode = function(palette)
	{
		// Check to see that this palette has a name
		if (
			typeof palette === 'undefined' ||
			typeof palette.name === 'undefined' ||
			palette.name.length < 1
		) {
			alert('To generate the code for a palette the palette must have a name.');
			return false;
		}

		// Generate palette's code
		palette.json = $scope.createDefinePalette(palette);

		// Show code
		$scope.showClipboard(palette.json);

		// Google Analytics Event Track
		ga('send', 'event', 'mcg', 'copy_code_palette');
	};

    // Function to show export json for loading carts later
    $scope.showImport = function()
	{
		$mdDialog
			// Show the dialog to allow import
			.show( {
				templateUrl: 'templates/dialogs/import.html',
				controller: DialogImportCtrl
			} )
			// Once the user clicks import...
			.then( function ( code )
			{
				// ...add the palette!
				if ( typeof code == "object" ) {
					$scope.addPaletteFromObject( code );
				}else{
					$scope.addPaletteFromJSON( code );
				}
			}, function () { } );

		// Google Analytics Event Track
		ga( 'send', 'event', 'mcg', 'import_code' );
    };

	// Function to show export json for loading carts later
	$scope.showAbout = function ()
	{
		// Show about us section!
		$mdDialog.show( {
			templateUrl: 'templates/dialogs/about.html',
			controller:  AboutCtrl
		} );

		// Google Analytics Event Track
		ga( 'send', 'event', 'mcg', 'about_us' );
	};

	// Function to show generic clipboard alert dialog
	$scope.showClipboard = function(code)
	{
		// TODO: Move these controllers and templates to their own files.
		$mdDialog.show({
			template   : '<md-dialog aria-label="Clipboard dialog">' +
			'  <md-content>' +
			'
{{code}}
' +
			'  </md-content>' +
			'
' +
			'    Code copied to clipboard!'+
			'    <md-button class="md-accent" ui-zeroclip zeroclip-model="code" zeroclip-copied="showNotice()">' +
			'      Copy' +
			'    </md-button>' +
			'    <md-button ng-click="closeDialog()">' +
			'      Close' +
			'    </md-button>' +
			'
' +
			'</md-dialog>',
			locals     : {
				code: code
			},
			controller : ClipboardDialogController
		});

		// Google Analytics Event Track
		ga('send', 'event', 'mcg', 'copy_code');

		// TODO: Move these controllers and templates to their own files.
		function ClipboardDialogController($scope, $mdDialog, $timeout, code)
		{
			$scope.code = code;
			$scope.copied = false;
			$scope.closeDialog = function () {
				$mdDialog.hide();
			};
			$scope.showNotice = function(){
				$scope.copied = true;
				$timeout(function(){
					$scope.copied = false;
				}, 1500);
			};
		}
	};

	// Function to show generic clipboard alert dialog
	$scope.showColourLovers = function () {
		$mdDialog.show( {
			templateUrl: '/templates/dialogs/colourlovers.html',
			controller: ColourLoversDialogController
		} );

		// Google Analytics Event Track
		ga( 'send', 'event', 'mcg', 'view_colourlovers' );

		function ColourLoversDialogController( $scope, $mdDialog, ColourLovers )
		{
			$scope.init = function(){
				$scope.colourlovers = [];
				$scope.setColors = $rootScope.setPalettesByColors;
				$scope.getTop();
			};

			// Get top colourlover palettes.
			$scope.getTop = function(){
				ColourLovers.getTop().success( function ( data ) {
					$scope.colourlovers = data;
				} );
			};

			// Get new colourlover palettes.
			$scope.getNew = function () {
				ColourLovers.getNew().success( function ( data ) {
					$scope.colourlovers = data;
				} );
			};

			// Get random colourlover palettes.
			$scope.getRandom = function () {
				ColourLovers.getRandom().success( function ( data ) {
					$scope.colourlovers = data;
				} );
			};

			// Function to close dialog
			$scope.closeDialog = function () {
				$mdDialog.hide();
			};

			$scope.init();
		}
	};

    // Function to darken a palette's color.
    $scope.darkenPaletteItem = function(color){
        color.hex = shadeColor(color.hex, -0.1);
    };

    // Function to lighten a palette's color.
    $scope.lightenPaletteItem = function(color){
        color.hex = shadeColor(color.hex, 0.1);
    };

	// Init controller
	$scope.init();
});
<commit_msg>Testing new color generation methodology.<commit_after>"use strict";

// Define our default color generator controller!
mcgApp.controller('ColorGeneratorCtrl',
function ($scope, $mdDialog, ColourLovers, $rootScope, $mdColorPalette )
{
	// Init function.
	// This is placed into a function
	// for ease-of-use in the future.
	// Often times an app needs to be
	// "Restarted" without a reload.
	$scope.init = function ()
	{
		// Reset palette to default color
		$scope.setDefaultPalette();

		// Define palettes
		$scope.palettes = [];
		$scope.colourlovers = [];

		// Toolbar is hidden by default.
		$scope.initSpeedDial();

		// Add a default palette
		$scope.addPaletteFromObject( $mdColorPalette.indigo );

		// Define theme defaults
		$scope.theme = {
			name: '',
            palettes: $scope.palettes
		};
	};

	$scope.initSpeedDial = function(){
		$scope.dialOpen = false;
	};

	// Function to replace all current palettes with an array of hex values.
	$rootScope.setPalettesByColors = function(colors){
		$scope.palettes = [];
		angular.forEach(colors, function( value ){
			$scope.palette.base = '#'+ value;
			$scope.addBasePalette();
		});
		$scope.setDefaultPalette();
	};

	// Function to add a palette from import code
	$scope.addPaletteFromJSON = function ( code )
	{
		// Break code into chunks to find JSON
		var chunks = code.split( /[{}]/ );
		var colorsObj = JSON.parse( '{' + chunks[ 1 ] + '}' );

		// Add this palette!
		$scope.addPaletteFromObject(colorsObj);
	};

	// Function to add a palette from
	// a JSON object (angularjs material
	// design format)
	$scope.addPaletteFromObject = function ( objectRef )
	{
		// First, clone object to clean it.
		var paletteObj = angular.copy( objectRef );

		// Init our customized palette values.
		var colors = [];
		var base = $scope.palette.base;

		// Build palette color json format
		angular.forEach( paletteObj, function ( value, key )
		{
			// If this is an object with RGB/Contrast values (Default angularjs palettes)
			if(typeof value == "object")
			{
				// Format it for tinycolor
				value = "rgb(" + value.value[ 0 ] + ", " + value.value[ 1 ] + ", " + value.value[ 2 ] + ")";
			}

			// Regardless, push this color to the colors using tinycolor!
			colors.push( { hex: tinycolor( value ).toHexString(), name: key } );

			// If this key is the base (500), set as base
			if ( key == 500 || key == "500" ) {
				base = value;
			}
		} );

		// Copy the base palette & add our customizations
		var palette = angular.copy( $scope.palette );
		palette.colors = colors;
		palette.base = base;

		// Push to the palette repository.
		$scope.palettes.push( palette );
	};

	// Function to add a palette to palettes.
	$scope.addBasePalette = function()
	{
		// Push on the default and then calculate it's values from it's base.
		$scope.palettes.push(angular.copy($scope.palette));
		$scope.calcPalette($scope.palettes.length-1);

		// Google Analytics Event Track
		ga('send', 'event', 'mcg', 'add_palette');
	};

	// Function to reset palette back to default.
	$scope.setDefaultPalette = function () {
		// Define base palette
		$scope.palette = {
			colors: [],
			orig:   [],
			base:   '#26a69a',
			json:   '',
			name:   ''
		};
	};

	// Function to calculate all colors for all palettes
	$scope.calcPalettes = function(){
		for(var i = 0; i < $scope.palettes.length; i++){
			$scope.calcPalette(i);
		}
	};

	// Function to delete a palette when passed it's key.
	$scope.deletePalette = function(key){
		$scope.palettes.remove(key);
		// Google Analytics Event Track
		ga('send', 'event', 'mcg', 'remove_palette');
	};

	// Function to assign watchers to all bases
	$scope.calcPalette = function(key){
		$scope.palettes[key].orig = $scope.computeColors($scope.palettes[key].base);
		$scope.palettes[key].colors = $scope.palettes[key].orig;
	};

	// Function to make the definePalette code for a palette.
	$scope.createDefinePalette = function(palette){
		return '$mdThemingProvider.definePalette(\'' + palette.name + '\', ' + $scope.makeColorsJson(palette.colors) + ');';
	};

	// Function to make an exportable json array for themes.
	$scope.makeColorsJson = function(colors){
		var exportable = {};
		angular.forEach(colors, function(value, key){
			exportable[value.name] = value.hex;
		});
		return angular.toJson(exportable, null, 4);
	};

	// Function to calculate all colors from base
	// These colors were determined by finding all
	// HSL values for a google palette, calculating
	// the difference in H, S, and L per color
	// change individually, and then applying these
	// here.
	$scope.computeColors = function(hex)
	{
		// Return array of color objects.
		return [
			{ hex : tinycolor( hex ).lighten( 37.7 ).toHexString(), name : '50' },
			{ hex : tinycolor( hex ).lighten( 31.8 ).toHexString(), name : '100' },
			{ hex : tinycolor( hex ).lighten( 18.7 ).toHexString(), name : '200' },
			{ hex : tinycolor( hex ).lighten( 9.1 ).toHexString(), name : '300' },
			{ hex : tinycolor( hex ).lighten( 4.5 ).desaturate( 6.7 ).spin( -3 ).toHexString(), name : '400' },
			{ hex : hex, name : '500' },
			{ hex : tinycolor( hex ).darken( 6 ).toHexString(), name: '600' },
			{ hex : tinycolor( hex ).darken( 12 ).toHexString(), name: '700' },
			{ hex : tinycolor( hex ).darken( 18 ).toHexString(), name: '800' },
			{ hex : tinycolor( hex ).darken( 24 ).toHexString(), name: '900' },
			{ hex : tinycolor( hex ).lighten( 52 ).toHexString(), name: 'A100' },
			{ hex : tinycolor( hex ).lighten( 37 ).toHexString(), name: 'A200' },
			{ hex : tinycolor( hex ).lighten( 6 ).toHexString(), name: 'A400' },
			{ hex : tinycolor( hex ).darken( 12 ).toHexString(), name: 'A700' }
		];
	};

    // Function to show theme's full code
    $scope.showThemeCode = function()
    {
	    // Check to see that a theme name and palette names are set.
	    if(
		    typeof $scope.theme.name === 'undefined' || $scope.theme.name.length < 1 ||
		    typeof $scope.palettes[0] === 'undefined' || typeof $scope.palettes[0].name === 'undefined' || $scope.palettes[0].name.length < 1 ||
		    typeof $scope.palettes[1] === 'undefined' || typeof $scope.palettes[1].name === 'undefined' || $scope.palettes[1].name.length < 1
	    ){
		    alert('To generate the code for a theme you must provide a theme name and at least two palettes with names.');
		    return false;
	    }

        // Init return string
        var themeCodeString = '';

        // For each palette, add it's declaration
        for(var i = 0; i < $scope.palettes.length; i++){
            themeCodeString = themeCodeString+$scope.createDefinePalette($scope.palettes[i])+'\n\r';
        }

        // Add theme configuration
        themeCodeString = themeCodeString +
        '$mdThemingProvider.theme(\'' + $scope.theme.name + '\')\n\r\t'+
        '.primaryPalette(\''+$scope.palettes[0].name+'\')\n\r\t'+
        '.accentPalette(\''+$scope.palettes[1].name+'\');'
        +'\n\r';

        // Show clipboard with theme code
        $scope.showClipboard(themeCodeString);

	    // Google Analytics Event Track
	    ga('send', 'event', 'mcg', 'copy_code_theme');
    };

	// Function to regenerate json and show dialog for palette.
	$scope.showPaletteCode = function(palette)
	{
		// Check to see that this palette has a name
		if (
			typeof palette === 'undefined' ||
			typeof palette.name === 'undefined' ||
			palette.name.length < 1
		) {
			alert('To generate the code for a palette the palette must have a name.');
			return false;
		}

		// Generate palette's code
		palette.json = $scope.createDefinePalette(palette);

		// Show code
		$scope.showClipboard(palette.json);

		// Google Analytics Event Track
		ga('send', 'event', 'mcg', 'copy_code_palette');
	};

    // Function to show export json for loading carts later
    $scope.showImport = function()
	{
		$mdDialog
			// Show the dialog to allow import
			.show( {
				templateUrl: 'templates/dialogs/import.html',
				controller: DialogImportCtrl
			} )
			// Once the user clicks import...
			.then( function ( code )
			{
				// ...add the palette!
				if ( typeof code == "object" ) {
					$scope.addPaletteFromObject( code );
				}else{
					$scope.addPaletteFromJSON( code );
				}
			}, function () { } );

		// Google Analytics Event Track
		ga( 'send', 'event', 'mcg', 'import_code' );
    };

	// Function to show export json for loading carts later
	$scope.showAbout = function ()
	{
		// Show about us section!
		$mdDialog.show( {
			templateUrl: 'templates/dialogs/about.html',
			controller:  AboutCtrl
		} );

		// Google Analytics Event Track
		ga( 'send', 'event', 'mcg', 'about_us' );
	};

	// Function to show generic clipboard alert dialog
	$scope.showClipboard = function(code)
	{
		// TODO: Move these controllers and templates to their own files.
		$mdDialog.show({
			template   : '<md-dialog aria-label="Clipboard dialog">' +
			'  <md-content>' +
			'
{{code}}
' +
			'  </md-content>' +
			'
' +
			'    Code copied to clipboard!'+
			'    <md-button class="md-accent" ui-zeroclip zeroclip-model="code" zeroclip-copied="showNotice()">' +
			'      Copy' +
			'    </md-button>' +
			'    <md-button ng-click="closeDialog()">' +
			'      Close' +
			'    </md-button>' +
			'
' +
			'</md-dialog>',
			locals     : {
				code: code
			},
			controller : ClipboardDialogController
		});

		// Google Analytics Event Track
		ga('send', 'event', 'mcg', 'copy_code');

		// TODO: Move these controllers and templates to their own files.
		function ClipboardDialogController($scope, $mdDialog, $timeout, code)
		{
			$scope.code = code;
			$scope.copied = false;
			$scope.closeDialog = function () {
				$mdDialog.hide();
			};
			$scope.showNotice = function(){
				$scope.copied = true;
				$timeout(function(){
					$scope.copied = false;
				}, 1500);
			};
		}
	};

	// Function to show generic clipboard alert dialog
	$scope.showColourLovers = function () {
		$mdDialog.show( {
			templateUrl: '/templates/dialogs/colourlovers.html',
			controller: ColourLoversDialogController
		} );

		// Google Analytics Event Track
		ga( 'send', 'event', 'mcg', 'view_colourlovers' );

		function ColourLoversDialogController( $scope, $mdDialog, ColourLovers )
		{
			$scope.init = function(){
				$scope.colourlovers = [];
				$scope.setColors = $rootScope.setPalettesByColors;
				$scope.getTop();
			};

			// Get top colourlover palettes.
			$scope.getTop = function(){
				ColourLovers.getTop().success( function ( data ) {
					$scope.colourlovers = data;
				} );
			};

			// Get new colourlover palettes.
			$scope.getNew = function () {
				ColourLovers.getNew().success( function ( data ) {
					$scope.colourlovers = data;
				} );
			};

			// Get random colourlover palettes.
			$scope.getRandom = function () {
				ColourLovers.getRandom().success( function ( data ) {
					$scope.colourlovers = data;
				} );
			};

			// Function to close dialog
			$scope.closeDialog = function () {
				$mdDialog.hide();
			};

			$scope.init();
		}
	};

    // Function to darken a palette's color.
    $scope.darkenPaletteItem = function(color){
        color.hex = shadeColor(color.hex, -0.1);
    };

    // Function to lighten a palette's color.
    $scope.lightenPaletteItem = function(color){
        color.hex = shadeColor(color.hex, 0.1);
    };

	// Init controller
	$scope.init();
});
<|endoftext|>


<commit_before>describe('eveResource', function() {
    var Resource;

    beforeEach(module('com.dailymotion.ngEveResource'));

    it('should correctly serialize the data toJSON', inject(function(eveResource) {
        var User = eveResource('/user/:userId', {
            userId:'@id'
        }), user = new User({
            hai: 'hello world!',
            _kthx: 'bai'
        });

        expect(angular.toJson(user)).toBe('{"hai":"hello world!"}');
    }));

    it('should respect the optional 4th param as replacerFn if not an Object', inject(function(eveResource) {
        var Notes = eveResource('/notes/:id', null, {
            update: {
                method: 'PATCH'
            }
        }, function (key, value) {
            if (key == 'selected') {
                return undefined;
            }
            return value;
        }), note = new Notes({
            selected: false,
            _id: '123'
        });

        expect(angular.toJson(note)).toBe('{}');
    }));
});
<commit_msg>tests(resource): add test for exists()<commit_after>describe('eveResource', function() {
    var Resource;

    beforeEach(module('com.dailymotion.ngEveResource'));

    it('should correctly serialize the data toJSON', inject(function(eveResource) {
        var User = eveResource('/user/:userId', {
            userId:'@id'
        }), user = new User({
            hai: 'hello world!',
            _kthx: 'bai'
        });

        expect(angular.toJson(user)).toBe('{"hai":"hello world!"}');
    }));

    it('should respect the optional 4th param as replacerFn if not an Object', inject(function(eveResource) {
        var Notes = eveResource('/notes/:id', null, {
            update: {
                method: 'PATCH'
            }
        }, function (key, value) {
            if (key == 'selected') {
                return undefined;
            }
            return value;
        }), note = new Notes({
            selected: false,
            _id: '123'
        });

        expect(angular.toJson(note)).toBe('{}');
    }));

    it('should check if the object resource is new or if it already exists in the database', inject(function(eveResource) {
        var CreditCard = eveResource('/user/:userId/card/:cardId', {
            userId:123,
            cardId:'@id'
        }, {
            charge: {
                method:'POST',
                params:{
                    charge: true
                }
            }
        }), creditCard = new CreditCard();

        expect(creditCard.exists()).toEqual(false);
    }));
});
<|endoftext|>


<commit_before>import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js';
import * as utils from '../src/utils.js';

const BIDDER_CODE = 'colossusssp';
const G_URL = 'https://colossusssp.com/?c=o&m=multi';
const G_URL_SYNC = 'https://colossusssp.com/?c=o&m=cookie';

function isBidResponseValid(bid) {
  if (!bid.requestId || !bid.cpm || !bid.creativeId || !bid.ttl || !bid.currency) {
    return false;
  }

  switch (bid.mediaType) {
    case BANNER:
      return Boolean(bid.width && bid.height && bid.ad);
    case VIDEO:
      return Boolean(bid.vastUrl);
    case NATIVE:
      return Boolean(bid.native);
    default:
      return false;
  }
}

function getUserId(eids, id, source, uidExt) {
  if (id) {
    var uid = { id };
    if (uidExt) {
      uid.ext = uidExt;
    }
    eids.push({
      source,
      uids: [ uid ]
    });
  }
}

export const spec = {
  code: BIDDER_CODE,
  supportedMediaTypes: [BANNER, VIDEO, NATIVE],
  /**
   * Determines whether or not the given bid request is valid.
   *
   * @param {object} bid The bid to validate.
   * @return boolean True if this is a valid bid, and false otherwise.
   */
  isBidRequestValid: (bid) => {
    return Boolean(bid.bidId && bid.params && !isNaN(bid.params.placement_id));
  },

  /**
   * Make a server request from the list of BidRequests.
   *
   * @param {BidRequest[]} validBidRequests A non-empty list of valid bid requests that should be sent to the Server.
   * @return ServerRequest Info describing the request to the server.
   */
  buildRequests: (validBidRequests, bidderRequest) => {
    let winTop = window;
    let location;
    try {
      location = new URL(bidderRequest.refererInfo.referer)
      winTop = window.top;
    } catch (e) {
      location = winTop.location;
      utils.logMessage(e);
    };
    let placements = [];
    let request = {
      'deviceWidth': winTop.screen.width,
      'deviceHeight': winTop.screen.height,
      'language': (navigator && navigator.language) ? navigator.language : '',
      'secure': location.protocol === 'https:' ? 1 : 0,
      'host': location.host,
      'page': location.pathname,
      'placements': placements,
    };

    if (bidderRequest) {
      if (bidderRequest.uspConsent) {
        request.ccpa = bidderRequest.uspConsent;
      }
      if (bidderRequest.gdprConsent) {
        request.gdpr_consent = bidderRequest.gdprConsent.consentString || 'ALL'
        request.gdpr_require = bidderRequest.gdprConsent.gdprApplies ? 1 : 0
      }
    }

    for (let i = 0; i < validBidRequests.length; i++) {
      let bid = validBidRequests[i];
      let traff = bid.params.traffic || BANNER
      let placement = {
        placementId: bid.params.placement_id,
        bidId: bid.bidId,
        sizes: bid.mediaTypes[traff].sizes,
        traffic: traff,
        eids: []
      };
      if (bid.schain) {
        placement.schain = bid.schain;
      }
      if (bid.userId) {
        getUserId(placement.eids, bid.userId.britepoolid, 'britepool.com');
        getUserId(placement.eids, bid.userId.idl_env, 'identityLink');
        getUserId(placement.eids, bid.userId.id5id, 'id5-sync.com')
        getUserId(placement.eids, bid.userId.tdid, 'adserver.org', {
          rtiPartner: 'TDID'
        });
      }
      placements.push(placement);
    }
    return {
      method: 'POST',
      url: G_URL,
      data: request
    };
  },

  /**
   * Unpack the response from the server into a list of bids.
   *
   * @param {*} serverResponse A successful response from the server.
   * @return {Bid[]} An array of bids which were nested inside the server.
   */
  interpretResponse: (serverResponse) => {
    let response = [];
    try {
      serverResponse = serverResponse.body;
      for (let i = 0; i < serverResponse.length; i++) {
        let resItem = serverResponse[i];
        if (isBidResponseValid(resItem)) {
          response.push(resItem);
        }
      }
    } catch (e) {
      utils.logMessage(e);
    };
    return response;
  },

  getUserSyncs: () => {
    return [{
      type: 'image',
      url: G_URL_SYNC
    }];
  }
};

registerBidder(spec);
<commit_msg>Update colossussspBidAdapter.js<commit_after>import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js';
import * as utils from '../src/utils.js';

const BIDDER_CODE = 'colossusssp';
const G_URL = 'https://colossusssp.com/?c=o&m=multi';
const G_URL_SYNC = 'https://colossusssp.com/?c=o&m=cookie';

function isBidResponseValid(bid) {
  if (!bid.requestId || !bid.cpm || !bid.creativeId || !bid.ttl || !bid.currency) {
    return false;
  }

  switch (bid.mediaType) {
    case BANNER:
      return Boolean(bid.width && bid.height && bid.ad);
    case VIDEO:
      return Boolean(bid.vastUrl);
    case NATIVE:
      return Boolean(bid.native);
    default:
      return false;
  }
}

function getUserId(eids, id, source, uidExt) {
  if (id) {
    var uid = { id };
    if (uidExt) {
      uid.ext = uidExt;
    }
    eids.push({
      source,
      uids: [ uid ]
    });
  }
}

export const spec = {
  code: BIDDER_CODE,
  supportedMediaTypes: [BANNER, VIDEO, NATIVE],
  /**
   * Determines whether or not the given bid request is valid.
   *
   * @param {object} bid The bid to validate.
   * @return boolean True if this is a valid bid, and false otherwise.
   */
  isBidRequestValid: (bid) => {
    return Boolean(bid.bidId && bid.params && !isNaN(bid.params.placement_id));
  },

  /**
   * Make a server request from the list of BidRequests.
   *
   * @param {BidRequest[]} validBidRequests A non-empty list of valid bid requests that should be sent to the Server.
   * @return ServerRequest Info describing the request to the server.
   */
  buildRequests: (validBidRequests, bidderRequest) => {
    let winTop = window;
    let location;
    try {
      location = new URL(bidderRequest.refererInfo.referer)
      winTop = window.top;
    } catch (e) {
      location = winTop.location;
      utils.logMessage(e);
    };
    let placements = [];
    let request = {
      'deviceWidth': winTop.screen.width,
      'deviceHeight': winTop.screen.height,
      'language': (navigator && navigator.language) ? navigator.language : '',
      'secure': location.protocol === 'https:' ? 1 : 0,
      'host': location.host,
      'page': location.pathname,
      'placements': placements,
    };

    if (bidderRequest) {
      if (bidderRequest.uspConsent) {
        request.ccpa = bidderRequest.uspConsent;
      }
      if (bidderRequest.gdprConsent) {
        request.gdpr_consent = bidderRequest.gdprConsent.consentString || 'ALL'
        request.gdpr_require = bidderRequest.gdprConsent.gdprApplies ? 1 : 0
      }
    }

    for (let i = 0; i < validBidRequests.length; i++) {
      let bid = validBidRequests[i];
      let traff = bid.params.traffic || BANNER
      let placement = {
        placementId: bid.params.placement_id,
        bidfloor: bid.params.bidfloor
        bidId: bid.bidId,
        sizes: bid.mediaTypes[traff].sizes,
        traffic: traff,
        eids: []
      };
      if (bid.schain) {
        placement.schain = bid.schain;
      }
      if (bid.userId) {
        getUserId(placement.eids, bid.userId.britepoolid, 'britepool.com');
        getUserId(placement.eids, bid.userId.idl_env, 'identityLink');
        getUserId(placement.eids, bid.userId.id5id, 'id5-sync.com')
        getUserId(placement.eids, bid.userId.tdid, 'adserver.org', {
          rtiPartner: 'TDID'
        });
      }
      placements.push(placement);
    }
    return {
      method: 'POST',
      url: G_URL,
      data: request
    };
  },

  /**
   * Unpack the response from the server into a list of bids.
   *
   * @param {*} serverResponse A successful response from the server.
   * @return {Bid[]} An array of bids which were nested inside the server.
   */
  interpretResponse: (serverResponse) => {
    let response = [];
    try {
      serverResponse = serverResponse.body;
      for (let i = 0; i < serverResponse.length; i++) {
        let resItem = serverResponse[i];
        if (isBidResponseValid(resItem)) {
          response.push(resItem);
        }
      }
    } catch (e) {
      utils.logMessage(e);
    };
    return response;
  },

  getUserSyncs: () => {
    return [{
      type: 'image',
      url: G_URL_SYNC
    }];
  }
};

registerBidder(spec);
<|endoftext|>


<commit_before>const r = require('./../db');
const client = require('./');
const { spawn } = require('child_process');
const request = require('request');
const ytdl = require('ytdl-core');

const connections = {};

const list = (message, callback) => {
	if (!message.member) {
		message.channel.createMessage('You need to be in a Guild!');
	} else {
		r.table('playlist')
			.get(message.channel.guild.id)
			.run(r.conn, (err, res) => {
				if (err) throw new Error('Failed to read Rethonk(TM) playlist.');
				if (res === null) {
					callback([]);
				} else {
					callback(res.playlist, res.repeat);
				}
			});
	}
};
const play = (message) => {
	list(message, (playlist) => {
		const after = () => {
			// When the playlist ends, either delete the next track, or not,
			// depending on if they have single repeat on or not
			connections[message.channel.guild.id].once('end', () => {
				r.table('playlist')
					.get(message.channel.guild.id)
					.run(r.conn, (err1, result) => {
						if (err1) throw new Error('Failed to obtain repeat data.');
						if (result.repeat) {
							play(message);
						} else {
							r.table('playlist')
								.get(message.channel.guild.id)
								.update({
									playlist: r.row('playlist').deleteAt(0)
								})
								.run(r.conn, (err2) => {
									if (err2) throw new Error('Failed to modify Rethonk(TM) playlist.');
									play(message);
								});
						}
					});
			});

			connections[message.channel.guild.id].once('error', (err) => {
				message.channel.createMessage(`Error playing audio! ${err.message}`);
			});
		};

		// If the playlist is empty, leave.
		if (playlist.length === 0 && connections[message.channel.guild.id].channelID) {
			client.leaveVoiceChannel(connections[message.channel.guild.id].channelID);
			connections[message.channel.guild.id] = false;
		} else if (!playlist[0]) {
			throw new Error('Found nothing to play, but skipped playlist end feature.');
		} else if (playlist[0].type === 'youtube-dl') { // Play from youtube-dl, which can do many many things.
			const youtube = spawn('youtube-dl', [
				'-o', '-',
				playlist[0].media
			]);

			connections[message.channel.guild.id].play(youtube.stdout);
			after();
		} else if (playlist[0].type === 'ytdl-core') { // Play with ytdl-core, which can do many many things.
			const stream = ytdl(playlist[0].media.url, playlist[0].media.search);

			connections[message.channel.guild.id].play(stream);
			after();
		} else if (playlist[0].type === 'get') { // Play directly with a GET request
			const ffmpeg = spawn('ffmpeg', [
				'-i', playlist[0].media,
				'-f', 'wav',
				'-ac', '2',
				'pipe:1'
			]);

			ffmpeg.stdout.once('error', (err) => {
				message.channel.createMessage(`Error playing audio! ${err.message}`);
			});
			ffmpeg.stderr.once('error', (err) => {
				message.channel.createMessage(`Error playing audio! ${err.message}`);
			});

			connections[message.channel.guild.id].play(ffmpeg.stdout);
			after();
		} else if (playlist[0].type === 'post') { // Send POST data then play the file
			const ffmpeg = spawn('ffmpeg', [
				'-i', 'pipe:0',
				'-f', 'wav',
				'-ac', '2',
				'pipe:1'
			]);

			ffmpeg.stdout.once('error', (err) => {
				message.channel.createMessage(`Error playing audio! ${err.message}`);
			});
			ffmpeg.stderr.once('error', (err) => {
				message.channel.createMessage(`Error playing audio! ${err.message}`);
			});

			request.post(playlist[0].media).pipe(ffmpeg.stdin);
			connections[message.channel.guild.id].play(ffmpeg.stdout);
			after();
		} else {
			throw new Error('Invalid audio type provided.');
		}
	});
};
const connect = (message) => {
	if (!connections[message.channel.guild.id]) {
		connections[message.channel.guild.id] = true;
		client.joinVoiceChannel(message.member.voiceState.channelID)
			.catch((err) => { // Join the user's voice channel
				message.channel.createMessage(`Error joining channel! ${err.message}`);
			})
			.then((connection) => {
				if (connection) {
					connections[message.channel.guild.id] = connection;
					play(message);
				}
			});
	}
};
const add = (message, details) => {
	if (!message.member) {
		if (!details.silent) {
			message.channel.createMessage('You need to be in a Guild!');
		}
	} else if (!message.member.voiceState || !message.member.voiceState.channelID) {
		if (!details.silent) {
			message.channel.createMessage('You need to be in a Voice Channel!');
		}
	} else {
		// Add the details to the playlist. If the playlist doesn't exist, create it.
		r.table('playlist')
			.get(message.channel.guild.id)
			.replace({
				id: message.channel.guild.id,
				playlist: r.row('playlist').append(details).default([details]),
				repeat: r.row('repeat').default(false)
			})
			.run(r.conn, (err) => {
				if (err) throw err;

				// If the bot is not connected to the guild, run the init procedures
				if (!connections[message.channel.guild.id]) connect(message);
			});
	}
};
const skip = (message) => {
	if (!message.member) {
		message.channel.createMessage('You need to be in a Guild!');
	} else if (connections[message.channel.guild.id] && connections[message.channel.guild.id].playing) connections[message.channel.guild.id].stopPlaying();
};
const stop = (message) => {
	if (!message.member) {
		message.channel.createMessage('You need to be in a Guild!');
	} else {
		r.table('playlist')
			.get(message.channel.guild.id)
			.replace({
				id: message.channel.guild.id,
				playlist: [],
				repeat: false
			})
			.run(r.conn, (err) => {
				if (err) throw err;
				skip(message);
			});
	}
};
const repeat = (message) => {
	if (!message.member) {
		message.channel.createMessage('You need to be in a Guild!');
	} else {
		r.table('playlist')
			.get(message.channel.guild.id)
			.replace({
				id: message.channel.guild.id,
				playlist: r.row('playlist'),
				repeat: r.row('repeat').not().default(false)
			})
			.run(r.conn, (err) => {
				if (err) throw err;
			});
	}
};

exports.connect = connect;
exports.add = add;
exports.stop = stop;
exports.skip = skip;
exports.list = list;
exports.repeat = repeat;

/*

{
	media: Object or string,
	type: string,
	name: string
}

*/
<commit_msg>quick bodge<commit_after>const r = require('./../db');
const client = require('./');
const { spawn } = require('child_process');
const request = require('request');
const ytdl = require('ytdl-core');

const connections = {};

const list = (message, callback) => {
	if (!message.member) {
		message.channel.createMessage('You need to be in a Guild!');
	} else {
		r.table('playlist')
			.get(message.channel.guild.id)
			.run(r.conn, (err, res) => {
				if (err) throw new Error('Failed to read Rethonk(TM) playlist.');
				if (res === null) {
					callback([]);
				} else {
					callback(res.playlist, res.repeat);
				}
			});
	}
};
const play = (message) => {
	list(message, (playlist) => {
		const after = () => {
			// When the playlist ends, either delete the next track, or not,
			// depending on if they have single repeat on or not
			connections[message.channel.guild.id].once('end', () => {
				r.table('playlist')
					.get(message.channel.guild.id)
					.run(r.conn, (err1, result) => {
						if (err1) throw new Error('Failed to obtain repeat data.');
						if (result.repeat) {
							play(message);
						} else {
							r.table('playlist')
								.get(message.channel.guild.id)
								.update({
									playlist: r.row('playlist').deleteAt(0)
								})
								.run(r.conn, (err2) => {
									if (err2) throw new Error('Failed to modify Rethonk(TM) playlist.');
									play(message);
								});
						}
					});
			});

			connections[message.channel.guild.id].once('error', (err) => {
				message.channel.createMessage(`Error playing audio! ${err.message}`);
			});
		};

		// If the playlist is empty, leave.
		if (playlist.length === 0 && connections[message.channel.guild.id].channelID) {
			client.leaveVoiceChannel(connections[message.channel.guild.id].channelID);
			connections[message.channel.guild.id] = false;
		} else if (!playlist[0]) {
			throw new Error('Found nothing to play, but skipped playlist end feature.');
		} else if (playlist[0].type === 'youtube-dl') { // Play from youtube-dl, which can do many many things.
			const youtube = spawn('youtube-dl', [
				'-o', '-',
				playlist[0].media
			]);

			connections[message.channel.guild.id].play(youtube.stdout);
			after();
		} else if (playlist[0].type === 'ytdl-core') { // Play with ytdl-core, which can do many many things.
			const stream = ytdl(playlist[0].media.url, playlist[0].media.search);

			connections[message.channel.guild.id].play(stream);
			after();
		} else if (playlist[0].type === 'get') { // Play directly with a GET request
			const ffmpeg = spawn('ffmpeg', [
				'-i', playlist[0].media,
				'-f', 'wav',
				'-ac', '2',
				'pipe:1'
			]);

			ffmpeg.stdout.once('error', (err) => {
				message.channel.createMessage(`Error playing audio! ${err.message}`);
			});
			ffmpeg.stderr.once('error', (err) => {
				message.channel.createMessage(`Error playing audio! ${err.message}`);
			});

			connections[message.channel.guild.id].play(ffmpeg.stdout);
			after();
		} else if (playlist[0].type === 'post') { // Send POST data then play the file
			const ffmpeg = spawn('ffmpeg', [
				'-i', 'pipe:0',
				'-f', 'wav',
				'-ac', '2',
				'pipe:1'
			]);

			ffmpeg.stdout.once('error', (err) => {
				message.channel.createMessage(`Error playing audio! ${err.message}`);
			});
			ffmpeg.stderr.once('error', (err) => {
				message.channel.createMessage(`Error playing audio! ${err.message}`);
			});

			request.post(playlist[0].media).pipe(ffmpeg.stdin);
			connections[message.channel.guild.id].play(ffmpeg.stdout);
			after();
		} else {
			throw new Error('Invalid audio type provided.');
		}
	});
};
const connect = (message) => {
	if (!connections[message.channel.guild.id]) {
		connections[message.channel.guild.id] = true;
		client.joinVoiceChannel(message.member.voiceState.channelID)
			.catch((err) => { // Join the user's voice channel
				message.channel.createMessage(`Error joining channel! ${err.message}`);
			})
			.then((connection) => {
				if (connection) {
					connections[message.channel.guild.id] = connection;
					play(message);
				}
			});
	}
};
const add = (message, details) => {
	if (!message.member) {
		if (!details.silent) {
			message.channel.createMessage('You need to be in a Guild!');
		}
	} else if (!message.member.voiceState || !message.member.voiceState.channelID) {
		if (!details.silent) {
			message.channel.createMessage('You need to be in a Voice Channel!');
		}
	} else {
		// Add the details to the playlist. If the playlist doesn't exist, create it.
		r.table('playlist')
			.get(message.channel.guild.id)
			.replace({
				id: message.channel.guild.id,
				playlist: r.row('playlist').default([]).append(details),
				repeat: r.row('repeat').default(false)
			})
			.run(r.conn, (err) => {
				if (err) throw err;

				// If the bot is not connected to the guild, run the init procedures
				if (!connections[message.channel.guild.id]) connect(message);
			});
	}
};
const skip = (message) => {
	if (!message.member) {
		message.channel.createMessage('You need to be in a Guild!');
	} else if (connections[message.channel.guild.id] && connections[message.channel.guild.id].playing) connections[message.channel.guild.id].stopPlaying();
};
const stop = (message) => {
	if (!message.member) {
		message.channel.createMessage('You need to be in a Guild!');
	} else {
		r.table('playlist')
			.get(message.channel.guild.id)
			.replace({
				id: message.channel.guild.id,
				playlist: [],
				repeat: false
			})
			.run(r.conn, (err) => {
				if (err) throw err;
				skip(message);
			});
	}
};
const repeat = (message) => {
	if (!message.member) {
		message.channel.createMessage('You need to be in a Guild!');
	} else {
		r.table('playlist')
			.get(message.channel.guild.id)
			.replace({
				id: message.channel.guild.id,
				playlist: r.row('playlist'),
				repeat: r.row('repeat').not().default(false)
			})
			.run(r.conn, (err) => {
				if (err) throw err;
			});
	}
};

exports.connect = connect;
exports.add = add;
exports.stop = stop;
exports.skip = skip;
exports.list = list;
exports.repeat = repeat;

/*

{
	media: Object or string,
	type: string,
	name: string
}

*/
<|endoftext|>


<commit_before>/* global Firebase angular */
  (function() {
    'use strict';

    angular.module('burybox').controller('LoginController', function($location) {

    var login = self
    //var newUser = true;
    var ref = new Firebase('https://sweltering-inferno-1762.firebaseio.com');
    var authData = ref.getAuth();
    if (authData) {
      console.log("you did it!", authData.uid);
    }
    this.login = function() {
      ref.authWithOAuthPopup('google', function(error) {
        if (error) {
          console.log("failed", error);
        } else {
          console.log("authenticated successfully", authData);
        }
      }, {
        scope: 'email'
      });
    };

    ref.onAuth(function() {
      if (authData) {
        ref.child('user').child(authData.uid).set({
          provider: authData.provider,
          name: authData.google.displayName,
          image: authData.google.profileImageURL
        });
      }
    });

  /*  document.getElementById('loginrouting').addEventListener('click', function(){
      if (Date.now >= timestamp) {
      $location.path('/closedbox')
    } else {
      $location.path('/home')
    }
  }); */

    });

  })();
<commit_msg>getting authentication working better<commit_after>/* global Firebase angular */
  (function() {
    'use strict';

    angular.module('burybox').controller('LoginController', function($location) {

    var login = self
    //var newUser = true;
    var ref = new Firebase('https://sweltering-inferno-1762.firebaseio.com');
    login.auth = Auth.magicAuth;
    login.authData = null;
    login.addUser = function(){
      login.auth.$onAuth(function(authData) {
        loin.authData = authData;
        if (authData) {
          ref.child('users').child(authData.uid).update({
            provider: authData.provider,
            name: authData.google.displayName,
            image: authData.google.profileImageURL
          });
        }
      });
    };
    login.login = function() {
      Auth.googleLogin();
    };
    login.checkAuth = function() {
      console.log(Auth.authStatus());
    };
    login.logout = function() {
      Auth.googleLogout();
    };
  });

  })();
<|endoftext|>


<commit_before>module.exports.name = 'quickFix';
module.exports.alias = [
  'fix'
];

module.exports.isAllowed = (message, server, bot) => {
  if (message.guild.id != '293787390710120449') return false; // My server
  return message.author.id == bot.owner_ID;
};

module.exports.help = '*Bot owner only* hot fix';
const fs = require('fs');
module.exports.command = (message, content, bot) => {
  for (let s of Object.values(bot.servers)) {
    if (fs.existsSync(`./backups/${s.guild.id}_log-11-18-2019.json`)) {
      let json = JSON.parse(fs.readFileSync(`./backups/${s.guild.id}_log-11-18-2019.json`, 'utf8'));
      s.sars = json['sars'] || {};
      s.categoryClocks = json['categoryClocks'] || [];
    }
  }

  message.channel.send('done');
};<commit_msg>remove fix<commit_after>module.exports.name = 'quickFix';
module.exports.alias = [
  'fix'
];

module.exports.isAllowed = (message, server, bot) => {
  if (message.guild.id != '293787390710120449') return false; // My server
  return message.author.id == bot.owner_ID;
};

module.exports.help = '*Bot owner only* hot fix';

module.exports.command = (message, content, bot) => {
  // for (let s of Object.values(bot.servers)) {
  //   if (fs.existsSync(`./backups/${s.guild.id}_log-11-18-2019.json`)) {
  //     let json = JSON.parse(fs.readFileSync(`./backups/${s.guild.id}_log-11-18-2019.json`, 'utf8'));
  //     s.sars = json['sars'] || {};
  //     s.categoryClocks = json['categoryClocks'] || [];
  //   }
  // }

  message.channel.send('done');
};<|endoftext|>