<commit_before>"use strict";

var async = require('async');
var Remarkable = require('remarkable');
var mjAPI = require("mathjax-node");
var pangu = require('pangu');
var ejs = require('ejs');
var ncp = require('ncp');
var recursive = require('recursive-readdir');
var mkdirp = require('mkdirp');
var moment = require('moment');
var fs = require('fs');
var path = require('path');
var crypto = require('crypto');
var cwd = process.cwd();
var config = require('./config')();

var ncpOpts = {
    filter: function (filepath) {
        var filename = path.basename(filepath);
        return filename.indexOf('.') !== 0;
    }
};

mjAPI.start();

module.exports = function () {

    var pages = [];
    var categories = [];
    var fprefix = path.resolve(cwd + '/' + config['dir'].source);
    var fcname = path.resolve(cwd + '/' + config['dir'].site + '/CNAME');

    config['runtime'] = {
        emailHash: crypto.createHash('md5').update(config['wiki'].email).digest("hex")
    };

    var gitlog = require('gitlog'),
        options = {
            repo: config['dir'].source,
            number: config['wiki'].logmax || 20,
            fields: [
                'hash',
                'abbrevHash',
                'subject',
                'committerName',
                'committerDate'
            ]
        };

    recursive(fprefix, ['.*'], function (err, files) {

        async.eachSeries(files, function (filename, cb) {
            // ignore non-md files
            if (path.extname(filename) === '.md') {
                var filelink = path.dirname(filename).replace(fprefix, '') + '/' + path.basename(filename, '.md');
                console.log('Parsing: ' + filename);
                parseFile(filename, fs.readFileSync(path.resolve(filename), 'utf8'), filelink, function (page) {
                    pages.push(page);
                    var ci = findWithAttr(categories, 'name', page.category);
                    if (typeof ci === 'number') {
                        categories[ci].pages.push(page);
                    } else {
                        categories.push({
                            name: page.category,
                            pages: [
                                page
                            ]
                        });
                    }
                    cb();
                });
            } else {
                cb();
            }
        }, function () {
            render(
                path.resolve(cwd + '/themes' + '/' + config['wiki'].theme + '/index.ejs'),
                path.resolve(cwd + '/' + config['dir'].site), {
                    config: config,
                    categories: categories,
                    page: {}
                });

            categories.forEach(function (category) {
                category.pages.forEach(function (page) {
                    render(
                        path.resolve(cwd + '/themes' + '/' + config['wiki'].theme + '/page.ejs'),
                        path.resolve(cwd + '/' + config['dir'].site + '/' + config['dir'].page + page.link),
                        {
                            config: config,
                            categories: categories,
                            page: page
                        }
                    );
                });
            });
        });

        if (config['deploy'].cname) {
            fs.writeFile(fcname, config['deploy'].cname + '\n', function () {
                console.log('Custom CNAME set to: ' + config['deploy'].cname);
            });
        } else {
            fs.stat(fcname, function (err, stat) {
                if (!err) {
                    console.log('Removing Custom CNAME file as config set to empty.');
                    fs.unlinkSync(fcname);
                } else if (err.code === 'ENOENT') {
                    console.log('Custom CNAME not set, skipping.');
                }
            });
        }

        console.log('Pages generated.');
    });

    syncAssets();
    syncSrc();

    if (config['wiki'].log) {
        gitlog(options, function (error, commits) {
            render(
                path.resolve(cwd + '/themes' + '/' + config['wiki'].theme + '/changes.ejs'),
                path.resolve(cwd + '/' + config['dir'].site + '/changelog'),
                {
                    page: {},
                    config: config,
                    commits: commits
                }
            );
        });
    }
};

var parseFile = function (filename, fd, filelink, callback) {

    try {
        var meta = fd.slice(0, fd.indexOf('\n---\n')).split('\n');
        var title = meta[0].split(/title:\s?/i)[1];
        var category = meta[1].split(/category:\s?/i)[1];
        var time = meta[2].split(/time:\s?/i)[1];
        var content = fd.slice(fd.indexOf('\n---\n') + 5);
    } catch (e) {
        console.error('Error when reading content properties. Please refer to source code for latest note format. File: ' + filename);
        return {};
    }

    content = lastUpdate(filename, content);

    var maths = content.match(/\^{3}math(.*?\n*?)+?\^{3}/gm);
    if (maths && maths.length !== 0) {
        if (!config['custom'].mathjax) {
            console.warn('WARNING: MathJax detected white it is disabled.');
            callback({
                title: title,
                category: category,
                link: filelink,
                content: mdParse(content)
            });
        } else {

            async.eachSeries(maths, function (m, cb) {

                var c = m.split(/(\^{3}math|\^{3})/g)[2];
                mjParse(c, function (mathxml) {
                    content = content.replace(m, mathxml);
                    cb();
                });

            }, function (err) {
                if (config['custom'].autospacing) {
                    title = pangu.spacing(title);
                    category = pangu.spacing(category);
                }
                callback({
                    title: title,
                    category: category,
                    link: filelink,
                    content: mdParse(content)
                })
            });
        }

    } else {
        callback({
            title: title,
            category: category,
            link: filelink,
            content: mdParse(content)
        });
    }

};

var syncAssets = function () {
    var themePath = path.resolve(cwd + '/themes' + '/' + config['wiki'].theme + '/assets');
    var assetsPath = path.resolve(cwd + '/' + config['dir'].site);
    mkdirp.sync(path.resolve(assetsPath + '/assets'), {mode: '0755'});
    mkdirp.sync(path.resolve(assetsPath + '/static'), {mode: '0755'});
    ncp(themePath, path.resolve(assetsPath + '/assets'));
    ncp(path.resolve(cwd + '/static'), path.resolve(assetsPath + '/static'));
    if (config['wiki'].favicon) {
        fs.stat('./config.yml', function (e, stat) {
            if (e && e.code === 'ENOENT') {
                console.log('WARNING: favicon configured but not found.');
            } else if (e) {
                console.error('WARNING: Error ' + e.code);
            } else {
                ncp(path.resolve(cwd + '/favicon.ico'), path.resolve(assetsPath + '/favicon.ico'));
            }
        });
    }
};

var syncSrc = function () {
    var srcPath = path.resolve(cwd + '/' + config['dir'].source);
    var dest = path.resolve(cwd + '/' + config['dir'].site + '/' + config['dir'].raw);
    mkdirp.sync(dest, {mode: '0755'});
    ncp(srcPath, dest, ncpOpts, function (err) {
        console.log('Source files synced.');
    });
};

var render = function (templatePath, destPath, data) {
    mkdirp.sync(destPath, {mode: '0755'});
    var templateFileData = fs.readFileSync(templatePath, 'utf8');
    fs.writeFile(path.resolve(destPath + '/index.html'), ejs.render(templateFileData, data, {
        filename: templatePath,
        rmWhitespace: true
    }), function (err) {
        if (err) {
            console.error('Error when compile page: ' + destPath);
            console.error(err);
            process.exit(1);
        }
        console.log('Rendered: ' + path.resolve(destPath + '/index.html'));
    });
};

var mjParse = function (data, callback) {

    mjAPI.typeset({
        html: data,
        inputs: ["TeX", "MathML"],
        mml: true
    }, function (result) {
        callback(result.html);
    });

};

var mdParse = function (data) {

    var md = new Remarkable(config['custom'].markdown);

    // config
    if (config['custom'].markdown.abbr) {
        md.core.ruler.enable(['abbr']);
    }
    if (config['custom'].markdown.sup_sub) {
        md.inline.ruler.enable([
            'sub',
            'sup'
        ]);
    }
    if (config['custom'].markdown.footnote) {
        md.block.ruler.enable(['footnote']);
        md.inline.ruler.enable(['footnote_inline']);
    }
    if (config['custom'].markdown.mark) {
        md.inline.ruler.enable(['mark']);
    }
    if (config['custom'].markdown.ins) {
        md.inline.ruler.enable(['ins']);
    }

    // orverride open heading tag to add heading anchor
    md.renderer.rules.heading_open = function (tokens, idx) {
        var escapedText = tokens[idx + 1].content.replace(/\s/g, "_");
        return '<h' + tokens[idx].hLevel + '>' +
            '' +
            '#' +
            ' ';
    };
    // override footnote ref & anchor in order to locate anchor in current tab (base set to `_blank` in theme)
    md.renderer.rules.footnote_ref = function (tokens, idx) {
        var n = Number(tokens[idx].id + 1).toString();
        var id = 'fnref' + n;
        if (tokens[idx].subId > 0) {
            id += ':' + tokens[idx].subId;
        }
        return '[' + n + ']';
    };
    md.renderer.rules.footnote_anchor = function (tokens, idx) {
        var n = Number(tokens[idx].id + 1).toString();
        var id = 'fnref' + n;
        if (tokens[idx].subId > 0) {
            id += ':' + tokens[idx].subId;
        }
        return ' ↩';
    };

    // autospacing in remarkable
    if (config['custom'].autospacing) {
        md.renderer.rules.text = function (tokens, idx) {
            return escapeHtml(pangu.spacing(tokens[idx].content));
        }
    }

    return md.render(data);

};

var lastUpdate = function (file, content) {
    var fstat = fs.statSync(file);
    var sourcepath = file.replace(path.resolve(cwd + '/' + config['dir'].source), config['base'].path + config['dir'].raw + '');
    var lastupdate = config['custom'].lastupdate ?
        config['custom'].lastupdate : '%n%%n%_Last Update: %mtime%_ [Source File](%sourcepath%)%n%';
    return content +
        lastupdate.replace(/%n%/g, '\n')
            .replace(/%mtime%/g, moment(fstat.mtimeMs).format(config['custom'].time))
            .replace(/%sourcepath%/g, sourcepath);
};

