<commit_before>/*
 * Tangram
 * Copyright 2009 Baidu Inc. All rights reserved.
 *
 * path: baidu/data/storage.js
 * author: kexin
 * version: 1.0
 * date: 2010/07/16
 */

///import baidu.data;
///import baidu.event.on;
///import baidu.cookie.get;
///import baidu.cookie.set;
///import baidu.cookie.remove;

/*
 * storage 浏览器本地存储，基于key-value
 *
 */
(function() {

	// escape spaces in name，单下划线替换为双下划线，空格替换为_s
	var esc = function(str) {
		return 'PS' + str.replace(/_/g, '__').replace(/ /g, '_s');
	};

	/**
    * 一些配置项
    */
	var Config = {

		// Backend search order.
		// TODO: flash, gears, whatwg_db, air, globalStorage, silverlight，去掉cookie
		searchList: ['userData', 'localStorage', 'cookie'],

		// list of backend methods
		// TODO: clear method
		methods: ['init', 'get', 'set', 'remove'],

		// set,get,remove操作结果状态标识
		status: {
			"SUCCESS": 0,
			"FAILURE": 1,
			"OVERFLOW": 2
		},

		// 保存参数设置
		option: {}
	};

  /**
   * 内建支持的后端
   * 目前包括：localStorage，userData，cookie
   *
   */
	var Backends = {

    /* HTML5标准  Firefox3.5+, Chrome4+, Safari4+(win)
     * (src: http://www.whatwg.org/specs/web-apps/current-work/#the-localstorage)
	 *
	 * 每个域名和子域名有他们自己独立的本地存储区域。主域可以访问子域的存储区域，子域也可以访问父域的存储区域。
	 *
	 */
		localStorage: {
			// (unknown?)
			size: 10 * 1024 * 1024,

			test: function() {
				return window.localStorage ? true: false;
			},

			methods: {
				init: function() {
					this.store = window.localStorage;
				},

				expand: function(key) {
					return esc(this.name) + esc(key);
				},

				set: function(key, val, fn, option) {
					var status = Config.status.SUCCESS;
					key = this.expand(key);

					var value;
					if (option && option.expires) {
						value = option.expires + "|" + val;
					} else {
						value = "0|" + val;
					};

					try {
						this.store.setItem(key, value);
					} catch(ex) {
						status = Config.status.OVERFLOW;
					};

					if (fn) {
						fn.call(this, status, val);
					};
				},

				get: function(key, fn) {
					var status = Config.status.SUCCESS;
					key = this.expand(key);

					try {
						var value = this.store.getItem(key);
						if (value == null) { // key不存在时返回null
							status = Config.status.FAILURE;
						};

						// 判断是否过期，过期返回null
						var pos = value.indexOf("|");
						var exp = value.substring(0, pos);
						var now = (new Date()).getTime();

						if (exp > now || exp == "0") {
							value = value.substring(pos + 1, value.length);
						} else {
							value = null;
							this.store.removeItem(key); // 过期时，再次读取删除key
							status = Config.status.FAILURE;
						};
					} catch(ex) {
						status = Config.status.FAILURE;
					};

					if (fn) {
						fn.call(this, status, value);
					};
				},

				remove: function(key, fn) {
					var status = Config.status.SUCCESS;
					var value = null;
					key = this.expand(key);

					try {
						var val = this.store.getItem(key);
						var pos = val.indexOf("|");
						value = val.substring(pos + 1, val.length);
						if (val == null) { // 若key不存在则返回失败状态
							status = Config.status.FAILURE;
						} else {
							this.store.removeItem(key);
						};
					} catch(ex) {
						status = Config.status.FAILURE;
					};

					if (fn) {
						fn.call(this, status, value);
					};
				}
			}
		},

		/**
	 * IE5+
	 * 受限站点，单个网页可存储64K，整个域可存储640K。
	 * Expires这个属性是用来设置userdata的超时时间的。Userdata的超时设置是针对一个文件的，一旦过期，整个文件都过期了，不能单独设置每个属性的过期时间。
	 * userData被人为删除，此时执行getAttribute()、setAttribute()会报错：“Error:数据无效"。
	 * 如果在一个浏览器进程中重复删除、写入userdata数据，userdata空间将很快被撑满，因为每次删除都是逻辑删除，等到浏览器进程结束后才会真正执行删除操作。
	 *
	 *
	 */
		userData: {
			size: 64 * 1024,

			test: function() {
				return window.ActiveXObject ? true: false;
			},

			methods: {
				/**
                 * 不兼容页面无body的情况，需要body加载完成调用
                 *
                 *
                 */
				init: function() {
					var prefix = '_storage_data_';
					var id = prefix + esc(this.name);
					this.el = document.createElement('div');
					this.el.id = id;
					this.el.style.display = 'none';
					this.el.addBehavior('#default#userData');
					var me = this;
					//document.body.appendChild(this.el);
					document.body.insertBefore(this.el, document.body.firstChild);

					// 防止内存泄漏
					baidu.on(window, "unload", function() {
						me.el = null;
					});
				},

				expand: function(key) {
					return esc(this.name) + esc(key);
				},

				/**
                 * setAttribute(key)
                 * 利用key生成文件名，一个文件存储一个key
                 *
                 */
				set: function(key, val, fn, option) {
					key = this.expand(key);
					var status = Config.status.SUCCESS;

					try {
						var value;
						// 添加过期时间
						if (option && option.expires) {
							this.el.expires = (new Date(option.expires + 8 * 60 * 60 * 1000)).toUTCString();
							value = option.expires + "|" + val;
						} else {
							value = "0|" + val;
						};

						this.el.setAttribute(key, value);
						this.el.save(key);
					} catch(ex) {
						status = Config.status.OVERFLOW; // 存储时抛出异常认为是溢出
						val = null;
					};

					if (fn) {
						fn.call(this, status, val);
					};
				},

				/**
                 * getAttribute(key)
                 * 利用key生成文件名，一个文件存储一个key
                 *
                 */
				get: function(key, fn) {
					key = this.expand(key);
					var status = Config.status.SUCCESS;
					try {
						this.el.load(key);
					} catch(e) {
						alert("error!");
					}

					var value = this.el.getAttribute(key); // 若过期则返回null
					if (value) {
						var pos = value.indexOf("|");
						var exp = value.substring(0, pos);
						var now = (new Date()).getTime();

						if (exp > now || exp == "0") {
							value = value.substring(pos + 1, value.length);
						} else {
							value = null;
							status = Config.status.FAILURE;
						};
					};

					if (value == null) {
						status = Config.status.FAILURE;
						this.remove(key);
					};

					if (fn) {
						fn.call(this, status, value);
					};
				},

				/**
                 * 通过设过期时间删除，需要关闭浏览器才能真正删除
                 * 如果手动删除XML文件，则用过的key不能再用，否则会出错
                 * removeAttribute方法好像不是很管用
                 */
				remove: function(key, fn) {
					key = this.expand(key);
					var status = Config.status.SUCCESS;
					var val = null;

					try {
						this.el.load(key);
						val = this.el.getAttribute(key);

						if (val == null) {
							status = Config.status.FAILURE;
						} else {
							var pos = val.indexOf("|");
							val = val.substring(pos + 1, val.length);
							this.el.expires = new Date(315532799000).toUTCString(); // 315532799000 是格林威治时间1979年12月31日23时59分59秒。这是删除UserData的最靠前的一个有效expires时间了，再往前一毫秒，expires = new Date(315532798999).toUTCString(); 就删不掉userdata了，可以认为是IE的一个bug。
							this.el.removeAttribute(key);
							this.el.save(key);
						};
					} catch(ex) {
						status = Config.status.FAILURE;
					};

					if (fn) {
						fn.call(this, status, val);
					};
				}
			}
		},

		// cookie backend
		// TODO: 加上设置项
		cookie: {
			size: 4 * 1024,

			test: function() {
				return true;
			},

			methods: {
				expand: function(key) {
					return this.name + key;
				},

				get: function(key, fn) {
					var status = Config.status.SUCCESS;
					key = this.expand(key);
					var val = baidu.cookie.get(key);
					if (val == null) {
						status = Config.status.FAILURE;
					};
					if (fn) {
						fn.call(this, status, val);
					};
				},

				set: function(key, val, fn, option) {
					var status = Config.status.SUCCESS;
					key = this.expand(key);

					// expires参数类型转换
					if (option && option.expires) {
						option.expires = new Date(expires);
					};
					baidu.cookie.set(key, val, option);
					if (fn) {
						fn.call(this, status, val);
					};
				},

				remove: function(key, fn) {
					var status = Config.status.SUCCESS;
					key = this.expand(key);
					var val = baidu.cookie.get(key);
					baidu.cookie.remove(key);
					if (val == null) {
						status = Config.status.FAILURE;
					};
					if (fn) {
						fn.call(this, status, val);
					};
				}
			}
		}
	};

	/**
     * 初始化Storage
     * 主要工作，确定一种后端，根据搜索列表或用户指定，加载会默认调用，实例化时会再次调用。
     *
     */
	var init = function(storage) {
		var empty = function() {};

		// 重置 type 和 size
		storage.type = null;
		storage.size = - 1;

		// 初始化后端方法列表
		for (var i = 0, l = Config.methods.length; i < l; i++) {
			storage.Store.prototype[Config.methods[i]] = empty;
		};

		if (Config.option.backend) {
			// TODO: 若参数后端不在支持列表的情况
			var b = Config.option.backend;

			if (Backends[b] && Backends[b].test()) {
				storage.type = b;
				storage.size = Backends[b].size;
				for (key in Backends[b].methods) {
					storage.Store.prototype[key] = Backends[b].methods[key];
				};
			} else {
				// 参数backend有误情况
				for (var i = 0, l = Config.searchList.length; ! storage.type && i < l; i++) {
					var b = Backends[Config.searchList[i]];

					if (b.test()) {
						storage.type = Config.searchList[i];
						storage.size = b.size;

						// 用实例方法扩展构造函数
						for (key in b.methods) {
							storage.Store.prototype[key] = b.methods[key];
						};
					};
				};
			};

		} else {
			// 遍历后端列表
			for (var i = 0, l = Config.searchList.length; ! storage.type && i < l; i++) {
				var b = Backends[Config.searchList[i]];

				if (b.test()) {
					storage.type = Config.searchList[i];
					storage.size = b.size;

					// 用实例方法扩展构造函数
					for (key in b.methods) {
						storage.Store.prototype[key] = b.methods[key];
					};
				};
			};
		};
	};

	/**
       * Storage接口
       *
       */
	var storage = {
		version: "1.0",
		type: null,
		size: - 1,

		// 获取浏览器支持列表
		getSupportList: function() {
			var result = [];
			for (var i = 0, l = Config.searchList.length; i < l; i++) {
				if (Backends[Config.searchList[i]].test()) {
					result.push(Config.searchList[i]);
				};
			};
			return result;
		},

		// store API
		Store: function(name, option) {
			// 名字检查
			var name_re = /^[a-z][a-z0-9_ -]+$/i;
			if (!name_re.exec(name)) {
				throw new Error("Invalid name");
			};

			if (!storage.type) {
				throw new Error("No suitable storage found");
			};

			this.name = name;

			Config.option = option || {};
			Config.option.domain = option.domain || location.hostname || 'localhost.localdomain';
			Config.option.expires = Config.option.expires || 365 * 24 * 60 * 60 * 1000;
			Config.option.path = Config.option.path || '/';

			this.init();
		},

		set: function(key, val, fn, option) {
			var st = new storage.Store("bd_storage", {});
			st.set(key, val, fn, option);
		},

		get: function(key, fn, option) {
			var st = new storage.Store("bd_storage", {});
			st.get(key, fn, option);
		},

		remove: function(key, fn) {
			var st = new storage.Store("bd_storage", {});
			st.remove(key, fn);
		}
	};

	// init persist
	init(storage);

    baidu.data.storage = storage;
})();
<commit_msg>storage升级<commit_after>/*
 * Tangram
 * Copyright 2009 Baidu Inc. All rights reserved.
 */

