<commit_before>"use strict";

var chalk, crypto, querystring;

// Required for the class
chalk = require("chalk");
crypto = require("crypto");
querystring = require("querystring");

/**
 * @typedef {Object} opentoken~functionalTestResponse
 * @property {*} body Can be anything, including objects.
 * @property {Object} headers
 * @property {Object} links The Link header reformatted for ease of use
 * @property {number} statusCode
 * @property {string} uri
 */

/**
 * Functional Test
 *
 * This object tracks important bits of information and allows tests to
 * perform actions that are required to functionally test the API.
 */
class FunctionalTest {
    /**
     * Initialization.
     *
     * @param {functionalRouteTester~functionalTest} test
     */
    constructor(test) {
        this.test = test;
        this.nodeMocksHttp = null;
        this.state = {};

        // The request handler needs to be assigned or nothing works.
        // It's the routing middleware function.
        this.requestHandler = null;

        // This is how the test sends email.  Make sure to set this
        // after the object is created.
        this.sendEmailSpy = null;
    }

    /**
     * Create access codes
     *
     * @return {Promise.<functionalTestResponse>}
     */
    createAccessCodesAsync() {
        return this.loginAsync().then((response) => {
            if (response.statusCode !== 200) {
                throw new Error(`Invalid status code from login. Status code ${response.statusCode}`);
            }

            return this.followAsync(response, "up", "account", {
                headers: {
                    Cookie: `login=${this.state.sessionId}`
                }
            });
        }).then((response) => {
            if (response.statusCode !== 200) {
                throw new Error(`Invalid status code from following 'up' link. Status code: ${response.statusCode}`);
            }

            return this.followAsync(response, "service", "account-accessCode", {
                body: {
                    description: "Test Codes"
                },
                headers: {
                    Cookie: `login=${this.state.sessionId}`
                }
            });
        }).then((response) => {
            var body;

            if (response.statusCode !== 201) {
                throw new Error("Error requesting access codes");
            }

            body = JSON.parse(response.body);
            this.state.accessCode = body.code;
            this.state.accessSecret = body.secret;

            return response;
        });
    }

    /**
     * Creates an account.  Returns a Promise that will be rejected with
     * an error or resolved with the response from creating the account.
     *
     * Usage:
     *
     *   return functionalTest.createAccountAsync().then((response) => { ... });
     *
     * @return {Promise.<functionalTestResponse>}
     */
    createAccountAsync() {
        return this.startAsync("service", "registration-register", {
            body: {
                email: "test@example.com"
            }
        }).then((response) => {
            if (response.statusCode !== 200) {
                throw new Error(`Initial POST was not successful. Status code ${response.statusCode}`);
            }

            this.state.registrationId = response.getHeader("Location").split("/")[2];

            // MFA validation is mocked to always succeed.
            return this.followAsync(response, "edit", "registration-secure", {
                body: {
                    mfa: {
                        totp: {
                            current: "000000",
                            previous: "111111"
                        }
                    },
                    passwordHash: "123456789012345678901234567890"
                },
                headers: {
                    "Content-Type": "application/json"
                }
            });
        }).then((response) => {
            var email, match, uri;

            if (response.statusCode !== 204) {
                throw new Error("Securing the registration failed");
            }

            if (!this.sendEmailSpy.calls.mostRecent()) {
                throw new Error("No email was sent");
            }

            email = this.sendEmailSpy.calls.mostRecent().args[2];
            match = email.match(/\/registration\/[a-zA-Z0-9_-]+\/confirm\/([a-zA-Z0-9-_]+)/);

            if (!match) {
                throw new Error("Unable to find confirmation link");
            }

            this.state.confirmationId = match[1];
            uri = match[0];

            return this.requestAsync({
                url: uri
            });
        }).then((response) => {
            var body;

            if (response.statusCode !== 201) {
                throw new Error(`Invalid status code from registration confirmation. Status code ${response.statusCode}`);
            }

            body = JSON.parse(response.body);
            this.state.accountId = body.accountId;

            return response;
        });
    }

    /**
     * Helper method to diagnose what's going wrong.
     *
     * Use this in your promise chain.
     *
     *   .then((response) => {
     *       test.debug(response);
     *   });
     *
     * @param {Promise.<opentoken~functionalTestAsyncResponse>} response
     */
    debug(response) {
        var links, logger;

        /**
         * Shows a heading.
         *
         * @param {string} text
         */
        function heading(text) {
            console.log(chalk.blue.bold(`----- ${text} -----`));
        }

        /**
         * Helper to list calls to logger.xxxxx methods, which are spies.
         *
         * @param {Object} call Items in Jasmine's spy.calls array.
         */
        function dumpCall(call) {
            console.log(call.args);
        }

        logger = this.container.resolve("logger");
        heading("LOGGER.INFO CALLS");
        logger.info.calls.forEach(dumpCall);
        heading("LOGGER.CONSOLE CALLS");
        logger.console.calls.forEach(dumpCall);
        heading("RESPONSE");
        links = response.links;
        response.links = "(Object dumped separately)";
        console.log(response);
        response.links = links;
        heading("RESPONSE.LINKS");
        console.log(links);
        heading("DEBUG COMPLETE");
    }

    /**
     * Finds the link definition object in a list of formatted links.
     *
     * @param {Object} links From HttpLinkHeader
     * @param {string} rel
     * @param {string} [title]
     * @return {(Object|Error)} Link definition or error message
     */
    findLink(links, rel, title) {
        var linkArray, suffix;

        linkArray = links.rel(rel);

        if (!linkArray) {
            return new Error(`No links found for relation ${rel}`);
        }

        suffix = "";

        if (title) {
            linkArray = linkArray.filter((item) => {
                return item.title === title;
            });
            suffix = `, title "${title}"`;
        }

        if (linkArray.length > 1) {
            return new Error(`Multiple links found for relation "${rel}"${suffix}`);
        }

        if (linkArray.length < 1) {
            return new Error(`No links exist for relation "${rel}"${suffix}`);
        }

        return linkArray[0];
    }

    /**
     * Searches for a given link.  If found, this follows the link and
     * the promise will be resolved with the response.
     *
     * @param {Function} response
     * @param {string} rel
     * @param {string} [title]
     * @param {nodeMocksHttp~mockRequestOptions} [options]
     * @return {Promise.<opentoken~functionalTestResponse>}
     */
    followAsync(response, rel, title, options) {
        var linkDefinition;

        if (typeof title === "object") {
            options = title;
            title = null;
        }

        if (!options) {
            options = {};
        }

        linkDefinition = this.findLink(response.links, rel, title);

        if (linkDefinition instanceof Error) {
            return Promise.reject(linkDefinition);
        }

        options.url = linkDefinition.uri;

        return this.requestAsync(options);
    }

    /**
     * Shortcut to login after an account is created.
     *
     * @return {Promise.<opentoken~functionalTestResponse>}
     */
    loginAsync() {
        var promise;

        if (this.state.accountId) {
            promise = Promise.resolve();
        } else {
            promise = this.createAccountAsync();
        }

        return promise.then(() => {
            return this.startAsync("service", "account-login", {
                body: {
                    challengeHash: "123456789012345678901234567890",
                    mfa: {
                        totp: "222222"
                    }
                },
                parameters: {
                    accountId: this.state.accountId
                }
            });
        }).then((response) => {
            var body;

            body = JSON.parse(response.body);
            this.state.sessionId = body.sessionId;

            return response;
        });
    }