/* functions in https://github.com/jonschlinkert/remarkable/blob/master/lib/common/utils.js */
var escapeHtml = function (str) {
    if (/[&<>"]/.test(str)) {
        return str.replace(/[&<>"]/g, replaceUnsafeChar);
    }
    return str;
};

var HTML_REPLACEMENTS = {
    '&': '&',
    '<': '<',
    '>': '>',
    '"': '"'
};

function replaceUnsafeChar(ch) {
    return HTML_REPLACEMENTS[ch];
}

// http://stackoverflow.com/questions/7176908/how-to-get-index-of-object-by-its-property-in-javascript
function findWithAttr(array, attr, value) {
    for (var i = 0; i < array.length; i += 1) {
        if (array[i][attr] === value) {
            return i;
        }
    }
}
<commit_msg>add table style<commit_after>"use strict";

var async = require('async');
var Remarkable = require('remarkable');
var mjAPI = require("mathjax-node");
var pangu = require('pangu');
var ejs = require('ejs');
var ncp = require('ncp');
var recursive = require('recursive-readdir');
var mkdirp = require('mkdirp');
var moment = require('moment');
var fs = require('fs');
var path = require('path');
var crypto = require('crypto');
var cwd = process.cwd();
var config = require('./config')();

var ncpOpts = {
    filter: function (filepath) {
        var filename = path.basename(filepath);
        return filename.indexOf('.') !== 0;
    }
};

mjAPI.start();

module.exports = function () {

    var pages = [];
    var categories = [];
    var fprefix = path.resolve(cwd + '/' + config['dir'].source);
    var fcname = path.resolve(cwd + '/' + config['dir'].site + '/CNAME');

    config['runtime'] = {
        emailHash: crypto.createHash('md5').update(config['wiki'].email).digest("hex")
    };

    var gitlog = require('gitlog'),
        options = {
            repo: config['dir'].source,
            number: config['wiki'].logmax || 20,
            fields: [
                'hash',
                'abbrevHash',
                'subject',
                'committerName',
                'committerDate'
            ]
        };

    recursive(fprefix, ['.*'], function (err, files) {

        async.eachSeries(files, function (filename, cb) {
            // ignore non-md files
            if (path.extname(filename) === '.md') {
                var filelink = path.dirname(filename).replace(fprefix, '') + '/' + path.basename(filename, '.md');
                console.log('Parsing: ' + filename);
                parseFile(filename, fs.readFileSync(path.resolve(filename), 'utf8'), filelink, function (page) {
                    pages.push(page);
                    var ci = findWithAttr(categories, 'name', page.category);
                    if (typeof ci === 'number') {
                        categories[ci].pages.push(page);
                    } else {
                        categories.push({
                            name: page.category,
                            pages: [
                                page
                            ]
                        });
                    }
                    cb();
                });
            } else {
                cb();
            }
        }, function () {
            render(
                path.resolve(cwd + '/themes' + '/' + config['wiki'].theme + '/index.ejs'),
                path.resolve(cwd + '/' + config['dir'].site), {
                    config: config,
                    categories: categories,
                    page: {}
                });

            categories.forEach(function (category) {
                category.pages.forEach(function (page) {
                    render(
                        path.resolve(cwd + '/themes' + '/' + config['wiki'].theme + '/page.ejs'),
                        path.resolve(cwd + '/' + config['dir'].site + '/' + config['dir'].page + page.link),
                        {
                            config: config,
                            categories: categories,
                            page: page
                        }
                    );
                });
            });
        });

        if (config['deploy'].cname) {
            fs.writeFile(fcname, config['deploy'].cname + '\n', function () {
                console.log('Custom CNAME set to: ' + config['deploy'].cname);
            });
        } else {
            fs.stat(fcname, function (err, stat) {
                if (!err) {
                    console.log('Removing Custom CNAME file as config set to empty.');
                    fs.unlinkSync(fcname);
                } else if (err.code === 'ENOENT') {
                    console.log('Custom CNAME not set, skipping.');
                }
            });
        }

        console.log('Pages generated.');
    });

    syncAssets();
    syncSrc();

    if (config['wiki'].log) {
        gitlog(options, function (error, commits) {
            render(
                path.resolve(cwd + '/themes' + '/' + config['wiki'].theme + '/changes.ejs'),
                path.resolve(cwd + '/' + config['dir'].site + '/changelog'),
                {
                    page: {},
                    config: config,
                    commits: commits
                }
            );
        });
    }
};

var parseFile = function (filename, fd, filelink, callback) {

    try {
        var meta = fd.slice(0, fd.indexOf('\n---\n')).split('\n');
        var title = meta[0].split(/title:\s?/i)[1];
        var category = meta[1].split(/category:\s?/i)[1];
        var time = meta[2].split(/time:\s?/i)[1];
        var content = fd.slice(fd.indexOf('\n---\n') + 5);
    } catch (e) {
        console.error('Error when reading content properties. Please refer to source code for latest note format. File: ' + filename);
        return {};
    }

    content = lastUpdate(filename, content);

    var maths = content.match(/\^{3}math(.*?\n*?)+?\^{3}/gm);
    if (maths && maths.length !== 0) {
        if (!config['custom'].mathjax) {
            console.warn('WARNING: MathJax detected white it is disabled.');
            callback({
                title: title,
                category: category,
                link: filelink,
                content: mdParse(content)
            });
        } else {

            async.eachSeries(maths, function (m, cb) {

                var c = m.split(/(\^{3}math|\^{3})/g)[2];
                mjParse(c, function (mathxml) {
                    content = content.replace(m, mathxml);
                    cb();
                });

            }, function (err) {
                if (config['custom'].autospacing) {
                    title = pangu.spacing(title);
                    category = pangu.spacing(category);
                }
                callback({
                    title: title,
                    category: category,
                    link: filelink,
                    content: mdParse(content)
                })
            });
        }

    } else {
        callback({
            title: title,
            category: category,
            link: filelink,
            content: mdParse(content)
        });
    }

};

var syncAssets = function () {
    var themePath = path.resolve(cwd + '/themes' + '/' + config['wiki'].theme + '/assets');
    var assetsPath = path.resolve(cwd + '/' + config['dir'].site);
    mkdirp.sync(path.resolve(assetsPath + '/assets'), {mode: '0755'});
    mkdirp.sync(path.resolve(assetsPath + '/static'), {mode: '0755'});
    ncp(themePath, path.resolve(assetsPath + '/assets'));
    ncp(path.resolve(cwd + '/static'), path.resolve(assetsPath + '/static'));
    if (config['wiki'].favicon) {
        fs.stat('./config.yml', function (e, stat) {
            if (e && e.code === 'ENOENT') {
                console.log('WARNING: favicon configured but not found.');
            } else if (e) {
                console.error('WARNING: Error ' + e.code);
            } else {
                ncp(path.resolve(cwd + '/favicon.ico'), path.resolve(assetsPath + '/favicon.ico'));
            }
        });
    }
};

var syncSrc = function () {
    var srcPath = path.resolve(cwd + '/' + config['dir'].source);
    var dest = path.resolve(cwd + '/' + config['dir'].site + '/' + config['dir'].raw);
    mkdirp.sync(dest, {mode: '0755'});
    ncp(srcPath, dest, ncpOpts, function (err) {
        console.log('Source files synced.');
    });
};

var render = function (templatePath, destPath, data) {
    mkdirp.sync(destPath, {mode: '0755'});
    var templateFileData = fs.readFileSync(templatePath, 'utf8');
    fs.writeFile(path.resolve(destPath + '/index.html'), ejs.render(templateFileData, data, {
        filename: templatePath,
        rmWhitespace: true
    }), function (err) {
        if (err) {
            console.error('Error when compile page: ' + destPath);
            console.error(err);
            process.exit(1);
        }
        console.log('Rendered: ' + path.resolve(destPath + '/index.html'));
    });
};

var mjParse = function (data, callback) {

    mjAPI.typeset({
        html: data,
        inputs: ["TeX", "MathML"],
        mml: true
    }, function (result) {
        callback(result.html);
    });

};

var mdParse = function (data) {

    var md = new Remarkable(config['custom'].markdown);

    // config
    if (config['custom'].markdown.abbr) {
        md.core.ruler.enable(['abbr']);
    }
    if (config['custom'].markdown.sup_sub) {
        md.inline.ruler.enable([
            'sub',
            'sup'
        ]);
    }
    if (config['custom'].markdown.footnote) {
        md.block.ruler.enable(['footnote']);
        md.inline.ruler.enable(['footnote_inline']);
    }
    if (config['custom'].markdown.mark) {
        md.inline.ruler.enable(['mark']);
    }
    if (config['custom'].markdown.ins) {
        md.inline.ruler.enable(['ins']);
    }

    // orverride open heading tag to add heading anchor
    md.renderer.rules.heading_open = function (tokens, idx) {
        var escapedText = tokens[idx + 1].content.replace(/\s/g, "_");
        return '<h' + tokens[idx].hLevel + '>' +
            '' +
            '#' +
            ' ';
    };
    // override footnote ref & anchor in order to locate anchor in current tab (base set to `_blank` in theme)
    md.renderer.rules.footnote_ref = function (tokens, idx) {
        var n = Number(tokens[idx].id + 1).toString();
        var id = 'fnref' + n;
        if (tokens[idx].subId > 0) {
            id += ':' + tokens[idx].subId;
        }
        return '[' + n + ']';
    };
    md.renderer.rules.footnote_anchor = function (tokens, idx) {
        var n = Number(tokens[idx].id + 1).toString();
        var id = 'fnref' + n;
        if (tokens[idx].subId > 0) {
            id += ':' + tokens[idx].subId;
        }
        return ' ↩';
    };

    // add table style
    md.renderer.rules.table_open = function (tokens, idx) {
        return '
\n'
    }

    // autospacing in remarkable
    if (config['custom'].autospacing) {
        md.renderer.rules.text = function (tokens, idx) {
            return escapeHtml(pangu.spacing(tokens[idx].content));
        }
    }

    return md.render(data);

};

var lastUpdate = function (file, content) {
    var fstat = fs.statSync(file);
    var sourcepath = file.replace(path.resolve(cwd + '/' + config['dir'].source), config['base'].path + config['dir'].raw + '');
    var lastupdate = config['custom'].lastupdate ?
        config['custom'].lastupdate : '%n%%n%_Last Update: %mtime%_ [Source File](%sourcepath%)%n%';
    return content +
        lastupdate.replace(/%n%/g, '\n')
            .replace(/%mtime%/g, moment(fstat.mtimeMs).format(config['custom'].time))
            .replace(/%sourcepath%/g, sourcepath);
};

/* functions in https://github.com/jonschlinkert/remarkable/blob/master/lib/common/utils.js */
var escapeHtml = function (str) {
    if (/[&<>"]/.test(str)) {
        return str.replace(/[&<>"]/g, replaceUnsafeChar);
    }
    return str;
};

var HTML_REPLACEMENTS = {
    '&': '&',
    '<': '<',
    '>': '>',
    '"': '"'
};

function replaceUnsafeChar(ch) {
    return HTML_REPLACEMENTS[ch];
}

// http://stackoverflow.com/questions/7176908/how-to-get-index-of-object-by-its-property-in-javascript
function findWithAttr(array, attr, value) {
    for (var i = 0; i < array.length; i += 1) {
        if (array[i][attr] === value) {
            return i;
        }
    }
}
<|endoftext|>


<commit_before>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const APIAI_LANG = process.env.APIAI_LANG || 'en';
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;

const apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "fb"});
const sessionIds = new Map();

function processEvent(event) {
    var sender = event.sender.id;

    if (event.message && event.message.text) {
        var text = event.message.text;
        // Handle a text message from this sender

        if (!sessionIds.has(sender)) {
            sessionIds.set(sender, uuid.v1());
        }

        console.log("Text", text);
        var userName = request({
        url: 'https://graph.facebook.com/v2.6/475973909193996',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            "fields" : "first_name,last_name,profile_pic"
        }
    }, function (error, response, body) {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }
    });

        let apiaiRequest = apiAiService.textRequest(text,
            {
                sessionId: sessionIds.get(sender),
                contexts: [
                    {
                    name: "generic",
                    parameters: {
                          facebook_user: userName
                        }
                    }]
            });

        apiaiRequest.on('response', (response) => {
            if (isDefined(response.result)) {
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.fulfillment.data;
                let action = response.result.action;

                if (isDefined(responseData) && isDefined(responseData.facebook)) {
                    try {
                        console.log('Response as formatted message');
                        sendFBMessage(sender, responseData.facebook);
                    } catch (err) {
                        sendFBMessage(sender, {text: err.message });
                    }
                } else if (isDefined(responseText)) {
                    console.log('Response as text message');
                    sendFBMessage(sender, {text: responseText});
                }

            }
        });

        apiaiRequest.on('error', (error) => console.error(error));
        apiaiRequest.end();
    }
}

function sendFBMessage(sender, messageData) {

    var APISpeech = messageData.text;
    if(APISpeech == "structured"){
        messageData = {
    "attachment":{
      "type":"template",
      "payload":{
        "template_type":"receipt",
        "recipient_name":"Stephane Crozatier",
        "order_number":"12345678902",
        "currency":"USD",
        "payment_method":"Visa 2345",
        "order_url":"http://petersapparel.parseapp.com/order?order_id=123456",
        "timestamp":"1428444852",
        "elements":[
          {
            "title":"Classic White T-Shirt",
            "subtitle":"100% Soft and Luxurious Cotton",
            "quantity":2,
            "price":50,
            "currency":"USD",
            "image_url":"http://petersapparel.parseapp.com/img/whiteshirt.png"
          },
          {
            "title":"Classic Gray T-Shirt",
            "subtitle":"100% Soft and Luxurious Cotton",
            "quantity":1,
            "price":25,
            "currency":"USD",
            "image_url":"http://petersapparel.parseapp.com/img/grayshirt.png"
          }
        ],
        "address":{
          "street_1":"1 Hacker Way",
          "street_2":"",
          "city":"Menlo Park",
          "postal_code":"94025",
          "state":"CA",
          "country":"US"
        },
        "summary":{
          "subtotal":75.00,
          "shipping_cost":4.95,
          "total_tax":6.19,
          "total_cost":56.14
        },
        "adjustments":[
          {
            "name":"New Customer Discount",
            "amount":20
          },
          {
            "name":"$10 Off Coupon",
            "amount":10
          }
        ]
      }
    }
  };
    }

    request({
        url: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: sender},
            message: messageData
        }
    }, function (error, response, body) {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }
    });
}