///import baidu.data;
///import baidu.lang.createSingle;
///import baidu.dom.insertHTML;
///import baidu.string.format;
///import baidu.object.extend;
///import baidu.lang.isDate;
///import baidu.cookie.set;
///import baidu.cookie.get;
///import baidu.cookie.remove;

/**
 * 一个本地存储对象，使用key-value的方式来存值，不具备夸浏览器通信功能，根据浏览器的不同自动选择userData或是localStorage或是cookie来存值.
 */
baidu.data.storage = baidu.data.storage || baidu.lang.createSingle({
    _status: {//各种成功或失败的状态
        'SUCCESS': 0,
        'FAILURE': 1,
        'OVERFLOW': 2
    },

    /**
     * 将一个key再进一步格式化为本地存储的格式来避免和其它的key种造成冲突
     * @param {String} key
     * @return {String}
     * @private
     */
    _getKey: function(key) {
        //escape spaces in name，单下划线替换为双下划线，空格替换为_s
        return 'PS' + key.replace(/[_\s]/g, function(matcher) {
            return matcher == '_' ? '__' : '_s';
        });
    },

    /**
     * 当是userData的存储方式时通过该方法来取得在页面中创建的用于存储的div对象
     * @return {HTMLElement} 返回一个div的html对象.
     * @private
     */
    _getElement: function() {
        return baidu.dom.g(this.guid + '-storage');
    },

    /**
     * 根据不同浏览器来返回一个本地存储对象
     * @return {Object} 返回一个对象，该对象包含set, get, del方法.
     * @private
     */
    _getInstance: function() {
        var me = this;
        if (!me._storage) {
            if (window.ActiveXObject) {
                me._storage = me._createUserData();
            }else if (window.localStorage) {
                me._storage = me._createLocalStorage();
            }else {
                me._storage = me._createCookie();
            }
        }
        return me._storage;
    },

    /**
     * 将userData进行包装并返回一个只包含三个方法的对象
     * @return {Object} 一个对象，包括set, get, del接口.
     * @private
     */
    _createUserData: function() {
        var me = this;
        baidu.dom.insertHTML(document.body,
            'beforeEnd',
            baidu.string.format('

',
                {id: me.guid + '-storage'})
        );
        me._getElement().addBehavior('#default#userData');
        return {
//            size: 64 * 1024,
            set: function(key, value, callback, options) {
                var status = me._status.SUCCESS,
                    ele = me._getElement(),
                    newKey = me._getKey(key),
                    time = options && options.expires ? options.expires
                        : new Date().getTime() + 365 * 24 * 60 * 60 * 1000;//默认保存一年时间
                baidu.lang.isDate(time) && (time = time.getTime());
                ele.expires = new Date(time).toUTCString();
                try {
                    ele.setAttribute(newKey, value);
                    ele.save(newKey);
                }catch (e) {
                    status = me._status.OVERFLOW;//存储时抛出异常认为是溢出
                }
                ele = null;
                callback && callback.call(me, status, value);
            },
            get: function(key, callback) {
                var status = me._status.SUCCESS,
                    ele = me._getElement(),
                    newKey = me._getKey(key),
                    val = null;
                try {
                    ele.load(newKey);
                    val = ele.getAttribute(newKey);//若过期则返回null
                }catch (e) {
                    status = me._status.FAILURE;
                    alert('baidu.data.storage.get error!');
                }
                callback && callback.call(me, status, val);
            },
            del: function(key, callback) {
                var status = me._status.SUCCESS,
                    ele = me._getElement(),
                    newKey = me._getKey(key),
                    val;
                try {
                    ele.load(newKey);
                    val = ele.getAttribute(newKey);
                    if (val) {
                        //315532799000 是格林威治时间1979年12月31日23时59分59秒。这是删除UserData的最靠前的一个有效expires时间了，再往前一毫秒，expires = new Date(315532798999).toUTCString(); 就删不掉userdata了，可以认为是IE的一个bug
                        ele.removeAttribute(newKey);
                        ele.expires = new Date(315532799000).toUTCString();
                        ele.save(newKey);
                    }else {
                        status = me._status.FAILURE;
                    }
                }catch (e) {
                    status = me._status.FAILURE;
                }
                callback && callback.call(me, status, val);
            }
        };
    },

    /**
     * 将localstorage进行包装并返回一个只包含三个方法的对象
     * @return {Object} 一个对象，包括set, get, del接口.
     * @private
     */
    _createLocalStorage: function() {
        var me = this;
        return {
//            size: 10 * 1024 * 1024,
            set: function(key, value, callback, options) {
                var status = me._status.SUCCESS,
                    storage = window.localStorage,
                    newKey = me._getKey(key),
                    time = options && options.expires ? options.expires : 0;
                baidu.lang.isDate(time) && (time = time.getTime());
                try {
                    storage.setItem(newKey, time + '|' + value);
                }catch (e) {
                    status = me._status.OVERFLOW;
                }
                callback && callback.call(me, status, value);
            },
            get: function(key, callback) {
                var status = me._status.SUCCESS,
                    storage = window.localStorage,
                    newKey = me._getKey(key),
                    val = null,
                    index,
                    time;
                try {
                    val = storage.getItem(newKey);
                }catch (e) {
                    status = me._status.FAILURE;
                }
                if (val) {
                    index = val.indexOf('|');
                    time = parseInt(val.substring(0, index), 10);
                    if (new Date(time).getTime() > new Date().getTime()
                        || time == 0) {
                        val = val.substring(index + 1, val.length);
                    }else{
                        val = null;
                        status = me._status.FAILURE;
                        this.del(key);
                    }
                }else {
                    status = me._status.FAILURE;
                }
                callback && callback.call(me, status, val);
            },
            del: function(key, callback) {
                var status = me._status.SUCCESS,
                    storage = window.localStorage,
                    newKey = me._getKey(key),
                    val = null;
                try {
                    val = storage.getItem(newKey);
                }catch (e) {
                    status = me._status.FAILURE;
                }
                if (val) {
                    val = val.substring(val.indexOf('|'), val.length);
                    status = me._status[val ? 'SUCCESS' : 'FAILURE'];
                    val && storage.removeItem(newKey);
                }else {
                    status = me._status.FAILURE;
                }
                callback && callback.call(me, status, val);
            }
        };
    },

    /**
     * 将baidu.cookie进行包装并返回一个只包含三个方法的对象
     * @return {Object} 一个对象，包括set, get, del接口.
     * @private
     */
    _createCookie: function() {
        var me = this;
        return {
//            size: 4 * 1024,
            set: function(key, value, callback, options) {
                baidu.cookie.set(me._getKey(key), value, options);
                callback && callback.call(me, me._status.SUCCESS, value);
            },

            get: function(key, callback) {
                var val = baidu.cookie.get(me._getKey(key));
                callback && callback.call(me, me._status[val ? 'SUCCESS' : 'FAILURE'], val);
            },
            del: function(key, callback) {
                var newKey = me._getKey(key),
                    val = baidu.cookie.get(newKey);
                baidu.cookie.remove(newKey);
                callback && callback.call(me, me._status[val ? 'SUCCESS' : 'FAILURE'], val);
            }
        };
    },

    /**
     * 将一个键值对存入到本地存储中
     * @param {String} key 一个键名.
     * @param {String} value 一个值.
     * @param {Function} callback 一个回调函数，函数的第一参数返回该次存储的状态码，各状码表示{0: 成功, 1: 失败, 2: 溢出}，第二参数返回当次的value.
     * @param {Object} options config参数.
     * @config {Date|Number} expires 设置一个过期时间，值的类型必须是一个Date对象或是一个毫秒数
     */
    set: function(key, value, callback, options) {
        var me = this, storage = me._getInstance();
        storage.set.apply(storage, arguments);
    },

    /**
     * 依据一个键名称来取得本地存储中的值
     * @param {String} key 一个键名称.
     * @param {Function} callback 一个回调函数，函数的第一参数返回该次存储的状态码，各状码表示{0: 成功, 1: 失败, 2: 溢出}，第二参数返回当次的value.
     */
    get: function(key, callback) {
        var me = this, storage = me._getInstance();
        storage.get.apply(storage, arguments);
    },

    /**
     * 根据一个键名称来删除在本地存储中的值
     * @param {String} key 一个键名称.
     * @param {Function} callback 一个回调函数，函数的第一参数返回该次存储的状态码，各状码表示{0: 成功, 1: 失败, 2: 溢出}，第二参数返回当次的value.
     */
    remove: function(key, callback) {
        var me = this, storage = me._getInstance();
        storage.del.apply(storage, arguments);
    }
});
<|endoftext|>


