<commit_before>/**
 * Views
 * =====
 *
 * The View defines the javascript interactions that are automatically attached
 * to the nunjucks views at rendering time. The views are extending the Backbone
 * View, and adding few additional features (such as event bubbling, publisher -
 * subscriber model among others.)
 *
 * The signature of the params provided to the view are the exact same signature
 * as the ones sent to the nunjucks view:
 *
 *     * **fetch** (`object`): the object that defines where the information
 *         need to be fetched from.
 *
 *     * **params** (`params`): options passed to the view, that defines how
 *         if should behave.
 *
 *     * **children** (`array`): All the children that are contained within
 *         this specific view.
 *
 * Creation of a new view is simple::
 *
 *     lemon.views.Name = lemon.views.register('Name',
 *         /** @lends {lemon.views.Name} *\/{
 *         // Code here.
 *     })
 *
 * @author Michael Ortali <mortali@theorchard.com>
 */

goog.provide('lemon.views');
goog.provide('lemon.View');

goog.require('lemon.router');

/**
 * @constructor
 * @extends {Backbone.View}
 * @param {Object} options The options of the view.
 */
lemon.View = Backbone.View.extend(/** @lends {lemon.View.prototype} */{

    /**
     * Generate the different parameters and attach the view.
     *
     * The view is responsible to manage the piece of HTML it is attached to
     * along with all the children that are under its responsibility. The
     * constructor is called, mostly, by the method `lemon.view.load`.
     *
     * @param {Object} options The options of the view. Some of the params
     *     includes:
     */
    constructor: function(options) {
        Backbone.View.prototype.constructor.call(this, options);

        options = options || {};
        this.setProperties(options);

        var $el = $('#' + options['id']);
        if ($el.length) {
            this.setElement($('#' + options['id']));
            this.$el.removeAttr('id');
        }
    },

    /**
     * Add a child.
     *
     * The parent should be aware of the children, and the children should also
     * know their parent. It allows children to bubble up events, and it allows
     * parents to ask children to do specific tasks.
     *
     * @param {lemon.View} child The child to add to the current view.
     */
    addChild: function(child) {
        this.children.push(child);
        child.parent = this;
    },

    /**
     * Remove child.
     *
     * @param {lemon.View} child The child to remove.
     */
    removeChild: function(child) {
        this.children = _.without(this.children, child);
        child.parent = null;
        child.remove();
    },

    /**
     * Set the main properties of the view.
     *
     * @param {Object} options The options of the view.
     */
    setProperties: function(options) {
        options = options || {};
        this.children = [];
        this.params = options['params'] || {};
        this.fetch = options['fetch'] || {};
        this['events'] = this['events'] || {};
        this['events']['click a'] = this.navigate;

        _.each(options['children'], function(child) {
            var view = lemon.views.initialize(child);
            this.addChild(view);
        }, this);
    },

    /**
     * Render a view.
     *
     * Rendering a view requires to call the server (GET method). The response
     * returns a json object with two main values:
     *
     *   * **html** (string): contains all the html requires to replace the
     *     current element.
     *
     *   * **tree** (json): represents the current view and all its children.
     * @return {jQuery.jqXHR}
     */
    render: function() {
        var callback = _.bind(Backbone.View.prototype.render, this);
        var ajaxOptions = {
            'url': '/view/',
            'type': 'POST',
            'data': JSON.stringify(this.getConfig()),
            'dataType': 'json'
        };

        var self = this;
        return $.ajax(ajaxOptions)
            .done(function(json, status, xhr) {
                self.replaceCurrentView(json, status, xhr);
            })
            .always(callback);
    },

    /**
     * Replace the current view with the new view from the xhr.
     *
     */
    replaceCurrentView: function(json) {
        var html = $(json['html']);
        this.$el.replaceWith(html);
        this.setElement(html);

        // Set the view configuration.
        this.setProperties(json['tree']);
    },

    /**
     * Return the configuration of the view.
     *
     * @param {Boolean} withChildren If the children need to be included in
     *      this list.
     * @return {Object} the Object representation of the current view.
     */
    getConfig: function(withChildren) {
        var config = {
            'path': this.name,
            'params': this.params,
            'fetch': this.fetch
        };

        if (withChildren && this.children) {
            config['children'] = _.map(this.children, function(child) {
                return child.getConfig(withChildren);
            });
        }

        return config;
    },

    /**
     * Navigate to a url.
     *
     * This method can be called from two different operations: as an event
     * handler (for clicks on links) or called directly by passing in the url
     * the browser should redirect the user to.
     *
     * @param {string|Object} link The url string or the event that contains
     *      the url the user should go to.
     * @param {boolean=} force If true, the user should be immediately
     *      redirected to this address.
     * @throws Error
     */
    navigate: function(link, force) {
        var url;
        if (typeof(link) === 'string') {
            url = /** @type {string} */ (link);
        } else if (link instanceof Object) {
            link.preventDefault();
            link.stopPropagation();
            url = /** @type {string} */($(link.target).attr('href'));
        } else {
            throw 'The url is not defined, the navigation is not possible.';
        }

        var view = lemon.router.instance().reverse(url);
        if (!view || force) {
            window.location.href = url;
            return;
        }

        var evt = new jQuery.Event('navigate', {
            target: this,
            view: view,
            url: url
        });

        this.triggerNavigate(evt);
    },

    /**
     * Trigger the navigate event.
     *
     * The triggering mechanism calls the `onNavigate` on the current View if
     * the event has not been prevented. If the event has been prevented, the
     * event bubbles up to the application view - which takes care of changing
     * the url if necessary.
     *
     * @param {jQuery.Event} evt The navigate event.
     */
    triggerNavigate: function(evt) {
        if (!evt.isDefaultPrevented()) {
            var appView = lemon.views.getMainView(this);
            var callback = lemon.router.instance().navigate;
            this.onNavigate(evt, _.bind(callback, null, evt['url'], appView));
        }

        if (this.parent) {
            this.parent.triggerNavigate(evt);
        } else if (!evt.isDefaultPrevented()) {
            window.location.href = evt['url'];
        }
    },

    /**
     * Event handler for navigation.
     *
     * @param {jQuery.Event} evt The jQuery event.
     * @param {Function=} callback Callback.
     * @override
     */
    onNavigate: goog.nullFunction
});

/**
 * All available views.
 */
lemon.views.all = {};

/**
 * Register a new view.
 *
 * @param {string} viewName The view name.
 * @param {Object} properties The additional view properties.
 */
lemon.views.register = function(viewName, properties) {
    properties = properties || {};
    properties.name = viewName;

    var view = lemon.View.extend(properties);
    lemon.views.all[viewName] = view;
    return view;
};

/**
 * Get the top of the tree.
 */
lemon.views.getMainView = function(view) {
    if (view.parent) {
        return lemon.views.getMainView(view.parent);
    } else {
        return view;
    }
};

/**
 * Initialize a view.
 *
 * @param {Object} view The json that describes the view. The path of the view
 *     defines which view will be instantiated.
 * @return {lemon.View} the View.
 */
lemon.views.initialize = function(view) {
    var viewName = view.path;
    return new /** @constructor */ (lemon.views.all[viewName])(view);
};
<commit_msg>Switch `target` to `currentTarget`.<commit_after>/**
 * Views
 * =====
 *
 * The View defines the javascript interactions that are automatically attached
 * to the nunjucks views at rendering time. The views are extending the Backbone
 * View, and adding few additional features (such as event bubbling, publisher -
 * subscriber model among others.)
 *
 * The signature of the params provided to the view are the exact same signature
 * as the ones sent to the nunjucks view:
 *
 *     * **fetch** (`object`): the object that defines where the information
 *         need to be fetched from.
 *
 *     * **params** (`params`): options passed to the view, that defines how
 *         if should behave.
 *
 *     * **children** (`array`): All the children that are contained within
 *         this specific view.
 *
 * Creation of a new view is simple::
 *
 *     lemon.views.Name = lemon.views.register('Name',
 *         /** @lends {lemon.views.Name} *\/{
 *         // Code here.
 *     })
 *
 * @author Michael Ortali <mortali@theorchard.com>
 */

goog.provide('lemon.views');
goog.provide('lemon.View');

goog.require('lemon.router');

/**
 * @constructor
 * @extends {Backbone.View}
 * @param {Object} options The options of the view.
 */