function doSubscribeRequest() {
    request({
            method: 'POST',
            uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
        },
        function (error, response, body) {
            if (error) {
                console.error('Error while subscription: ', error);
            } else {
                console.log('Subscription result: ', response.body);
            }
        });
}

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

const app = express();
app.use(bodyParser.json());
app.all('*', function (req, res, next) {
    // res.header("Access-Control-Allow-Origin", '*');
    // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, content-type, accept");
    next();
});

app.get('/webhook/', function (req, res) {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);

        setTimeout(function () {
            doSubscribeRequest();
        }, 3000);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', function (req, res) {
    try {
        var messaging_events = req.body.entry[0].messaging;
        for (var i = 0; i < messaging_events.length; i++) {
            var event = req.body.entry[0].messaging[i];

             if (event.message) {
                  processEvent(event);
             }else{
                 if (event.postback) {
                    sendFBMessage(event.sender.id, {"text" : JSON.stringify(event)});
                  }
             }

        }
        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.listen(REST_PORT, function () {
    console.log('Rest service ready on port ' + REST_PORT);
});

doSubscribeRequest();
<commit_msg>Update app.js<commit_after>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const APIAI_LANG = process.env.APIAI_LANG || 'en';
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;

const apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "fb"});
const sessionIds = new Map();

function processEvent(event) {
    var sender = event.sender.id;

    if (event.message && event.message.text) {
        var text = event.message.text;
        // Handle a text message from this sender

        if (!sessionIds.has(sender)) {
            sessionIds.set(sender, uuid.v1());
        }

        console.log("Text", text);
        var userName = request({
        url: 'https://graph.facebook.com/v2.6/475973909193996',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            "fields" : "first_name,last_name,profile_pic"
        }
    }, function (error, response, body) {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }
    });

        let apiaiRequest = apiAiService.textRequest(text,
            {
                sessionId: sessionIds.get(sender),
                contexts: [
                    {
                    name: "generic",
                    parameters: {
                          facebook_user: JSON.stringify(userName)
                        }
                    }]
            });

        apiaiRequest.on('response', (response) => {
            if (isDefined(response.result)) {
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.fulfillment.data;
                let action = response.result.action;

                if (isDefined(responseData) && isDefined(responseData.facebook)) {
                    try {
                        console.log('Response as formatted message');
                        sendFBMessage(sender, responseData.facebook);
                    } catch (err) {
                        sendFBMessage(sender, {text: err.message });
                    }
                } else if (isDefined(responseText)) {
                    console.log('Response as text message');
                    sendFBMessage(sender, {text: responseText});
                }

            }
        });

        apiaiRequest.on('error', (error) => console.error(error));
        apiaiRequest.end();
    }
}

function sendFBMessage(sender, messageData) {

    var APISpeech = messageData.text;
    if(APISpeech == "structured"){
        messageData = {
    "attachment":{
      "type":"template",
      "payload":{
        "template_type":"receipt",
        "recipient_name":"Stephane Crozatier",
        "order_number":"12345678902",
        "currency":"USD",
        "payment_method":"Visa 2345",
        "order_url":"http://petersapparel.parseapp.com/order?order_id=123456",
        "timestamp":"1428444852",
        "elements":[
          {
            "title":"Classic White T-Shirt",
            "subtitle":"100% Soft and Luxurious Cotton",
            "quantity":2,
            "price":50,
            "currency":"USD",
            "image_url":"http://petersapparel.parseapp.com/img/whiteshirt.png"
          },
          {
            "title":"Classic Gray T-Shirt",
            "subtitle":"100% Soft and Luxurious Cotton",
            "quantity":1,
            "price":25,
            "currency":"USD",
            "image_url":"http://petersapparel.parseapp.com/img/grayshirt.png"
          }
        ],
        "address":{
          "street_1":"1 Hacker Way",
          "street_2":"",
          "city":"Menlo Park",
          "postal_code":"94025",
          "state":"CA",
          "country":"US"
        },
        "summary":{
          "subtotal":75.00,
          "shipping_cost":4.95,
          "total_tax":6.19,
          "total_cost":56.14
        },
        "adjustments":[
          {
            "name":"New Customer Discount",
            "amount":20
          },
          {
            "name":"$10 Off Coupon",
            "amount":10
          }
        ]
      }
    }
  };
    }

    request({
        url: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: sender},
            message: messageData
        }
    }, function (error, response, body) {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }
    });
}