<commit_before>import React, { PropTypes, Component } from 'react';
import * as UserActionCreators from '../../actions/UserActionCreators';
import FullWidthButton from '../ui/FullWidthButton';
import ThreadFilterList from './filters/ThreadFilterList';
import LocationFilter from './filters/LocationFilter';
import IntegerRangeFilter from './filters/IntegerRangeFilter';
import ChoiceFilter from './filters/ChoiceFilter';
import DoubleChoiceFilter from './filters/DoubleChoiceFilter';
import MultipleChoicesFilter from './filters/MultipleChoicesFilter';
import TagFilter from './filters/TagFilter';
import TagsAndChoiceFilter from './filters/TagsAndChoiceFilter';
import selectn from 'selectn';

export default class CreateUsersThread extends Component {
    static contextTypes = {
        history: PropTypes.object.isRequired
    };

    static propTypes = {
        userId: PropTypes.number.isRequired,
        filters: PropTypes.object.isRequired,
        threadName: PropTypes.string
        // TODO: defFilters should be a prop
    };

    constructor(props) {
        super(props);

        this.handleClickAddFilter = this.handleClickAddFilter.bind(this);
        this.handleClickFilterOnList = this.handleClickFilterOnList.bind(this);
        this.renderActiveFilters = this.renderActiveFilters.bind(this);
        this.handleClickFilter = this.handleClickFilter.bind(this);
        this.handleClickRemoveFilter = this.handleClickRemoveFilter.bind(this);
        this.renderLocationFilter = this.renderLocationFilter.bind(this);
        this.handleClickLocationSuggestion = this.handleClickLocationSuggestion.bind(this);
        this.renderChoiceFilter = this.renderChoiceFilter.bind(this);
        this.renderDoubleChoiceFilter = this.renderDoubleChoiceFilter.bind(this);
        this.renderMultipleChoicesFilter = this.renderMultipleChoicesFilter.bind(this);
        this.renderIntegerRangeFilter = this.renderIntegerRangeFilter.bind(this);
        this.renderTagFilter = this.renderTagFilter.bind(this);
        this.renderTagAndChoiceFilter = this.renderTagAndChoiceFilter.bind(this);
        this.handleClickChoice = this.handleClickChoice.bind(this);
        this.handleClickDoubleChoiceChoice = this.handleClickDoubleChoiceChoice.bind(this);
        this.handleClickDoubleChoiceDetail = this.handleClickDoubleChoiceDetail.bind(this);
        this.handleClickMultipleChoice = this.handleClickMultipleChoice.bind(this);
        this.handleClickRemoveTagsAndChoice = this.handleClickRemoveTagsAndChoice.bind(this);
        this.handleClickTagAndChoiceChoice = this.handleClickTagAndChoiceChoice.bind(this);
        this.handleClickTagAndChoiceTagSuggestion = this.handleClickTagAndChoiceTagSuggestion.bind(this);
        this.handleChangeIntegerInput = this.handleChangeIntegerInput.bind(this);
        this.handleClickTagSuggestion = this.handleClickTagSuggestion.bind(this);
        this.createThread = this.createThread.bind(this);
        this.handleClickOutside = this.handleClickOutside.bind(this);
        this.findSelectedFilterIndex = this.findSelectedFilterIndex.bind(this);

        this.state = {
            selectFilter: false,
            selectedFilter: {},
            filters: []
        }
    }

    componentDidMount () {
        window.nekunoContainer.addEventListener('click', this.handleClickOutside)
    }

    componentWillUnmount () {
        window.nekunoContainer.removeEventListener('click', this.handleClickOutside)
    }

    handleClickAddFilter() {
        this.setState({
            selectFilter: true
        })
    }

    handleClickFilterOnList(checked, value) {
        let filters = this.state.filters;
        let filter = filters.find(key => key === value);
        if (typeof filter == 'undefined') {
            let defaultFilters = Object.assign({}, this.props.filters);
            filter = Object.keys(defaultFilters).map(key => defaultFilters[key]).find(function (defaultFilter) {
                return defaultFilter.key === value;
            });
        }
        if (checked) {
            filters.push(filter);
            this.setState({
                selectFilter: false,
                selectedFilter: filter,
                filters: filters
            });
            clearTimeout(this.selectFilterTimeout);
            this.selectFilterTimeout = setTimeout(() => {
                let selectedFilterElem = this.refs.selectedFilter;
                if (selectedFilterElem) {
                    selectedFilterElem.getSelectedFilter().scrollIntoView();
                    document.getElementsByClassName('view')[0].scrollTop -= 100;
                }
            })
        } else {
            let index = filters.findIndex(savedFilter => savedFilter.key === filter.key);
            filters.splice(index, 1);
            this.setState({
                filters: filters,
                selectedFilter: {}
            });
        }
    }

    renderActiveFilters() {
        let filters = this.state.filters;
        return (
            filters.map((filter, index) => {
                const selected = this.state.selectedFilter && this.state.selectedFilter.key === filter.key;
                switch (filter.type) {
                    case 'location_distance':
                        return this.renderLocationFilter(filter, index, selected);
                        break;
                    case 'integer_range':
                        return this.renderIntegerRangeFilter(filter, index, selected);
                        break;
                    case 'choice':
                        return this.renderChoiceFilter(filter, index, selected);
                        break;
                    case 'double_choice':
                        return this.renderDoubleChoiceFilter(filter, index, selected);
                        break;
                    case 'multiple_choices':
                        return this.renderMultipleChoicesFilter(filter, index, selected);
                        break;
                    case 'tags_and_choice':
                        return this.renderTagAndChoiceFilter(filter, index, selected);
                        break;
                    case 'tags':
                        return this.renderTagFilter(filter, index, selected);
                }
            })
        );
    }

    renderLocationFilter(filter, index, selected) {
        return (
            <LocationFilter key={index} ref={selected ? 'selectedFilter' : ''}
                            filter={filter}
                            selected={selected}
                            handleClickRemoveFilter={this.handleClickRemoveFilter}
                            handleClickLocationSuggestion={this.handleClickLocationSuggestion}
                            handleClickFilter={this.handleClickFilter}
            />
        );
    }

    renderIntegerRangeFilter(filter, index, selected) {
        return(
            <IntegerRangeFilter key={index} ref={selected ? 'selectedFilter' : ''}
                           filter={filter}
                           selected={selected}
                           handleClickRemoveFilter={this.handleClickRemoveFilter}
                           handleChangeIntegerInput={this.handleChangeIntegerInput}
                           handleClickFilter={this.handleClickFilter}
            />
        )
    }

    renderChoiceFilter(filter, index, selected) {
        return (
            <ChoiceFilter key={index} ref={selected ? 'selectedFilter' : ''}
                          filter={filter}
                          selected={selected}
                          handleClickRemoveFilter={this.handleClickRemoveFilter}
                          handleClickChoice={this.handleClickChoice}
                          handleClickFilter={this.handleClickFilter}
            />
        );
    }

    renderDoubleChoiceFilter(filter, index, selected) {
        return (
            <DoubleChoiceFilter key={index} ref={selected ? 'selectedFilter' : ''}
                                filter={filter}
                                selected={selected}
                                handleClickRemoveFilter={this.handleClickRemoveFilter}
                                handleClickDoubleChoiceChoice={this.handleClickDoubleChoiceChoice}
                                handleClickDoubleChoiceDetail={this.handleClickDoubleChoiceDetail}
                                handleClickFilter={this.handleClickFilter}
            />
        );
    }

    renderMultipleChoicesFilter(filter, index, selected) {
        return (
            <MultipleChoicesFilter key={index} ref={selected ? 'selectedFilter' : ''}
                                   filter={filter}
                                   selected={selected}
                                   handleClickRemoveFilter={this.handleClickRemoveFilter}
                                   handleClickMultipleChoice={this.handleClickMultipleChoice}
                                   handleClickFilter={this.handleClickFilter}
            />
        );
    }

    renderTagFilter(filter, index, selected) {
        return (
            <TagFilter key={index} ref={selected ? 'selectedFilter' : ''}
                       filter={filter}
                       selected={selected}
                       handleClickRemoveFilter={this.handleClickRemoveFilter}
                       handleClickTagSuggestion={this.handleClickTagSuggestion}
                       handleClickFilter={this.handleClickFilter}
            />
        );
    }

    renderTagAndChoiceFilter(filter, index, selected) {
        return (
            <TagsAndChoiceFilter key={index} ref={selected ? 'selectedFilter' : ''}
                                 filter={filter}
                                 selected={selected}
                                 handleClickRemoveFilter={this.handleClickRemoveFilter}
                                 handleClickTagAndChoiceTagSuggestion={this.handleClickTagAndChoiceTagSuggestion}
                                 handleClickTagAndChoiceChoice={this.handleClickTagAndChoiceChoice}
                                 handleClickRemoveTagsAndChoice={this.handleClickRemoveTagsAndChoice}
                                 handleClickTagAndChoiceTag={this.handleClickTagAndChoiceTag}
                                 handleClickFilter={this.handleClickFilter}
            />
        );
    }

    handleClickLocationSuggestion(location) {
        let {filters, selectedFilter} = this.state;
        filters[this.findSelectedFilterIndex()] = this.refs.selectedFilter.updateFilterLocation(selectedFilter, location);
        this.setState({
            filters: filters,
            selectedFilter: {}
        });
    }

    handleChangeIntegerInput(value, minOrMax) {
        let {filters, selectedFilter} = this.state;
        let filter = this.refs.selectedFilter.updateFilterInteger(selectedFilter, value, minOrMax)
        filters[this.findSelectedFilterIndex()] = filter;
        this.setState({
            selectedFilter: filter,
            filters: filters
        });
    }

    handleClickChoice(choice) {
        let {filters, selectedFilter} = this.state;
        let filter = this.refs.selectedFilter.updateFilterChoice(selectedFilter, choice);
        filters[this.findSelectedFilterIndex()] = filter;
        this.setState({
            filters: filters,
            selectedFilter: filter
        });
    }