    /**
     * This function formats the request options and makes requests.
     *
     * @param {nodeMocksHttp~mockRequestOptions} options
     * @return {Promise.<functionalRouteTester~response>}
     */
    requestAsync(options) {
        this.reformatRequestOptions(options);

        return this.test.requestAsync(options.method, options.url, options);
    }

    /**
     * Set up reasonable defaults and convert incoming data into what is
     * expected by the middleware.
     *
     * Modifies the object directly.
     *
     * @param {nodeMocksHttp~mockRequestOptions} options
     */
    reformatRequestOptions(options) {
        if (!options.headers) {
            options.headers = {};
        }

        if (!this.test.getHeader(options.headers, "Host")) {
            options.headers.Host = "localhost";
        }

        // Set some default properties for posting data
        if (options.body) {
            if (!options.method) {
                options.method = "POST";
            }

            if (!this.test.getHeader(options.headers, "Content-Type")) {
                options.headers["Content-Type"] = "application/json";
            }
        }

        if (!options.method) {
            options.method = "GET";
        }

        if (options.signed) {
            this.signRequest(options);
        }
    }

    /**
     * Signs a request and adds the necessary headers to the options
     * being passed to the mock HTTP request.
     *
     * Modifies the object directly
     *
     * @param {nodeMocksHttp~mockRequestOptions} options
     */
    signRequest(options) {
        var dateString, hmac, path, queryString, signature, signingContent;

        if (!options.headers) {
            options.headers = {};
        }

        if (!this.test.getHeader(options.headers, "Content-Type")) {
            options.headers["Content-Type"] = "application/octet-stream";
        }

        dateString = new Date().toISOString();
        options.headers["X-OpenToken-Date"] = dateString;

        if (options.body) {
            options.body = this.test.coerseToBuffer(options.body);
        } else if (Buffer.alloc) {
            // node.js v5.10.0 and newer
            options.body = Buffer.alloc(0, 0, "binary");
        } else {
            // Deprecated as of node.js 6.0.0
            options.body = new Buffer(0);
        }

        path = options.url;
        queryString = querystring.stringify(options.query);

        if (options.parameters) {
            Object.keys(options.parameters).forEach((key) => {
                path = path.replace(`{${key}}`, options.parameters[key]);
            });
        }

        if (!this.test.getHeader(options.headers, "Host")) {
            options.headers.Host = "localhost";
        }

        // Build the signing content as a big buffer
        signingContent = [
            options.method.toUpperCase(),
            path,
            queryString,
            `host:${this.test.getHeader(options.headers, "Host").toLowerCase()}`,
            `content-type:${this.test.getHeader(options.headers, "Content-Type")}`,
            `x-opentoken-date:${dateString}`,
            "",
            options.body.toString("binary")
        ];
        signingContent = signingContent.join("\n");
        signingContent = new Buffer(signingContent, "binary");

        // Calculate the HMAC
        hmac = crypto.createHmac("sha256", this.state.accessSecret);
        hmac.update(signingContent);
        signature = hmac.digest("hex").toLowerCase();

        // Add the header to the request
        options.headers.Authorization = `OT1-HMAC-SHA256-HEX; access-code=${this.state.accessCode}; signed-headers=host content-type x-opentoken-date; signature=${signature}`;
    }

    /**
     * Initiates a request chain.  It will start with the self discovery
     * endpoint.  If given additional arguments, a link will be followed
     * off of the self discovery endpoint.
     *
     * @param {string} [rel]
     * @param {string} [title]
     * @param {nodeMocksHttp~mockRequestOptions} options
     * @return {Promise.<opentoken~functionalTestResponse>}
     */
    startAsync(rel, title, options) {
        var promise;

        promise = this.requestAsync({
            url: "/"
        });

        if (rel && title) {
            promise = promise.then((response) => {
                return this.followAsync(response, rel, title, options);
            });
        }

        return promise;
    }
}

jasmine.FunctionalTest = FunctionalTest;
<commit_msg>Added error checking for functional login.<commit_after>"use strict";

var chalk, crypto, querystring;

// Required for the class
chalk = require("chalk");
crypto = require("crypto");
querystring = require("querystring");

/**
 * @typedef {Object} opentoken~functionalTestResponse
 * @property {*} body Can be anything, including objects.
 * @property {Object} headers
 * @property {Object} links The Link header reformatted for ease of use
 * @property {number} statusCode
 * @property {string} uri
 */

/**
 * Functional Test
 *
 * This object tracks important bits of information and allows tests to
 * perform actions that are required to functionally test the API.
 */
class FunctionalTest {
    /**
     * Initialization.
     *
     * @param {functionalRouteTester~functionalTest} test
     */
    constructor(test) {
        this.test = test;
        this.nodeMocksHttp = null;
        this.state = {};

        // The request handler needs to be assigned or nothing works.
        // It's the routing middleware function.
        this.requestHandler = null;

        // This is how the test sends email.  Make sure to set this
        // after the object is created.
        this.sendEmailSpy = null;
    }

    /**
     * Create access codes
     *
     * @return {Promise.<functionalTestResponse>}
     */
    createAccessCodesAsync() {
        return this.loginAsync().then((response) => {
            if (response.statusCode !== 200) {
                throw new Error(`Invalid status code from login. Status code ${response.statusCode}`);
            }

            return this.followAsync(response, "up", "account", {
                headers: {
                    Cookie: `login=${this.state.sessionId}`
                }
            });
        }).then((response) => {
            if (response.statusCode !== 200) {
                throw new Error(`Invalid status code from following 'up' link. Status code: ${response.statusCode}`);
            }

            return this.followAsync(response, "service", "account-accessCode", {
                body: {
                    description: "Test Codes"
                },
                headers: {
                    Cookie: `login=${this.state.sessionId}`
                }
            });
        }).then((response) => {
            var body;

            if (response.statusCode !== 201) {
                throw new Error("Error requesting access codes");
            }

            body = JSON.parse(response.body);
            this.state.accessCode = body.code;
            this.state.accessSecret = body.secret;

            return response;
        });
    }

    /**
     * Creates an account.  Returns a Promise that will be rejected with
     * an error or resolved with the response from creating the account.
     *
     * Usage:
     *
     *   return functionalTest.createAccountAsync().then((response) => { ... });
     *
     * @return {Promise.<functionalTestResponse>}
     */
    createAccountAsync() {
        return this.startAsync("service", "registration-register", {
            body: {
                email: "test@example.com"
            }
        }).then((response) => {
            if (response.statusCode !== 200) {
                throw new Error(`Initial POST was not successful. Status code ${response.statusCode}`);
            }

            this.state.registrationId = response.getHeader("Location").split("/")[2];

            // MFA validation is mocked to always succeed.
            return this.followAsync(response, "edit", "registration-secure", {
                body: {
                    mfa: {
                        totp: {
                            current: "000000",
                            previous: "111111"
                        }
                    },
                    passwordHash: "123456789012345678901234567890"
                },
                headers: {
                    "Content-Type": "application/json"
                }
            });
        }).then((response) => {
            var email, match, uri;

            if (response.statusCode !== 204) {
                throw new Error("Securing the registration failed");
            }

            if (!this.sendEmailSpy.calls.mostRecent()) {
                throw new Error("No email was sent");
            }

            email = this.sendEmailSpy.calls.mostRecent().args[2];
            match = email.match(/\/registration\/[a-zA-Z0-9_-]+\/confirm\/([a-zA-Z0-9-_]+)/);

            if (!match) {
                throw new Error("Unable to find confirmation link");
            }

            this.state.confirmationId = match[1];
            uri = match[0];

            return this.requestAsync({
                url: uri
            });
        }).then((response) => {
            var body;

            if (response.statusCode !== 201) {
                throw new Error(`Invalid status code from registration confirmation. Status code ${response.statusCode}`);
            }

            body = JSON.parse(response.body);
            this.state.accountId = body.accountId;

            return response;
        });
    }