function doSubscribeRequest() {
    request({
            method: 'POST',
            uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
        },
        function (error, response, body) {
            if (error) {
                console.error('Error while subscription: ', error);
            } else {
                console.log('Subscription result: ', response.body);
            }
        });
}

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

const app = express();
app.use(bodyParser.json());
app.all('*', function (req, res, next) {
    // res.header("Access-Control-Allow-Origin", '*');
    // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, content-type, accept");
    next();
});

app.get('/webhook/', function (req, res) {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);

        setTimeout(function () {
            doSubscribeRequest();
        }, 3000);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', function (req, res) {
    try {
        var messaging_events = req.body.entry[0].messaging;
        for (var i = 0; i < messaging_events.length; i++) {
            var event = req.body.entry[0].messaging[i];

             if (event.message) {
                  processEvent(event);
             }else{
                 if (event.postback) {
                    sendFBMessage(event.sender.id, {"text" : JSON.stringify(event)});
                  }
             }

        }
        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.listen(REST_PORT, function () {
    console.log('Rest service ready on port ' + REST_PORT);
});

doSubscribeRequest();
<|endoftext|>


<commit_before>/* jslint node: true, esnext: true */

'use strict';

const endpoint = require('kronos-endpoint'),
	service = require('kronos-service'),
	mat = require('model-attributes'),
	Gelf = require('gelf');

/**
 * Log receiving service
 */
class GelfLogger extends service.Logger {

	static get name() {
		return 'gelf-logger';
	}

	static get configurationAttributes() {
		return Object.assign(mat.createAttributes({
			graylogPort: {
				description: 'gelf server port',
				type: 'ip-port',
				default: 12201,
				needsRestart: true
			},
			graylogHostname: {
				description: 'gelf server name',
				type: 'hostname',
				default: '127.0.0.1',
				needsRestart: true
			},
			connection: {
				type: 'string',
				default: 'wan',
				needsRestart: true
			},
			maxChunkSizeWan: {
				type: 'integer',
				default: 1420,
				needsRestart: true
			},
			maxChunkSizeLan: {
				type: 'integer',
				default: 8154,
				needsRestart: true
			}
		}), service.Service.configurationAttributes);
	}

	_start() {
		const gelf = new Gelf({
			graylogPort: this.graylogPort,
			graylogHostname: this.graylogHostname,
			connection: this.connection,
			maxChunkSizeWan: this.maxChunkSizeWan,
			maxChunkSizeLan: this.maxChunkSizeLan
		});

		this.endpoints.log.receive = entry => {
			try {
				gelf.emit('gelf.log', entry);
			} catch (e) {
				console.error(`Unable to log entry with the following keys: ${Object.keys(entry)} ${e}`);
				return Promise.reject(e);
			}
			return Promise.resolve();
		};

		return Promise.resolve();
	}
}

module.exports.registerWithManager = manager =>
	manager.registerServiceFactory(GelfLogger).then(sf => {
		return manager.declareService({
			type: GelfLogger.name,
			name: 'logger'
		});
	});
<commit_msg>fix(config): declare attribute types<commit_after>/* jslint node: true, esnext: true */

'use strict';

const endpoint = require('kronos-endpoint'),
	service = require('kronos-service'),
	mat = require('model-attributes'),
	Gelf = require('gelf');

/**
 * Log receiving service
 */
class GelfLogger extends service.Logger {

	static get name() {
		return 'gelf-logger';
	}

	static get configurationAttributes() {
		return Object.assign(mat.createAttributes({
			graylogPort: {
				description: 'gelf server port',
				type: 'ip-port',
				default: 12201,
				needsRestart: true
			},
			graylogHostname: {
				description: 'gelf server name',
				type: 'hostname',
				default: '127.0.0.1',
				needsRestart: true
			},
			connection: {
				type: 'string',
				default: 'wan',
				needsRestart: true
			},
			maxChunkSizeWan: {
				type: 'unsigned-integer',
				default: 1420,
				needsRestart: true
			},
			maxChunkSizeLan: {
				type: 'unsigned-integer',
				default: 8154,
				needsRestart: true
			}
		}), service.Service.configurationAttributes);
	}

	_start() {
		const gelf = new Gelf({
			graylogPort: this.graylogPort,
			graylogHostname: this.graylogHostname,
			connection: this.connection,
			maxChunkSizeWan: this.maxChunkSizeWan,
			maxChunkSizeLan: this.maxChunkSizeLan
		});

		this.endpoints.log.receive = entry => {
			try {
				gelf.emit('gelf.log', entry);
			} catch (e) {
				console.error(`Unable to log entry with the following keys: ${Object.keys(entry)} ${e}`);
				return Promise.reject(e);
			}
			return Promise.resolve();
		};

		return Promise.resolve();
	}
}

module.exports.registerWithManager = manager =>
	manager.registerServiceFactory(GelfLogger).then(sf => {
		return manager.declareService({
			type: GelfLogger.name,
			name: 'logger'
		});
	});
<|endoftext|>


<commit_before>//
// This is main file containing code implementing the Express server and functionality for the Express echo bot.
//
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const path = require('path');
const dotenv = require('dotenv').config();
const schedule = require('node-schedule');
var winston = require('winston');
const db = require('../src/models/db')(winston);
const dbRelated = require('../src/models/dbRelated');
//const text = require('../src/models/textParser');
var messengerButton = "<title>Facebook Messenger Bot</title>
Facebook Messenger Bot
This is a bot based on Messenger Platform QuickStart. For more details, see their docs.

";

const synonyms = require("synonyms");

// The rest of the code implements the routes for our Express server.
let app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: true
}));

// Webhook validation
app.get('/webhook', function(req, res) {
    if (req.query['hub.mode'] === 'subscribe' &&
        req.query['hub.verify_token'] === (process.env.VERIFY_TOKEN || 'test') /*process.env.VERIFY_TOKEN*/ ) {
        winston.log('info', "Validating webhook");
        res.status(200).send(req.query['hub.challenge']);
    } else {
        winston.log('error', "Failed validation. Make sure the validation tokens match.");
        res.sendStatus(403);
    }
});

app.get('/syn', function(req, res) {
    text.test2('this is a test string containing words like yellow, happy, angry and Copenhagen');
    //winston.log('info', synonyms(req.query.query));
    res.send(JSON.stringify(synonyms(req.query.query)));
});
// Display the web page
app.get('/', function(req, res) {
    res.writeHead(200, {
        'Content-Type': 'text/html'
    });
    res.write(messengerButton);
    res.end();
});

// Message processing
app.post('/webhook', function(req, res) {
    var data = req.body;

    winston.log('info', 'got request', data);

    // Make sure this is a page subscription
    if (data.object === 'page') {

        // Iterate over each entry - there may be multiple if batched
        data.entry.forEach(function(entry) {
            var pageID = entry.id;
            var timeOfEvent = entry.time;

                // Iterate over each messaging event
                entry.messaging.forEach(function(event) {
                    if(event.get_started){
                        winston.log('info', "received get_started as message", event);
                        sendTextMessage(event.sender.id, 'Velkommen!');
                    }
                    if (event.message) {
                        winston.log('info', "received message", event);
                        receivedMessage(event);
                    } else if (event.postback) {
                        //receivedPostback(event);
                        winston.log('info', "received postback", event);
                        handlePostBack(event.postback, event.sender.id, res);
                    } else if (event.read) {
                        winston.log('info', "received read event");
                    } else {
                        winston.log('info', "Webhook received unknown event: ", event);
                    }
                });
        });

        // Assume all went well.
        //
        // You must send back a 200, within 20 seconds, to let us know
        // you've successfully received the callback. Otherwise, the request
        // will time out and we will keep trying to resend.
        //res.sendStatus(200);
    }
    //All went kind of well, even if we dont support other types of requests than pages
    res.sendStatus(200);
});

function handlePostBack(postback, user_id, res) {
    winston.log('info','postback received',postback);
    var payload = JSON.parse(postback.payload);

    //Postback actions:
    //subscribe (payload.type*)
    //unsubscribe (payload.type*)
    //unsubscribe_reason (payload.type*, payload.reason*, payload.art_id*)
    //image_reaction (payload.type*,payload.art_id*, payload.reaction*)

    switch(payload.type){
        case 'subscribe':
            subscribe(payload);
        break;
        case 'unsubscribe':
            unsubscribe(payload);
        break;
        case 'unsubscribe_reason':
            unsubscribeReason(payload);
        break;
        case 'image_reaction':
            saveImageResponse(payload);
        break;
        case 'get_started':
            sendTextMessage(user_id, 'Welcome.:)')
        break;
        default:
            winston.log('warn', 'unhandled postback type. This is the postback: ', postback);
    }

    function subscribe(payload){
        db.subscribeUser(user_id, function(){
            res.sendStatus(200);
        });
    }

    function unsubscribe(payload){
        winston.log('info', 'unsubscribe for user ' + user_id);
        var reason = null;
        db.unsubscribeUser(user_id, reason, function sendStatus() {
            sendUnsubscribeReasonButton();
        });
    }

    function unsubscribeReason(payload){
        var reason =  payload.reason;
        db.unsubscribeUser(user_id, reason, function sendStatus() {
            sendTextMessage(payload.user_id, 'Okay. Got it. Hopefully we\'ll see you again. :)');
        });
    }

    function saveImageResponse(payload){
        db.saveResponse(payload.art_id, user_id, payload.reaction, respondOnPostback);

        function respondOnPostback() {
            if (payload.reaction == 0) {
                sendTextMessage(payload.user_id, 'Got that. You won\'t get art like that again.');
            } else {
                sendTextMessage(payload.user_id, 'Got that. Glad you liked it! :)');
            }
        }
    }
}

