<commit_before>/**
 * Shopify OAuth2 node.js API
 *
 *
 *
 */

function ShopifyAPI(config) {

    if (typeof config === "undefined") {
        var msg = "ShopifyAPI module expects a config object\nPlease see documentation at: https://github.com/sinechris/shopify-node-api\n";
        throw new Error(msg);
    }

    var $this = this;

    $this.config = config;

    if ($this.config.verbose !== false) {
        $this.config.verbose = true;
    }

    function conditional_console_log(msg) {
        if ($this.config.verbose) {
            console.log( msg );
        }
    }

    $this.buildAuthURL = function() {
        var auth_url = 'https://' + $this.config.shop.split(".")[0];
        auth_url += ".myshopify.com/admin/oauth/authorize?";
        auth_url += "client_id=" + $this.config.shopify_api_key;
        auth_url += "&scope=" + $this.config.shopify_scope;
        auth_url += "&redirect_uri=" + $this.config.redirect_uri;
        return auth_url;
    };

    function is_valid_signature(params) {
        var md5 = require('MD5'),
            signature = params['signature'],
            calculated_signature = [];

        delete params['signature']; // Not needed to build hash

        for (var key in params){
            calculated_signature.push(key + '=' + params[key]);
        }

        var hash = md5($this.config.shopify_shared_secret + calculated_signature.sort().join(""));

        return (hash === signature) ? true : false;

    }

    $this.set_access_token = function(token) {
        $this.config.access_token = token;
    };

    $this.exchange_temporary_token = function(query_params, callback) {
        var data = {
            client_id: $this.config.shopify_api_key,
            client_secret: $this.config.shopify_shared_secret,
            code: query_params['code']
        };
        $this.makeRequest('/admin/oauth/access_token', 'POST', data, function(err, body){

            if (err) { callback(new Error(err)); }

            if (is_valid_signature(query_params)) {
                $this.set_access_token(body['access_token']);
                callback(null, body);
            } else {
                callback(new Error("Signature is not authentic!"));
            }

        });
    };

    $this.makeRequest = function(endpoint, method, data, callback) {

        var https = require('https'),
            dataString = JSON.stringify(data);

        var options = {
            hostname: $this.config.shop.split(".")[0] + '.myshopify.com',
            path: endpoint,
            method: method.toLowerCase() || 'get',
            port: 443,
            headers: {
                'Content-Type': 'application/json',
                'X-Shopify-Access-Token': $this.config.access_token
            }
        };

        if (options.method === 'post' || options.method === 'put' || options.method === 'delete') {
            options.headers['Content-Length'] = dataString.length;
        }

        var request = https.request(options, function(response){
            conditional_console_log( 'STATUS: ' + response.statusCode );
            conditional_console_log( 'HEADERS: ' + JSON.stringify(response.headers) );

            if (response.headers.hasOwnProperty('http_x_shopify_shop_api_call_limit')) {
                console.log( response.headers['http_x_shopify_shop_api_call_limit'] );
            }

            response.setEncoding('utf8');

            var body = '';

            response.on('data', function(chunk){
                conditional_console_log( 'BODY: ' + chunk );
                body += chunk;
            });

            response.on('end', function(){
                try {
                    var json = JSON.parse(body);
                    callback(null, json, response.headers);
                } catch(e) {
                    callback(e);
                }
            });

        });

        request.on('error', function(e){
            callback(e);
        });

        if (options.method === 'post' || options.method === 'put' || options.method === 'delete') {
            request.write(JSON.stringify(data));
        }

        request.end();

    };

    $this.get = function(endpoint, data, callback) {
        if (typeof data === 'function' && arguments.length < 3) {
            callback = data;
            data = null;
        }
        $this.makeRequest(endpoint,'GET', data, callback);
    };

    $this.post = function(endpoint, data, callback) {
        $this.makeRequest(endpoint,'POST', data, callback);
    };

    $this.put = function(endpoint, data, callback) {
        $this.makeRequest(endpoint, 'PUT', data, callback);
    };

    $this.delete = function(endpoint, data, callback) {
        if (typeof data === 'function' && arguments.length < 3) {
            callback = data;
            data = null;
        }
        $this.makeRequest(endpoint, 'DELETE', data, callback);
    };

    return $this;

}

module.exports = ShopifyAPI;<commit_msg>Refactored module for readability, extensibility and efficiency<commit_after>/**
 * Shopify OAuth2 node.js API
 *
 *
 *
 */
    
var md5 = require('MD5');