    /**
     * Helper method to diagnose what's going wrong.
     *
     * Use this in your promise chain.
     *
     *   .then((response) => {
     *       test.debug(response);
     *   });
     *
     * @param {Promise.<opentoken~functionalTestAsyncResponse>} response
     */
    debug(response) {
        var links, logger;

        /**
         * Shows a heading.
         *
         * @param {string} text
         */
        function heading(text) {
            console.log(chalk.blue.bold(`----- ${text} -----`));
        }

        /**
         * Helper to list calls to logger.xxxxx methods, which are spies.
         *
         * @param {Object} call Items in Jasmine's spy.calls array.
         */
        function dumpCall(call) {
            console.log(call.args);
        }

        logger = this.container.resolve("logger");
        heading("LOGGER.INFO CALLS");
        logger.info.calls.forEach(dumpCall);
        heading("LOGGER.CONSOLE CALLS");
        logger.console.calls.forEach(dumpCall);
        heading("RESPONSE");
        links = response.links;
        response.links = "(Object dumped separately)";
        console.log(response);
        response.links = links;
        heading("RESPONSE.LINKS");
        console.log(links);
        heading("DEBUG COMPLETE");
    }

    /**
     * Finds the link definition object in a list of formatted links.
     *
     * @param {Object} links From HttpLinkHeader
     * @param {string} rel
     * @param {string} [title]
     * @return {(Object|Error)} Link definition or error message
     */
    findLink(links, rel, title) {
        var linkArray, suffix;

        linkArray = links.rel(rel);

        if (!linkArray) {
            return new Error(`No links found for relation ${rel}`);
        }

        suffix = "";

        if (title) {
            linkArray = linkArray.filter((item) => {
                return item.title === title;
            });
            suffix = `, title "${title}"`;
        }

        if (linkArray.length > 1) {
            return new Error(`Multiple links found for relation "${rel}"${suffix}`);
        }

        if (linkArray.length < 1) {
            return new Error(`No links exist for relation "${rel}"${suffix}`);
        }

        return linkArray[0];
    }

    /**
     * Searches for a given link.  If found, this follows the link and
     * the promise will be resolved with the response.
     *
     * @param {Function} response
     * @param {string} rel
     * @param {string} [title]
     * @param {nodeMocksHttp~mockRequestOptions} [options]
     * @return {Promise.<opentoken~functionalTestResponse>}
     */
    followAsync(response, rel, title, options) {
        var linkDefinition;

        if (typeof title === "object") {
            options = title;
            title = null;
        }

        if (!options) {
            options = {};
        }

        linkDefinition = this.findLink(response.links, rel, title);

        if (linkDefinition instanceof Error) {
            return Promise.reject(linkDefinition);
        }

        options.url = linkDefinition.uri;

        return this.requestAsync(options);
    }

    /**
     * Shortcut to login after an account is created.
     *
     * @return {Promise.<opentoken~functionalTestResponse>}
     */
    loginAsync() {
        var promise;

        if (this.state.accountId) {
            promise = Promise.resolve();
        } else {
            promise = this.createAccountAsync();
        }

        return promise.then(() => {
            return this.startAsync("service", "account-login", {
                body: {
                    challengeHash: "123456789012345678901234567890",
                    mfa: {
                        totp: "222222"
                    }
                },
                parameters: {
                    accountId: this.state.accountId
                }
            });
        }).then((response) => {
            var body;

            if (response.statusCode !== 200) {
                throw new Error(`Invalid status code from login. Status code: ${response.statusCode}`);
            }

            body = JSON.parse(response.body);
            this.state.sessionId = body.sessionId;

            return response;
        });
    }

    /**
     * This function formats the request options and makes requests.
     *
     * @param {nodeMocksHttp~mockRequestOptions} options
     * @return {Promise.<functionalRouteTester~response>}
     */
    requestAsync(options) {
        this.reformatRequestOptions(options);

        return this.test.requestAsync(options.method, options.url, options);
    }

    /**
     * Set up reasonable defaults and convert incoming data into what is
     * expected by the middleware.
     *
     * Modifies the object directly.
     *
     * @param {nodeMocksHttp~mockRequestOptions} options
     */
    reformatRequestOptions(options) {
        if (!options.headers) {
            options.headers = {};
        }

        if (!this.test.getHeader(options.headers, "Host")) {
            options.headers.Host = "localhost";
        }

        // Set some default properties for posting data
        if (options.body) {
            if (!options.method) {
                options.method = "POST";
            }

            if (!this.test.getHeader(options.headers, "Content-Type")) {
                options.headers["Content-Type"] = "application/json";
            }
        }

        if (!options.method) {
            options.method = "GET";
        }

        if (options.signed) {
            this.signRequest(options);
        }
    }

    /**
     * Signs a request and adds the necessary headers to the options
     * being passed to the mock HTTP request.
     *
     * Modifies the object directly
     *
     * @param {nodeMocksHttp~mockRequestOptions} options
     */
    signRequest(options) {
        var dateString, hmac, path, queryString, signature, signingContent;

        if (!options.headers) {
            options.headers = {};
        }

        if (!this.test.getHeader(options.headers, "Content-Type")) {
            options.headers["Content-Type"] = "application/octet-stream";
        }

        dateString = new Date().toISOString();
        options.headers["X-OpenToken-Date"] = dateString;

        if (options.body) {
            options.body = this.test.coerseToBuffer(options.body);
        } else if (Buffer.alloc) {
            // node.js v5.10.0 and newer
            options.body = Buffer.alloc(0, 0, "binary");
        } else {
            // Deprecated as of node.js 6.0.0
            options.body = new Buffer(0);
        }

        path = options.url;
        queryString = querystring.stringify(options.query);

        if (options.parameters) {
            Object.keys(options.parameters).forEach((key) => {
                path = path.replace(`{${key}}`, options.parameters[key]);
            });
        }

        if (!this.test.getHeader(options.headers, "Host")) {
            options.headers.Host = "localhost";
        }

        // Build the signing content as a big buffer
        signingContent = [
            options.method.toUpperCase(),
            path,
            queryString,
            `host:${this.test.getHeader(options.headers, "Host").toLowerCase()}`,
            `content-type:${this.test.getHeader(options.headers, "Content-Type")}`,
            `x-opentoken-date:${dateString}`,
            "",
            options.body.toString("binary")
        ];
        signingContent = signingContent.join("\n");
        signingContent = new Buffer(signingContent, "binary");

        // Calculate the HMAC
        hmac = crypto.createHmac("sha256", this.state.accessSecret);
        hmac.update(signingContent);
        signature = hmac.digest("hex").toLowerCase();

        // Add the header to the request
        options.headers.Authorization = `OT1-HMAC-SHA256-HEX; access-code=${this.state.accessCode}; signed-headers=host content-type x-opentoken-date; signature=${signature}`;
    }

