<commit_before>// # Update Checking Service
//
// Makes a request to Ghost.org to check if there is a new version of Ghost available.
// The service is provided in return for users opting in to anonymous usage data collection
// Blog owners can opt-out of update checks by setting 'updateCheck: false' in their config.js
//
// The data collected is as follows:
// - blog id - a hash of the blog hostname, pathname and dbHash, we do not store URL, IP or other identifiable info
// - ghost version
// - node version
// - npm version
// - env - production or development
// - database type - SQLite, MySQL, pg
// - email transport - mail.options.service, or otherwise mail.transport
// - created date - the date the database was created
// - post count - total number of posts
// - user count - total number of users
// - theme - name of the currently active theme
// - apps - names of any active plugins

var crypto   = require('crypto'),
    exec     = require('child_process').exec,
    https    = require('https'),
    moment   = require('moment'),
    semver   = require('semver'),
    when     = require('when'),
    nodefn   = require('when/node/function'),
    _        = require('underscore'),
    url      = require('url'),

    api      = require('./api'),
    config   = require('./config'),
    errors   = require('./errorHandling'),

    allowedCheckEnvironments = ['development', 'production'],
    checkEndpoint = 'updates.ghost.org',
    currentVersion;

function updateCheckError(error) {
    errors.logError(
        error,
        "Checking for updates failed, your blog will continue to function.",
        "If you get this error repeatedly, please seek help from http://ghost.org/forum."
    );
}