app.post('/subscribe', function(req, res) {
    winston.log('info', db);
    winston.log('info', 'subscribe endpoint reached');

    var data = req.body;
    //if(data.object === 'page'){
    if (req.body['messenger user id']) {
        winston.log('info', data.entry);
        db.subscribeUser(req.body['messenger user id'])
    } else {
        winston.log('info', 'message user id not set!');
    }
    //    }
    //    else{
    //Didn't receive the right format
    //        winston.log('info', 'subscribe data wasn\'t a page');
    //    }

    res.sendStatus(200);
});

app.post('/unsubscribe', function(req, res) {
    winston.log('info', 'unsubscribe endpoint reached');

    var data = req.body;
    //if(data.object === 'page'){
    if (req.body['messenger user id']) {
        var reason = req.query.reason || false;
        winston.log('info', data.entry);
        db.unsubscribeUser(req.body['messenger user id'], reason, function sendStatus() {
            res.sendStatus(200);
        });
    }
    //    }
    //    else{
    //Didn't receive the right format
    //    winston.log('info', 'unsubscribe data wasn\'t a page');
    //    }

});

// Incoming events handling
function receivedMessage(event) {
    var senderID = event.sender.id;
    var recipientID = event.recipient.id;
    var timeOfMessage = event.timestamp;
    var message = event.message;

    winston.log('info', "Received message for user %d and page %d at %d with message:",
        senderID, recipientID, timeOfMessage);
    //    winston.log('info', JSON.stringify(message));

    var messageId = message.mid;
    winston.log('info', message.message);
    var messageText = message.text;
    var messageAttachments = message.attachments;

    if (messageText) {
        // If we receive a text message, check to see if it matches a keyword
        // and send back the template example. Otherwise, just echo the text we received.
        switch (messageText.toLowerCase()) {
            //Return a random image
            case 'image':
                winston.log('info', 'search for image ' + messageText);
                getAssetsByText(senderID);
                break;

                //Reponse on unsubscription
            case 'it\'s too often.':
            case 'paintings are ugly':
            case 'i was just curious':
                winston.log('info', 'Got subscription feedback.');
                break;

                //Search art by keyword or get tags from sentence
            default:
                //If question get image by description, artist or tag
                if (messageText.indexOf('?') !== -1) {
                    var n = messageText.split(" ");
                    winston.log('info', 'Searching for', n);
                    getAssetsByText(senderID, n[n.length - 1].replace('?', ''));
                } else {
                    //Save tags for image
                    var n = messageText.split(" ");
                    winston.log('info', 'Saving', n);
                    db.saveTags(senderID, n, sendThankYouMessage);
                }

                break;
        }
    } else if (messageAttachments) {
        //        sendTextMessage(senderID, "Message with attachment received");
    }

    function sendThankYouMessage() {
        sendTextMessage(senderID, 'Thank you for your input, I can probaply use it for the image!');
    }
}

function getAssetsByText(recipientId, text) {
    if (text == undefined) {
        text = "";
        db.getImage(recipientId, sendResultAsImageOrSearchByText);
        return;
    }

    dbRelated.searchFavoritesRelatedImagesByText(recipientId, text, sendResultAsImageOrSearchByText);

    function sendResultAsImageOrSearchByText(result) {

        if (!result) {
            console.log('!result');
            winston.log('info', 'no result when searching for related images. Trying to search by text: ' + text);
            db.searchImagesByText(recipientId, text, sendImageOrNoResultsText);
            return;
        }
        console.log('here is the result: ', result.id, result.title);

        sendImageOrNoResultsText(result);
    }

    function sendImageOrNoResultsText(result) {
        console.log('sendImageOrNoResultsText');
        if (result) {
            winston.log('info', 'heres the result', result.id, result.title);
            sendImageMessage(recipientId, result);
        } else {
            winston.log('info', "could not find anyting, sending sorry message");
            sendTextMessage(recipientId, "Sorry, I couldn't find anything for you. Want a random painting? Write \"image\". Looking for something particular? Write a name, year, or title and an \"?\" Then we'll go through our collection to see if we have something for you!");
        }
    }
}

//////////////////////////
// Sending helpers
//////////////////////////
function sendTextMessage(recipientId, messageText) {
    winston.log('info', 'sending text' + messageText);
    var messageData = {
        recipient: {
            id: recipientId
        },
        message: {
            text: messageText
        }
    };

    callSendAPI(messageData);
}

function sendImageMessage(recipientId, image_data) {
    winston.log('info', 'sending image');
    db.insertSeenArt(recipientId, image_data.id);
    var messageData = {
        recipient: {
            id: recipientId
        },
        message: {
            attachment: {
                type: "image",
                payload: {
                    url: image_data.image_url
                }
            }
        }
    };

    callSendAPI(messageData, sendButtons);

    function sendButtons() {
        sendRespondButtons(recipientId, image_data.title, image_data.id);
    }
}

function sendRespondButtons(recipientId, image_title, art_id) {
    var messageData = {
        recipient: {
            id: recipientId
        },
        message: {
            attachment: {
                type: "template",
                payload: {
                    template_type: "generic",
                    elements: [{
                        title: image_title,
                        subtitle: 'Do you like it?',
                        //image_url: image_data.image_url,
                        //item_url: image_data.image_url,
                        buttons: [{
                            type: "postback",
                            title: "Nice! 😍",
                            payload: JSON.stringify({
                                type: 'image_reaction',
                                art_id: art_id,
                                reaction: 1,
                                user_id: recipientId
                            }),
                        }, {
                            type: "postback",
                            title: "Nah... 😒",
                            payload: JSON.stringify({
                                type: 'image_reaction',
                                art_id: art_id,
                                reaction: 0,
                                user_id: recipientId
                            }),
                        }],
                    }],
                }
            }
        }
    };
    callSendAPI(messageData);
}

function sendUnsubscribeReasonButton(recipientId, art_id) {
    var messageData = {
        recipient: {
            id: recipientId
        },
        message: {
            attachment: {
                type: "template",
                payload: {
                    template_type: "generic",
                    elements: [{
                        title: 'You will not receive any more pictures from us. \n We could really use a bit of feedback, so please let us know why you don\'t want daily pictures anymore:',
                        buttons: [{
                            type: "postback",
                            title: "It's too often",
                            payload: JSON.stringify({
                                type: 'unsubscribe_reason',
                                art_id: art_id,
                                reaction: 'too_often',
                                user_id: recipientId
                            }),
                        }, {
                            type: "postback",
                            title: "Paintings are ugly",
                            payload: JSON.stringify({
                                type: 'unsubscribe_reason',
                                art_id: art_id,
                                reaction: 'painting_are_ugly',
                                user_id: recipientId
                            }),
                        }, {
                            type: "postback",
                            title: "I was just curious",
                            payload: JSON.stringify({
                                type: 'unsubscribe_reason',
                                art_id: art_id,
                                reaction: 'just_curious',
                                user_id: recipientId
                            })
                        }],
                    }],
                }
            }
        }
    };
    callSendAPI(messageData);
}

function callSendAPI(messageData, cb) {
    if (process.env.mode && process.env.mode.toLowerCase() == 'dev') {
        winston.log('info', 'if not in dev mode, this would be sent: ', messageData);
        winston.log('info', 'with this token' + process.env.ACCESS_TOKEN);
        if (cb) {
            cb();
        }
        return;
    }

    request({
        uri: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {
            access_token: process.env.ACCESS_TOKEN
        },
        method: 'POST',
        json: messageData,
    }, function(error, response, body) {
        if (!error && response.statusCode == 200) {
            var recipientId = body.recipient_id;
            var messageId = body.message_id;

            winston.log('info', "Successfully sent generic message with id %s to recipient %s",
                messageId, recipientId);
        } else {
            winston.log('error', "Unable to send message.", response);
            //            winston.log('error', response);
            //            winston.log('error', error);
        }

        if (cb) {
            cb();
        }
    });
}

//Send images to recipients every 24 hours (or so)
/*var j = schedule.scheduleJob('* * * * *', function(){
  winston.log('info', 'Sending messages for recipients now!');
});*/

if (process.env.MODE && process.env.MODE.toLowerCase() == 'dev') {
    winston.log('info', 'running in dev mode');
} else {
    winston.add(winston.transports.File, {
        filename: 'log.log',
        timestamp: true,
        level: 'info'
    });

    winston.handleExceptions(new winston.transports.File({
        filename: 'exceptions.log',
        timestamp: true,
        humanReadableUnhandledException: true
    }));

    winston.remove(winston.transports.Console);
}

// Set Express to listen out for HTTP requests
var server = app.listen(process.env.PORT || 3000, function() {
    console.log("Listening on port %s", server.address().port);
});
<commit_msg>Added quick reply buttons<commit_after>//
// This is main file containing code implementing the Express server and functionality for the Express echo bot.
//
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const path = require('path');
const dotenv = require('dotenv').config();
const schedule = require('node-schedule');
var winston = require('winston');
const db = require('../src/models/db')(winston);
const dbRelated = require('../src/models/dbRelated');
//const text = require('../src/models/textParser');
var messengerButton = "<title>Facebook Messenger Bot</title>
Facebook Messenger Bot
This is a bot based on Messenger Platform QuickStart. For more details, see their docs.

";

const synonyms = require("synonyms");

// The rest of the code implements the routes for our Express server.
let app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: true
}));