function ShopifyAPI(config) {
    
    if (!(this instanceof ShopifyAPI)) return new ShopifyAPI(config);

    if (config == null) { // == checks for null and undefined
        var msg = "ShopifyAPI module expects a config object\nPlease see documentation at: https://github.com/sinechris/shopify-node-api\n";
        throw new Error(msg);
    }

    this.config = config;

    if (this.config.verbose !== false){
        this.config.verbose = true;
    }

}

ShopifyAPI.prototype.buildAuthURL = function(){
    var auth_url = 'https://' + this.config.shop.split(".")[0];
    auth_url += ".myshopify.com/admin/oauth/authorize?";
    auth_url += "client_id=" + this.config.shopify_api_key;
    auth_url += "&scope=" + this.config.shopify_scope;
    auth_url += "&redirect_uri=" + this.config.redirect_uri;
    return auth_url;
};

ShopifyAPI.prototype.set_access_token = function(token) {
    this.config.access_token = token;
};

ShopifyAPI.prototype.conditional_console_log = function(msg) {
    if (this.config.verbose) {
        console.log( msg );
    }
};

ShopifyAPI.prototype.is_valid_signature = function(params) {
    var signature = params['signature'],
        calculated_signature = [];

    delete params['signature']; // Not needed to build hash

    for (var key in params){
        calculated_signature.push(key + '=' + params[key]);
    }

    var hash = md5(this.config.shopify_shared_secret + calculated_signature.sort().join(""));

    return (hash === signature) ? true : false;
};

ShopifyAPI.prototype.exchange_temporary_token = function(query_params, callback) {
    var data = {
            client_id: this.config.shopify_api_key,
            client_secret: this.config.shopify_shared_secret,
            code: query_params['code']
        },
        self = this;

    this.makeRequest('/admin/oauth/access_token', 'POST', data, function(err, body){

        if (err) { callback(new Error(err)); }

        if (self.is_valid_signature(query_params)) {
            self.set_access_token(body['access_token']);
            callback(null, body);
        } else {
            callback(new Error("Signature is not authentic!"));
        }

    });
};

ShopifyAPI.prototype.makeRequest = function(endpoint, method, data, callback) {

    var https = require('https'),
        dataString = JSON.stringify(data),
        options = {
            hostname: this.config.shop.split(".")[0] + '.myshopify.com',
            path: endpoint,
            method: method.toLowerCase() || 'get',
            port: 443,
            headers: {
                'Content-Type': 'application/json',
                'X-Shopify-Access-Token': this.config.access_token
            }
        },
        self = this;

    if (options.method === 'post' || options.method === 'put' || options.method === 'delete') {
        options.headers['Content-Length'] = dataString.length;
    }

    var request = https.request(options, function(response){
        self.conditional_console_log( 'STATUS: ' + response.statusCode );
        self.conditional_console_log( 'HEADERS: ' + JSON.stringify(response.headers) );

        if (response.headers.hasOwnProperty('http_x_shopify_shop_api_call_limit')) {
            console.log( response.headers['http_x_shopify_shop_api_call_limit'] );
        }

        response.setEncoding('utf8');

        var body = '';

        response.on('data', function(chunk){
            self.conditional_console_log( 'BODY: ' + chunk );
            body += chunk;
        });

        response.on('end', function(){
            try {
                var json = JSON.parse(body);
                callback(null, json, response.headers);
            } catch(e) {
                callback(e);
            }
        });

    });

    request.on('error', function(e){
        callback(e);
    });

    if (options.method === 'post' || options.method === 'put' || options.method === 'delete') {
        request.write(JSON.stringify(data));
    }

    request.end();

};

ShopifyAPI.prototype.get = function(endpoint, data, callback) {
    if (typeof data === 'function' && arguments.length < 3) {
        callback = data;
        data = null;
    }
    this.makeRequest(endpoint,'GET', data, callback);
};

ShopifyAPI.prototype.post = function(endpoint, data, callback) {
    this.makeRequest(endpoint,'POST', data, callback);
};

ShopifyAPI.prototype.put = function(endpoint, data, callback) {
    this.makeRequest(endpoint, 'PUT', data, callback);
};

ShopifyAPI.prototype.delete = function(endpoint, data, callback) {
    if (typeof data === 'function' && arguments.length < 3) {
        callback = data;
        data = null;
    }
    this.makeRequest(endpoint, 'DELETE', data, callback);
};

module.exports = ShopifyAPI;
{'fraction_non_alphanumeric': 0.1441194393662401, 'fraction_numerical': 0.002437538086532602, 'mean_word_length': 2.279054279054279, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 4, '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': '3547145', 'n_tokens_mistral': 2895, 'n_tokens_neox': 2803, 'n_words': 543}