function updateCheckData() {
    var data = {},
        ops = [],
        mailConfig = config().mail;

    ops.push(api.settings.read('dbHash').otherwise(errors.rejectError));
    ops.push(api.settings.read('activeTheme').otherwise(errors.rejectError));
    ops.push(api.settings.read('activePlugins')
        .then(function (apps) {
            try {
                apps = JSON.parse(apps.value);
            } catch (e) {
                return errors.rejectError(e);
            }

            return _.reduce(apps, function (memo, item) { return memo === '' ? memo + item : memo + ', ' + item; }, '');
        }).otherwise(errors.rejectError));
    ops.push(api.posts.browse().otherwise(errors.rejectError));
    ops.push(api.users.browse().otherwise(errors.rejectError));
    ops.push(nodefn.call(exec, 'npm -v').otherwise(errors.rejectError));

    data.ghost_version   = currentVersion;
    data.node_version    = process.versions.node;
    data.env             = process.env.NODE_ENV;
    data.database_type   = require('./models/base').client;
    data.email_transport = mailConfig && mailConfig.options && mailConfig.options.service ? mailConfig.options.service : mailConfig.transport;

    return when.settle(ops).then(function (descriptors) {
        var hash             = descriptors[0].value,
            theme            = descriptors[1].value,
            apps             = descriptors[2].value,
            posts            = descriptors[3].value,
            users            = descriptors[4].value,
            npm              = descriptors[5].value,
            blogUrl          = url.parse(config().url),
            blogId           = blogUrl.hostname + blogUrl.pathname.replace(/\//, '') + hash.value;

        data.blog_id         = crypto.createHash('md5').update(blogId).digest('hex');
        data.theme           = theme ? theme.value : '';
        data.apps            = apps || '';
        data.post_count      = posts && posts.total ? posts.total : 0;
        data.user_count      = users && users.length ? users.length : 0;
        data.blog_created_at = users && users[0] && users[0].created_at ? moment(users[0].created_at).unix() : '';
        data.npm_version     = _.isArray(npm) && npm[0] ? npm[0].toString().replace(/\n/, '') : '';

        return data;
    }).otherwise(updateCheckError);
}

function updateCheckRequest() {
    return updateCheckData().then(function (reqData) {
        var deferred = when.defer(),
            resData = '',
            headers,
            req;

        reqData = JSON.stringify(reqData);<commit_msg>Fix TypeError due to missing mail config<commit_after>// # Update Checking Service
//
// Makes a request to Ghost.org to check if there is a new version of Ghost available.
// The service is provided in return for users opting in to anonymous usage data collection
// Blog owners can opt-out of update checks by setting 'updateCheck: false' in their config.js
//
// The data collected is as follows:
// - blog id - a hash of the blog hostname, pathname and dbHash, we do not store URL, IP or other identifiable info
// - ghost version
// - node version
// - npm version
// - env - production or development
// - database type - SQLite, MySQL, pg
// - email transport - mail.options.service, or otherwise mail.transport
// - created date - the date the database was created
// - post count - total number of posts
// - user count - total number of users
// - theme - name of the currently active theme
// - apps - names of any active plugins

var crypto   = require('crypto'),
    exec     = require('child_process').exec,
    https    = require('https'),
    moment   = require('moment'),
    semver   = require('semver'),
    when     = require('when'),
    nodefn   = require('when/node/function'),
    _        = require('underscore'),
    url      = require('url'),

    api      = require('./api'),
    config   = require('./config'),
    errors   = require('./errorHandling'),

    allowedCheckEnvironments = ['development', 'production'],
    checkEndpoint = 'updates.ghost.org',
    currentVersion;

function updateCheckError(error) {
    errors.logError(
        error,
        "Checking for updates failed, your blog will continue to function.",
        "If you get this error repeatedly, please seek help from http://ghost.org/forum."
    );
}

function updateCheckData() {
    var data = {},
        ops = [],
        mailConfig = config().mail;

    ops.push(api.settings.read('dbHash').otherwise(errors.rejectError));
    ops.push(api.settings.read('activeTheme').otherwise(errors.rejectError));
    ops.push(api.settings.read('activePlugins')
        .then(function (apps) {
            try {
                apps = JSON.parse(apps.value);
            } catch (e) {
                return errors.rejectError(e);
            }

            return _.reduce(apps, function (memo, item) { return memo === '' ? memo + item : memo + ', ' + item; }, '');
        }).otherwise(errors.rejectError));
    ops.push(api.posts.browse().otherwise(errors.rejectError));
    ops.push(api.users.browse().otherwise(errors.rejectError));
    ops.push(nodefn.call(exec, 'npm -v').otherwise(errors.rejectError));

    data.ghost_version   = currentVersion;
    data.node_version    = process.versions.node;
    data.env             = process.env.NODE_ENV;
    data.database_type   = require('./models/base').client;
    data.email_transport = mailConfig && (mailConfig.options && mailConfig.options.service ? mailConfig.options.service : mailConfig.transport);

    return when.settle(ops).then(function (descriptors) {
        var hash             = descriptors[0].value,
            theme            = descriptors[1].value,
            apps             = descriptors[2].value,
            posts            = descriptors[3].value,
            users            = descriptors[4].value,
            npm              = descriptors[5].value,
            blogUrl          = url.parse(config().url),
            blogId           = blogUrl.hostname + blogUrl.pathname.replace(/\//, '') + hash.value;

        data.blog_id         = crypto.createHash('md5').update(blogId).digest('hex');
        data.theme           = theme ? theme.value : '';
        data.apps            = apps || '';
        data.post_count      = posts && posts.total ? posts.total : 0;
        data.user_count      = users && users.length ? users.length : 0;
        data.blog_created_at = users && users[0] && users[0].created_at ? moment(users[0].created_at).unix() : '';
        data.npm_version     = _.isArray(npm) && npm[0] ? npm[0].toString().replace(/\n/, '') : '';

        return data;
    }).otherwise(updateCheckError);
}

function updateCheckRequest() {
    return updateCheckData().then(function (reqData) {
        var deferred = when.defer(),
            resData = '',
            headers,
            req;

        reqData = JSON.stringify(reqData);
{'fraction_non_alphanumeric': 0.13571511425588678, 'fraction_numerical': 0.0032478830762092564, 'mean_word_length': 2.325106054762823, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '895189', 'n_tokens_mistral': 2403, 'n_tokens_neox': 2324, 'n_words': 603}