    /**
     * Initiates a request chain.  It will start with the self discovery
     * endpoint.  If given additional arguments, a link will be followed
     * off of the self discovery endpoint.
     *
     * @param {string} [rel]
     * @param {string} [title]
     * @param {nodeMocksHttp~mockRequestOptions} options
     * @return {Promise.<opentoken~functionalTestResponse>}
     */
    startAsync(rel, title, options) {
        var promise;

        promise = this.requestAsync({
            url: "/"
        });

        if (rel && title) {
            promise = promise.then((response) => {
                return this.followAsync(response, rel, title, options);
            });
        }

        return promise;
    }
}

jasmine.FunctionalTest = FunctionalTest;
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var mongo = require('../modules/database');
var email = require('../modules/email');
var db_collection = 'hawk_websites';

/* Show page for new app registration */
router.get('/create', function(req, res, next) {
  res.render('yard/websites/create', { title: 'Register new website' });
});

/* App registration callback */
router.post('/create', function(req, res, next) {

    'use strict';

    /**
     * Register site template
     * @type {String}
     */
    let resultTemplate = 'yard/websites/result';

    var name = req.body.app_name;

    if (!name) {
        res.render(resultTemplate, {title: 'Error', error: "Website domain is empty"});
        return;
    }

    /* Check if application is already exists */
    checkApplicationName(name).then(function(result) {

        /* if not exists -> generate token and add to DB*/
        if (result) {
            var uuid = require('uuid');
            var client_token = uuid.v4();
            var server_token = uuid.v4();

            addNewApplication(name, client_token, server_token);
            res.render(resultTemplate, {
                title: 'Get your token',
                client_token: client_token,
                server_token: server_token
            });
        }
        else {
            res.render(resultTemplate, {title: 'Error', error: "Website already connected"});
        }
    });

});

/* Return if application with name specified is not exists */
function checkApplicationName(name) {
    return mongo.findOne(db_collection, {'name': name})
        .then(function (result) {
            if (result) {
                return false;
            }
            else {
                return true;
            }
        });
}

/* Add new application and token to DB */
function addNewApplication(app_name, client_token, server_token) {
    return mongo.insertOne(db_collection, {'name': app_name, 'client_token': client_token, 'server_token': server_token})
        .then(function (result) {
            if (result) {
                email.init();
                email.send(
                    {name:'CodeX Hawk', email:'codex.ifmo@yandex.ru'},
                    'ntpcp@yandex.ru',
                    'Your token',
                    'Your client access token: ' + client_token + '\n' + 'Your server access token: ' + server_token,
                    '');
                return true;
            }
            else {
                return false;
            }
        });
}

module.exports = router;
<commit_msg>Add connection between tokens and auth<commit_after>var express = require('express');
var router = express.Router();
var mongo = require('../modules/database');
var email = require('../modules/email');
var db_collection = 'hawk_websites';

/* Show page for new app registration */
router.get('/create', function(req, res, next) {
  res.render('yard/websites/create', { title: 'Register new website' });
});

/* App registration callback */
router.post('/create', function(req, res, next) {

    'use strict';

    /**
     * Register site template
     * @type {String}
     */
    let resultTemplate = 'yard/websites/result';

    if (!userId) {
        res.redirect("/login");
        return;
    }

    var name = req.body.app_name;

    if (!name) {
        res.render(resultTemplate, {title: 'Error', error: "Website domain is empty"});
        return;
    }

    /* Check if application is already exists */
    checkApplicationName(name).then(function(result) {

        /* if not exists -> generate token and add to DB*/
        if (result) {
            var uuid = require('uuid');
            var client_token = uuid.v4();
            var server_token = uuid.v4();

            addNewApplication(name, client_token, server_token);
            res.render(resultTemplate, {
                title: 'Get your token',
                client_token: client_token,
                server_token: server_token
            });
        }
        else {
            res.render(resultTemplate, {title: 'Error', error: "Website already connected"});
        }
    });

});

/* Return if application with name specified is not exists */
function checkApplicationName(name) {
    return mongo.findOne(db_collection, {'name': name, 'user': userId})
        .then(function (result) {
            if (result) {
                return false;
            }
            else {
                return true;
            }
        });
}

/* Add new application and token to DB */
function addNewApplication(app_name, client_token, server_token) {
    return mongo.insertOne(db_collection, {
            'name': app_name,
            'client_token': client_token,
            'server_token': server_token,
            'user': userId
        }
    )
    .then(function (result) {
        if (result) {
            email.init();
            email.send(
                {name:'CodeX Hawk', email:'codex.ifmo@yandex.ru'},
                'ntpcp@yandex.ru',
                'Your token',
                'Your client access token: ' + client_token + '\n' + 'Your server access token: ' + server_token,
                '');
            return true;
        }
        else {
            return false;
        }
    });
}

module.exports = router;
<|endoftext|>