lemon.View = Backbone.View.extend(/** @lends {lemon.View.prototype} */{

    /**
     * Generate the different parameters and attach the view.
     *
     * The view is responsible to manage the piece of HTML it is attached to
     * along with all the children that are under its responsibility. The
     * constructor is called, mostly, by the method `lemon.view.load`.
     *
     * @param {Object} options The options of the view. Some of the params
     *     includes:
     */
    constructor: function(options) {
        Backbone.View.prototype.constructor.call(this, options);

        options = options || {};
        this.setProperties(options);

        var $el = $('#' + options['id']);
        if ($el.length) {
            this.setElement($('#' + options['id']));
            this.$el.removeAttr('id');
        }
    },

    /**
     * Add a child.
     *
     * The parent should be aware of the children, and the children should also
     * know their parent. It allows children to bubble up events, and it allows
     * parents to ask children to do specific tasks.
     *
     * @param {lemon.View} child The child to add to the current view.
     */
    addChild: function(child) {
        this.children.push(child);
        child.parent = this;
    },

    /**
     * Remove child.
     *
     * @param {lemon.View} child The child to remove.
     */
    removeChild: function(child) {
        this.children = _.without(this.children, child);
        child.parent = null;
        child.remove();
    },

    /**
     * Set the main properties of the view.
     *
     * @param {Object} options The options of the view.
     */
    setProperties: function(options) {
        options = options || {};
        this.children = [];
        this.params = options['params'] || {};
        this.fetch = options['fetch'] || {};
        this['events'] = this['events'] || {};
        this['events']['click a'] = this.navigate;

        _.each(options['children'], function(child) {
            var view = lemon.views.initialize(child);
            this.addChild(view);
        }, this);
    },

    /**
     * Render a view.
     *
     * Rendering a view requires to call the server (GET method). The response
     * returns a json object with two main values:
     *
     *   * **html** (string): contains all the html requires to replace the
     *     current element.
     *
     *   * **tree** (json): represents the current view and all its children.
     * @return {jQuery.jqXHR}
     */
    render: function() {
        var callback = _.bind(Backbone.View.prototype.render, this);
        var ajaxOptions = {
            'url': '/view/',
            'type': 'POST',
            'data': JSON.stringify(this.getConfig()),
            'dataType': 'json'
        };

        var self = this;
        return $.ajax(ajaxOptions)
            .done(function(json, status, xhr) {
                self.replaceCurrentView(json, status, xhr);
            })
            .always(callback);
    },

    /**
     * Replace the current view with the new view from the xhr.
     *
     */
    replaceCurrentView: function(json) {
        var html = $(json['html']);
        this.$el.replaceWith(html);
        this.setElement(html);

        // Set the view configuration.
        this.setProperties(json['tree']);
    },

    /**
     * Return the configuration of the view.
     *
     * @param {Boolean} withChildren If the children need to be included in
     *      this list.
     * @return {Object} the Object representation of the current view.
     */
    getConfig: function(withChildren) {
        var config = {
            'path': this.name,
            'params': this.params,
            'fetch': this.fetch
        };

        if (withChildren && this.children) {
            config['children'] = _.map(this.children, function(child) {
                return child.getConfig(withChildren);
            });
        }

        return config;
    },

    /**
     * Navigate to a url.
     *
     * This method can be called from two different operations: as an event
     * handler (for clicks on links) or called directly by passing in the url
     * the browser should redirect the user to.
     *
     * @param {string|Object} link The url string or the event that contains
     *      the url the user should go to.
     * @param {boolean=} force If true, the user should be immediately
     *      redirected to this address.
     * @throws Error
     */
    navigate: function(link, force) {
        var url;
        if (typeof(link) === 'string') {
            url = /** @type {string} */ (link);
        } else if (link instanceof Object) {
            link.preventDefault();
            link.stopPropagation();
            url = /** @type {string} */($(link.currentTarget).attr('href'));
        } else {
            throw 'The url is not defined, the navigation is not possible.';
        }

        var view = lemon.router.instance().reverse(url);
        if (!view || force) {
            window.location.href = url;
            return;
        }

        var evt = new jQuery.Event('navigate', {
            target: this,
            view: view,
            url: url
        });

        this.triggerNavigate(evt);
    },

    /**
     * Trigger the navigate event.
     *
     * The triggering mechanism calls the `onNavigate` on the current View if
     * the event has not been prevented. If the event has been prevented, the
     * event bubbles up to the application view - which takes care of changing
     * the url if necessary.
     *
     * @param {jQuery.Event} evt The navigate event.
     */
    triggerNavigate: function(evt) {
        if (!evt.isDefaultPrevented()) {
            var appView = lemon.views.getMainView(this);
            var callback = lemon.router.instance().navigate;
            this.onNavigate(evt, _.bind(callback, null, evt['url'], appView));
        }

        if (this.parent) {
            this.parent.triggerNavigate(evt);
        } else if (!evt.isDefaultPrevented()) {
            window.location.href = evt['url'];
        }
    },

    /**
     * Event handler for navigation.
     *
     * @param {jQuery.Event} evt The jQuery event.
     * @param {Function=} callback Callback.
     * @override
     */
    onNavigate: goog.nullFunction
});

/**
 * All available views.
 */
lemon.views.all = {};

/**
 * Register a new view.
 *
 * @param {string} viewName The view name.
 * @param {Object} properties The additional view properties.
 */
lemon.views.register = function(viewName, properties) {
    properties = properties || {};
    properties.name = viewName;

    var view = lemon.View.extend(properties);
    lemon.views.all[viewName] = view;
    return view;
};

/**
 * Get the top of the tree.
 */
lemon.views.getMainView = function(view) {
    if (view.parent) {
        return lemon.views.getMainView(view.parent);
    } else {
        return view;
    }
};

/**
 * Initialize a view.
 *
 * @param {Object} view The json that describes the view. The path of the view
 *     defines which view will be instantiated.
 * @return {lemon.View} the View.
 */
lemon.views.initialize = function(view) {
    var viewName = view.path;
    return new /** @constructor */ (lemon.views.all[viewName])(view);
};
<|endoftext|>


<commit_before>#!/usr/bin/env node

var keypress = require('keypress');

keypress(process.stdin);

process.stdin.on('keypress', function (ch, key) {
  console.log('got "keypress"', key);
  if (key && key.ctrl && key.name == 'c') {
    process.stdin.pause();
  }
});

// 詳細不明だけど、setRawMode しないと arrow keys を解釈してくれなくなる
process.stdin.setRawMode(true);

// 入力待ち
process.stdin.resume();
<commit_msg>Update<commit_after>#!/usr/bin/env node

var keypress = require('keypress');

keypress(process.stdin);

// 詳細不明だけど、数値は ch の方にしか入らない
// shift や ctrl 同時押しどうするんだろう
process.stdin.on('keypress', function (ch, key) {
  console.log('got "keypress"', ch, key);
  if (key && key.ctrl && key.name == 'c') {
    process.stdin.pause();
  }
});

// 詳細不明だけど、setRawMode しないと arrow keys を解釈してくれなくなる
process.stdin.setRawMode(true);

// 入力待ち
process.stdin.resume();
<|endoftext|>


<commit_before>Package.describe({
    summary: "Accounts Templates styled for Semantic UI.",
    version: "1.3.1",
    name: "useraccounts:semantic-ui",
    git: "https://github.com/meteor-useraccounts/semantic-ui.git",
});

Package.on_use(function(api, where) {
    api.versionsFrom("METEOR@1.0");

    api.use([
        "less",
        "templating",
    ], "client");

    api.use([
        "useraccounts:core",
    ], ["client", "server"]);

    api.imply([
        "useraccounts:core@1.3.1",
    ], ["client", "server"]);

    api.add_files([
        "lib/at_error.html",
        "lib/at_error.js",
        "lib/at_form.html",
        "lib/at_form.js",
        "lib/at_input.html",
        "lib/at_input.js",
        "lib/at_nav_button.html",
        "lib/at_nav_button.js",
        "lib/at_oauth.html",
        "lib/at_oauth.js",
        "lib/at_pwd_form.html",
        "lib/at_pwd_form.js",
        "lib/at_pwd_form_btn.html",
        "lib/at_pwd_form_btn.js",
        "lib/at_pwd_link.html",
        "lib/at_pwd_link.js",
        "lib/at_result.html",
        "lib/at_result.js",
        "lib/at_sep.html",
        "lib/at_sep.js",
        "lib/at_signin_link.html",
        "lib/at_signin_link.js",
        "lib/at_signup_link.html",
        "lib/at_signup_link.js",
        "lib/at_social.html",
        "lib/at_social.js",
        "lib/at_terms_link.html",
        "lib/at_terms_link.js",
        "lib/at_title.html",
        "lib/at_title.js",
        "lib/full_page_at_form.html",
        "lib/at_semantic-ui.less"
    ], ["client"]);
});

Package.on_test(function(api) {
    api.use([
        "useraccounts:semantic-ui",
        "useraccounts:core@1.3.1",
    ]);

    api.use([
        "accounts-password",
        "tinytest",
        "test-helpers"
    ], ["client", "server"]);

    api.add_files([
        "tests/tests.js"
    ], ["client", "server"]);
});
<commit_msg>patch release - Bump to version 1.3.2<commit_after>Package.describe({
    summary: "Accounts Templates styled for Semantic UI.",
    version: "1.3.2",
    name: "useraccounts:semantic-ui",
    git: "https://github.com/meteor-useraccounts/semantic-ui.git",
});

Package.on_use(function(api, where) {
    api.versionsFrom("METEOR@1.0");

    api.use([
        "less",
        "templating",
    ], "client");

    api.use([
        "useraccounts:core",
    ], ["client", "server"]);

    api.imply([
        "useraccounts:core@1.3.2",
    ], ["client", "server"]);

    api.add_files([
        "lib/at_error.html",
        "lib/at_error.js",
        "lib/at_form.html",
        "lib/at_form.js",
        "lib/at_input.html",
        "lib/at_input.js",
        "lib/at_nav_button.html",
        "lib/at_nav_button.js",
        "lib/at_oauth.html",
        "lib/at_oauth.js",
        "lib/at_pwd_form.html",
        "lib/at_pwd_form.js",
        "lib/at_pwd_form_btn.html",
        "lib/at_pwd_form_btn.js",
        "lib/at_pwd_link.html",
        "lib/at_pwd_link.js",
        "lib/at_result.html",
        "lib/at_result.js",
        "lib/at_sep.html",
        "lib/at_sep.js",
        "lib/at_signin_link.html",
        "lib/at_signin_link.js",
        "lib/at_signup_link.html",
        "lib/at_signup_link.js",
        "lib/at_social.html",
        "lib/at_social.js",
        "lib/at_terms_link.html",
        "lib/at_terms_link.js",
        "lib/at_title.html",
        "lib/at_title.js",
        "lib/full_page_at_form.html",
        "lib/at_semantic-ui.less"
    ], ["client"]);
});

Package.on_test(function(api) {
    api.use([
        "useraccounts:semantic-ui",
        "useraccounts:core@1.3.2",
    ]);

    api.use([
        "accounts-password",
        "tinytest",
        "test-helpers"
    ], ["client", "server"]);

    api.add_files([
        "tests/tests.js"
    ], ["client", "server"]);
});
<|endoftext|>


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