    handleClickDoubleChoiceChoice(choice) {
        let {filters, selectedFilter} = this.state;
        let filter = this.refs.selectedFilter.updateFilterChoice(selectedFilter, choice);
        filters[this.findSelectedFilterIndex()] = filter;
        this.setState({
            filters: filters,
            selectedFilter: filter
        });
    }

    handleClickDoubleChoiceDetail(detail) {
        let {filters, selectedFilter} = this.state;
        let filter = this.refs.selectedFilter.updateFilterDetail(selectedFilter, detail);
        filters[this.findSelectedFilterIndex()] = filter;
        this.setState({
            filters: filters,
            selectedFilter: filter
        });
    }

    handleClickMultipleChoice(choice) {
        let {filters, selectedFilter} = this.state;
        let filter = this.refs.selectedFilter.updateFilterChoice(selectedFilter, choice);
        filters[this.findSelectedFilterIndex()] = filter;
        this.setState({
            filters: filters,
            selectedFilter: filter
        });
    }

    handleClickRemoveTagsAndChoice(tagAndChoiceIndex) {
        let {filters, selectedFilter} = this.state;
        let filter = this.refs.selectedFilter.removeTagAndChoice(selectedFilter, tagAndChoiceIndex);
        filters[this.findSelectedFilterIndex()] = filter;
        this.setState({
            filters: filters,
            selectedFilter: filter
        });
    }

    handleClickTagSuggestion(tagString) {
        let {filters, selectedFilter} = this.state;
        filters[this.findSelectedFilterIndex()] = this.refs.selectedFilter.updateFilterTag(selectedFilter, tagString);
        this.setState({
            filters: filters,
            selectedFilter: {}
        });
    }

    handleClickTagAndChoiceTagSuggestion(tagString) {
        let {filters, selectedFilter} = this.state;
        filters[this.findSelectedFilterIndex()] = this.refs.selectedFilter.updateFilterTag(selectedFilter, tagString);
        this.setState({
            filters: filters
        });
    }

    handleClickTagAndChoiceChoice(choice, selectedTag) {
        let {filters, selectedFilter} = this.state;
        let filter = this.refs.selectedFilter.updateFilterChoice(selectedFilter, choice, selectedTag);
        filters[this.findSelectedFilterIndex()] = filter;
        this.setState({
            filters: filters,
            selectedFilter: filter
        });
    }

    handleClickFilter(key) {
        let filters = this.state.filters;
        this.setState({
            selectedFilter: filters.find(filter => filter.key === key)
        });
    }

    handleClickRemoveFilter() {
        let filters = this.state.filters;
        filters.splice(this.findSelectedFilterIndex(), 1);
        this.setState({
            filters: filters,
            selectedFilter: {}
        })
    }

    handleClickOutside(e) {
        const selectedFilter = this.refs.selectedFilter;
        if (selectedFilter && selectedFilter.getSelectedFilter() && !selectedFilter.selectedFilterContains(e.target)) {
            this.setState({selectedFilter: {}});
        }
    }

    findSelectedFilterIndex() {
        let {filters, selectedFilter} = this.state;
        let index = filters.findIndex(savedFilter => savedFilter.key === selectedFilter.key);

        return index > -1 ? index : null;
    }

    createThread() {
        let data = {
            name: this.props.threadName,
            filters: {profileFilters: {}, userFilters: {}},
            category: 'ThreadUsers'
        };

        let stateFilters = this.state.filters;

        for (let stateFilter of stateFilters) {
            //TODO: Improve reading from metadata
            let box = 'profileFilters';
            switch (stateFilter.type) {
                case 'choice':
                    data.filters[box][stateFilter.key] = stateFilter.choice;
                    break;
                case 'location_distance':
                    data.filters[box][stateFilter.key] = {};
                    data.filters[box][stateFilter.key]['location'] = stateFilter.value;
                    data.filters[box][stateFilter.key]['distance'] = 50;
                    break;
                case 'tags':
                    data.filters[box][stateFilter.key] = stateFilter.values;
                    break;
                case 'double_choice':
                    data.filters[box][stateFilter.key] = {};
                    data.filters[box][stateFilter.key]['choice'] = stateFilter.choice;
                    data.filters[box][stateFilter.key]['detail'] = stateFilter.detail;
                    break;
                case 'multiple_choices':
                    data.filters[box][stateFilter.key] = stateFilter.values;
                    break;
                case 'integer_range':
                    if (stateFilter.key == 'similarity' || stateFilter.key == 'compatibility'){
                        box = 'userFilters';
                    }
                    data.filters[box][stateFilter.key] = {};
                    data.filters[box][stateFilter.key]['min'] = selectn('value_min', stateFilter)? stateFilter.value_min : stateFilter.min;
                    data.filters[box][stateFilter.key]['max'] = selectn('value_max', stateFilter)? stateFilter.value_max : stateFilter.max;
                    break;
                default:
                    break;
            }
        }
        let history = this.context.history;
        UserActionCreators.createThread(this.props.userId, data)
            .then(function(){
                history.pushState(null, `threads`);
            });
    }

    render() {
        let filtersMetadata = Object.assign({}, this.props.filters);
        Object.keys(filtersMetadata).forEach(key => filtersMetadata[key].key = key);
        return (
            this.state.selectFilter ?

Selecciona un filtro

                    <ThreadFilterList filters={this.state.filters}
                                      filtersMetadata={filtersMetadata}
                                      handleClickFilterOnList={this.handleClickFilterOnList}
                    />

                :

                    {this.renderActiveFilters()}

                                Añadir filtro

                    <FullWidthButton onClick={this.createThread}>Crear hilo</FullWidthButton>

        );
    }
}
<commit_msg>QS-987: Small refactor<commit_after>import React, { PropTypes, Component } from 'react';
import * as UserActionCreators from '../../actions/UserActionCreators';
import FullWidthButton from '../ui/FullWidthButton';
import ThreadFilterList from './filters/ThreadFilterList';
import LocationFilter from './filters/LocationFilter';
import IntegerRangeFilter from './filters/IntegerRangeFilter';
import ChoiceFilter from './filters/ChoiceFilter';
import DoubleChoiceFilter from './filters/DoubleChoiceFilter';
import MultipleChoicesFilter from './filters/MultipleChoicesFilter';
import TagFilter from './filters/TagFilter';
import TagsAndChoiceFilter from './filters/TagsAndChoiceFilter';
import selectn from 'selectn';

export default class CreateUsersThread extends Component {
    static contextTypes = {
        history: PropTypes.object.isRequired
    };

    static propTypes = {
        userId: PropTypes.number.isRequired,
        filters: PropTypes.object.isRequired,
        threadName: PropTypes.string
        // TODO: defFilters should be a prop
    };

    constructor(props) {
        super(props);

        this.handleClickAddFilter = this.handleClickAddFilter.bind(this);
        this.handleClickFilterOnList = this.handleClickFilterOnList.bind(this);
        this.renderActiveFilters = this.renderActiveFilters.bind(this);
        this.handleClickFilter = this.handleClickFilter.bind(this);
        this.handleClickRemoveFilter = this.handleClickRemoveFilter.bind(this);
        this.renderLocationFilter = this.renderLocationFilter.bind(this);
        this.handleClickLocationSuggestion = this.handleClickLocationSuggestion.bind(this);
        this.renderChoiceFilter = this.renderChoiceFilter.bind(this);
        this.renderDoubleChoiceFilter = this.renderDoubleChoiceFilter.bind(this);
        this.renderMultipleChoicesFilter = this.renderMultipleChoicesFilter.bind(this);
        this.renderIntegerRangeFilter = this.renderIntegerRangeFilter.bind(this);
        this.renderTagFilter = this.renderTagFilter.bind(this);
        this.renderTagAndChoiceFilter = this.renderTagAndChoiceFilter.bind(this);
        this.handleClickChoice = this.handleClickChoice.bind(this);
        this.handleClickDoubleChoiceChoice = this.handleClickDoubleChoiceChoice.bind(this);
        this.handleClickDoubleChoiceDetail = this.handleClickDoubleChoiceDetail.bind(this);
        this.handleClickMultipleChoice = this.handleClickMultipleChoice.bind(this);
        this.handleClickRemoveTagsAndChoice = this.handleClickRemoveTagsAndChoice.bind(this);
        this.handleClickTagAndChoiceChoice = this.handleClickTagAndChoiceChoice.bind(this);
        this.handleClickTagAndChoiceTagSuggestion = this.handleClickTagAndChoiceTagSuggestion.bind(this);
        this.handleChangeIntegerInput = this.handleChangeIntegerInput.bind(this);
        this.handleClickTagSuggestion = this.handleClickTagSuggestion.bind(this);
        this.createThread = this.createThread.bind(this);
        this.handleClickOutside = this.handleClickOutside.bind(this);
        this.findSelectedFilterIndex = this.findSelectedFilterIndex.bind(this);
        this.scrollToFilter = this.scrollToFilter.bind(this);

        this.state = {
            selectFilter: false,
            selectedFilter: {},
            filters: []
        }
    }

    componentDidMount () {
        window.nekunoContainer.addEventListener('click', this.handleClickOutside)
    }

    componentWillUnmount () {
        window.nekunoContainer.removeEventListener('click', this.handleClickOutside)
    }

    handleClickAddFilter() {
        this.setState({
            selectFilter: true
        })
    }

    handleClickFilterOnList(checked, value) {
        let filters = this.state.filters;
        let filter = filters.find(key => key === value);
        if (typeof filter == 'undefined') {
            let defaultFilters = Object.assign({}, this.props.filters);
            filter = Object.keys(defaultFilters).map(key => defaultFilters[key]).find(function (defaultFilter) {
                return defaultFilter.key === value;
            });
        }
        if (checked) {
            filters.push(filter);
            this.setState({
                selectFilter: false,
                selectedFilter: filter,
                filters: filters
            });
            this.scrollToFilter();
        } else {
            const index = filters.findIndex(savedFilter => savedFilter.key === filter.key);
            filters.splice(index, 1);
            this.setState({
                filters: filters,
                selectedFilter: {}
            });
        }
    }