<commit_before>module.exports = function (grunt) {

  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-nodeunit');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-type');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-reload');

  /*
   grunt.loadNpmTasks('grunt-typescript');
   */

  // Project configuration.
  var port = grunt.option('webapp_port');
  if (!port) {
    port = 8181;
  }

  var appFiles = ['src/main/d.ts/**/*.ts', 'src/main/webapp/app/**/*.ts'];

  grunt.initConfig({
    test:{
      files:['src/test/js/**/*.js']
    },
    type:{
      compile:{
        files: [
          {
            src: appFiles,
            dest: "<%= grunt.option('webapp_outdir') %>/app/app.js"
          }
        ],
        options:{
          sourcemap: true,
          target: 'es5',
          //module:'amd',
          style:'eqeqeq;bitwise'
        }
      }
    },
    copy:{
      dist: {
        files: [
          {
            expand: true,
            cwd: "src/main/webapp/",
            src: ["./**"],
            dest: "<%= grunt.option('webapp_outdir') %>/"
          }
        ]
      },
      test: {
        files: [
          {
            expand: true,
            cwd: "<%= grunt.option('webapp_outdir') %>/",
            src: ["./**"],
            dest: "src/test/unit/"
          }]
      }
    },
    concat: {
      main: {
        src: ["target/schema/js/*.js", "src/main/webapp/app/**/*.js", "<%= grunt.option('webapp_outdir') %>/app/app.js"],
        dest: "<%= grunt.option('webapp_outdir') %>/app/app.js"
      }
    },
    reload: {
      port: 35729,
      liveReload: {},
      proxy: {
        host: 'localhost',
        port: port
      }
    },
    watch: {
      app: {
        files: ["src/main/webapp/**", "target/schema/js/*.js"],
        tasks: ['type', 'concat', 'copy', 'reload']
      }
    }
  });

  // Default task.
  grunt.registerTask('default', ['type', 'concat', 'copy']);

  // watch source for changes
  grunt.registerTask('watchSrc', ['type', 'concat', 'copy', 'reload', 'watch']);

};
<commit_msg>trying to fix watch...<commit_after>module.exports = function (grunt) {

  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-nodeunit');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-type');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-reload');

  /*
   grunt.loadNpmTasks('grunt-typescript');
   */

  // Project configuration.
  var port = grunt.option('webapp_port');
  if (!port) {
    port = 8181;
  }

  var appFiles = ['src/main/d.ts/*.ts', 'src/main/webapp/app/**/*.ts'];

  grunt.initConfig({
    test:{
      files:['src/test/js/**/*.js']
    },
    type:{
      compile:{
        files: [
          {
            src: appFiles,
            dest: "<%= grunt.option('webapp_outdir') %>/app/app.js"
          }
        ],
        options:{
          sourcemap: false,
          target: 'es5',
          //module:'amd',
          style:'eqeqeq;bitwise'
        }
      }
    },
    copy:{
      dist: {
        files: [
          {
            expand: true,
            cwd: "src/main/webapp/",
            src: ["./**"],
            dest: "<%= grunt.option('webapp_outdir') %>/"
          }
        ]
      },
      test: {
        files: [
          {
            expand: true,
            cwd: "<%= grunt.option('webapp_outdir') %>/",
            src: ["./**"],
            dest: "src/test/unit/"
          }]
      }
    },
    concat: {
      main: {
        src: ["target/schema/js/*.js", "src/main/webapp/app/**/*.js", "<%= grunt.option('webapp_outdir') %>/app/app.js"],
        dest: "<%= grunt.option('webapp_outdir') %>/app/app.js"
      }
    },
    reload: {
      port: 35729,
      liveReload: {},
      proxy: {
        host: 'localhost',
        port: port
      }
    },
    watch: {
      app: {
        files: ["src/main/webapp/**", "target/schema/js/*.js"],
        //tasks: ['type', 'concat', 'copy', 'reload']
        tasks: ['type']
      }
    }
  });

  // Default task.
  grunt.registerTask('default', ['type', 'concat', 'copy']);

  // watch source for changes
  grunt.registerTask('watchSrc', ['type', 'concat', 'copy', 'reload', 'watch']);

};
<|endoftext|>