// Webhook validation
app.get('/webhook', function(req, res) {
    if (req.query['hub.mode'] === 'subscribe' &&
        req.query['hub.verify_token'] === (process.env.VERIFY_TOKEN || 'test') /*process.env.VERIFY_TOKEN*/ ) {
        winston.log('info', "Validating webhook");
        res.status(200).send(req.query['hub.challenge']);
    } else {
        winston.log('error', "Failed validation. Make sure the validation tokens match.");
        res.sendStatus(403);
    }
});

app.get('/syn', function(req, res) {
    text.test2('this is a test string containing words like yellow, happy, angry and Copenhagen');
    //winston.log('info', synonyms(req.query.query));
    res.send(JSON.stringify(synonyms(req.query.query)));
});
// Display the web page
app.get('/', function(req, res) {
    res.writeHead(200, {
        'Content-Type': 'text/html'
    });
    res.write(messengerButton);
    res.end();
});

// Message processing
app.post('/webhook', function(req, res) {
    var data = req.body;

    winston.log('info', 'got request', data);

    // Make sure this is a page subscription
    if (data.object === 'page') {

        // Iterate over each entry - there may be multiple if batched
        data.entry.forEach(function(entry) {
            var pageID = entry.id;
            var timeOfEvent = entry.time;

                // Iterate over each messaging event
                entry.messaging.forEach(function(event) {
                    if(event.get_started){
                        winston.log('info', "received get_started as message", event);
                        sendTextMessage(event.sender.id, 'Velkommen!');
                    }
                    if (event.message) {
                        winston.log('info', "received message", event);
                        receivedMessage(event);
                    } else if (event.postback) {
                        handlePostBack(event.postback, event.sender.id, res);
                    } else if (event.read) {
                        winston.log('info', "received read event");
                    } else {
                        winston.log('info', "Webhook received unknown event: ", event);
                    }
                });
        });

        // Assume all went well.
        //
        // You must send back a 200, within 20 seconds, to let us know
        // you've successfully received the callback. Otherwise, the request
        // will time out and we will keep trying to resend.
        //res.sendStatus(200);
    }
    //All went kind of well, even if we dont support other types of requests than pages
    res.sendStatus(200);
});

function handlePostBack(postback, user_id, res) {
    winston.log('info','postback received',postback);
    var payload = JSON.parse(postback.payload);

    //Postback actions:
    //subscribe (payload.type*)
    //unsubscribe (payload.type*)
    //unsubscribe_reason (payload.type*, payload.reason*, payload.art_id*)
    //image_reaction (payload.type*,payload.art_id*, payload.reaction*)

    switch(payload.type){
        case 'subscribe':
            subscribe(payload);
        break;
        case 'unsubscribe':
            unsubscribe(payload);
        break;
        case 'unsubscribe_reason':
            unsubscribeReason(payload);
        break;
        case 'image_reaction':
            saveImageResponse(payload);
        break;
        case 'get_started':
            sendTextMessage(user_id, 'Welcome.:)');
        break;
        default:
            winston.log('warn', 'unhandled postback type. This is the postback: ', postback);
        break;
    }

    function subscribe(payload){
        db.subscribeUser(user_id, function(){
            res.sendStatus(200);
        });
    }

    function unsubscribe(payload){
        winston.log('info', 'unsubscribe for user ' + user_id);
        var reason = null;
        db.unsubscribeUser(user_id, reason, function sendStatus() {
            sendUnsubscribeReasonButton();
        });
    }

    function unsubscribeReason(payload){
        var reason =  payload.reason;
        db.unsubscribeUser(user_id, reason, function sendStatus() {
            sendTextMessage(payload.user_id, 'Okay. Got it. Hopefully we\'ll see you again. :)');
        });
    }

    function saveImageResponse(payload){
        db.saveResponse(payload.art_id, user_id, payload.reaction, respondOnPostback);

        function respondOnPostback() {
            if (payload.reaction == 0) {
                sendTextMessage(payload.user_id, 'Got that. You won\'t get art like that again.');
            } else {
                sendTextMessage(payload.user_id, 'Got that. Glad you liked it! :)');
            }
        }
    }
}

app.post('/subscribe', function(req, res) {
    winston.log('info', db);
    winston.log('info', 'subscribe endpoint reached');

    var data = req.body;
    //if(data.object === 'page'){
    if (req.body['messenger user id']) {
        winston.log('info', data.entry);
        db.subscribeUser(req.body['messenger user id'])
    } else {
        winston.log('info', 'message user id not set!');
    }
    //    }
    //    else{
    //Didn't receive the right format
    //        winston.log('info', 'subscribe data wasn\'t a page');
    //    }

    res.sendStatus(200);
});

app.post('/unsubscribe', function(req, res) {
    winston.log('info', 'unsubscribe endpoint reached');

    var data = req.body;
    //if(data.object === 'page'){
    if (req.body['messenger user id']) {
        var reason = req.query.reason || false;
        winston.log('info', data.entry);
        db.unsubscribeUser(req.body['messenger user id'], reason, function sendStatus() {
            res.sendStatus(200);
        });
    }
    //    }
    //    else{
    //Didn't receive the right format
    //    winston.log('info', 'unsubscribe data wasn\'t a page');
    //    }

});

// Incoming events handling
function receivedMessage(event) {
    var senderID = event.sender.id;
    var recipientID = event.recipient.id;
    var timeOfMessage = event.timestamp;
    var message = event.message;

    winston.log('info', "Received message for user %d and page %d at %d with message:",
        senderID, recipientID, timeOfMessage);
    //    winston.log('info', JSON.stringify(message));

    var messageId = message.mid;
    winston.log('info', message.message);
    var messageText = message.text;
    var messageAttachments = message.attachments;

    if (messageText) {
        // If we receive a text message, check to see if it matches a keyword
        // and send back the template example. Otherwise, just echo the text we received.
        switch (messageText.toLowerCase()) {
            //Return a random image
            case 'image':
                winston.log('info', 'search for image ' + messageText);
                getAssetsByText(senderID);
                break;

                //Reponse on unsubscription
            case 'it\'s too often.':
            case 'paintings are ugly':
            case 'i was just curious':
                winston.log('info', 'Got subscription feedback.');
                break;

                //Search art by keyword or get tags from sentence
            default:
                sendSenderAction(senderID);
                //If question get image by description, artist or tag
                if (messageText.indexOf('?') !== -1) {
                    var n = messageText.split(" ");
                    winston.log('info', 'Searching for', n);
                    getAssetsByText(senderID, n[n.length - 1].replace('?', ''));
                } else {
                    //Save tags for image
                    var n = messageText.split(" ");
                    winston.log('info', 'Saving', n);
                    db.saveTags(senderID, n, sendThankYouMessage);
                }

                break;
        }
    } else if (messageAttachments) {
        //        sendTextMessage(senderID, "Message with attachment received");
    }

    function sendThankYouMessage() {
        sendTextMessage(senderID, 'Thank you for your input, I can probaply use it for the image!');
    }
}

function getAssetsByText(recipientId, text) {
    if (text == undefined) {
        text = "";
        db.getImage(recipientId, sendResultAsImageOrSearchByText);
        return;
    }

    dbRelated.searchFavoritesRelatedImagesByText(recipientId, text, sendResultAsImageOrSearchByText);

    function sendResultAsImageOrSearchByText(result) {

        if (!result) {
            console.log('!result');
            winston.log('info', 'no result when searching for related images. Trying to search by text: ' + text);
            db.searchImagesByText(recipientId, text, sendImageOrNoResultsText);
            return;
        }
        console.log('here is the result: ', result.id, result.title);

        sendImageOrNoResultsText(result);
    }

    function sendImageOrNoResultsText(result) {
        console.log('sendImageOrNoResultsText');
        if (result) {
            winston.log('info', 'heres the result', result.id, result.title);
            sendImageMessage(recipientId, result);
        } else {
            winston.log('info', "could not find anyting, sending sorry message");
            sendTextMessage(recipientId, "Sorry, I couldn't find anything for you. Want a random painting? Write \"image\". Looking for something particular? Write a name, year, or title and an \"?\" Then we'll go through our collection to see if we have something for you!");
        }
    }
}

//////////////////////////
// Sending helpers
//////////////////////////
function sendTextMessage(recipientId, messageText) {
    winston.log('info', 'sending text' + messageText);
    var messageData = {
        recipient: {
            id: recipientId
        },
        message: {
            text: messageText
        }
    };

    callSendAPI(messageData);
}

function sendImageMessage(recipientId, image_data) {
    winston.log('info', 'sending image');
    db.insertSeenArt(recipientId, image_data.id);
    var messageData = {
        recipient: {
            id: recipientId
        },
        message: {
            attachment: {
                type: "image",
                payload: {
                    url: image_data.image_url
                }
            },
            quick_replies:[
              {
                content_type:"text",
                title:"Nice! 😍",
                payload: JSON.stringify({
                    type: 'image_reaction',
                    art_id: image_data.id,
                    reaction: 1,
                    user_id: recipientId
                })
            },
            {
                content_type: 'text',
                title: 'Nah... 😒',
                payload: JSON.stringify({
                    type: 'image_reaction',
                    art_id: image_data.id,
                    reaction: 0,
                    user_id: recipientId
                })
            }
            ]
        }
    };

    callSendAPI(messageData, sendButtons);

    function sendButtons() {
        sendRespondButtons(recipientId, image_data.title, image_data.id);
    }
}