couchTests.attachments= function(debug) {
  var db = new CouchDB("test_suite_db");
  db.deleteDb();
  db.createDb();
  if (debug) debugger;

  var binAttDoc = {
    _id: "bin_doc",
    _attachments:{
      "foo.txt": {
        content_type:"text/plain",
        data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
      }
    }
  }

  var save_response = db.save(binAttDoc);
  T(save_response.ok);

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc/foo.txt");
  T(xhr.responseText == "This is a base64 encoded text");
  T(xhr.getResponseHeader("Content-Type") == "text/plain");
  T(xhr.getResponseHeader("Etag") == '"' + save_response.rev + '"');

  // empty attachment
  var binAttDoc2 = {
    _id: "bin_doc2",
    _attachments:{
      "foo.txt": {
        content_type:"text/plain",
        data: ""
      }
    }
  }

  T(db.save(binAttDoc2).ok);

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc2/foo.txt");
  T(xhr.responseText.length == 0);
  T(xhr.getResponseHeader("Content-Type") == "text/plain");

  // test RESTful doc API

  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc2/foo2.txt?rev=" + binAttDoc2._rev, {
    body:"This is no base64 encoded text",
    headers:{"Content-Type": "text/plain;charset=utf-8"}
  });
  T(xhr.status == 201);
  var rev = JSON.parse(xhr.responseText).rev;

  binAttDoc2 = db.open("bin_doc2");

  T(binAttDoc2._attachments["foo.txt"] !== undefined);
  T(binAttDoc2._attachments["foo2.txt"] !== undefined);
  T(binAttDoc2._attachments["foo2.txt"].content_type == "text/plain;charset=utf-8");
  T(binAttDoc2._attachments["foo2.txt"].length == 30);

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc2/foo2.txt");
  T(xhr.responseText == "This is no base64 encoded text");
  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");

  // test without rev, should fail
  var xhr = CouchDB.request("DELETE", "/test_suite_db/bin_doc2/foo2.txt");
  T(xhr.status == 409);

  // test with rev, should not fail
  var xhr = CouchDB.request("DELETE", "/test_suite_db/bin_doc2/foo2.txt?rev=" + rev);
  T(xhr.status == 200);

  // test binary data
  var bin_data = "JHAPDO*AU£PN ){(3u[d 93DQ9¡€])}    ææøo'∂ƒæ≤çæππ•¥∫¶®#†π¶®¥π€ª®˙π8np";
  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc3/attachment.txt", {
    headers:{"Content-Type":"text/plain;charset=utf-8"},
    body:bin_data
  });
  T(xhr.status == 201);
  var rev = JSON.parse(xhr.responseText).rev;

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc3/attachment.txt");
  T(xhr.responseText == bin_data);
  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");

  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc3/attachment.txt", {
    headers:{"Content-Type":"text/plain;charset=utf-8"},
    body:bin_data
  });
  T(xhr.status == 409);

  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc3/attachment.txt?rev=" + rev, {
    headers:{"Content-Type":"text/plain;charset=utf-8"},
    body:bin_data
  });
  T(xhr.status == 201);
  var rev = JSON.parse(xhr.responseText).rev;

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc3/attachment.txt");
  T(xhr.responseText == bin_data);
  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc3/attachment.txt?rev=" + rev);
  T(xhr.responseText == bin_data);
  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");

  var xhr = CouchDB.request("DELETE", "/test_suite_db/bin_doc3/attachment.txt?rev=" + rev);
  T(xhr.status == 200);

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc3/attachment.txt");
  T(xhr.status == 404);

  // deleted attachment is still accessible with revision
  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc3/attachment.txt?rev=" + rev);
  T(xhr.status == 200);
  T(xhr.responseText == bin_data);
  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");

  // empty attachments
  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc4/attachment.txt", {
    headers:{"Content-Type":"text/plain;charset=utf-8"},
    body:""
  });
  T(xhr.status == 201);
  var rev = JSON.parse(xhr.responseText).rev;

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc4/attachment.txt");
  T(xhr.status == 200);
  T(xhr.responseText.length == 0);

  // overwrite previsously empty attachment
  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc4/attachment.txt?rev=" + rev, {
    headers:{"Content-Type":"text/plain;charset=utf-8"},
    body:"This is a string"
  });
  T(xhr.status == 201);

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc4/attachment.txt");
  T(xhr.status == 200);
  T(xhr.responseText == "This is a string");

  // Attachment sparseness COUCHDB-220

  var docs = []
  for (var i = 0; i < 5; i++) {
      var doc = {
	  _id: (i).toString(),
	  _attachments:{
	      "foo.txt": {
		  content_type:"text/plain",
		  data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
	      }
	  }
      }
      docs.push(doc)
  }

  db.bulkSave(docs);

  var before = db.info().disk_size;

  // Compact it.
  T(db.compact().ok);
  T(db.last_req.status == 202);
  // compaction isn't instantaneous, loop until done
  while (db.info().compact_running) {};

  var after = db.info().disk_size;

  // Compaction should reduce the database slightly, but not
  // orders of magnitude (unless attachments introduce sparseness)
  T(after > before * 0.1, "before: " + before + " after: " + after);

  // test large attachments - COUCHDB-366
  var lorem = CouchDB.request("GET", "/_utils/script/test/lorem.txt").responseText;

  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc5/lorem.txt", {
    headers:{"Content-Type":"text/plain;charset=utf-8"},
    body:lorem
  });
  T(xhr.status == 201);
  var rev = JSON.parse(xhr.responseText).rev;

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc5/lorem.txt");
  T(xhr.responseText == lorem);
  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");

  // test large inline attachment too
  var lorem_b64 = CouchDB.request("GET", "/_utils/script/test/lorem_b64.txt").responseText;
  var doc = db.open("bin_doc5", {attachments:true});
  T(doc._attachments["lorem.txt"].data == lorem_b64);

  // test etags for attachments.
  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc5/lorem.txt");
  T(xhr.status == 200);
  var etag = xhr.getResponseHeader("etag");
  console.log(etag)
  xhr = CouchDB.request("GET", "/test_suite_db/bin_doc5/lorem.txt", {
    headers: {"if-none-match": etag}
  });
  T(xhr.status == 304);
};
<commit_msg>remove log statement<commit_after>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License.  You may obtain a copy
// of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
// License for the specific language governing permissions and limitations under
// the License.

couchTests.attachments= function(debug) {
  var db = new CouchDB("test_suite_db");
  db.deleteDb();
  db.createDb();
  if (debug) debugger;

  var binAttDoc = {
    _id: "bin_doc",
    _attachments:{
      "foo.txt": {
        content_type:"text/plain",
        data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
      }
    }
  }

  var save_response = db.save(binAttDoc);
  T(save_response.ok);

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc/foo.txt");
  T(xhr.responseText == "This is a base64 encoded text");
  T(xhr.getResponseHeader("Content-Type") == "text/plain");
  T(xhr.getResponseHeader("Etag") == '"' + save_response.rev + '"');

  // empty attachment
  var binAttDoc2 = {
    _id: "bin_doc2",
    _attachments:{
      "foo.txt": {
        content_type:"text/plain",
        data: ""
      }
    }
  }

  T(db.save(binAttDoc2).ok);

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc2/foo.txt");
  T(xhr.responseText.length == 0);
  T(xhr.getResponseHeader("Content-Type") == "text/plain");

  // test RESTful doc API

  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc2/foo2.txt?rev=" + binAttDoc2._rev, {
    body:"This is no base64 encoded text",
    headers:{"Content-Type": "text/plain;charset=utf-8"}
  });
  T(xhr.status == 201);
  var rev = JSON.parse(xhr.responseText).rev;

  binAttDoc2 = db.open("bin_doc2");

  T(binAttDoc2._attachments["foo.txt"] !== undefined);
  T(binAttDoc2._attachments["foo2.txt"] !== undefined);
  T(binAttDoc2._attachments["foo2.txt"].content_type == "text/plain;charset=utf-8");
  T(binAttDoc2._attachments["foo2.txt"].length == 30);

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc2/foo2.txt");
  T(xhr.responseText == "This is no base64 encoded text");
  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");

  // test without rev, should fail
  var xhr = CouchDB.request("DELETE", "/test_suite_db/bin_doc2/foo2.txt");
  T(xhr.status == 409);

  // test with rev, should not fail
  var xhr = CouchDB.request("DELETE", "/test_suite_db/bin_doc2/foo2.txt?rev=" + rev);
  T(xhr.status == 200);

  // test binary data
  var bin_data = "JHAPDO*AU£PN ){(3u[d 93DQ9¡€])}    ææøo'∂ƒæ≤çæππ•¥∫¶®#†π¶®¥π€ª®˙π8np";
  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc3/attachment.txt", {
    headers:{"Content-Type":"text/plain;charset=utf-8"},
    body:bin_data
  });
  T(xhr.status == 201);
  var rev = JSON.parse(xhr.responseText).rev;

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc3/attachment.txt");
  T(xhr.responseText == bin_data);
  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");

  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc3/attachment.txt", {
    headers:{"Content-Type":"text/plain;charset=utf-8"},
    body:bin_data
  });
  T(xhr.status == 409);

  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc3/attachment.txt?rev=" + rev, {
    headers:{"Content-Type":"text/plain;charset=utf-8"},
    body:bin_data
  });
  T(xhr.status == 201);
  var rev = JSON.parse(xhr.responseText).rev;

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc3/attachment.txt");
  T(xhr.responseText == bin_data);
  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc3/attachment.txt?rev=" + rev);
  T(xhr.responseText == bin_data);
  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");

  var xhr = CouchDB.request("DELETE", "/test_suite_db/bin_doc3/attachment.txt?rev=" + rev);
  T(xhr.status == 200);

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc3/attachment.txt");
  T(xhr.status == 404);

  // deleted attachment is still accessible with revision
  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc3/attachment.txt?rev=" + rev);
  T(xhr.status == 200);
  T(xhr.responseText == bin_data);
  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");

  // empty attachments
  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc4/attachment.txt", {
    headers:{"Content-Type":"text/plain;charset=utf-8"},
    body:""
  });
  T(xhr.status == 201);
  var rev = JSON.parse(xhr.responseText).rev;

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc4/attachment.txt");
  T(xhr.status == 200);
  T(xhr.responseText.length == 0);

  // overwrite previsously empty attachment
  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc4/attachment.txt?rev=" + rev, {
    headers:{"Content-Type":"text/plain;charset=utf-8"},
    body:"This is a string"
  });
  T(xhr.status == 201);

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc4/attachment.txt");
  T(xhr.status == 200);
  T(xhr.responseText == "This is a string");

  // Attachment sparseness COUCHDB-220

  var docs = []
  for (var i = 0; i < 5; i++) {
      var doc = {
	  _id: (i).toString(),
	  _attachments:{
	      "foo.txt": {
		  content_type:"text/plain",
		  data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
	      }
	  }
      }
      docs.push(doc)
  }

  db.bulkSave(docs);

  var before = db.info().disk_size;

  // Compact it.
  T(db.compact().ok);
  T(db.last_req.status == 202);
  // compaction isn't instantaneous, loop until done
  while (db.info().compact_running) {};

  var after = db.info().disk_size;

  // Compaction should reduce the database slightly, but not
  // orders of magnitude (unless attachments introduce sparseness)
  T(after > before * 0.1, "before: " + before + " after: " + after);

  // test large attachments - COUCHDB-366
  var lorem = CouchDB.request("GET", "/_utils/script/test/lorem.txt").responseText;

  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc5/lorem.txt", {
    headers:{"Content-Type":"text/plain;charset=utf-8"},
    body:lorem
  });
  T(xhr.status == 201);
  var rev = JSON.parse(xhr.responseText).rev;

  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc5/lorem.txt");
  T(xhr.responseText == lorem);
  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");

  // test large inline attachment too
  var lorem_b64 = CouchDB.request("GET", "/_utils/script/test/lorem_b64.txt").responseText;
  var doc = db.open("bin_doc5", {attachments:true});
  T(doc._attachments["lorem.txt"].data == lorem_b64);

  // test etags for attachments.
  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc5/lorem.txt");
  T(xhr.status == 200);
  var etag = xhr.getResponseHeader("etag");
  xhr = CouchDB.request("GET", "/test_suite_db/bin_doc5/lorem.txt", {
    headers: {"if-none-match": etag}
  });
  T(xhr.status == 304);
};
<|endoftext|>