<commit_before>(function() {
    'use strict';

    angular
        .module('openeApp')
        .factory('documentPreviewService', DocumentPreviewService);

    DocumentPreviewService.$inject = ['$mdDialog', 'alfrescoDocumentService', 'alfrescoDownloadService', 'PDFViewerService'];

    function DocumentPreviewService($mdDialog, alfrescoDocumentService, alfrescoDownloadService, pdf) {

        var templatesUrl = 'app/src/shared/services/document/preview/view/';

        var service = {
            previewDocument: previewDocument,
            _getPluginByMimeType: _getPluginByMimeType,
            plugins: getPlugins()
        };
        return service;

        function previewDocument(nodeRef){
            var _this = this;
            alfrescoDocumentService.retrieveSingleDocument(nodeRef).then(function(item){
                var plugin = _this._getPluginByMimeType(item);
                previewDialog(plugin);
            });
        }

        function previewDialog(plugin){
            return $mdDialog.show({
                controller: DialogController,
                templateUrl: templatesUrl + 'previewDialog.html',
                parent: angular.element(document.body),
                targetEvent: null,
                clickOutsideToClose: true,
                locals: {
                    plugin: plugin
                }
            });
        }

        function DialogController($scope, $mdDialog, plugin) {

            $scope.config = plugin;
            $scope.viewerTemplateUrl = templatesUrl + plugin.templateUrl;

            $scope.cancel = function() {
              $mdDialog.cancel();
            };

            $scope.close = function(){
                $mdDialog.hide();
            };

            $scope.download = function(){
                alfrescoDownloadService.downloadFile($scope.config.nodeRef, $scope.config.fileName);
            };

            if(plugin.init){
                plugin.init($scope);
            }

        }

        function getPlugins(){
            var plugins = [
                           audioViewer(),
                           pdfViewer(),
                           imageViewer(),
                           videoViewer(),
                           strobeMediaPlayback()
                       ];
            return plugins;
        }

        function _getPluginByMimeType(item){
            var mimeType = item.node.mimetype;
            var resultPlugin = null;
            for(var i in this.plugins){
                var plugin = this.plugins[i];
                if(plugin.acceptsMimeType(mimeType)){
                    resultPlugin = plugin;
                    break;
                }
            }

            if(resultPlugin == null){
                resultPlugin = {
                    templateUrl: 'cannotPreview.html',
                };
            }

            resultPlugin.nodeRef = item.node.nodeRef;
            resultPlugin.fileName = item.location.file;
            resultPlugin.contentUrl = '/alfresco/service' + item.node.contentURL;
            resultPlugin.itemSize = item.node.size;
            resultPlugin.mimeType = item.node.mimetype;

            return resultPlugin;
        }

        function audioViewer(){
            var viewer = {
                    mimeTypes: ['audio/x-wav'],
                    templateUrl: 'audio.html'
                };
            var result = generalPlaybackPlugin();
            return angular.extend(result, viewer);
        }

        function videoViewer(){
            var viewer = {
                mimeTypes: [
                            'video/ogg',
                            'video/webm',
                            'video/x-m4v',
                            'video/mp4'
                            ],
                templateUrl: 'video.html'
            };
            var result = generalPlaybackPlugin();
            return angular.extend(result, viewer);
        }

        function strobeMediaPlayback(){
            var viewer = {
                mimeTypes: [
                            'video/x-m4v',
                            'video/x-flv',
                            'video/mp4',
                            'video/quicktime',
                            'audio/mpeg'
                            ],
                templateUrl: 'strobeMediaPlayBack.html'
            };

            var result = generalPlaybackPlugin();
            return angular.extend(result, viewer);
        }

        function imageViewer(mimeType){
            var viewer = {
                mimeTypes: [
                            'image/png',
                            'image/gif',
                            'image/jpeg'
                            ],
                templateUrl: 'image.html',
                maxItemSize: 2000000,
                init: function($scope){
                    $scope.itemMaxSizeExceeded = (this.itemSize && parseInt(this.itemSize) > this.maxItemSize);
                    if($scope.itemMaxSizeExceeded === false){
                        $scope.imageUrl = $scope.config.contentUrl;
                    }
                }
            };
            var result = generalPreviewPlugin();
            return angular.extend(result, viewer);
        }

        function pdfViewer(){
            return {
                templateUrl: 'pdf.html',
                init: function($scope){
                    $scope.viewer = pdf.Instance("viewer");

                    $scope.nextPage = function() {
                        $scope.viewer.nextPage();
                    };

                    $scope.prevPage = function() {
                        $scope.viewer.prevPage();
                    };

                    $scope.pageLoaded = function(curPage, totalPages) {
                        $scope.currentPage = curPage;
                        $scope.totalPages = totalPages;
                    };
                },
                acceptsMimeType: function(mimeType){
                    return mimeType == 'application/pdf';
                }
            };
        }

        function generalPlaybackPlugin(){
            var plugin = {
                    init: function($scope){
                        var hostUrl = location.protocol+'//'+location.hostname+(location.port ? ':'+location.port: '');
                        this.contentUrl = hostUrl + this.contentUrl;
                    }
            };
            var result = generalPreviewPlugin();
            return angular.extend(result, plugin);
        }

        function generalPreviewPlugin(){
            return {
                acceptsMimeType: function(mimeType){
                    for(var i in this.mimeTypes){
                        var mimeT = this.mimeTypes[i];
                        if(mimeT == mimeType){
                            return true;
                        }
                    }
                    return false;
                }
            };
        }

    }
})();
<commit_msg>Add ticket to contentURL<commit_after>(function() {
    'use strict';

    angular
        .module('openeApp')
        .factory('documentPreviewService', DocumentPreviewService);

    DocumentPreviewService.$inject = ['$mdDialog', 'alfrescoDocumentService', 'alfrescoDownloadService', 'PDFViewerService', 'sessionService'];

    function DocumentPreviewService($mdDialog, alfrescoDocumentService, alfrescoDownloadService, pdf, sessionService) {

        var templatesUrl = 'app/src/shared/services/document/preview/view/';

        var service = {
            previewDocument: previewDocument,
            _getPluginByMimeType: _getPluginByMimeType,
            plugins: getPlugins()
        };
        return service;

        function previewDocument(nodeRef){
            var _this = this;
            alfrescoDocumentService.retrieveSingleDocument(nodeRef).then(function(item){
                var plugin = _this._getPluginByMimeType(item);
                previewDialog(plugin);
            });
        }

        function previewDialog(plugin){
            return $mdDialog.show({
                controller: DialogController,
                templateUrl: templatesUrl + 'previewDialog.html',
                parent: angular.element(document.body),
                targetEvent: null,
                clickOutsideToClose: true,
                locals: {
                    plugin: plugin
                }
            });
        }

        function DialogController($scope, $mdDialog, plugin) {

            $scope.config = plugin;
            $scope.viewerTemplateUrl = templatesUrl + plugin.templateUrl;

            $scope.cancel = function() {
              $mdDialog.cancel();
            };

            $scope.close = function(){
                $mdDialog.hide();
            };

            $scope.download = function(){
                alfrescoDownloadService.downloadFile($scope.config.nodeRef, $scope.config.fileName);
            };

            if(plugin.init){
                plugin.init($scope);
            }

        }

        function getPlugins(){
            var plugins = [
                           audioViewer(),
                           pdfViewer(),
                           imageViewer(),
                           videoViewer(),
                           strobeMediaPlayback()
                       ];
            return plugins;
        }

        function _getPluginByMimeType(item){
            var mimeType = item.node.mimetype;
            var resultPlugin = null;
            for(var i in this.plugins){
                var plugin = this.plugins[i];
                if(plugin.acceptsMimeType(mimeType)){
                    resultPlugin = plugin;
                    break;
                }
            }

            if(resultPlugin == null){
                resultPlugin = {
                    templateUrl: 'cannotPreview.html',
                };
            }

            resultPlugin.nodeRef = item.node.nodeRef;
            resultPlugin.fileName = item.location.file;
            resultPlugin.contentUrl = '/alfresco/service' + item.node.contentURL + '?alf_ticket='+sessionService.getUserInfo().ticket;
            resultPlugin.itemSize = item.node.size;
            resultPlugin.mimeType = item.node.mimetype;

            return resultPlugin;
        }

        function audioViewer(){
            var viewer = {
                    mimeTypes: ['audio/x-wav'],
                    templateUrl: 'audio.html'
                };
            var result = generalPlaybackPlugin();
            return angular.extend(result, viewer);
        }

        function videoViewer(){
            var viewer = {
                mimeTypes: [
                            'video/ogg',
                            'video/webm',
                            'video/x-m4v',
                            'video/mp4'
                            ],
                templateUrl: 'video.html'
            };
            var result = generalPlaybackPlugin();
            return angular.extend(result, viewer);
        }

        function strobeMediaPlayback(){
            var viewer = {
                mimeTypes: [
                            'video/x-m4v',
                            'video/x-flv',
                            'video/mp4',
                            'video/quicktime',
                            'audio/mpeg'
                            ],
                templateUrl: 'strobeMediaPlayBack.html'
            };

            var result = generalPlaybackPlugin();
            return angular.extend(result, viewer);
        }

        function imageViewer(mimeType){
            var viewer = {
                mimeTypes: [
                            'image/png',
                            'image/gif',
                            'image/jpeg'
                            ],
                templateUrl: 'image.html',
                maxItemSize: 2000000,
                init: function($scope){
                    $scope.itemMaxSizeExceeded = (this.itemSize && parseInt(this.itemSize) > this.maxItemSize);
                    if($scope.itemMaxSizeExceeded === false){
                        $scope.imageUrl = $scope.config.contentUrl;
                    }
                }
            };
            var result = generalPreviewPlugin();
            return angular.extend(result, viewer);
        }

        function pdfViewer(){
            return {
                templateUrl: 'pdf.html',
                init: function($scope){
                    $scope.viewer = pdf.Instance("viewer");

                    $scope.nextPage = function() {
                        $scope.viewer.nextPage();
                    };

                    $scope.prevPage = function() {
                        $scope.viewer.prevPage();
                    };

                    $scope.pageLoaded = function(curPage, totalPages) {
                        $scope.currentPage = curPage;
                        $scope.totalPages = totalPages;
                    };
                },
                acceptsMimeType: function(mimeType){
                    return mimeType == 'application/pdf';
                }
            };
        }

        function generalPlaybackPlugin(){
            var plugin = {
                    init: function($scope){
                        var hostUrl = location.protocol+'//'+location.hostname+(location.port ? ':'+location.port: '');
                        this.contentUrl = hostUrl + this.contentUrl;
                    }
            };
            var result = generalPreviewPlugin();
            return angular.extend(result, plugin);
        }

        function generalPreviewPlugin(){
            return {
                acceptsMimeType: function(mimeType){
                    for(var i in this.mimeTypes){
                        var mimeT = this.mimeTypes[i];
                        if(mimeT == mimeType){
                            return true;
                        }
                    }
                    return false;
                }
            };
        }

    }
})();
<|endoftext|>


<commit_before>'use strict';

(function(){
    jQuery(document).ready(function () {
        function _delete_export(export_id) {
            var panel_container = jQuery("#export-panel-" + export_id);
            var csrftoken = Cookies.get('csrftoken');
            jQuery.ajax({
                url: '/api/exports/' + export_id + '/',
                dataType: 'json',
                type: 'DELETE',
                beforeSend: function(xhr, settings) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
                },
                success: function() {
                    panel_container.remove();
                }
            });
        }

        var html_id = 'delete-export-';

        jQuery("div[id^=" + html_id + "]").each(function (discarded, elem) {
            var export_id = elem.id.replace(html_id, '');

            var delete_button = jQuery(elem);
            var group_title = delete_button.closest("div.panel-body").closest("div.panel").find(".panel-title").first();
            var existing_deletable_children = group_title.attr("deletable_children");
            if (existing_deletable_children === undefined) {
                group_title.attr("deletable_children", export_id);
            } else {
                group_title.attr("deletable_children", existing_deletable_children + "," + export_id);
            }
            if (group_title.attr('id') !== "delete-export-all") {
                group_title.attr("id", "delete-export-all");
                group_title.prepend(' ');
                group_title.on('click', function () {
                    if (confirm('Are you sure you want to delete all deletable items of "' + group_title.text() + '"?')) {
                        var deletebale_ids = group_title.attr("deletable_children").split(',');
                        console.log(deletebale_ids);
                        deletebale_ids.forEach(function (export_id) {
                            _delete_export(export_id);
                        })
                    }
                });
            }

            delete_button.attr('class', '');
            delete_button.on('click', function (e, element) {
                var export_id = elem.id.replace(html_id, '');
                if (confirm('Are you sure you want to delete this?')) {
                    _delete_export(export_id);
                }
            });
        });
    });
})();
<commit_msg>trim leading and following whitespace<commit_after>'use strict';