    renderActiveFilters() {
        let filters = this.state.filters;
        return (
            filters.map((filter, index) => {
                const selected = this.state.selectedFilter && this.state.selectedFilter.key === filter.key;
                switch (filter.type) {
                    case 'location_distance':
                        return this.renderLocationFilter(filter, index, selected);
                        break;
                    case 'integer_range':
                        return this.renderIntegerRangeFilter(filter, index, selected);
                        break;
                    case 'choice':
                        return this.renderChoiceFilter(filter, index, selected);
                        break;
                    case 'double_choice':
                        return this.renderDoubleChoiceFilter(filter, index, selected);
                        break;
                    case 'multiple_choices':
                        return this.renderMultipleChoicesFilter(filter, index, selected);
                        break;
                    case 'tags_and_choice':
                        return this.renderTagAndChoiceFilter(filter, index, selected);
                        break;
                    case 'tags':
                        return this.renderTagFilter(filter, index, selected);
                }
            })
        );
    }

    renderLocationFilter(filter, index, selected) {
        return (
            <LocationFilter key={index} ref={selected ? 'selectedFilter' : ''}
                            filter={filter}
                            selected={selected}
                            handleClickRemoveFilter={this.handleClickRemoveFilter}
                            handleClickLocationSuggestion={this.handleClickLocationSuggestion}
                            handleClickFilter={this.handleClickFilter}
            />
        );
    }

    renderIntegerRangeFilter(filter, index, selected) {
        return(
            <IntegerRangeFilter key={index} ref={selected ? 'selectedFilter' : ''}
                           filter={filter}
                           selected={selected}
                           handleClickRemoveFilter={this.handleClickRemoveFilter}
                           handleChangeIntegerInput={this.handleChangeIntegerInput}
                           handleClickFilter={this.handleClickFilter}
            />
        )
    }

    renderChoiceFilter(filter, index, selected) {
        return (
            <ChoiceFilter key={index} ref={selected ? 'selectedFilter' : ''}
                          filter={filter}
                          selected={selected}
                          handleClickRemoveFilter={this.handleClickRemoveFilter}
                          handleClickChoice={this.handleClickChoice}
                          handleClickFilter={this.handleClickFilter}
            />
        );
    }

    renderDoubleChoiceFilter(filter, index, selected) {
        return (
            <DoubleChoiceFilter key={index} ref={selected ? 'selectedFilter' : ''}
                                filter={filter}
                                selected={selected}
                                handleClickRemoveFilter={this.handleClickRemoveFilter}
                                handleClickDoubleChoiceChoice={this.handleClickDoubleChoiceChoice}
                                handleClickDoubleChoiceDetail={this.handleClickDoubleChoiceDetail}
                                handleClickFilter={this.handleClickFilter}
            />
        );
    }

    renderMultipleChoicesFilter(filter, index, selected) {
        return (
            <MultipleChoicesFilter key={index} ref={selected ? 'selectedFilter' : ''}
                                   filter={filter}
                                   selected={selected}
                                   handleClickRemoveFilter={this.handleClickRemoveFilter}
                                   handleClickMultipleChoice={this.handleClickMultipleChoice}
                                   handleClickFilter={this.handleClickFilter}
            />
        );
    }

    renderTagFilter(filter, index, selected) {
        return (
            <TagFilter key={index} ref={selected ? 'selectedFilter' : ''}
                       filter={filter}
                       selected={selected}
                       handleClickRemoveFilter={this.handleClickRemoveFilter}
                       handleClickTagSuggestion={this.handleClickTagSuggestion}
                       handleClickFilter={this.handleClickFilter}
            />
        );
    }

    renderTagAndChoiceFilter(filter, index, selected) {
        return (
            <TagsAndChoiceFilter key={index} ref={selected ? 'selectedFilter' : ''}
                                 filter={filter}
                                 selected={selected}
                                 handleClickRemoveFilter={this.handleClickRemoveFilter}
                                 handleClickTagAndChoiceTagSuggestion={this.handleClickTagAndChoiceTagSuggestion}
                                 handleClickTagAndChoiceChoice={this.handleClickTagAndChoiceChoice}
                                 handleClickRemoveTagsAndChoice={this.handleClickRemoveTagsAndChoice}
                                 handleClickTagAndChoiceTag={this.handleClickTagAndChoiceTag}
                                 handleClickFilter={this.handleClickFilter}
            />
        );
    }

    handleClickLocationSuggestion(location) {
        let {filters, selectedFilter} = this.state;
        filters[this.findSelectedFilterIndex()] = this.refs.selectedFilter.updateFilterLocation(selectedFilter, location);
        this.setState({
            filters: filters,
            selectedFilter: {}
        });
    }

    handleChangeIntegerInput(value, minOrMax) {
        let {filters, selectedFilter} = this.state;
        let filter = this.refs.selectedFilter.updateFilterInteger(selectedFilter, value, minOrMax)
        filters[this.findSelectedFilterIndex()] = filter;
        this.setState({
            filters: filters,
            selectedFilter: filter
        });
    }

    handleClickChoice(choice) {
        let {filters, selectedFilter} = this.state;
        let filter = this.refs.selectedFilter.updateFilterChoice(selectedFilter, choice);
        filters[this.findSelectedFilterIndex()] = filter;
        this.setState({
            filters: filters,
            selectedFilter: filter
        });
    }

    handleClickDoubleChoiceChoice(choice) {
        let {filters, selectedFilter} = this.state;
        let filter = this.refs.selectedFilter.updateFilterChoice(selectedFilter, choice);
        filters[this.findSelectedFilterIndex()] = filter;
        this.setState({
            filters: filters,
            selectedFilter: filter
        });
    }

    handleClickDoubleChoiceDetail(detail) {
        let {filters, selectedFilter} = this.state;
        let filter = this.refs.selectedFilter.updateFilterDetail(selectedFilter, detail);
        filters[this.findSelectedFilterIndex()] = filter;
        this.setState({
            filters: filters,
            selectedFilter: filter
        });
    }

    handleClickMultipleChoice(choice) {
        let {filters, selectedFilter} = this.state;
        let filter = this.refs.selectedFilter.updateFilterChoice(selectedFilter, choice);
        filters[this.findSelectedFilterIndex()] = filter;
        this.setState({
            filters: filters,
            selectedFilter: filter
        });
    }

    handleClickRemoveTagsAndChoice(tagAndChoiceIndex) {
        let {filters, selectedFilter} = this.state;
        let filter = this.refs.selectedFilter.removeTagAndChoice(selectedFilter, tagAndChoiceIndex);
        filters[this.findSelectedFilterIndex()] = filter;
        this.setState({
            filters: filters,
            selectedFilter: filter
        });
    }

    handleClickTagSuggestion(tagString) {
        let {filters, selectedFilter} = this.state;
        filters[this.findSelectedFilterIndex()] = this.refs.selectedFilter.updateFilterTag(selectedFilter, tagString);
        this.setState({
            filters: filters,
            selectedFilter: {}
        });
    }

    handleClickTagAndChoiceTagSuggestion(tagString) {
        let {filters, selectedFilter} = this.state;
        filters[this.findSelectedFilterIndex()] = this.refs.selectedFilter.updateFilterTag(selectedFilter, tagString);
        this.setState({
            filters: filters
        });
    }

    handleClickTagAndChoiceChoice(choice, selectedTag) {
        let {filters, selectedFilter} = this.state;
        let filter = this.refs.selectedFilter.updateFilterChoice(selectedFilter, choice, selectedTag);
        filters[this.findSelectedFilterIndex()] = filter;
        this.setState({
            filters: filters,
            selectedFilter: filter
        });
    }

    handleClickFilter(key) {
        let filters = this.state.filters;
        this.setState({
            selectedFilter: filters.find(filter => filter.key === key)
        });
    }

    handleClickRemoveFilter() {
        let filters = this.state.filters;
        filters.splice(this.findSelectedFilterIndex(), 1);
        this.setState({
            filters: filters,
            selectedFilter: {}
        })
    }

    handleClickOutside(e) {
        const selectedFilter = this.refs.selectedFilter;
        if (selectedFilter && selectedFilter.getSelectedFilter() && !selectedFilter.selectedFilterContains(e.target)) {
            this.setState({selectedFilter: {}});
        }
    }

    findSelectedFilterIndex() {
        let {filters, selectedFilter} = this.state;
        let index = filters.findIndex(savedFilter => savedFilter.key === selectedFilter.key);

        return index > -1 ? index : null;
    }

    scrollToFilter() {
        clearTimeout(this.selectFilterTimeout);
        this.selectFilterTimeout = setTimeout(() => {
            let selectedFilterElem = this.refs.selectedFilter;
            if (selectedFilterElem) {
                selectedFilterElem.getSelectedFilter().scrollIntoView();
                document.getElementsByClassName('view')[0].scrollTop -= 100;
            }
        }, 0);
    }

    createThread() {
        let data = {
            name: this.props.threadName,
            filters: {profileFilters: {}, userFilters: {}},
            category: 'ThreadUsers'
        };

        let stateFilters = this.state.filters;

        for (let stateFilter of stateFilters) {
            //TODO: Improve reading from metadata
            let box = 'profileFilters';
            switch (stateFilter.type) {
                case 'choice':
                    data.filters[box][stateFilter.key] = stateFilter.choice;
                    break;
                case 'location_distance':
                    data.filters[box][stateFilter.key] = {};
                    data.filters[box][stateFilter.key]['location'] = stateFilter.value;
                    data.filters[box][stateFilter.key]['distance'] = 50;
                    break;
                case 'tags':
                    data.filters[box][stateFilter.key] = stateFilter.values;
                    break;
                case 'double_choice':
                    data.filters[box][stateFilter.key] = {};
                    data.filters[box][stateFilter.key]['choice'] = stateFilter.choice;
                    data.filters[box][stateFilter.key]['detail'] = stateFilter.detail;
                    break;
                case 'multiple_choices':
                    data.filters[box][stateFilter.key] = stateFilter.values;
                    break;
                case 'integer_range':
                    if (stateFilter.key == 'similarity' || stateFilter.key == 'compatibility'){
                        box = 'userFilters';
                    }
                    data.filters[box][stateFilter.key] = {};
                    data.filters[box][stateFilter.key]['min'] = selectn('value_min', stateFilter)? stateFilter.value_min : stateFilter.min;
                    data.filters[box][stateFilter.key]['max'] = selectn('value_max', stateFilter)? stateFilter.value_max : stateFilter.max;
                    break;
                default:
                    break;
            }
        }
        let history = this.context.history;
        UserActionCreators.createThread(this.props.userId, data)
            .then(function(){
                history.pushState(null, `threads`);
            });
    }

