<commit_before>/* webhook.js
 * Written by <NAME>.
 * An Express based app that listens for queries from a Slack channel and responds with netrunnerdb card info.
 */
'use strict';
var express = require('express');
var bodyParser = require('body-parser');

var nrdb = require('./nrdb-local');
var formatting = require('./formatting');
// A list of common card shorthands and their corresponding full names
var shorthands = require('./shorthands.json');
// Regex generated from the shorthand keys to be used in find/replace
// Only matches whole words
var shorthandRegExp = new RegExp(
    Object.keys(shorthands).reduce((pv, cv, ci, a) => {
        var o = pv;
        if (ci !== 0) {
            o += '\\b|\\b';
        }
        o += cv;
        if (ci === a.length - 1) {
            o += '\\b';
        }
        return o;
    }, '\\b')
);

var port = process.env.PORT || 3000;
var token = process.env.TOKEN || '';
var authorizedDomains = process.env.AUTHORIZED_DOMAINS || undefined;
if (authorizedDomains) {
    authorizedDomains = authorizedDomains.toLowerCase().split(',');
}

// Find all search strings enclosed in square brackets in the given text.
function findSearchStrings(text) {
    var cardFinder = new RegExp('.*?\\[(.*?)\\]', 'g'),
        searches = [],
        i = cardFinder.exec(text);
    while (i) {
        searches.push(i[1]);
        i = cardFinder.exec(text);
    }
    return searches;
}

// Search the db for the specified cards
function findCards(searches) {
    // Create an array of promises, 1 for each card searched.
    var promises = [];
    searches.forEach((search, i) => {
        // Clean the search and expand any shorthands.
        var cleanSearch = search.toLowerCase().replace(shorthandRegExp, (sh) => {
            return shorthands[sh];
        });
        promises[i] = nrdb.getCardByTitle(cleanSearch);
    });
    return new Promise((resolve, reject) => {
        Promise.all(promises).then((cards) => {
            var hits = [];
            var misses = [];
            // Iterate through the cards returned by the searches, appending them to the hits or misses array.
            cards.forEach((card, i) => {
                if (card) {
                    hits.push(card);
                } else {
                    misses.push(searches[i]);
                }
            });
            resolve({hits, misses});
        }, reject);
    });
}

var app = express();

var domainWhitelist = express.Router().use((req, res, next) => {
    // Ensure the requester is on the authorized list
    var teamDomain = req.body.team_domain || "";
    teamDomain = teamDomain.toLowerCase();
    if (authorizedDomains && authorizedDomains.indexOf(teamDomain) === -1) {
        return res.json(formatting.unauthorizedMessage());
    }
    next();
});

// Intercept requests and perform several checks before serving
var requestValidator = express.Router().use((req, res, next) => {
    // Reject queries with empty bodies.
    if (!req.body || Object.keys(req.body).length === 0) {
        return res.sendStatus(400);
    }

    // Ignore automated slackbot messages.
    if (req.body.user_name === 'slackbot') {
        return res.send('');
    }
    next();
});

// Send empty response if the index isn't ready.
var loadedCheck = express.Router().use((req, res, next) => {
    // TODO Put a nice message here instead
    if (nrdbLoaded) {
        next();
    } else {
        return res.send('');
    }
});


var nrdbLoaded = false;
var nrdbLoadFailed = false;

nrdb.init().then(() => {
    nrdbLoaded = true;
}, () => {
    nrdbLoadFailed = true;
});

// Load middlewares
app.use(bodyParser.urlencoded({extended: false}));
app.use(domainWhitelist);
app.use(requestValidator);
app.use(loadedCheck);

// Listen on the /decklist url for decklist requests.
app.post('/decklist', (req, res) => {
    // Get the decklist url from the query text.
    var match = req.body.text.match(/(\d+)/);
    if (match) {
        var id = match[1];
        nrdb.getDecklist(id).then((decklist) => {
            // The decklist was found
            res.json(formatting.formatDecklist(decklist));
        }, () => {
            // The decklist wasn't found
            res.json(formatting.deckNoHitsMessage());
        });
    } else {
        // Search was invalid, display help
        if (req.body.trigger_word) {
            res.json(formatting.deckHelpMessage(req.body.trigger_word));
        } else {
            res.json(formatting.deckHelpMessage(req.body.command));
        }
    }
});