(function(){
    jQuery(document).ready(function () {
        function _delete_export(export_id) {
            var panel_container = jQuery("#export-panel-" + export_id);
            var csrftoken = Cookies.get('csrftoken');
            jQuery.ajax({
                url: '/api/exports/' + export_id + '/',
                dataType: 'json',
                type: 'DELETE',
                beforeSend: function(xhr, settings) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
                },
                success: function() {
                    panel_container.remove();
                }
            });
        }

        var html_id = 'delete-export-';

        jQuery("div[id^=" + html_id + "]").each(function (discarded, elem) {
            var export_id = elem.id.replace(html_id, '');

            var delete_button = jQuery(elem);
            var group_title = delete_button.closest("div.panel-body").closest("div.panel").find(".panel-title").first();
            var existing_deletable_children = group_title.attr("deletable_children");
            if (existing_deletable_children === undefined) {
                group_title.attr("deletable_children", export_id);
            } else {
                group_title.attr("deletable_children", existing_deletable_children + "," + export_id);
            }
            if (group_title.attr('id') !== "delete-export-all") {
                group_title.attr("id", "delete-export-all");
                group_title.prepend(' ');
                group_title.on('click', function () {
                    if (confirm('Are you sure you want to delete all deletable items of "' + jQuery.trim(group_title.text()) + '"?')) {
                        var deletebale_ids = group_title.attr("deletable_children").split(',');
                        console.log(deletebale_ids);
                        deletebale_ids.forEach(function (export_id) {
                            _delete_export(export_id);
                        })
                    }
                });
            }

            delete_button.attr('class', '');
            delete_button.on('click', function (e, element) {
                var export_id = elem.id.replace(html_id, '');
                if (confirm('Are you sure you want to delete this?')) {
                    _delete_export(export_id);
                }
            });
        });
    });
})();
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import PresenceAvatar from '@ciscospark/react-container-presence-avatar';
import ActivityPostAction from '@ciscospark/react-component-activity-post-action';
import {
  ICON_TYPE_DELETE,
  ICON_TYPE_FLAGGED_OUTLINE
} from '@ciscospark/react-component-icon';

import styles from './styles.css';

const propTypes = {
  actorId: PropTypes.string,
  children: PropTypes.element.isRequired,
  hasError: PropTypes.bool,
  id: PropTypes.string.isRequired,
  isAdditional: PropTypes.bool,
  isFlagged: PropTypes.bool,
  isPending: PropTypes.bool,
  isSelf: PropTypes.bool,
  name: PropTypes.string.isRequired,
  onActivityDelete: PropTypes.func,
  onActivityFlag: PropTypes.func,
  onActivityRetry: PropTypes.func,
  timestamp: PropTypes.string
};

const defaultProps = {
  actorId: '',
  hasError: false,
  isAdditional: false,
  isFlagged: false,
  isPending: false,
  isSelf: false,
  onActivityDelete: () => {},
  onActivityFlag: () => {},
  onActivityRetry: () => {},
  timestamp: ''
};

function ActivityItemBase({
  actorId,
  children,
  id,
  isAdditional,
  hasError,
  isFlagged,
  isPending,
  isSelf,
  name,
  onActivityDelete,
  onActivityFlag,
  onActivityRetry,
  timestamp
}) {
  let deleteAction;
  let flagAction;
  let errorDisplay;
  const displayName = isSelf ? 'You' : name;

  function handleOnDelete() {
    onActivityDelete(id);
  }

  function handleOnFlag() {
    onActivityFlag(id);
  }

  function handleOnRetry() {
    onActivityRetry(id);
  }

  function getActionClassNames(highlight) {
    const actionClassNames = ['activity-post-action', styles.activityPostAction];
    if (highlight) {
      actionClassNames.push('isHighlighted', styles.isHighlighted);
    }
    return actionClassNames;
  }

  if (!isPending) {
    flagAction = (

        <ActivityPostAction
          iconType={ICON_TYPE_FLAGGED_OUTLINE}
          onClick={handleOnFlag}
          title="Flag this message"
        />

    );
    if (isSelf) {
      deleteAction = (

          <ActivityPostAction
            iconType={ICON_TYPE_DELETE}
            onClick={handleOnDelete}
            title="Delete this message"
          />

      );
    }
    else {
      deleteAction = (

      );
    }
  }

  if (hasError) {
    errorDisplay = (

        <button onClick={handleOnRetry}>Unable to post. Click to retry</button>

    );
  }

  const activityItemClasses = [
    'activity-item',
    styles.activityItem,
    isAdditional ? styles.additional : '',
    isPending ? styles.pending : ''
  ];

  const avatarClasses = [
    'ciscospark-avatar-wrapper',
    'ciscospark-activity-item-avatar-wrapper',
    styles.avatarWrapper,
    isSelf ? styles.selfAvatar : ''
  ];

  return (

        <PresenceAvatar
          avatarId={actorId}
          iconSize="30px"
          isSelfAvatar={isSelf}
          name={name}
        />

{displayName}

{timestamp}

          {children}

        {errorDisplay}

        {flagAction}
        {deleteAction}

  );
}

ActivityItemBase.propTypes = propTypes;
ActivityItemBase.defaultProps = defaultProps;

export default ActivityItemBase;
<commit_msg>fix(react-component-activity-item-base): Remove required name propType<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import PresenceAvatar from '@ciscospark/react-container-presence-avatar';
import ActivityPostAction from '@ciscospark/react-component-activity-post-action';
import {
  ICON_TYPE_DELETE,
  ICON_TYPE_FLAGGED_OUTLINE
} from '@ciscospark/react-component-icon';

import styles from './styles.css';

const propTypes = {
  actorId: PropTypes.string,
  children: PropTypes.element.isRequired,
  hasError: PropTypes.bool,
  id: PropTypes.string.isRequired,
  isAdditional: PropTypes.bool,
  isFlagged: PropTypes.bool,
  isPending: PropTypes.bool,
  isSelf: PropTypes.bool,
  name: PropTypes.string,
  onActivityDelete: PropTypes.func,
  onActivityFlag: PropTypes.func,
  onActivityRetry: PropTypes.func,
  timestamp: PropTypes.string
};

const defaultProps = {
  actorId: '',
  hasError: false,
  isAdditional: false,
  isFlagged: false,
  isPending: false,
  isSelf: false,
  name: '',
  onActivityDelete: () => {},
  onActivityFlag: () => {},
  onActivityRetry: () => {},
  timestamp: ''
};