    render() {
        let filtersMetadata = Object.assign({}, this.props.filters);
        Object.keys(filtersMetadata).forEach(key => filtersMetadata[key].key = key);
        return (
            this.state.selectFilter ?

Selecciona un filtro

                    <ThreadFilterList filters={this.state.filters}
                                      filtersMetadata={filtersMetadata}
                                      handleClickFilterOnList={this.handleClickFilterOnList}
                    />

                :

                    {this.renderActiveFilters()}

                                Añadir filtro

                    <FullWidthButton onClick={this.createThread}>Crear hilo</FullWidthButton>

        );
    }
}
<|endoftext|>


<commit_before>'use strict';

(function(){

angular
  .module('bitcoincom.services')
  .factory('moonPayApiService', moonPayApiService);

  function moonPayApiService(
    moonPayConfig
    , localStorageService
    , $http
    , $q
    , $log
    , $sce
  ) {

    var tokenKey = 'moonPayToken_' + moonPayConfig.env;
    var currentToken = null;
    var baseUrl = moonPayConfig.baseUrl

    var service = {
      // Variables

      // Functions
      preAuthenticateCustomer: preAuthenticateCustomer
      , authenticateCustomer: authenticateCustomer
      , getCustomer: getCustomer
      , updateCustomer: updateCustomer
      , createCard: createCard
      , removeCard: removeCard
      , getCards: getCards
      , createTransaction: createTransaction
      , getTransactions: getTransactions
      , getTransaction: getTransaction
      , getRates: getRates
      , getAllCountries: getAllCountries
      , getIdentityCheck: getIdentityCheck
      , createIdentityCheck: createIdentityCheck
      , uploadFile: uploadFile
      , getFiles: getFiles
      , deleteFile: deleteFile
      , getConfig: getConfig
    };

    return service;

    /**
     * Pre-authenticate a customer with an email address
     * @param {String} email
     */
    function preAuthenticateCustomer(email) {
      var deferred = $q.defer();
      getConfig(false).then(function onGetConfig(config) {
        $http.post(baseUrl + '/v2/customers/email_login?apiKey=' + moonPayConfig.pubKey, {
          'email': email
        }, config).then(function onPreAuthenticateCustomerSuccess(response) {
          deferred.resolve(response.data);
        }, function onPreAuthenticateCustomerError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Authenticate a customer with an email address and a security code
     * @param {String} email
     * @param {String} securityCode
     */
    function authenticateCustomer(email, securityCode) {
      var deferred = $q.defer();
      getConfig(false).then(function onGetConfig(config) {
        $http.post(baseUrl + '/v2/customers/email_login?apiKey=' + moonPayConfig.pubKey, {
          'email': email,
          'securityCode': securityCode
        }, config).then(function onAuthenticateCustomerSuccess(response) {
          var data = response.data;
          currentToken = data.token;
          deferred.resolve(data.customer);
          localStorageService.set(tokenKey, data.token, function onTokenSaved(err) {
            if (err) {
              $log.debug('Error setting moonpay customer token in the local storage');
              deferred.reject(err);
            } else {
              deferred.resolve(data.customer);
            }
          });
        }, function onAuthenticateCustomerError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Creates an Error object from an HTTP response.
     * @param {Object} response
     * @returns {Error}
     */
    function _errorFromResponse(response) {

      var message = '';
      try {
        message = Object.values(response.data.errors[0].constraints)[0];
      } catch(e) {
        if (response.data && response.data.message) {
          message = response.data.message;
        } else if (Math.floor(response.status / 100) !== 2) { // 2xx HTTP Status code, considered success.
          message = response.statusText;
        }
      }

      if (message) {
        return new Error(message);
      } else {
        return null;
      }
    }

    /**
     * Get customer
     */
    function getCustomer() {
      var deferred = $q.defer();
      getConfig(true).then(function onGetConfig(config) {
        $http.get(baseUrl + '/v2/customers/me', config).then(function onGetMeSuccess(response) {
          var customer = response.data;
          deferred.resolve(customer);
        }, function onGetMeError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Update a customer
     * @param {Object} customer
     */
    function updateCustomer(customer) {
      var deferred = $q.defer();
      getConfig(true).then(function onGetConfig(config) {
        $http.patch(baseUrl + '/v2/customers/me', customer, config).then(function onPatchCustomerSuccess(response) {
          var customer = response.data;
          deferred.resolve(customer);
        }, function onPatchCustomerError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Get cards
     */
    function getCards() {
      var deferred = $q.defer();
      getConfig(true).then(function onGetConfig(config) {
        $http.get(baseUrl + '/v2/cards', config).then(function onGetCardsSuccess(response) {
          var cards = response.data;
          deferred.resolve(cards);
        }, function onGetCardsError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Create a card
     * @param {Object} card
     */
    function createCard(card) {
      var deferred = $q.defer();
      getConfig(true).then(function onGetConfig(config) {
        $http.post(baseUrl + '/v2/cards', card, config).then(function onPostCardSuccess(response) {
          var card = response.data;
          deferred.resolve(card);
        }, function onPostCardError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Remove a card
     * @param {String} cardId
     */
    function removeCard(cardId) {
      var deferred = $q.defer();
      getConfig(true).then(function onGetConfig(config) {
        $http.delete(baseUrl + '/v2/cards/' + cardId, config).then(function onDeleteCardSuccess() {
          deferred.resolve();
        }, function onDeleteCardError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Get transactions
     */
    function getTransactions() {
      var deferred = $q.defer();
      getConfig(true).then(function onGetConfig(config) {
        $http.get(baseUrl + '/v2/transactions', config).then(function onGetTransactionsSuccess(response) {
          var transactions = response.data;
          deferred.resolve(transactions);
        }, function onGetTransactionsError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Get transaction
     * @param {String} transactionId
     */
    function getTransaction(transactionId) {
      var deferred = $q.defer();
      getConfig(true).then(function onGetConfig(config) {
        $http.get(baseUrl + '/v2/transactions/' + transactionId, config).then(function onGetTransactionSuccess(response) {
          var transaction = response.data;
          deferred.resolve(transaction);
        }, function onGetTransactionError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Create a transaction
     * @param {Object} transaction
     */
    function createTransaction(transaction) {
      var deferred = $q.defer();
      getConfig(true).then(function getConfig(config) {
        $http.post(baseUrl + '/v2/transactions', transaction, config).then(function onPostTransactionSuccess(response) {
          var transaction = response.data;
          deferred.resolve(transaction);
        }, function onPostTransactionError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Get rates
     * @param {String} code
     */
    function getRates(code) {
      var deferred = $q.defer();
      getConfig(false).then(function(config) {
        $http.get(baseUrl + '/v2/currencies/' + code + '/price', config).then(function onGetRatesSuccess(response) {
          var rates = response.data;
          deferred.resolve(rates);
        }, function onGetRatesError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Get all countries
     */
    function getAllCountries(onlySendAllowedCountries) {
      var deferred = $q.defer();
      getConfig(false).then(function(config) {
        $http.get(baseUrl + '/v2/countries', config).then(function onGetAllCountries(response) {
          var countries = response.data;

          if (onlySendAllowedCountries) {
            countries = countries.filter(function(country) {
              return country.isAllowed;
            });
          }

          deferred.resolve(countries);
        }, function onGetAllCountriesError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Get identity check
     */
    function getIdentityCheck() {
      var deferred = $q.defer();
      getConfig(true).then(function(config) {
        $http.get(baseUrl + '/v2/identity_check', config).then(function onGetIdentityCheckSuccess(response) {
          var identity = response.data;
          deferred.resolve(identity);
        }, function onGetIdentityCheckError(err) {
          // If identity check if not yet created, expect 404
          if (err.status === 404) {
            deferred.resolve();
          } else {
            var httpErr = _errorFromResponse(err);
            deferred.reject(httpErr);
          }
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Create an identity check
     */
    function createIdentityCheck() {
      var deferred = $q.defer();
      getConfig(true).then(function(config) {
        $http.post(baseUrl + '/v2/identity_check', {}, config).then(function onPostIdentityCheckSuccess(response) {
          var identity = response.data;
          deferred.resolve(identity);
        }, function onPostIdentityCheckError(err) {
            var httpErr = _errorFromResponse(err);
            deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Upload File
     */
    function uploadFile(data) {
      var deferred = $q.defer();
      getConfig(true).then(function(config) {
        var customConfig = Object.assign({}, config);

        customConfig.headers['Content-Type'] = undefined;
        customConfig.transformRequest = angular.identity;

        console.log(customConfig);

        $sce.trustAs($sce.RESOURCE_URL, baseUrl + '/v2/files');

        $http.post(baseUrl + '/v2/files', data, customConfig).then(function onUploadFileSuccess(response) {
          var file = response.data;
          deferred.resolve(file);
        }, function onUploadFileError(err) {
            var httpErr = _errorFromResponse(err);
            deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Get Files
     */
    function getFiles() {
      var deferred = $q.defer();
      getConfig(true).then(function(config) {
        $http.get(baseUrl + '/v2/files', config).then(function onGetFilesSuccess(response) {
          var files = response.data;
          deferred.resolve(files);
        }, function onGetFilesError(err) {
            var httpErr = _errorFromResponse(err);
            deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Delete File
     */
    function deleteFile(fileId) {
      var deferred = $q.defer();
      getConfig(true).then(function(config) {
        $http.delete(baseUrl + '/v2/files' + fileId, config).then(function onDeleteFileSuccess(response) {
          var file = response.data;
          deferred.resolve(file);
        }, function onDeleteFileError(err) {
            var httpErr = _errorFromResponse(err);
            deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    //
    // Private methods
    //

    /**
     * Get config for the http request
     * @param {Boolean} tokenIsNeeded
     */
    function getConfig(tokenIsNeeded) {
      var deferred = $q.defer();
      var config = {
        headers: {
          'Content-Type': 'application/json'
        }
      };

      if (!tokenIsNeeded) {
        deferred.resolve(config);
      } else {
        if (currentToken != null) {
          config.headers['Authorization'] = 'Bearer ' + currentToken;
          deferred.resolve(config);
        } else {
          localStorageService.get(tokenKey, function onGetToken(err, token) {
            if (err) {
              $log.debug('Error getting moonpay customer token in the local storage');
              deferred.reject(err);
            } else {
              currentToken = token
              config.headers['Authorization'] = 'Bearer ' + currentToken;
              deferred.resolve(config);
            }
          });
        }
      }
      return deferred.promise;
    }
  }
})();
<commit_msg>Feature: Checking HTTP status code of response from Moonpay API.<commit_after>'use strict';

(function(){

angular
  .module('bitcoincom.services')
  .factory('moonPayApiService', moonPayApiService);

  function moonPayApiService(
    moonPayConfig
    , localStorageService
    , $http
    , $q
    , $log
    , $sce
  ) {

    var tokenKey = 'moonPayToken_' + moonPayConfig.env;
    var currentToken = null;
    var baseUrl = moonPayConfig.baseUrl

    var service = {
      // Variables

      // Functions
      preAuthenticateCustomer: preAuthenticateCustomer
      , authenticateCustomer: authenticateCustomer
      , getCustomer: getCustomer
      , updateCustomer: updateCustomer
      , createCard: createCard
      , removeCard: removeCard
      , getCards: getCards
      , createTransaction: createTransaction
      , getTransactions: getTransactions
      , getTransaction: getTransaction
      , getRates: getRates
      , getAllCountries: getAllCountries
      , getIdentityCheck: getIdentityCheck
      , createIdentityCheck: createIdentityCheck
      , uploadFile: uploadFile
      , getFiles: getFiles
      , deleteFile: deleteFile
      , getConfig: getConfig
    };

    return service;

    /**
     * Pre-authenticate a customer with an email address
     * @param {String} email
     */
    function preAuthenticateCustomer(email) {
      var deferred = $q.defer();
      getConfig(false).then(function onGetConfig(config) {
        $http.post(baseUrl + '/v2/customers/email_login?apiKey=' + moonPayConfig.pubKey, {
          'email': email
        }, config).then(function onPreAuthenticateCustomerSuccess(response) {
          deferred.resolve(response.data);
        }, function onPreAuthenticateCustomerError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Authenticate a customer with an email address and a security code
     * @param {String} email
     * @param {String} securityCode
     */
    function authenticateCustomer(email, securityCode) {
      var deferred = $q.defer();
      getConfig(false).then(function onGetConfig(config) {
        $http.post(baseUrl + '/v2/customers/email_login?apiKey=' + moonPayConfig.pubKey, {
          'email': email,
          'securityCode': securityCode
        }, config).then(function onAuthenticateCustomerSuccess(response) {
          if (response.status === 200 || response.status === 201) {
            var data = response.data;
            currentToken = data.token;
            deferred.resolve(data.customer);
            localStorageService.set(tokenKey, data.token, function onTokenSaved(err) {
              if (err) {
                $log.debug('Error setting moonpay customer token in the local storage');
                deferred.reject(err);
              } else {
                deferred.resolve(data.customer);
              }
            });
          } else {
            deferred.reject(response.statusText);
          }
        }, function onAuthenticateCustomerError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Creates an Error object from an HTTP response.
     * @param {Object} response
     * @returns {Error}
     */
    function _errorFromResponse(response) {

      var message = '';
      try {
        message = Object.values(response.data.errors[0].constraints)[0];
      } catch(e) {
        if (response.data && response.data.message) {
          message = response.data.message;
        } else if (Math.floor(response.status / 100) !== 2) { // 2xx HTTP Status code, considered success.
          message = response.statusText;
        }
      }

      if (message) {
        return new Error(message);
      } else {
        return null;
      }
    }

    /**
     * Get customer
     */
    function getCustomer() {
      var deferred = $q.defer();
      getConfig(true).then(function onGetConfig(config) {
        $http.get(baseUrl + '/v2/customers/me', config).then(function onGetMeSuccess(response) {
          if (response.status === 200 || response.status === 201) {
            var customer = response.data;
            deferred.resolve(customer);
          } else {
            deferred.reject(response.statusText);
          }
        }, function onGetMeError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Update a customer
     * @param {Object} customer
     */
    function updateCustomer(customer) {
      var deferred = $q.defer();
      getConfig(true).then(function onGetConfig(config) {
        $http.patch(baseUrl + '/v2/customers/me', customer, config).then(function onPatchCustomerSuccess(response) {
          if (response.status === 200 || response.status === 201) {
            var customer = response.data;
            deferred.resolve(customer);
          } else {
            deferred.reject(response.statusText);
          }
        }, function onPatchCustomerError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Get cards
     */
    function getCards() {
      var deferred = $q.defer();
      getConfig(true).then(function onGetConfig(config) {
        $http.get(baseUrl + '/v2/cards', config).then(function onGetCardsSuccess(response) {
          if (response.status === 200 || response.status === 201) {
            var cards = response.data;
            deferred.resolve(cards);
          } else {
            deferred.reject(response.statusText);
          }
        }, function onGetCardsError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Create a card
     * @param {Object} card
     */
    function createCard(card) {
      var deferred = $q.defer();
      getConfig(true).then(function onGetConfig(config) {
        $http.post(baseUrl + '/v2/cards', card, config).then(function onPostCardSuccess(response) {
          if (response.status === 200 || response.status === 201) {
            var card = response.data;
            deferred.resolve(card);
          } else {
            deferred.reject(response.statusText);
          }
        }, function onPostCardError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Remove a card
     * @param {String} cardId
     */
    function removeCard(cardId) {
      var deferred = $q.defer();
      getConfig(true).then(function onGetConfig(config) {
        $http.delete(baseUrl + '/v2/cards/' + cardId, config).then(function onDeleteCardSuccess(response) {
          if (response.status === 200 || response.status === 201) {
            deferred.resolve();
          } else {
            deferred.reject(response.statusText);
          }
        }, function onDeleteCardError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Get transactions
     */
    function getTransactions() {
      var deferred = $q.defer();
      getConfig(true).then(function onGetConfig(config) {
        $http.get(baseUrl + '/v2/transactions', config).then(function onGetTransactionsSuccess(response) {
          if (response.status === 200 || response.status === 201) {
            var transactions = response.data;
            deferred.resolve(transactions);
          } else {
            deferred.reject(response.statusText);
          }
        }, function onGetTransactionsError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Get transaction
     * @param {String} transactionId
     */
    function getTransaction(transactionId) {
      var deferred = $q.defer();
      getConfig(true).then(function onGetConfig(config) {
        $http.get(baseUrl + '/v2/transactions/' + transactionId, config).then(function onGetTransactionSuccess(response) {
          if (response.status === 200 || response.status === 201) {
            var transaction = response.data;
            deferred.resolve(transaction);
          } else {
            deferred.reject(response.statusText);
          }
        }, function onGetTransactionError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Create a transaction
     * @param {Object} transaction
     */
    function createTransaction(transaction) {
      var deferred = $q.defer();
      getConfig(true).then(function getConfig(config) {
        $http.post(baseUrl + '/v2/transactions', transaction, config).then(function onPostTransactionSuccess(response) {
          if (response.status) {
            var transaction = response.data;
            deferred.resolve(transaction);
          } else {
            deferred.reject(response.statusText);
          }
        }, function onPostTransactionError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Get rates
     * @param {String} code
     */
    function getRates(code) {
      var deferred = $q.defer();
      getConfig(false).then(function(config) {
        $http.get(baseUrl + '/v2/currencies/' + code + '/price', config).then(function onGetRatesSuccess(response) {
          if (response.status === 200 || response.status === 201) {
            var rates = response.data;
            deferred.resolve(rates);
          } else {
            deferred.reject(response.statusText);
          }
        }, function onGetRatesError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Get all countries
     */
    function getAllCountries(onlySendAllowedCountries) {
      var deferred = $q.defer();
      getConfig(false).then(function(config) {
        $http.get(baseUrl + '/v2/countries', config).then(function onGetAllCountries(response) {
          if (response.status === 200 || response.status === 201) {
            var countries = response.data;

            if (onlySendAllowedCountries) {
              countries = countries.filter(function(country) {
                return country.isAllowed;
              });
            }

            deferred.resolve(countries);
          } else {
            deferred.reject(response.statusText);
          }
        }, function onGetAllCountriesError(err) {
          var httpErr = _errorFromResponse(err);
          deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Get identity check
     */
    function getIdentityCheck() {
      var deferred = $q.defer();
      getConfig(true).then(function(config) {
        $http.get(baseUrl + '/v2/identity_check', config).then(function onGetIdentityCheckSuccess(response) {
          if (response.status === 200 || response.status === 201) {
            var identity = response.data;
            deferred.resolve(identity);
          } else {
            deferred.reject(response.statusText);
          }
        }, function onGetIdentityCheckError(err) {
          // If identity check if not yet created, expect 404
          if (err.status === 404) {
            deferred.resolve();
          } else {
            var httpErr = _errorFromResponse(err);
            deferred.reject(httpErr);
          }
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Create an identity check
     */
    function createIdentityCheck() {
      var deferred = $q.defer();
      getConfig(true).then(function(config) {
        $http.post(baseUrl + '/v2/identity_check', {}, config).then(function onPostIdentityCheckSuccess(response) {
          if (response.status === 200 || response.status === 201) {
            var identity = response.data;
            deferred.resolve(identity);
          } else {
            deferred.reject(response.statusText);
          }
        }, function onPostIdentityCheckError(err) {
            var httpErr = _errorFromResponse(err);
            deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Upload File
     */
    function uploadFile(data) {
      var deferred = $q.defer();
      getConfig(true).then(function(config) {
        var customConfig = Object.assign({}, config);

        customConfig.headers['Content-Type'] = undefined;
        customConfig.transformRequest = angular.identity;

        console.log(customConfig);

        $sce.trustAs($sce.RESOURCE_URL, baseUrl + '/v2/files');

        $http.post(baseUrl + '/v2/files', data, customConfig).then(function onUploadFileSuccess(response) {
          if (response.status === 200 || response.status === 201) {
            var file = response.data;
            deferred.resolve(file);
          } else {
            deferred.reject(response.statusText);
          }
        }, function onUploadFileError(err) {
            var httpErr = _errorFromResponse(err);
            deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Get Files
     */
    function getFiles() {
      var deferred = $q.defer();
      getConfig(true).then(function(config) {
        $http.get(baseUrl + '/v2/files', config).then(function onGetFilesSuccess(response) {
          if (response.status === 200 || response.status === 201) {
            var files = response.data;
            deferred.resolve(files);
          } else {
            deferred.reject(response.statusText);
          }
        }, function onGetFilesError(err) {
            var httpErr = _errorFromResponse(err);
            deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    /**
     * Delete File
     */
    function deleteFile(fileId) {
      var deferred = $q.defer();
      getConfig(true).then(function(config) {
        $http.delete(baseUrl + '/v2/files' + fileId, config).then(function onDeleteFileSuccess(response) {
          if (response.status === 200 || response.status === 201) {
            var file = response.data;
            deferred.resolve(file);
          } else {
            deferred.reject(response.statusText);
          }
        }, function onDeleteFileError(err) {
            var httpErr = _errorFromResponse(err);
            deferred.reject(httpErr);
        });
      }, function (err) {
        deferred.reject(err);
      });
      return deferred.promise;
    }

    //
    // Private methods
    //

    /**
     * Get config for the http request
     * @param {Boolean} tokenIsNeeded
     */
    function getConfig(tokenIsNeeded) {
      var deferred = $q.defer();
      var config = {
        headers: {
          'Content-Type': 'application/json'
        }
      };

      if (!tokenIsNeeded) {
        deferred.resolve(config);
      } else {
        if (currentToken != null) {
          config.headers['Authorization'] = 'Bearer ' + currentToken;
          deferred.resolve(config);
        } else {
          localStorageService.get(tokenKey, function onGetToken(err, token) {
            if (err) {
              $log.debug('Error getting moonpay customer token in the local storage');
              deferred.reject(err);
            } else {
              currentToken = token
              config.headers['Authorization'] = 'Bearer ' + currentToken;
              deferred.resolve(config);
            }
          });
        }
      }
      return deferred.promise;
    }
  }
})();
<|endoftext|>


<commit_before>var hashname = require('hashname');
var lob = require('lob-enc');
var crypto = require('crypto');

// handle type:peer paths to create peer channels
exports.name = 'peer';

exports.mesh = function(mesh, cbExt)
{
  var log = mesh.log;
  var Pipe = mesh.lib.Pipe;
  var pipes = [];
  var peer = {};
  peer.open = {};

  // actually create/return the pipe
  function piper(to, cbPiper)
  {
    if(pipes[to]) return cbPiper(pipes[to]);

    // make a new pipe for this peering
    var pipe = pipes[to] = new Pipe('peer');
    pipe.to = to;
    pipe.path = {type:'peer',hn:to};

    // handle any peer delivery through the router
    pipe.onSend = function(packet, link, cbSend)
    {
      var router = mesh.index[to];
      if(!router) return cbSend('cannot peer to an unknown router: '+pipe.to);
      if(!router.x) return cbSend('cannot peer yet via this router: '+pipe.to);
      if(!link) return cbSend('requires link');

      // no packet means try to send our keys
      if(!packet)
      {
        Object.keys(mesh.keys).forEach(function(csid){
          if(link.csid && link.csid != csid) return; // if we know the csid, only send that key
          var json = {type:'peer',peer:link.hashname,c:router.x.cid()};
          var body = lob.encode(hashname.toPacket(mesh.keys,csid));
          log.debug('sending peer key to',router.hashname,json,csid);
          router.x.send({json:json,body:body});
        });
        return;
      }

      // if it's an encrypted channel packet, pass through direct to router
      if(packet.head.length == 0) return router.x.sending(packet);

      // otherwise we're always creating a new peer channel to carry the request
      var json = {type:'peer',peer:link.hashname,c:router.x.cid()};
      var body = lob.encode(packet);
      log.debug('sending peer handshake to',router.hashname,json,body);
      router.x.send({json:json,body:body});
      cbSend();
    }

    cbPiper(pipe);
  }

  peer.pipe = function(link, path, cbPipe){
    if(path.type != 'peer') return;
    if(!hashname.isHashname(path.hn)) return log.warn(link.hashname,'given invalid peer path',path);

    // TODO clean up link.json.paths remove any if to a default router

    piper(path.hn, cbPipe);
  }

  // exchange handlers for new opens
  peer.open.peer = function(args, open, cbOpen){

    // be extra paranoid when routing
    var from = this;
    if(typeof open.json.peer != 'string') return log.debug('invalid peer request',open.json.peer);
    var to = mesh.index[open.json.peer];
    if(!to) return log.debug('dropping peer, no link to',open.json.peer);
    if(!to.x) return log.debug('dropping peer to unknown link',open.json.peer);
    if(to.down && from.down) return log.debug('can only route when either to or from is up',to.down,from.down);

    // if a handshake, grab the token for routing
    var attached = lob.decode(open.body);
    if(attached && attached.head.length == 1)
    {
      var token = crypto.createHash('sha256').update(attached.body.slice(0,16)).digest().slice(0,16).toString('hex');
      log.debug('setting route for',token,args.pipe.path);
      mesh.routes[token] = args.pipe;
    }

    // just forward the body directly as a connect
    var json = {type:'connect',c:to.x.cid()};
    log.debug('sending connect to',to.hashname,json,open.body);
    to.x.send({json:json,body:open.body});
  }

  // handle incoming connect requests
  peer.open.connect = function(args, open, cbOpen){
    var via = this;
    var attached = lob.decode(open.body);
    if(!attached) return log.debug('dropping connect, invalid attached');

    if(attached.head.length == 0) log.debug('dropping connect, encrypted attached');

    // get the peer pipe
    piper(via.hashname, function(pipe){
      log.debug('handling connect',attached.head.length==1?'handshake':'keys',pipe.path);
      if(attached.head.length == 1)
      {
        // handle a handshake by delivering via a peer pipe AND the router's pipe
        mesh.receive(attached, pipe);
        mesh.receive(attached, args.pipe);
      }else{
        // otherwise try processing any keys
        mesh.from(attached, pipe);
      }
      cbOpen();
    });
  }

  cbExt(undefined, peer);
}
<commit_msg>vanity, no<commit_after>var hashname = require('hashname');
var lob = require('lob-enc');
var crypto = require('crypto');

// handle type:peer paths to create peer channels
exports.name = 'peer';

exports.mesh = function(mesh, cbExt)
{
  var log = mesh.log;
  var Pipe = mesh.lib.Pipe;
  var pipes = [];
  var peer = {};
  peer.open = {};

  // actually create/return the pipe
  function piper(to, cbPiper)
  {
    if(pipes[to]) return cbPiper(pipes[to]);

    // make a new pipe for this peering
    var pipe = pipes[to] = new Pipe('peer');
    pipe.to = to;
    pipe.path = {type:'peer',hn:to};

    // handle any peer delivery through the router
    pipe.onSend = function(packet, link, cbSend)
    {
      var router = mesh.index[to];
      if(!router) return cbSend('cannot peer to an unknown router: '+pipe.to);
      if(!router.x) return cbSend('cannot peer yet via this router: '+pipe.to);
      if(!link) return cbSend('requires link');

      // no packet means try to send our keys
      if(!packet)
      {
        Object.keys(mesh.keys).forEach(function(csid){
          if(link.csid && link.csid != csid) return; // if we know the csid, only send that key
          var json = {type:'peer',peer:link.hashname,c:router.x.cid()};
          var body = lob.encode(hashname.toPacket(mesh.keys,csid));
          log.debug('sending peer key to',router.hashname,json,csid);
          router.x.send({json:json,body:body});
        });
        return;
      }

      // if it's an encrypted channel packet, pass through direct to router
      if(packet.head.length == 0) return router.x.sending(packet);

      // otherwise we're always creating a new peer channel to carry the request
      var json = {type:'peer',peer:link.hashname,c:router.x.cid()};
      var body = lob.encode(packet);
      log.debug('sending peer handshake to',router.hashname,json,body);
      router.x.send({json:json,body:body});
      cbSend();
    }

    cbPiper(pipe);
  }

  peer.pipe = function(link, path, cbPipe){
    if(path.type != 'peer') return;
    if(!hashname.isHashname(path.hn)) return log.warn(link.hashname,'given invalid peer path',path);

    // TODO clean up link.json.paths remove any if to a default router

    piper(path.hn, cbPipe);
  }

  // exchange handlers for new opens
  peer.open.peer = function(args, open, cbOpen){

    // be extra paranoid when routing
    var from = this;
    if(typeof open.json.peer != 'string') return log.debug('invalid peer request',open.json.peer);
    if(open.json.peer == mesh.hashname) return log.debug('invalid peer to self');
    var to = mesh.index[open.json.peer];
    if(!to) return log.debug('dropping peer, no link to',open.json.peer);
    if(!to.x) return log.debug('dropping peer to unknown link',open.json.peer);
    if(to.down && from.down) return log.debug('can only route when either to or from is up',to.down,from.down);

    // if a handshake, grab the token for routing
    var attached = lob.decode(open.body);
    if(attached && attached.head.length == 1)
    {
      var token = crypto.createHash('sha256').update(attached.body.slice(0,16)).digest().slice(0,16).toString('hex');
      log.debug('setting route for',token,args.pipe.path);
      mesh.routes[token] = args.pipe;
    }

    // just forward the body directly as a connect
    var json = {type:'connect',c:to.x.cid()};
    log.debug('sending connect to',to.hashname,json,open.body);
    to.x.send({json:json,body:open.body});
  }

  // handle incoming connect requests
  peer.open.connect = function(args, open, cbOpen){
    var via = this;
    var attached = lob.decode(open.body);
    if(!attached) return log.debug('dropping connect, invalid attached');

    if(attached.head.length == 0) log.debug('dropping connect, encrypted attached');

    // get the peer pipe
    piper(via.hashname, function(pipe){
      log.debug('handling connect',attached.head.length==1?'handshake':'keys',pipe.path);
      if(attached.head.length == 1)
      {
        // handle a handshake by delivering via a peer pipe AND the router's pipe
        mesh.receive(attached, pipe);
        mesh.receive(attached, args.pipe);
      }else{
        // otherwise try processing any keys
        mesh.from(attached, pipe);
      }
      cbOpen();
    });
  }

  cbExt(undefined, peer);
}
<|endoftext|>