function sendRespondButtons(recipientId, image_title, art_id) {
    var messageData = {
        recipient: {
            id: recipientId
        },
        message: {
            attachment: {
                type: "template",
                payload: {
                    template_type: "generic",
                    elements: [{
                        title: image_title,
                /*        subtitle: 'Do you like it?',
                        //image_url: image_data.image_url,
                        //item_url: image_data.image_url,
                        buttons: [{
                            type: "postback",
                            title: "Nice! 😍",
                            payload: JSON.stringify({
                                type: 'image_reaction',
                                art_id: art_id,
                                reaction: 1,
                                user_id: recipientId
                            }),
                        }, {
                            type: "postback",
                            title: "Nah... 😒",
                            payload: JSON.stringify({
                                type: 'image_reaction',
                                art_id: art_id,
                                reaction: 0,
                                user_id: recipientId
                            }),
                        },*/{
                          type:"element_share"
                        }],
                    }],
                }
            }
        }
    };
    callSendAPI(messageData);
}

function sendUnsubscribeReasonButton(recipientId, art_id) {
    var messageData = {
        recipient: {
            id: recipientId
        },
        message: {
            attachment: {
                type: "template",
                payload: {
                    template_type: "generic",
                    elements: [{
                        title: 'You will not receive any more pictures from us. \n We could really use a bit of feedback, so please let us know why you don\'t want daily pictures anymore:',
                        buttons: [{
                            type: "postback",
                            title: "It's too often",
                            payload: JSON.stringify({
                                type: 'unsubscribe_reason',
                                art_id: art_id,
                                reaction: 'too_often',
                                user_id: recipientId
                            }),
                        }, {
                            type: "postback",
                            title: "Paintings are ugly",
                            payload: JSON.stringify({
                                type: 'unsubscribe_reason',
                                art_id: art_id,
                                reaction: 'painting_are_ugly',
                                user_id: recipientId
                            }),
                        }, {
                            type: "postback",
                            title: "I was just curious",
                            payload: JSON.stringify({
                                type: 'unsubscribe_reason',
                                art_id: art_id,
                                reaction: 'just_curious',
                                user_id: recipientId
                            })
                        }],
                    }],
                }
            }
        }
    };
    callSendAPI(messageData);
}

//type can be typing_on, typing_off, mark_seen
function sendSenderAction(recipientId, type){
    var action = type || 'typing_on';
    callSendAPI({
      "recipient":{
        "id":recipientId
      },
      "sender_action":action
    });
}

function callSendAPI(messageData, cb) {
    if (process.env.mode && process.env.mode.toLowerCase() == 'dev') {
        winston.log('info', 'if not in dev mode, this would be sent: ', messageData);
        winston.log('info', 'with this token' + process.env.ACCESS_TOKEN);
        if (cb) {
            cb();
        }
        return;
    }

    request({
        uri: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {
            access_token: process.env.ACCESS_TOKEN
        },
        method: 'POST',
        json: messageData,
    }, function(error, response, body) {
        if (!error && response.statusCode == 200) {
            var recipientId = body.recipient_id;
            var messageId = body.message_id;

            winston.log('info', "Successfully sent generic message with id %s to recipient %s",
                messageId, recipientId);
        } else {
            winston.log('error', "Unable to send message.", response);
            //            winston.log('error', response);
            //            winston.log('error', error);
        }

        if (cb) {
            cb();
        }
    });
}

//Send images to recipients every 24 hours (or so)
/*var j = schedule.scheduleJob('* * * * *', function(){
  winston.log('info', 'Sending messages for recipients now!');
});*/

if (process.env.MODE && process.env.MODE.toLowerCase() == 'dev') {
    winston.log('info', 'running in dev mode');
} else {
    winston.add(winston.transports.File, {
        filename: 'log.log',
        timestamp: true,
        level: 'info'
    });

    winston.handleExceptions(new winston.transports.File({
        filename: 'exceptions.log',
        timestamp: true,
        humanReadableUnhandledException: true
    }));

    winston.remove(winston.transports.Console);
}

// Set Express to listen out for HTTP requests
var server = app.listen(process.env.PORT || 3000, function() {
    console.log("Listening on port %s", server.address().port);
});
<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var express = require('express');

var app = express();
var port = parseInt(process.env.PORT, 10) || 8001;
var html = fs.readFileSync(path.join(process.cwd(), 'src', 'index.html'), {
  encoding: 'utf8'
});

app.use('/scripts', express.static(path.join(process.cwd(), 'bower_components')));

app.get('/', function(req, res) {
  res.send(html);
});

var server = app.listen(port, function() {
  console.log('Server started on port %d', server.address().port);
});
<commit_msg>read index file everytime<commit_after>var fs = require('fs');
var path = require('path');
var express = require('express');

var app = express();
var port = parseInt(process.env.PORT, 10) || 8001;

function html() {
  return fs.readFileSync(path.join(process.cwd(), 'src', 'index.html'), { encoding: 'utf8' });
}

app.use('/scripts', express.static(path.join(process.cwd(), 'bower_components')));

app.get('/', function(req, res) {
  res.send(html());
});

var server = app.listen(port, function() {
  console.log('Server started on port %d', server.address().port);
});
<|endoftext|>


<commit_before>var slackMessage = require('./slackMessage.js');
var hipChatMessage = require('./hipChatMessage.js');
var url = require('url');
var dateFormat = require('dateformat');
var request = require('request');
var moment = require('moment-timezone');
var winston = require('winston');
winston.level = process.env.LOG_LEVEL;

var defaultResponse = "Hi, I'm a 10bis bot, searching for restaurants\n" +
                        "To use me - enter /10bis Restaurant, e.g. '/10bis דיקסי'";

var TOTAL_KEYWORD = "total";
var DATE_FORMAT = 'dd/mm/yyyy';
var TIME_FORMAT = 'HH:MM:ss';
var TIMEZONE = 'Asia/Jerusalem';

var formatDateTime = function(now) {
    // 10bis query format is: 10%2F09%2F2017+19%3A45%3A57
    // which is 'dd/mm/yyyy HH:MM:ss' but the encodeURI struggles with the space
    return encodeURI(dateFormat(now, DATE_FORMAT)) + ' ' + encodeURI(dateFormat(now, TIME_FORMAT));
};

var generateSearchRequest = function(restaurantName) {
    var now = moment.tz(TIMEZONE).toDate();

    var parsed_url = url.format({
        pathname: 'https://www.10bis.co.il/Restaurants/SearchRestaurants',
        query: {
            deliveryMethod: 'Delivery',
            ShowOnlyOpenForDelivery: false,
            id: process.env.USER_ID,
            pageNum: 0,
            pageSize: 50,
            OrderBy: "Default",
            cuisineType: "",
            CityId: process.env.CITY_ID,
            StreetId: process.env.STREET_ID,
            FilterByKosher: false,
            FilterByBookmark: false,
            FilterByCoupon: false,
            searchPhrase: restaurantName,
            Latitude: process.env.LAT,
            Longitude: process.env.LONG,
            HouseNumber: process.env.HOUSE_NUMBER,
            desiredDateAndTime: formatDateTime(now),
            timestamp: now.getTime()
        }
    });

    return parsed_url;
};

var generateGetTotalOrdersRequest = function() {
    var now = moment.tz(TIMEZONE).toDate();

    var parsed_url = url.format({
        pathname: 'https://www.10bis.co.il/Restaurants/SearchRestaurants',
        query: {
            deliveryMethod: 'Delivery',
            ShowOnlyOpenForDelivery: false,
            id: process.env.USER_ID,
            pageNum: 0,
            pageSize: 50,
            OrderBy: 'pool_sum',
            cuisineType: '',
            CityId: process.env.CITY_ID,
            StreetId: process.env.STREET_ID,
            FilterByKosher: false,
            FilterByBookmark: false,
            FilterByCoupon: false,
            searchPhrase: '',
            Latitude: process.env.LAT,
            Longitude: process.env.LONG,
            HouseNumber: process.env.HOUSE_NUMBER,
            desiredDateAndTime: formatDateTime(now),
            timestamp: now.getTime()
        }
    });

    return parsed_url;
};

var filterByRestaurantName = function(data) {
    var flags = {};
    var filteredRestaurants = data.filter(function(restarant) {
        if (flags[restarant.RestaurantName]) {
            return false;
        }
        flags[restarant.RestaurantName] = true;
        return true;
    });

    return filteredRestaurants;
};

var sortRestaurantsByDistance = function(data) {
        return data.sort(
            function(objectA, objectB) {
                if (!objectA.distanceFromUserInMeters && objectB.distanceFromUserInMeters) return -1;
                if (objectA.distanceFromUserInMeters && !objectB.distanceFromUserInMeters) return 1;
                if (!objectA.distanceFromUserInMeters && !objectB.distanceFromUserInMeters) return 0;

                if (objectA.distanceFromUserInMeters > objectB.distanceFromUserInMeters)
                    return 1;
                if (objectB.distanceFromUserInMeters > objectA.distanceFromUserInMeters)
                    return -1;

                return 0;
            }
        );
};

var verifyMessage = function(req, formatters) {
    if (!req || !formatters || formatters.constructor != Array)
        return null;

    return formatters.find(function(formatter){
        return formatter.isValidMessage(req);
        });
};