function ActivityItemBase({
  actorId,
  children,
  id,
  isAdditional,
  hasError,
  isFlagged,
  isPending,
  isSelf,
  name,
  onActivityDelete,
  onActivityFlag,
  onActivityRetry,
  timestamp
}) {
  let deleteAction;
  let flagAction;
  let errorDisplay;
  const displayName = isSelf ? 'You' : name;

  function handleOnDelete() {
    onActivityDelete(id);
  }

  function handleOnFlag() {
    onActivityFlag(id);
  }

  function handleOnRetry() {
    onActivityRetry(id);
  }

  function getActionClassNames(highlight) {
    const actionClassNames = ['activity-post-action', styles.activityPostAction];
    if (highlight) {
      actionClassNames.push('isHighlighted', styles.isHighlighted);
    }
    return actionClassNames;
  }

  if (!isPending) {
    flagAction = (

        <ActivityPostAction
          iconType={ICON_TYPE_FLAGGED_OUTLINE}
          onClick={handleOnFlag}
          title="Flag this message"
        />

    );
    if (isSelf) {
      deleteAction = (

          <ActivityPostAction
            iconType={ICON_TYPE_DELETE}
            onClick={handleOnDelete}
            title="Delete this message"
          />

      );
    }
    else {
      deleteAction = (

      );
    }
  }

  if (hasError) {
    errorDisplay = (

        <button onClick={handleOnRetry}>Unable to post. Click to retry</button>

    );
  }

  const activityItemClasses = [
    'activity-item',
    styles.activityItem,
    isAdditional ? styles.additional : '',
    isPending ? styles.pending : ''
  ];

  const avatarClasses = [
    'ciscospark-avatar-wrapper',
    'ciscospark-activity-item-avatar-wrapper',
    styles.avatarWrapper,
    isSelf ? styles.selfAvatar : ''
  ];

  return (

        <PresenceAvatar
          avatarId={actorId}
          iconSize="30px"
          isSelfAvatar={isSelf}
          name={name}
        />

{displayName}

{timestamp}

          {children}

        {errorDisplay}

        {flagAction}
        {deleteAction}

  );
}

ActivityItemBase.propTypes = propTypes;
ActivityItemBase.defaultProps = defaultProps;

export default ActivityItemBase;
<|endoftext|>


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

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { STORE_NAME as CORE_SITE } from '../../../../googlesitekit/datastore/site/constants';
import { STORE_NAME } from '../../datastore/constants';
import { ExistingTagNotice } from '.';
const { useSelect } = Data;

export default function FormInstructions() {
	const hasExistingTag = useSelect( ( select ) => select( STORE_NAME ).hasExistingTag() );
	const isSecondaryAMP = useSelect( ( select ) => select( CORE_SITE ).isSecondaryAMP() );

	if ( hasExistingTag ) {
		return <ExistingTagNotice />;
	}

	if ( isSecondaryAMP ) {
		return (

				{ __( 'Looks like your site is using paired AMP. Please select your Tag Manager account and relevant containers below, the snippets will be inserted automatically on your site.', 'google-site-kit' ) }

		);
	}

	return (

			{ __( 'Please select your Tag Manager account and container below, the snippet will be inserted automatically on your site.', 'google-site-kit' ) }

	);
}
<commit_msg>Import ExistingTagNotice directly.<commit_after>/**
 * Tag Manager Form Instructions component.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { STORE_NAME as CORE_SITE } from '../../../../googlesitekit/datastore/site/constants';
import { STORE_NAME } from '../../datastore/constants';
import { ExistingTagNotice } from './ExistingTagNotice';
const { useSelect } = Data;

export default function FormInstructions() {
	const hasExistingTag = useSelect( ( select ) => select( STORE_NAME ).hasExistingTag() );
	const isSecondaryAMP = useSelect( ( select ) => select( CORE_SITE ).isSecondaryAMP() );

	if ( hasExistingTag ) {
		return <ExistingTagNotice />;
	}

	if ( isSecondaryAMP ) {
		return (

				{ __( 'Looks like your site is using paired AMP. Please select your Tag Manager account and relevant containers below, the snippets will be inserted automatically on your site.', 'google-site-kit' ) }

		);
	}

	return (

			{ __( 'Please select your Tag Manager account and container below, the snippet will be inserted automatically on your site.', 'google-site-kit' ) }

	);
}
<|endoftext|>


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

/**
 * WordPress dependencies
 */
import { useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { MODULES_TAGMANAGER } from '../../datastore/constants';
import Switch from '../../../../components/Switch';
const { useSelect, useDispatch } = Data;

export default function UseSnippetSwitch() {
	const useSnippet = useSelect( ( select ) =>
		select( MODULES_TAGMANAGER ).getUseSnippet()
	);

	const { setUseSnippet } = useDispatch( MODULES_TAGMANAGER );
	const onChange = useCallback( () => {
		setUseSnippet( ! useSnippet );
	}, [ useSnippet, setUseSnippet ] );

	if ( useSnippet === undefined ) {
		return null;
	}

	return (

			<Switch
				label={ __(
					'Let Site Kit place code on your site',
					'google-site-kit'
				) }
				checked={ useSnippet }
				onClick={ onChange }
				hideLabel={ false }
			/>

				{ useSnippet
					? __(
							'Site Kit will add the code automatically.',
							'google-site-kit'
					  )
					: __(
							'Site Kit will not add the code to your site.',
							'google-site-kit'
					  ) }

	);
}
<commit_msg>Add trackEvent to tagmanager snippet toggle.<commit_after>/**
 * Tag Manager Use Snippet Switch component.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * WordPress dependencies
 */
import { useCallback, useContext } from '@wordpress/element';
import React from 'react';
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { MODULES_TAGMANAGER } from '../../datastore/constants';
import Switch from '../../../../components/Switch';
import ViewContextContext from '../../../../components/Root/ViewContextContext';
import { trackEvent } from '../../../../util';

const { useSelect, useDispatch } = Data;

export default function UseSnippetSwitch() {
	const useSnippet = useSelect( ( select ) =>
		select( MODULES_TAGMANAGER ).getUseSnippet()
	);

	const viewContext = useContext( ViewContextContext );

	const { setUseSnippet } = useDispatch( MODULES_TAGMANAGER );
	const onChange = useCallback( () => {
		const newUseSnippet = ! useSnippet;
		setUseSnippet( newUseSnippet );
		trackEvent(
			`${ viewContext }_tagmanager`,
			newUseSnippet ? 'enable_tag' : 'disable_tag'
		);
	}, [ setUseSnippet, useSnippet, viewContext ] );

	if ( useSnippet === undefined ) {
		return null;
	}

	return (

			<Switch
				label={ __(
					'Let Site Kit place code on your site',
					'google-site-kit'
				) }
				checked={ useSnippet }
				onClick={ onChange }
				hideLabel={ false }
			/>

				{ useSnippet
					? __(
							'Site Kit will add the code automatically.',
							'google-site-kit'
					  )
					: __(
							'Site Kit will not add the code to your site.',
							'google-site-kit'
					  ) }

	);
}
<|endoftext|>