<commit_before>wwm.shell = (function () {
	var jqMap;
	function setJqMap($con) {
		jqMap = {
			$con: $con,
			$view: $con.find('#view'),
			$modal: $con.find('#modal'),
			$kakaoLogin: $con.find('#kakao-login-btn')
		};
	}
	function initModule($con) {
		console.log('login: ' + localStorage.login);
		console.log('first: ' + localStorage.first)
		var logged = localStorage.login && JSON.parse(localStorage.login);
		var first = localStorage.first && JSON.parse(localStorage.first);
		setJqMap($con);
		//if (first) {
		//	wwm.modal.initModule($('#wwm-intro').html());
		//}
		if (logged) {
			wwm.lobby.initModule(jqMap.$view);
			return;
		}
		$.get('/status').done(function(res) {
			if (res) {
				localStorage.login = JSON.stringify(res);
				wwm.lobby.initModule(jqMap.$view);
			} else {
				$con.find('#view').html($('#wwm-login').html());
				setJqMap($con);
				jqMap.$kakaoLogin.on({
					click: function () {
						location.href = '/login/kakao';
					},
					mouseover: function () {
						this.src = '/kakao_account_login_btn_medium_narrow_ov.png';
					},
					mouseout: function () {
						this.src = '/kakao_account_login_btn_medium_narrow.png';
					}
				});
			}
		}).fail(function(err) {
			console.log(err);
			alert('인터넷 연결이 필요합니다.');
		});
		Kakao.init('a35623411563ec424430d3bd5dc7a93e');
	}
	return {
		initModule: initModule
	};
}());
<commit_msg>Update wwm.shell.js<commit_after>wwm.shell = (function () {
	var jqMap;
	function setJqMap($con) {
		jqMap = {
			$con: $con,
			$view: $con.find('#view'),
			$modal: $con.find('#modal'),
			$kakaoLogin: $con.find('#kakao-login-btn')
		};
	}
	function initModule($con) {
		console.log('login: ' + localStorage.login);
		console.log('first: ' + localStorage.first)
		var logged = localStorage.login && JSON.parse(localStorage.login);
		var first = localStorage.first && JSON.parse(localStorage.first);
		setJqMap($con);
		//if (first) {
		//	wwm.modal.initModule($('#wwm-intro').html());
		//}
		console.log('logged: ', logged);
		if (logged) {
			wwm.lobby.initModule(jqMap.$view);
			return;
		}
		$.get('/status').done(function(res) {
			console.log('res: ', res)
			if (res) {
				localStorage.login = JSON.stringify(res);
				wwm.lobby.initModule(jqMap.$view);
			} else {
				$con.find('#view').html($('#wwm-login').html());
				setJqMap($con);
				jqMap.$kakaoLogin.on({
					click: function () {
						location.href = '/login/kakao';
					},
					mouseover: function () {
						this.src = '/kakao_account_login_btn_medium_narrow_ov.png';
					},
					mouseout: function () {
						this.src = '/kakao_account_login_btn_medium_narrow.png';
					}
				});
			}
		}).fail(function(err) {
			console.log(err);
			alert('인터넷 연결이 필요합니다.');
		});
		Kakao.init('a35623411563ec424430d3bd5dc7a93e');
	}
	return {
		initModule: initModule
	};
}());
<|endoftext|>


<commit_before>import $ from 'jquery';
import ModalComponent from 'ghost-admin/components/modal-base';
import boundOneWay from '../utils/bound-one-way';
import copyTextToClipboard from 'ghost-admin/utils/copy-text-to-clipboard';
import {alias, reads} from '@ember/object/computed';
import {computed} from '@ember/object';
import {htmlSafe} from '@ember/string';
import {run} from '@ember/runloop';
import {inject as service} from '@ember/service';
import {task, timeout} from 'ember-concurrency';
const ICON_EXTENSIONS = ['ico', 'png', 'svg', 'jpg', 'jpeg'];