app.post('/', (req, res) => {
    var helpResponse = formatting.cardHelpMessage();
    var searches = [];
    // slash-commands have commands
    if (req.body.command) {
        searches[0] = req.body.text;
        helpResponse = formatting.cardHelpMessage(req.body.command);
    // other public commands have triggers
    } else if (req.body.trigger_word) {
        searches[0] = req.body.text.replace(new RegExp('^' + req.body.trigger_word + '\\s*', 'i'), '');
        helpResponse = formatting.cardHelpMessage(req.body.trigger_word);
    } else {
        // Otherwise look for strings enclosed in square brackets.
        searches = findSearchStrings(req.body.text);
    }
    if (searches && searches.length > 0) {
        // Respond to a call for help.
        if (searches[0].toLowerCase() === "help" && searches.length === 1) {
            return res.json(helpResponse);
        }
        // Check if the search appears to be a decklist
        var match = searches[0].match(/(?:netrunnerdb.com\/\w\w\/decklist\/)(\d+)/);
        if (match) {
            var id = match[1];
            nrdb.getDecklist(id).then((decklist) => {
                res.json(formatting.formatDecklist(decklist));<commit_msg>Undo accidental commit to webhook.js from 36faa7d<commit_after>/* webhook.js
 * Written by <NAME>.
 * An Express based app that listens for queries from a Slack channel and responds with netrunnerdb card info.
 */
'use strict';
var express = require('express');
var bodyParser = require('body-parser');

var nrdb = require('./nrdb-local');
var formatting = require('./formatting');
// A list of common card shorthands and their corresponding full names
var shorthands = require('./shorthands.json');
// Regex generated from the shorthand keys to be used in find/replace
// Only matches whole words
var shorthandRegExp = new RegExp(
    Object.keys(shorthands).reduce((pv, cv, ci, a) => {
        var o = pv;
        if (ci !== 0) {
            o += '\\b|\\b';
        }
        o += cv;
        if (ci === a.length - 1) {
            o += '\\b';
        }
        return o;
    }, '\\b')
);

var port = process.env.PORT || 3000;
var token = process.env.TOKEN || '';
var authorizedDomains = process.env.AUTHORIZED_DOMAINS || undefined;
if (authorizedDomains) {
    authorizedDomains = authorizedDomains.toLowerCase().split(',');
}

var app = express();
app.use(bodyParser.urlencoded({extended: false}));

var nrdbLoaded = false;

nrdb.init().then(() => {
    nrdbLoaded = true;
});

// Find all search strings enclosed in square brackets in the given text.
function findSearchStrings(text) {
    var cardFinder = new RegExp('.*?\\[(.*?)\\]', 'g'),
        searches = [],
        i = cardFinder.exec(text);
    while (i) {
        searches.push(i[1]);
        i = cardFinder.exec(text);
    }
    return searches;
}

// Search the db for the specified cards
function findCards(searches) {
    // Create an array of promises, 1 for each card searched.
    var promises = [];
    searches.forEach((search, i) => {
        // Clean the search and expand any shorthands.
        var cleanSearch = search.toLowerCase().replace(shorthandRegExp, (sh) => {
            return shorthands[sh];
        });
        promises[i] = nrdb.getCardByTitle(cleanSearch);
    });
    return new Promise((resolve, reject) => {
        Promise.all(promises).then((cards) => {
            var hits = [];
            var misses = [];
            // Iterate through the cards returned by the searches, appending them to the hits or misses array.
            cards.forEach((card, i) => {
                if (card) {
                    hits.push(card);
                } else {
                    misses.push(searches[i]);
                }
            });
            resolve({hits, misses});
        }, reject);
    });
}

// Intercept requests and check if DB is loaded before responding
app.use((req, res, next) => {
    if (nrdbLoaded) {
        next();
    } else {
        return res.send('');
    }
});

// Listen on the /decklist url for decklist requests.
app.post('/decklist', (req, res) => {
    if (!req.body.team_domain ||
            (authorizedDomains && authorizedDomains.indexOf(req.body.team_domain.toLowerCase()) === -1)) {
        return res.json(formatting.unauthorizedMessage());
    }
    // Get the decklist url from the query text.
    var match = req.body.text.match(/(\d+)/);
    if (match) {
        var id = match[1];
        nrdb.getDecklist(id).then((decklist) => {
            // The decklist was found
            res.json(formatting.formatDecklist(decklist));
        }, () => {
            // The decklist wasn't found
            res.json(formatting.deckNoHitsMessage());
        });
    } else {
        // Search was invalid, display help
        if (req.body.trigger_word) {
            res.json(formatting.deckHelpMessage(req.body.trigger_word));
        } else {
            res.json(formatting.deckHelpMessage(req.body.command));
        }
    }
});

app.post('/', (req, res) => {
    if (!req.body.team_domain ||
            (authorizedDomains && authorizedDomains.indexOf(req.body.team_domain.toLowerCase()) === -1)) {
        return res.json(formatting.unauthorizedMessage());
    }
    var helpResponse = formatting.cardHelpMessage();
    var searches = [];
    // Reject queries with empty bodies.
    if (!req.body || Object.keys(req.body).length === 0) {
        return res.sendStatus(400);
    }

    // Ignore automated slackbot messages.
    if (req.body.user_name === 'slackbot') {
        return res.send('');
    }

    // slash-commands have commands
    if (req.body.command) {
        searches[0] = req.body.text;
        helpResponse = formatting.cardHelpMessage(req.body.command);
    // other public commands have triggers
    } else if (req.body.trigger_word) {
        searches[0] = req.body.text.replace(new RegExp('^' + req.body.trigger_word + '\\s*', 'i'), '');
        helpResponse = formatting.cardHelpMessage(req.body.trigger_word);
    } else {
        // Otherwise look for strings enclosed in square brackets.
        searches = findSearchStrings(req.body.text);
    }
    if (searches && searches.length > 0) {
        // Respond to a call for help.
        if (searches[0].toLowerCase() === "help" && searches.length === 1) {
            return res.json(helpResponse);
        }
        // Check if the search appears to be a decklist
        var match = searches[0].match(/(?:netrunnerdb.com\/\w\w\/decklist\/)(\d+)/);
        if (match) {
            var id = match[1];
            nrdb.getDecklist(id).then((decklist) => {
                res.json(formatting.formatDecklist(decklist));
{'fraction_non_alphanumeric': 0.14772014691391203, 'fraction_numerical': 0.004120756069157037, 'mean_word_length': 2.3147268408551067, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 36, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '164273', 'n_tokens_mistral': 3383, 'n_tokens_neox': 3315, 'n_words': 853}