var search = function(res, messageFormatter, restaurantName){
    if(restaurantName.length === 0){ // Behavior for empty command ('/10bis' with no content)
            var body = messageFormatter.getSuccessMessage(defaultResponse, "");
            res.send(body);
            return;
        }

        var parsed_url = generateSearchRequest(restaurantName);

        request(parsed_url, function(error, response, body) {
            if (!error && response.statusCode == 200) {
                var data = JSON.parse(body);

                var resBody = "";
                if (!data || !data.length || data.length < 1) {
                    resBody = messageFormatter.getErrorMessage(restaurantName);
                    res.send(resBody);
                    return;
                }

                resBody = messageFormatter.generateSearchResponse(filterByRestaurantName(sortRestaurantsByDistance(data)));
                res.send(resBody);
            } else {
                res.status(400);
                res.send('None shall pass');
            }
        });
};

var filterTotalOrders = function (restarant){
    // Filter all restaurants will positive pool value
    return restarant.PoolSumNumber > 0;
};

var getTotalOrders = function(res, messageFormatter){
         var parsed_url = generateGetTotalOrdersRequest();
         winston.debug('Total Orders Url: ' + parsed_url);

         request(parsed_url, function(error, response, body) {
             if (!error && response.statusCode == 200) {
                 var data = JSON.parse(body);

                 var resBody = "";
                 if (!data || !data.length || data.length < 1) {
                     resBody = messageFormatter.getErrorMessage();
                     res.send(resBody);
                     return;
                 }

                var restaurants = data.filter(filterTotalOrders);

                resBody = messageFormatter.generateTotalOrdersResponse(filterByRestaurantName(restaurants));
                res.send(resBody);
            } else {
                res.status(400);
                res.send('None shall pass');
            }
        });
};

module.exports = {
    process: function(req, res) {
        var messageFormatter = verifyMessage(req, [hipChatMessage, slackMessage]);
        if (!messageFormatter){
            res.status(400);
            res.send("Invalid Message");
            return;
        }

        var restaurantName = messageFormatter.getRestaurantName(req);
        var body = "";

        if (!restaurantName) {
            body = messageFormatter.getErrorMessage();
            res.send(body);
            return;
        }

        restaurantName = restaurantName.trim();

        if (restaurantName.toLowerCase() == TOTAL_KEYWORD.toLowerCase())
            getTotalOrders(res, messageFormatter);
        else search(res, messageFormatter, restaurantName);
    }
};
<commit_msg>DateTime to Jerusalem timezone<commit_after>var slackMessage = require('./slackMessage.js');
var hipChatMessage = require('./hipChatMessage.js');
var url = require('url');
var request = require('request');
var moment = require('moment-timezone');
var winston = require('winston');
winston.level = process.env.LOG_LEVEL;

var defaultResponse = "Hi, I'm a 10bis bot, searching for restaurants\n" +
                        "To use me - enter /10bis Restaurant, e.g. '/10bis דיקסי'";

var TOTAL_KEYWORD = "total";
var DATE_TIME_FORMAT = "DD/MM/YYYY HH:mm:ss";
var TIMEZONE = 'Asia/Jerusalem';

var generateSearchRequest = function(restaurantName) {
    var now = moment.tz(TIMEZONE).format(DATE_TIME_FORMAT);

    var parsed_url = url.format({
        pathname: 'https://www.10bis.co.il/Restaurants/SearchRestaurants',
        query: {
            deliveryMethod: 'Delivery',
            ShowOnlyOpenForDelivery: false,
            id: process.env.USER_ID,
            pageNum: 0,
            pageSize: 50,
            OrderBy: "Default",
            cuisineType: "",
            CityId: process.env.CITY_ID,
            StreetId: process.env.STREET_ID,
            FilterByKosher: false,
            FilterByBookmark: false,
            FilterByCoupon: false,
            searchPhrase: restaurantName,
            Latitude: process.env.LAT,
            Longitude: process.env.LONG,
            HouseNumber: process.env.HOUSE_NUMBER,
            desiredDateAndTime: encodeURI(now),
            timestamp: new Date().getTime()
        }
    });

    return parsed_url;
};

var generateGetTotalOrdersRequest = function() {
    var now = moment.tz(TIMEZONE).format(DATE_TIME_FORMAT);

    var parsed_url = url.format({
        pathname: 'https://www.10bis.co.il/Restaurants/SearchRestaurants',
        query: {
            deliveryMethod: 'Delivery',
            ShowOnlyOpenForDelivery: false,
            id: process.env.USER_ID,
            pageNum: 0,
            pageSize: 50,
            OrderBy: 'pool_sum',
            cuisineType: '',
            CityId: process.env.CITY_ID,
            StreetId: process.env.STREET_ID,
            FilterByKosher: false,
            FilterByBookmark: false,
            FilterByCoupon: false,
            searchPhrase: '',
            Latitude: process.env.LAT,
            Longitude: process.env.LONG,
            HouseNumber: process.env.HOUSE_NUMBER,
            desiredDateAndTime: encodeURI(now),
            timestamp: new Date().getTime()
        }
    });

    return parsed_url;
};

var filterByRestaurantName = function(data) {
    var flags = {};
    var filteredRestaurants = data.filter(function(restarant) {
        if (flags[restarant.RestaurantName]) {
            return false;
        }
        flags[restarant.RestaurantName] = true;
        return true;
    });

    return filteredRestaurants;
};

var sortRestaurantsByDistance = function(data) {
        return data.sort(
            function(objectA, objectB) {
                if (!objectA.distanceFromUserInMeters && objectB.distanceFromUserInMeters) return -1;
                if (objectA.distanceFromUserInMeters && !objectB.distanceFromUserInMeters) return 1;
                if (!objectA.distanceFromUserInMeters && !objectB.distanceFromUserInMeters) return 0;

                if (objectA.distanceFromUserInMeters > objectB.distanceFromUserInMeters)
                    return 1;
                if (objectB.distanceFromUserInMeters > objectA.distanceFromUserInMeters)
                    return -1;

                return 0;
            }
        );
};

var verifyMessage = function(req, formatters) {
    if (!req || !formatters || formatters.constructor != Array)
        return null;

    return formatters.find(function(formatter){
        return formatter.isValidMessage(req);
        });
};

var search = function(res, messageFormatter, restaurantName){
    if(restaurantName.length === 0){ // Behavior for empty command ('/10bis' with no content)
            var body = messageFormatter.getSuccessMessage(defaultResponse, "");
            res.send(body);
            return;
        }

        var parsed_url = generateSearchRequest(restaurantName);

        request(parsed_url, function(error, response, body) {
            if (!error && response.statusCode == 200) {
                var data = JSON.parse(body);

                var resBody = "";
                if (!data || !data.length || data.length < 1) {
                    resBody = messageFormatter.getErrorMessage(restaurantName);
                    res.send(resBody);
                    return;
                }

                resBody = messageFormatter.generateSearchResponse(filterByRestaurantName(sortRestaurantsByDistance(data)));
                res.send(resBody);
            } else {
                res.status(400);
                res.send('None shall pass');
            }
        });
};

var filterTotalOrders = function (restarant){
    // Filter all restaurants will positive pool value
    return restarant.PoolSumNumber > 0;
};

var getTotalOrders = function(res, messageFormatter){
         var parsed_url = generateGetTotalOrdersRequest();
         winston.debug('Total Orders Url: ' + parsed_url);

         request(parsed_url, function(error, response, body) {
             if (!error && response.statusCode == 200) {
                 var data = JSON.parse(body);

                 var resBody = "";
                 if (!data || !data.length || data.length < 1) {
                     resBody = messageFormatter.getErrorMessage();
                     res.send(resBody);
                     return;
                 }

                var restaurants = data.filter(filterTotalOrders);

                resBody = messageFormatter.generateTotalOrdersResponse(filterByRestaurantName(restaurants));
                res.send(resBody);
            } else {
                res.status(400);
                res.send('None shall pass');
            }
        });
};

module.exports = {
    process: function(req, res) {
        var messageFormatter = verifyMessage(req, [hipChatMessage, slackMessage]);
        if (!messageFormatter){
            res.status(400);
            res.send("Invalid Message");
            return;
        }

        var restaurantName = messageFormatter.getRestaurantName(req);
        var body = "";

        if (!restaurantName) {
            body = messageFormatter.getErrorMessage();
            res.send(body);
            return;
        }

        restaurantName = restaurantName.trim();

        if (restaurantName.toLowerCase() == TOTAL_KEYWORD.toLowerCase())
            getTotalOrders(res, messageFormatter);
        else search(res, messageFormatter, restaurantName);
    }
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Dependencies.
 */

var Parser = require('./parser');
var Loader = require('./loader');
var hasOwnProp = Object.prototype.hasOwnProperty;

/**
 * Load given `.env` file and set the variables
 * to `process.env` if not defined already.
 *
 * @param {String} path to .env file, default - .env
 * @returns {Object}
 * @api public
 */

module.exports = function(options) {
  var parser = null;
  var loader = new Loader(options);
  var files = loader.load();

  files.forEach(function(file) {
    var parser = new Parser(options);
    var vars = parser.parse(file);

    Object.keys(vars).forEach(function(key) {
      process.env[key] = vars[key];
    });
  });

  return process.env;
};
<commit_msg>Remove unused var<commit_after>'use strict';

/**
 * Dependencies.
 */

var Parser = require('./parser');
var Loader = require('./loader');

/**
 * Load given `.env` file and set the variables
 * to `process.env` if not defined already.
 *
 * @param {String} path to .env file, default - .env
 * @returns {Object}
 * @api public
 */

module.exports = function(options) {
  var parser = null;
  var loader = new Loader(options);
  var files = loader.load();

  files.forEach(function(file) {
    var parser = new Parser(options);
    var vars = parser.parse(file);

    Object.keys(vars).forEach(function(key) {
      process.env[key] = vars[key];
    });
  });

  return process.env;
};
<|endoftext|>