export default ModalComponent.extend({
    settings: service(),
    membersUtils: service(),
    config: service(),
    page: 'signup',
    iconExtensions: null,
    defaultButtonIcons: null,
    isShowModalLink: true,
    customIcon: null,
    confirm() {},

    signupButtonText: boundOneWay('settings.portalButtonSignupText'),
    buttonIcon: boundOneWay('settings.portalButtonIcon'),
    allowSelfSignup: alias('model.allowSelfSignup'),

    isStripeConfigured: reads('membersUtils.isStripeEnabled'),

    backgroundStyle: computed('settings.accentColor', function () {
        let color = this.get('settings.accentColor') || '#ffffff';
        return htmlSafe(`background-color: ${color}`);
    }),

    accentColor: computed('settings.accentColor', function () {
        let color = this.get('settings.accentColor');
        if (color && color[0] === '#') {
            return color.slice(1);
        }
        return color;
    }),

    showModalLinkOrAttribute: computed('isShowModalLink', function () {
        if (this.isShowModalLink) {
            return `${this.config.get('blogUrl')}/#/portal`;
        }
        return `data-portal`;
    }),

    portalPreviewUrl: computed('selectedButtonStyle', 'buttonIcon', 'signupButtonText', 'page', 'isFreeChecked', 'isMonthlyChecked', 'isYearlyChecked', 'settings.{portalName,portalButton,accentColor}', function () {
        const baseUrl = this.config.get('blogUrl');
        const portalBase = '/#/portal';
        const settingsParam = new URLSearchParams();
        settingsParam.append('button', this.settings.get('portalButton'));
        settingsParam.append('name', this.settings.get('portalName'));
        settingsParam.append('isFree', this.isFreeChecked);
        settingsParam.append('isMonthly', this.isMonthlyChecked);
        settingsParam.append('isYearly', this.isYearlyChecked);
        settingsParam.append('page', this.page);
        settingsParam.append('buttonIcon', encodeURIComponent(this.buttonIcon));
        settingsParam.append('signupButtonText', encodeURIComponent(this.signupButtonText));
        if (this.settings.get('accentColor')) {
            settingsParam.append('accentColor', encodeURIComponent(`${this.settings.get('accentColor')}`));
        }
        if (this.selectedButtonStyle) {
            settingsParam.append('buttonStyle', encodeURIComponent(this.selectedButtonStyle.name));
        }
        return `${baseUrl}${portalBase}?${settingsParam.toString()}`;
    }),

    showIconSetting: computed('selectedButtonStyle', function () {
        const selectedButtonStyle = this.get('selectedButtonStyle.name') || '';
        return selectedButtonStyle.includes('icon');
    }),

    isFreeChecked: computed('settings.portalPlans.[]', 'allowSelfSignup', function () {
        const allowedPlans = this.settings.get('portalPlans') || [];
        return (this.allowSelfSignup && allowedPlans.includes('free'));
    }),

    isMonthlyChecked: computed('settings.portalPlans.[]', 'isStripeConfigured', function () {
        const allowedPlans = this.settings.get('portalPlans') || [];
        return (this.isStripeConfigured && allowedPlans.includes('monthly'));
    }),

    isYearlyChecked: computed('settings.portalPlans.[]', 'isStripeConfigured', function () {
        const allowedPlans = this.settings.get('portalPlans') || [];
        return (this.isStripeConfigured && allowedPlans.includes('yearly'));
    }),

    selectedButtonStyle: computed('settings.portalButtonStyle', function () {
        return this.buttonStyleOptions.find((buttonStyle) => {
            return (buttonStyle.name === this.settings.get('portalButtonStyle'));
        });
    }),

    init() {
        this._super(...arguments);
        this.buttonStyleOptions = [
            {name: 'icon-and-text', label: 'Icon and text'},
            {name: 'icon-only', label: 'Icon only'},
            {name: 'text-only', label: 'Text only'}
        ];
        this.defaultButtonIcons = [
            'https://raw.githubusercontent.com/leungwensen/svg-icon/master/dist/trimmed-svg/metro/user.svg',
            'https://raw.githubusercontent.com/leungwensen/svg-icon/master/dist/svg/icomoon/user-tie.svg',
            'https://raw.githubusercontent.com/leungwensen/svg-icon/master/dist/trimmed-svg/evil/user.svg'
        ];
        this.iconExtensions = ICON_EXTENSIONS;
        if (!this.settings.get('portalButtonIcon').includes('githubusercontent')) {
            return this.set('customIcon', this.settings.get('portalButtonIcon'));
        }
    },

    actions: {
        toggleFreePlan(isChecked) {
            this.updateAllowedPlan('free', isChecked);
        },
        toggleMonthlyPlan(isChecked) {
            this.updateAllowedPlan('monthly', isChecked);
        },
        toggleYearlyPlan(isChecked) {
            this.updateAllowedPlan('yearly', isChecked);
        },
        togglePortalButton(showButton) {
            this.settings.set('portalButton', showButton);
        },

        togglePortalName(showSignupName) {
            this.settings.set('portalName', showSignupName);
        },

        confirm() {
            return this.saveTask.perform();
        },

        isPlanSelected(plan) {
            const allowedPlans = this.settings.get('portalPlans');
            return allowedPlans.includes(plan);
        },

        switchPreviewPage(page) {
            this.set('page', page);
        },

        validateAccentColor() {
            let newColor = this.get('accentColor');
            let oldColor = this.get('settings.accentColor');
            let errMessage = '';

            // reset errors and validation
            this.get('settings.errors').remove('accentColor');
            this.get('settings.hasValidated').removeObject('accentColor');

            if (newColor === '') {
                // Clear out the accent color
                this.set('settings.accentColor', '');
                return;
            }

            // accentColor will be null unless the user has input something
            if (!newColor) {
                newColor = oldColor;
            }

            if (newColor[0] !== '#') {
                newColor = `#${newColor}`;
            }

            if (newColor.match(/#[0-9A-Fa-f]{6}$/)) {
                this.set('settings.accentColor', '');
                run.schedule('afterRender', this, function () {
                    this.set('settings.accentColor', newColor);
                });
            } else {
                errMessage = 'The color should be in valid hex format';
                this.get('settings.errors').add('accentColor', errMessage);
                this.get('settings.hasValidated').pushObject('accentColor');
                return;
            }
        },
        setButtonStyle(buttonStyle) {
            this.set('selectedButtonStyle', buttonStyle);
        },
        setSignupButtonText(event) {
            this.set('signupButtonText', event.target.value);
        },
        /**
         * Fired after an image upload completes
         * @param  {string} property - Property name to be set on `this.settings`
         * @param  {UploadResult[]} results - Array of UploadResult objects
         * @return {string} The URL that was set on `this.settings.property`
         */
        imageUploaded(property, results) {
            if (results[0]) {
                this.set('customIcon', results[0].url);
                this.set('buttonIcon', results[0].url);
            }
        },
        /**
         * Opens a file selection dialog - Triggered by "Upload Image" buttons,
         * searches for the hidden file input within the .gh-setting element
         * containing the clicked button then simulates a click
         * @param  {MouseEvent} event - MouseEvent fired by the button click
         */
        triggerFileDialog(event) {
            // simulate click to open file dialog
            // using jQuery because IE11 doesn't support MouseEvent
            $(event.target)
                .closest('.gh-setting-action')
                .find('input[type="file"]')
                .click();
        },

        selectDefaultIcon(icon) {
            this.set('buttonIcon', icon);
        }
    },

    updateAllowedPlan(plan, isChecked) {
        const allowedPlans = this.settings.get('portalPlans') || [];

        if (!isChecked) {
            this.settings.set('portalPlans', allowedPlans.filter(p => p !== plan));
        } else {
            allowedPlans.push(plan);
            this.settings.set('portalPlans', [...allowedPlans]);
        }
    },

    copyLinkOrAttribute: task(function* () {
        copyTextToClipboard(this.showModalLinkOrAttribute);
        yield timeout(this.isTesting ? 50 : 3000);
    }),

    saveTask: task(function* () {
        this.settings.set('portalButtonStyle', this.selectedButtonStyle.name);
        this.settings.set('portalButtonSignupText', this.signupButtonText);
        this.settings.set('portalButtonIcon', this.buttonIcon);
        yield this.settings.save();
        this.closeModal();
    }).drop()
});
<commit_msg>Fixed check for empty portal button icon<commit_after>import $ from 'jquery';
import ModalComponent from 'ghost-admin/components/modal-base';
import boundOneWay from '../utils/bound-one-way';
import copyTextToClipboard from 'ghost-admin/utils/copy-text-to-clipboard';
import {alias, reads} from '@ember/object/computed';
import {computed} from '@ember/object';
import {htmlSafe} from '@ember/string';
import {run} from '@ember/runloop';
import {inject as service} from '@ember/service';
import {task, timeout} from 'ember-concurrency';
const ICON_EXTENSIONS = ['ico', 'png', 'svg', 'jpg', 'jpeg'];

export default ModalComponent.extend({
    settings: service(),
    membersUtils: service(),
    config: service(),
    page: 'signup',
    iconExtensions: null,
    defaultButtonIcons: null,
    isShowModalLink: true,
    customIcon: null,
    confirm() {},

    signupButtonText: boundOneWay('settings.portalButtonSignupText'),
    buttonIcon: boundOneWay('settings.portalButtonIcon'),
    allowSelfSignup: alias('model.allowSelfSignup'),

    isStripeConfigured: reads('membersUtils.isStripeEnabled'),

    backgroundStyle: computed('settings.accentColor', function () {
        let color = this.get('settings.accentColor') || '#ffffff';
        return htmlSafe(`background-color: ${color}`);
    }),

    accentColor: computed('settings.accentColor', function () {
        let color = this.get('settings.accentColor');
        if (color && color[0] === '#') {
            return color.slice(1);
        }
        return color;
    }),

    showModalLinkOrAttribute: computed('isShowModalLink', function () {
        if (this.isShowModalLink) {
            return `${this.config.get('blogUrl')}/#/portal`;
        }
        return `data-portal`;
    }),

    portalPreviewUrl: computed('selectedButtonStyle', 'buttonIcon', 'signupButtonText', 'page', 'isFreeChecked', 'isMonthlyChecked', 'isYearlyChecked', 'settings.{portalName,portalButton,accentColor}', function () {
        const baseUrl = this.config.get('blogUrl');
        const portalBase = '/#/portal';
        const settingsParam = new URLSearchParams();
        settingsParam.append('button', this.settings.get('portalButton'));
        settingsParam.append('name', this.settings.get('portalName'));
        settingsParam.append('isFree', this.isFreeChecked);
        settingsParam.append('isMonthly', this.isMonthlyChecked);
        settingsParam.append('isYearly', this.isYearlyChecked);
        settingsParam.append('page', this.page);
        if (this.buttonIcon) {
            settingsParam.append('buttonIcon', encodeURIComponent(this.buttonIcon));
        }
        settingsParam.append('signupButtonText', encodeURIComponent(this.signupButtonText));
        if (this.settings.get('accentColor')) {
            settingsParam.append('accentColor', encodeURIComponent(`${this.settings.get('accentColor')}`));
        }
        if (this.selectedButtonStyle) {
            settingsParam.append('buttonStyle', encodeURIComponent(this.selectedButtonStyle.name));
        }
        return `${baseUrl}${portalBase}?${settingsParam.toString()}`;
    }),

    showIconSetting: computed('selectedButtonStyle', function () {
        const selectedButtonStyle = this.get('selectedButtonStyle.name') || '';
        return selectedButtonStyle.includes('icon');
    }),

    isFreeChecked: computed('settings.portalPlans.[]', 'allowSelfSignup', function () {
        const allowedPlans = this.settings.get('portalPlans') || [];
        return (this.allowSelfSignup && allowedPlans.includes('free'));
    }),

    isMonthlyChecked: computed('settings.portalPlans.[]', 'isStripeConfigured', function () {
        const allowedPlans = this.settings.get('portalPlans') || [];
        return (this.isStripeConfigured && allowedPlans.includes('monthly'));
    }),

    isYearlyChecked: computed('settings.portalPlans.[]', 'isStripeConfigured', function () {
        const allowedPlans = this.settings.get('portalPlans') || [];
        return (this.isStripeConfigured && allowedPlans.includes('yearly'));
    }),

    selectedButtonStyle: computed('settings.portalButtonStyle', function () {
        return this.buttonStyleOptions.find((buttonStyle) => {
            return (buttonStyle.name === this.settings.get('portalButtonStyle'));
        });
    }),

    init() {
        this._super(...arguments);
        this.buttonStyleOptions = [
            {name: 'icon-and-text', label: 'Icon and text'},
            {name: 'icon-only', label: 'Icon only'},
            {name: 'text-only', label: 'Text only'}
        ];
        this.defaultButtonIcons = [
            'https://raw.githubusercontent.com/leungwensen/svg-icon/master/dist/trimmed-svg/metro/user.svg',
            'https://raw.githubusercontent.com/leungwensen/svg-icon/master/dist/svg/icomoon/user-tie.svg',
            'https://raw.githubusercontent.com/leungwensen/svg-icon/master/dist/trimmed-svg/evil/user.svg'
        ];
        this.iconExtensions = ICON_EXTENSIONS;
        const portalButtonIcon = this.settings.get('portalButtonIcon') || '';
        if (portalButtonIcon && !portalButtonIcon.includes('githubusercontent')) {
            return this.set('customIcon', this.settings.get('portalButtonIcon'));
        }
    },

    actions: {
        toggleFreePlan(isChecked) {
            this.updateAllowedPlan('free', isChecked);
        },
        toggleMonthlyPlan(isChecked) {
            this.updateAllowedPlan('monthly', isChecked);
        },
        toggleYearlyPlan(isChecked) {
            this.updateAllowedPlan('yearly', isChecked);
        },
        togglePortalButton(showButton) {
            this.settings.set('portalButton', showButton);
        },

        togglePortalName(showSignupName) {
            this.settings.set('portalName', showSignupName);
        },

        confirm() {
            return this.saveTask.perform();
        },

        isPlanSelected(plan) {
            const allowedPlans = this.settings.get('portalPlans');
            return allowedPlans.includes(plan);
        },

        switchPreviewPage(page) {
            this.set('page', page);
        },

        validateAccentColor() {
            let newColor = this.get('accentColor');
            let oldColor = this.get('settings.accentColor');
            let errMessage = '';

            // reset errors and validation
            this.get('settings.errors').remove('accentColor');
            this.get('settings.hasValidated').removeObject('accentColor');

            if (newColor === '') {
                // Clear out the accent color
                this.set('settings.accentColor', '');
                return;
            }

            // accentColor will be null unless the user has input something
            if (!newColor) {
                newColor = oldColor;
            }

            if (newColor[0] !== '#') {
                newColor = `#${newColor}`;
            }

            if (newColor.match(/#[0-9A-Fa-f]{6}$/)) {
                this.set('settings.accentColor', '');
                run.schedule('afterRender', this, function () {
                    this.set('settings.accentColor', newColor);
                });
            } else {
                errMessage = 'The color should be in valid hex format';
                this.get('settings.errors').add('accentColor', errMessage);
                this.get('settings.hasValidated').pushObject('accentColor');
                return;
            }
        },
        setButtonStyle(buttonStyle) {
            this.set('selectedButtonStyle', buttonStyle);
        },
        setSignupButtonText(event) {
            this.set('signupButtonText', event.target.value);
        },
        /**
         * Fired after an image upload completes
         * @param  {string} property - Property name to be set on `this.settings`
         * @param  {UploadResult[]} results - Array of UploadResult objects
         * @return {string} The URL that was set on `this.settings.property`
         */
        imageUploaded(property, results) {
            if (results[0]) {
                this.set('customIcon', results[0].url);
                this.set('buttonIcon', results[0].url);
            }
        },
        /**
         * Opens a file selection dialog - Triggered by "Upload Image" buttons,
         * searches for the hidden file input within the .gh-setting element
         * containing the clicked button then simulates a click
         * @param  {MouseEvent} event - MouseEvent fired by the button click
         */
        triggerFileDialog(event) {
            // simulate click to open file dialog
            // using jQuery because IE11 doesn't support MouseEvent
            $(event.target)
                .closest('.gh-setting-action')
                .find('input[type="file"]')
                .click();
        },

        selectDefaultIcon(icon) {
            this.set('buttonIcon', icon);
        }
    },

    updateAllowedPlan(plan, isChecked) {
        const allowedPlans = this.settings.get('portalPlans') || [];

        if (!isChecked) {
            this.settings.set('portalPlans', allowedPlans.filter(p => p !== plan));
        } else {
            allowedPlans.push(plan);
            this.settings.set('portalPlans', [...allowedPlans]);
        }
    },

    copyLinkOrAttribute: task(function* () {
        copyTextToClipboard(this.showModalLinkOrAttribute);
        yield timeout(this.isTesting ? 50 : 3000);
    }),

    saveTask: task(function* () {
        this.settings.set('portalButtonStyle', this.selectedButtonStyle.name);
        this.settings.set('portalButtonSignupText', this.signupButtonText);
        this.settings.set('portalButtonIcon', this.buttonIcon);
        yield this.settings.save();
        this.closeModal();
    }).drop()
});
<|endoftext|>


<commit_before>import httpStatus from 'http-status';
import sqlClient from 'squel'

import Sequelize from 'sequelize';
import config from '../../../config/config';

const sequelize = new Sequelize(config.dbUriG, {
  define: {
    charset: 'utf8mb4',
    collate: 'utf8_general_ci',
    timestamps: true
  },
  logging: false
});

const selectWithOutOperation = "select {0}";
const fromWithOutJoins = "from {0}";
const groupBy = "group by {0}";

const replaceAll = (search, replacement, target) => {
    return target.split(search).join(replacement);
}
const buildConstraints = (baseQuery, columns, operations, values, baseColumnDate, operationColumnDate) => {
    for(let x = 0; x < columns.length; x++){
        let column = columns[x];
        let operation = operations[x];
        let value = values[x];
        let condition = ""
        if(!baseColumnDate && !operationColumnDate){
            baseQuery = baseQuery.where(buildOperation(column, value, operation));
        }
    }
    return baseQuery;
}

const buildOperation = (column, value, operation) =>{
    let sentence = ""
    if(operation.value_type == 1){
        switch(operation.name){
            case "Igual a": {
                sentence = "a." + column.name + "=" + "'" + value + "'";;
                return sentence;
            }
            case "Diferente de":{
                sentence ="a."  + column.name + "!=" + "'" + value + "'";
                return sentence;
            }
            case "Contiene":{
                sentence = "a." + column.name + " like " + "'" + "%" + value + "%" + "'";
                return sentence;
            }

            default:{
                break;
            }
        }
    }
    if(operation.value_type == 2 || operation.value_type == 4){
        switch(operation.name){
            case "Mayor que":{
                sentence = "a." + column.name + ">" + value;
                return sentence;
            }
            case "Menor que": {
                sentence = "a." + column.name + "<" + value;
                return sentence;
            }
            case "Igual a": {
                sentence = "a." + column.name + "="  + value ;
                return sentence;
            }
            case "Diferente de":{
                sentence ="a."  + column.name + "!=" + value;
                return sentence;
            }
        }

    }

}

const baseQueryHandler = (baseColumn, operation, column, filterList) => {
    let sqlOperation = "";
    if(column.second_table != "dim_fecha" && baseColumn.second_table != "dim_fecha"){
        switch(operation.name){
            case "Contar": {
                sqlOperation = "COUNT(" + 'q.' + column.name + ") as value"
                break;
            }
            case "Sumar":{
                sqlOperation = "SUM(" + 'q.' + column.name + ") as value"
                break;
            }
            case "Promedio":{
                sqlOperation = "AVG(" + 'q.' + column.name + ") as value"
                break;
            }
            default: {
                break;
            }
        }
        let sqlColumn = column.name;
        let calculateColumn = "q." + baseColumn.name;
        let groupBy =  calculateColumn;
        let selectFrom = "";
        if( baseColumn.name == "monto" || column.name == "monto"){
            selectFrom = sqlClient.select().distinct().field("a.nit_proveedor").field("a.nog").field("a." + column.name).field("a."+baseColumn.name).from("consolidated_table","a").join("dim_fecha","b","b.id_fecha = a.fecha_adjudicada");
        }
        else{
            selectFrom = sqlClient.select().distinct().field("a.nog").field("a." + column.name).field("a."+baseColumn.name).from("consolidated_table","a").join("dim_fecha","b","b.id_fecha = a.fecha_adjudicada")
        }
        if(filterList[0] != undefined){
            if (filterList[0].length > 0){
                selectFrom = buildConstraints(selectFrom, filterList[0], filterList[1], filterList[2], false, false)
            }
        }

        let query = sqlClient.select().field(sqlOperation).field(calculateColumn).from(selectFrom, "q")

        query = query.group(groupBy);

        return query.toString();
    }
    else if (column.second_table != "dim_fecha" && baseColumn.second_table == "dim_fecha"){
        let sqlOperation = "";
        switch(operation.name){
            case "Contar": {
                sqlOperation = "COUNT(" + 'q.' + column.name + ") as value"
                break;
            }
            case "Sumar":{
                sqlOperation = "SUM(" + 'q.' + column.name + ") as value"
                break;
            }
            case "Promedio":{
                sqlOperation = "AVG(" + 'q.' + column.name + ") as value"
                break;
            }
            default: {
                break;
            }
        }

        let joinDateField = "b." + baseColumn.date_column;
        let joinOpFielf = "a." + column.name;
        let joinCondition = "a." + baseColumn.name + "=" + "b.id_fecha";
        let sqlColumn = column.date_column;
        let displayColumn = "q." +  baseColumn.date_column;
        let groupBy = displayColumn;
        let selectFrom = "";
        if( baseColumn.name == "monto" || column.name == "monto"){
            selectFrom = sqlClient.select().distinct().field("a.nit_proveedor").field("a.nog").field(joinOpFielf).field(joinDateField).from("consolidated_table","a").join("dim_fecha","b",joinCondition);
        }
        else{
            selectFrom = sqlClient.select().distinct().field("a.nog").field(joinOpFielf).field(joinDateField).from("consolidated_table","a").join("dim_fecha","b",joinCondition);
        }
        if(filterList[0] != undefined){
            if (filterList[0].length > 0){
                selectFrom = buildConstraints(selectFrom, filterList[0], filterList[1], filterList[2], false, false)
            }
        }
        let query = sqlClient.select().field(sqlOperation).field(displayColumn).from(selectFrom, "q").group(groupBy);
        return query.toString();
    }
    else if (column.second_table == "dim_fecha" && baseColumn.second_table != "dim_fecha"){
        let sqlOperation = "";
        switch(operation.name){
            case "Contar": {
                sqlOperation = "COUNT(" + 'q.' + column.date_column + ") as value"
                break;
            }
            case "Sumar":{
                sqlOperation = "SUM(" + 'q.' + column.date_column + ") as value"
                break;
            }
            case "Promedio":{
                sqlOperation = "AVG(" + 'q.' + column.date_column + ") as value"
                break;
            }
            default: {
                break;
            }
        }

        let joinDateField = "b." + column.name ;
        let joinOpFielf = "a." + baseColumn.name;
        let joinCondition = "a." + column.name + "=" + "b.id_fecha";
        let realColumn = "b." + column.date_column;
        let sqlColumn = column.name;
        let displayColumn = "q." +  baseColumn.name;
        let groupBy = displayColumn;
        let selectFrom = "";
        if( baseColumn.name == "monto" || column.name == "monto"){
            selectFrom = sqlClient.select().distinct().field("a.nit_proveedor").field("a.nog").field(joinOpFielf).field(realColumn).from("consolidated_table","a").join("dim_fecha","b",joinCondition);
        }
        else{
            selectFrom = sqlClient.select().distinct().field("a.nog").field(joinOpFielf).field(realColumn).from("consolidated_table","a").join("dim_fecha","b",joinCondition);
        }

        if(filterList[0] != undefined){
            if (filterList[0].length > 0){
                selectFrom = buildConstraints(selectFrom, filterList[0], filterList[1], filterList[2], false, false)
            }
        }

        let query = sqlClient.select().field(sqlOperation).field(displayColumn).from(selectFrom, "q").group(groupBy);
        return query.toString();
    }else{
        let sqlOperation = "";
        switch(operation.name){
            case "Contar": {
                sqlOperation = "COUNT(" + 'q.' + column.date_column + ") as value"
                break;
            }
            case "Sumar":{
                sqlOperation = "SUM(" + 'q.' + column.date_column + ") as value"
                break;
            }
            case "Promedio":{
                sqlOperation = "AVG(" + 'q.' + column.date_column + ") as value"
                break;
            }
            default: {
                break;
            }
        }

        let joinDateField = "b." + column.name ;
        let joinOpFielf = "a." + baseColumn.name;
        let joinCondition = "a." + column.name + "=" + "b.id_fecha";
        let realColumn = "b." + column.date_column;
        let sqlColumn = column.name;
        let displayColumn = "q." +  baseColumn.date_column;
        let groupBy = displayColumn;
        let selectFrom = "";
        if( baseColumn.name == "monto" || column.name == "monto"){
            selectFrom = sqlClient.select().distinct().field("a.nit_proveedor").field("a.nog").field(joinOpFielf).field(realColumn).from("consolidated_table","a").join("dim_fecha","b",joinCondition);
        }else{
            selectFrom = sqlClient.select().distinct().field("a.nog").field(joinOpFielf).field(realColumn).from("consolidated_table","a").join("dim_fecha","b",joinCondition);
        }

        if(filterList[0] != undefined){
            if (filterList[0].length > 0){
                selectFrom = buildConstraints(selectFrom, filterList[0], filterList[1], filterList[2], false, false)
            }
        }
        let query = sqlClient.select().field(sqlOperation).field(displayColumn).from(selectFrom, "q").group(groupBy);
        return query.toString();
    }

};

const getDataForPreview = async(req, res) => {
    try{

        const filters = req.body.definition.filters;

        const dateFilters = req.body.definition.dateFilters;
        let finalQuery = "";

        //Base Query data
        let baseColumn = req.body.definition.baseColumn;
        let category = req.body.definition.category;

        //Filters data
        let filterColumns = [];
        let filterOperations = [];
        let filterValues = [];
        let filterList = [];

        if(filters!= undefined){
            if(filters.length > 0){
                filters.forEach(function(item, index){

                    filterColumns.push(item.column);
                    filterOperations.push(item.operation);
                    filterValues.push(item.value);

                });
                filterList.push(filterColumns, filterOperations, filterValues)
            }

        }

        //Date Filter Data

        //Run query
        finalQuery = baseQueryHandler(baseColumn, category.operation, category.column, filterList);
        let queryString = replaceAll("`","",finalQuery);
        const data = await sequelize.query(queryString);

        return res.json(data);
    }
    catch (e) {
        console.log(e);
        return res.status(httpStatus.INTERNAL_SERVER_ERROR).json(e);
    }

}

export default {
    getDataForPreview
  };

<commit_msg>upper case value in the filters<commit_after>import httpStatus from 'http-status';
import sqlClient from 'squel'

import Sequelize from 'sequelize';
import config from '../../../config/config';

const sequelize = new Sequelize(config.dbUriG, {
  define: {
    charset: 'utf8mb4',
    collate: 'utf8_general_ci',
    timestamps: true
  },
  logging: false
});

const selectWithOutOperation = "select {0}";
const fromWithOutJoins = "from {0}";
const groupBy = "group by {0}";

const replaceAll = (search, replacement, target) => {
    return target.split(search).join(replacement);
}
const buildConstraints = (baseQuery, columns, operations, values, baseColumnDate, operationColumnDate) => {
    for(let x = 0; x < columns.length; x++){
        let column = columns[x];
        let operation = operations[x];
        let value = values[x];
        let condition = ""
        if(!baseColumnDate && !operationColumnDate){
            baseQuery = baseQuery.where(buildOperation(column, value, operation));
        }
    }
    return baseQuery;
}

const buildOperation = (column, value, operation) =>{
    let sentence = ""
    if(operation.value_type == 1){
        let upperValue = value.toUpperCase();
        switch(operation.name){
            case "Igual a": {
                sentence = "a." + column.name + "=" + "'" + upperValue + "'";;
                return sentence;
            }
            case "Diferente de":{
                sentence ="a."  + column.name + "!=" + "'" + upperValue + "'";
                return sentence;
            }
            case "Contiene":{
                sentence = "a." + column.name + " like " + "'" + "%" + upperValue + "%" + "'";
                return sentence;
            }

            default:{
                break;
            }
        }
    }
    if(operation.value_type == 2 || operation.value_type == 4){
        switch(operation.name){
            case "Mayor que":{
                sentence = "a." + column.name + ">" + value;
                return sentence;
            }
            case "Menor que": {
                sentence = "a." + column.name + "<" + value;
                return sentence;
            }
            case "Igual a": {
                sentence = "a." + column.name + "="  + value ;
                return sentence;
            }
            case "Diferente de":{
                sentence ="a."  + column.name + "!=" + value;
                return sentence;
            }
        }

    }

}

const baseQueryHandler = (baseColumn, operation, column, filterList) => {
    let sqlOperation = "";
    if(column.second_table != "dim_fecha" && baseColumn.second_table != "dim_fecha"){
        switch(operation.name){
            case "Contar": {
                sqlOperation = "COUNT(" + 'q.' + column.name + ") as value"
                break;
            }
            case "Sumar":{
                sqlOperation = "SUM(" + 'q.' + column.name + ") as value"
                break;
            }
            case "Promedio":{
                sqlOperation = "AVG(" + 'q.' + column.name + ") as value"
                break;
            }
            default: {
                break;
            }
        }
        let sqlColumn = column.name;
        let calculateColumn = "q." + baseColumn.name;
        let groupBy =  calculateColumn;
        let selectFrom = "";
        if( baseColumn.name == "monto" || column.name == "monto"){
            selectFrom = sqlClient.select().distinct().field("a.nit_proveedor").field("a.nog").field("a." + column.name).field("a."+baseColumn.name).from("consolidated_table","a").join("dim_fecha","b","b.id_fecha = a.fecha_adjudicada");
        }
        else{
            selectFrom = sqlClient.select().distinct().field("a.nog").field("a." + column.name).field("a."+baseColumn.name).from("consolidated_table","a").join("dim_fecha","b","b.id_fecha = a.fecha_adjudicada")
        }
        if(filterList[0] != undefined){
            if (filterList[0].length > 0){
                selectFrom = buildConstraints(selectFrom, filterList[0], filterList[1], filterList[2], false, false)
            }
        }

        let query = sqlClient.select().field(sqlOperation).field(calculateColumn).from(selectFrom, "q")

        query = query.group(groupBy);

        return query.toString();
    }
    else if (column.second_table != "dim_fecha" && baseColumn.second_table == "dim_fecha"){
        let sqlOperation = "";
        switch(operation.name){
            case "Contar": {
                sqlOperation = "COUNT(" + 'q.' + column.name + ") as value"
                break;
            }
            case "Sumar":{
                sqlOperation = "SUM(" + 'q.' + column.name + ") as value"
                break;
            }
            case "Promedio":{
                sqlOperation = "AVG(" + 'q.' + column.name + ") as value"
                break;
            }
            default: {
                break;
            }
        }

        let joinDateField = "b." + baseColumn.date_column;
        let joinOpFielf = "a." + column.name;
        let joinCondition = "a." + baseColumn.name + "=" + "b.id_fecha";
        let sqlColumn = column.date_column;
        let displayColumn = "q." +  baseColumn.date_column;
        let groupBy = displayColumn;
        let selectFrom = "";
        if( baseColumn.name == "monto" || column.name == "monto"){
            selectFrom = sqlClient.select().distinct().field("a.nit_proveedor").field("a.nog").field(joinOpFielf).field(joinDateField).from("consolidated_table","a").join("dim_fecha","b",joinCondition);
        }
        else{
            selectFrom = sqlClient.select().distinct().field("a.nog").field(joinOpFielf).field(joinDateField).from("consolidated_table","a").join("dim_fecha","b",joinCondition);
        }
        if(filterList[0] != undefined){
            if (filterList[0].length > 0){
                selectFrom = buildConstraints(selectFrom, filterList[0], filterList[1], filterList[2], false, false)
            }
        }
        let query = sqlClient.select().field(sqlOperation).field(displayColumn).from(selectFrom, "q").group(groupBy);
        return query.toString();
    }
    else if (column.second_table == "dim_fecha" && baseColumn.second_table != "dim_fecha"){
        let sqlOperation = "";
        switch(operation.name){
            case "Contar": {
                sqlOperation = "COUNT(" + 'q.' + column.date_column + ") as value"
                break;
            }
            case "Sumar":{
                sqlOperation = "SUM(" + 'q.' + column.date_column + ") as value"
                break;
            }
            case "Promedio":{
                sqlOperation = "AVG(" + 'q.' + column.date_column + ") as value"
                break;
            }
            default: {
                break;
            }
        }

        let joinDateField = "b." + column.name ;
        let joinOpFielf = "a." + baseColumn.name;
        let joinCondition = "a." + column.name + "=" + "b.id_fecha";
        let realColumn = "b." + column.date_column;
        let sqlColumn = column.name;
        let displayColumn = "q." +  baseColumn.name;
        let groupBy = displayColumn;
        let selectFrom = "";
        if( baseColumn.name == "monto" || column.name == "monto"){
            selectFrom = sqlClient.select().distinct().field("a.nit_proveedor").field("a.nog").field(joinOpFielf).field(realColumn).from("consolidated_table","a").join("dim_fecha","b",joinCondition);
        }
        else{
            selectFrom = sqlClient.select().distinct().field("a.nog").field(joinOpFielf).field(realColumn).from("consolidated_table","a").join("dim_fecha","b",joinCondition);
        }

        if(filterList[0] != undefined){
            if (filterList[0].length > 0){
                selectFrom = buildConstraints(selectFrom, filterList[0], filterList[1], filterList[2], false, false)
            }
        }

        let query = sqlClient.select().field(sqlOperation).field(displayColumn).from(selectFrom, "q").group(groupBy);
        return query.toString();
    }else{
        let sqlOperation = "";
        switch(operation.name){
            case "Contar": {
                sqlOperation = "COUNT(" + 'q.' + column.date_column + ") as value"
                break;
            }
            case "Sumar":{
                sqlOperation = "SUM(" + 'q.' + column.date_column + ") as value"
                break;
            }
            case "Promedio":{
                sqlOperation = "AVG(" + 'q.' + column.date_column + ") as value"
                break;
            }
            default: {
                break;
            }
        }

        let joinDateField = "b." + column.name ;
        let joinOpFielf = "a." + baseColumn.name;
        let joinCondition = "a." + column.name + "=" + "b.id_fecha";
        let realColumn = "b." + column.date_column;
        let sqlColumn = column.name;
        let displayColumn = "q." +  baseColumn.date_column;
        let groupBy = displayColumn;
        let selectFrom = "";
        if( baseColumn.name == "monto" || column.name == "monto"){
            selectFrom = sqlClient.select().distinct().field("a.nit_proveedor").field("a.nog").field(joinOpFielf).field(realColumn).from("consolidated_table","a").join("dim_fecha","b",joinCondition);
        }else{
            selectFrom = sqlClient.select().distinct().field("a.nog").field(joinOpFielf).field(realColumn).from("consolidated_table","a").join("dim_fecha","b",joinCondition);
        }

        if(filterList[0] != undefined){
            if (filterList[0].length > 0){
                selectFrom = buildConstraints(selectFrom, filterList[0], filterList[1], filterList[2], false, false)
            }
        }
        let query = sqlClient.select().field(sqlOperation).field(displayColumn).from(selectFrom, "q").group(groupBy);
        return query.toString();
    }

};

const getDataForPreview = async(req, res) => {
    try{

        const filters = req.body.definition.filters;

        const dateFilters = req.body.definition.dateFilters;
        let finalQuery = "";

        //Base Query data
        let baseColumn = req.body.definition.baseColumn;
        let category = req.body.definition.category;

        //Filters data
        let filterColumns = [];
        let filterOperations = [];
        let filterValues = [];
        let filterList = [];

        if(filters!= undefined){
            if(filters.length > 0){
                filters.forEach(function(item, index){

                    filterColumns.push(item.column);
                    filterOperations.push(item.operation);
                    filterValues.push(item.value);

                });
                filterList.push(filterColumns, filterOperations, filterValues)
            }

        }

        //Date Filter Data

        //Run query
        finalQuery = baseQueryHandler(baseColumn, category.operation, category.column, filterList);
        let queryString = replaceAll("`","",finalQuery);
        const data = await sequelize.query(queryString);

        return res.json(data);
    }
    catch (e) {
        console.log(e);
        return res.status(httpStatus.INTERNAL_SERVER_ERROR).json(e);
    }

}

export default {
    getDataForPreview
  };

<|endoftext|>


<commit_before>/**
@Name: Element.prototype.serializeNamedChildren
@Description:  Serialzies all named child elements with values elements contained within the Element including text, textarea, select, select-multiple, radio, checkbox
@Param: object o Optional, The properties of an sb.ajax instance, e.g. url, onResponse, etc, if sent the data is send to that address
@Return: String first_name=paul&day=monday
@Example:
var string = $('#myElement').serializeNamedChildren();

var string = $('#myElement').serializeNamedChildren({
    url : '/some/page',
    onResponse : function(r){
        alert(r);
    }
});
*/

Element.prototype.serializeNamedChildren = function(o) {
    var dat=[],s,enc=encodeURIComponent;

    $('*[name]').forEach(function(v,k,a){
        var n=v.getAttribute('name'),t=v.type,val=v.getAttribute('value')||'',enc=encodeURIComponent;

        switch(t){
            case 'select-one':
                dat.push(n + "=" + enc(v.options[v.selectedIndex].value));
                break;

            case 'select-multiple':
                for(s=0;s<v.options.length;s++){
                    if(v.options[s].selected === true){
                        dat.push(n + "=" + enc(v.options[s].value));
                    }
                }
                break;

            default:
                if(t == "checkbox" || t=="radio" && v.checked ==  false){ break; }
                 dat.push(n + "=" + enc(val));
                break;
        }

    });

    s = dat.join('&');
    if(o && o.url){
        var aj = new sb.ajax(o);
        aj.data = s+'&'+aj.data;
        aj.fetch();
    }

    return s;

};<commit_msg>updated docs<commit_after>/**
@Name: Element.prototype.serializeNamedChildren
@Description: Serialzies all child elements that have name attributes contained within the Element including text, textarea, select, select-multiple, radio, checkbox and any other misc elements with name attributes
@Param: object o Optional, The properties of an sb.ajax instance, e.g. url, onResponse, etc, if sent the data is send to that address
@Return: String first_name=paul&day=monday
@Example:
var string = $('#myElement').serializeNamedChildren();

var string = $('#myElement').serializeNamedChildren({
    url : '/some/page',
    onResponse : function(r){
        alert(r);
    }
});
*/

Element.prototype.serializeNamedChildren = function(o) {
    var dat=[],s,enc=encodeURIComponent;

    $('*[name]').forEach(function(v,k,a){
        var n=v.getAttribute('name'),t=v.type,val=v.getAttribute('value')||'',enc=encodeURIComponent;

        switch(t){
            case 'select-one':
                dat.push(n + "=" + enc(v.options[v.selectedIndex].value));
                break;

            case 'select-multiple':
                for(s=0;s<v.options.length;s++){
                    if(v.options[s].selected === true){
                        dat.push(n + "=" + enc(v.options[s].value));
                    }
                }
                break;

            default:
                if(t == "checkbox" || t=="radio" && v.checked ==  false){ break; }
                 dat.push(n + "=" + enc(val));
                break;
        }

    });

    s = dat.join('&');
    if(o && o.url){
        var aj = new sb.ajax(o);
        aj.data = s+'&'+aj.data;
        aj.fetch();
    }

    return s;

};<|endoftext|>


<commit_before>// @flow

import * as React from 'react'
import {NoticeView} from '@frogpond/notice'
import {BuildingHoursList} from './list'
import {type ReduxState} from '../../redux'
import {connect} from 'react-redux'
import type {TopLevelViewPropsType} from '../types'
import type {BuildingType} from './types'
import * as defaultData from '../../../docs/building-hours.json'
import {reportNetworkProblem} from '@frogpond/analytics'
import toPairs from 'lodash/toPairs'
import groupBy from 'lodash/groupBy'
import delay from 'delay'
import {timezone} from '@frogpond/constants'
import {API} from '@frogpond/api'
import {Timer} from '@frogpond/timer'

const buildingHoursUrl = API('/spaces/hours')

const groupBuildings = (buildings: BuildingType[], favorites: string[]) => {
	const favoritesGroup = {
		title: 'Favorites',
		data: buildings.filter(b => favorites.includes(b.name)),
	}

	const grouped = groupBy(buildings, b => b.category || 'Other')
	let groupedBuildings = toPairs(grouped).map(([key, value]) => ({
		title: key,
		data: value,
	}))

	if (favoritesGroup.data.length > 0) {
		groupedBuildings = [favoritesGroup, ...groupedBuildings]
	}

	return groupedBuildings
}

type ReduxStateProps = {
	favoriteBuildings: Array<string>,
}

type Props = TopLevelViewPropsType & ReduxStateProps

type State = {|
	error: ?Error,
	loading: boolean,
	buildings: Array<{title: string, data: Array<BuildingType>}>,
	allBuildings: Array<BuildingType>,
|}

export class BuildingHoursView extends React.PureComponent<Props, State> {
	static navigationOptions = {
		title: 'Building Hours',
		headerBackTitle: 'Hours',
	}

	state = {
		error: null,
		loading: false,
		buildings: groupBuildings(defaultData.data, this.props.favoriteBuildings),
		allBuildings: defaultData.data,
	}

	static getDerivedStateFromProps(nextProps: Props, prevState: State) {
		return {
			buildings: groupBuildings(
				prevState.allBuildings,
				nextProps.favoriteBuildings,
			),
		}
	}

	componentDidMount() {
		this.fetchData()
	}

	refresh = async (): any => {
		let start = Date.now()
		this.setState(() => ({loading: true}))

		await this.fetchData()

		// wait 0.5 seconds – if we let it go at normal speed, it feels broken.
		let elapsed = Date.now() - start
		if (elapsed < 500) {
			await delay(500 - elapsed)
		}

		this.setState(() => ({loading: false}))
	}

	fetchData = async () => {
		let {data: buildings} = await fetchJson(buildingHoursUrl).catch(err => {
			reportNetworkProblem(err)
			return defaultData
		})
		if (process.env.NODE_ENV === 'development') {
			buildings = defaultData.data
		}
		this.setState(() => ({
			buildings: groupBuildings(buildings, this.props.favoriteBuildings),
			allBuildings: buildings,
		}))
	}

	render() {
		if (this.state.error) {
			return <NoticeView text={`Error: ${this.state.error.message}`} />
		}

		return (
			<Timer
				interval={60000}
				moment={true}
				render={({now}) => (
					<BuildingHoursList
						buildings={this.state.buildings}
						loading={this.state.loading}
						navigation={this.props.navigation}
						now={now}
						onRefresh={this.refresh}
					/>
				)}
				timezone={timezone()}
			/>
		)
	}
}

function mapStateToProps(state: ReduxState): ReduxStateProps {
	return {
		favoriteBuildings: state.buildings ? state.buildings.favorites : [],
	}
}

export const ConnectedBuildingHoursView = connect(mapStateToProps)(
	BuildingHoursView,
)
<commit_msg>make use of new caching module in building-hours<commit_after>// @flow

import * as React from 'react'
import {NoticeView} from '@frogpond/notice'
import {BuildingHoursList} from './list'
import {type ReduxState} from '../../redux'
import {connect} from 'react-redux'
import type {TopLevelViewPropsType} from '../types'
import type {BuildingType} from './types'
import toPairs from 'lodash/toPairs'
import groupBy from 'lodash/groupBy'
import {timezone} from '@frogpond/constants'
import {Timer} from '@frogpond/timer'

import {fetchAndCacheItem, type CacheResult} from '../../lib/cache'
import {API} from '@frogpond/api'

function fetchBuildingHours(
	args: {reload?: boolean} = {},
): CacheResult<?Array<BuildingType>> {
	return fetchAndCacheItem({
		key: 'spaces:hours',
		url: API('/spaces/hours'),
		afterFetch: parsed => parsed.data,
		ttl: [1, 'hour'],
		cbForBundledData: () =>
			Promise.resolve(require('../../../docs/building-hours.json')),
		force: args.reload,
		delay: args.reload,
	})
}

const groupBuildings = (
	buildings: Array<BuildingType>,
	favorites: Array<string>,
): Array<{title: string, data: Array<BuildingType>}> => {
	const favoritesGroup = {
		title: 'Favorites',
		data: buildings.filter(b => favorites.includes(b.name)),
	}

	const grouped = groupBy(buildings, b => b.category || 'Other')
	let groupedBuildings = toPairs(grouped).map(([key, value]) => ({
		title: key,
		data: value,
	}))

	if (favoritesGroup.data.length > 0) {
		groupedBuildings = [favoritesGroup, ...groupedBuildings]
	}

	return groupedBuildings
}

type ReduxStateProps = {
	favoriteBuildings: Array<string>,
}

type Props = TopLevelViewPropsType & ReduxStateProps

type State = {|
	error: ?Error,
	loading: boolean,
	buildings: Array<BuildingType>,
|}

export class BuildingHoursView extends React.PureComponent<Props, State> {
	static navigationOptions = {
		title: 'Building Hours',
		headerBackTitle: 'Hours',
	}

	state = {
		error: null,
		loading: false,
		buildings: [],
	}

	componentDidMount() {
		this.fetchData()
	}

	refresh = async (): any => {
		this.setState(() => ({loading: true}))
		await this.fetchData(true)
		this.setState(() => ({loading: false}))
	}

	fetchData = async (reload?: boolean) => {
		let {value} = await fetchBuildingHours({reload})
		this.setState(() => ({buildings: value || []}))
	}

	render() {
		if (this.state.error) {
			return <NoticeView text={`Error: ${this.state.error.message}`} />
		}

		let {buildings} = this.state
		let {favoriteBuildings} = this.props
		let grouped = groupBuildings(buildings, favoriteBuildings)

		return (
			<Timer
				interval={60000}
				moment={true}
				render={({now}) => (
					<BuildingHoursList
						buildings={grouped}
						loading={this.state.loading}
						navigation={this.props.navigation}
						now={now}
						onRefresh={this.refresh}
					/>
				)}
				timezone={timezone()}
			/>
		)
	}
}

function mapStateToProps(state: ReduxState): ReduxStateProps {
	return {
		favoriteBuildings: state.buildings ? state.buildings.favorites : [],
	}
}

export const ConnectedBuildingHoursView = connect(mapStateToProps)(
	BuildingHoursView,
)
<|endoftext|>