<commit_before>/*
Copyright 2019 New Vector Ltd

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

    http://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.
*/

import React from 'react';
import PropTypes from 'prop-types';
import {_t} from "../../../../../languageHandler";
import SettingsStore, {SettingLevel} from "../../../../../settings/SettingsStore";
import {MatrixClientPeg} from "../../../../../MatrixClientPeg";
import * as FormattingUtils from "../../../../../utils/FormattingUtils";
import AccessibleButton from "../../../elements/AccessibleButton";
import Analytics from "../../../../../Analytics";
import Modal from "../../../../../Modal";
import * as sdk from "../../../../..";
import {sleep} from "../../../../../utils/promise";

export class IgnoredUser extends React.Component {
    static propTypes = {
        userId: PropTypes.string.isRequired,
        onUnignored: PropTypes.func.isRequired,
    };

    _onUnignoreClicked = (e) => {
        this.props.onUnignored(this.props.userId);
    };

    render() {
        const id = `mx_SecurityUserSettingsTab_ignoredUser_${this.props.userId}`;
        return (

                <AccessibleButton onClick={this._onUnignoreClicked} kind='primary_sm' aria-describedby={id}>
                    { _t('Unignore') }
                </AccessibleButton>
                { this.props.userId }

        );
    }
}

export default class SecurityUserSettingsTab extends React.Component {
    constructor() {
        super();

        // Get number of rooms we're invited to
        const invitedRooms = this._getInvitedRooms();

        this.state = {
            ignoredUserIds: MatrixClientPeg.get().getIgnoredUsers(),
            managingInvites: false,
            invitedRoomAmt: invitedRooms.length,
        };
    }

    _updateBlacklistDevicesFlag = (checked) => {
        MatrixClientPeg.get().setGlobalBlacklistUnverifiedDevices(checked);
    };

    _updateAnalytics = (checked) => {
        checked ? Analytics.enable() : Analytics.disable();
    };

    _onExportE2eKeysClicked = () => {
        Modal.createTrackedDialogAsync('Export E2E Keys', '',
            import('../../../../../async-components/views/dialogs/ExportE2eKeysDialog'),
            {matrixClient: MatrixClientPeg.get()},
        );
    };

    _onImportE2eKeysClicked = () => {
        Modal.createTrackedDialogAsync('Import E2E Keys', '',
            import('../../../../../async-components/views/dialogs/ImportE2eKeysDialog'),
            {matrixClient: MatrixClientPeg.get()},
        );
    };

    _onUserUnignored = async (userId) => {
        // Don't use this.state to get the ignored user list as it might be
        // ever so slightly outdated. Instead, prefer to get a fresh list and
        // update that.
        const ignoredUserIds = MatrixClientPeg.get().getIgnoredUsers();
        const index = ignoredUserIds.indexOf(userId);
        if (index !== -1) {
            ignoredUserIds.splice(index, 1);
            MatrixClientPeg.get().setIgnoredUsers(ignoredUserIds);
        }
        this.setState({ignoredUserIds});
    };

    _getInvitedRooms = () => {
        return MatrixClientPeg.get().getRooms().filter((r) => {
            return r.hasMembershipState(MatrixClientPeg.get().getUserId(), "invite");
        });
    };

    _manageInvites = async (accept) => {
        this.setState({
            managingInvites: true,
        });

        // Compile array of invitation room ids
        const invitedRoomIds = this._getInvitedRooms().map((room) => {
            return room.roomId;
        });

        // Execute all acceptances/rejections sequentially
        const self = this;
        const cli = MatrixClientPeg.get();
        const action = accept ? cli.joinRoom.bind(cli) : cli.leave.bind(cli);
        for (let i = 0; i < invitedRoomIds.length; i++) {
            const roomId = invitedRoomIds[i];

            // Accept/reject invite
            await action(roomId).then(() => {
                // No error, update invited rooms button
                this.setState({invitedRoomAmt: self.state.invitedRoomAmt - 1});
            }, async (e) => {
                // Action failure
                if (e.errcode === "M_LIMIT_EXCEEDED") {
                    // Add a delay between each invite change in order to avoid rate
                    // limiting by the server.
                    await sleep(e.retry_after_ms || 2500);

                    // Redo last action
                    i--;
                } else {
                    // Print out error with joining/leaving room
                    console.warn(e);
                }
            });
        }

        this.setState({
            managingInvites: false,
        });
    };

    _onAcceptAllInvitesClicked = (ev) => {
        this._manageInvites(true);
    };

    _onRejectAllInvitesClicked = (ev) => {
        this._manageInvites(false);
    };

    _renderCurrentDeviceInfo() {
        const SettingsFlag = sdk.getComponent('views.elements.SettingsFlag');

        const client = MatrixClientPeg.get();
        const deviceId = client.deviceId;
        let identityKey = client.getDeviceEd25519Key();
        if (!identityKey) {
            identityKey = _t("<not supported>");
        } else {
            identityKey = FormattingUtils.formatCryptoKey(identityKey);
        }

        let importExportButtons = null;
        if (client.isCryptoEnabled()) {
            importExportButtons = (

                    <AccessibleButton kind='primary' onClick={this._onExportE2eKeysClicked}>
                        {_t("Export E2E room keys")}
                    </AccessibleButton>
                    <AccessibleButton kind='primary' onClick={this._onImportE2eKeysClicked}>
                        {_t("Import E2E room keys")}
                    </AccessibleButton>

            );
        }

        return (

                {_t("Cryptography")}

                        {_t("Session ID:")}
                        {deviceId}

                        {_t("Session key:")}
                        {identityKey}

                {importExportButtons}
                <SettingsFlag name='blacklistUnverifiedDevices' level={SettingLevel.DEVICE}
                              onChange={this._updateBlacklistDevicesFlag} />

        );
    }

    _renderIgnoredUsers() {
        if (!this.state.ignoredUserIds || this.state.ignoredUserIds.length === 0) return null;

        const userIds = this.state.ignoredUserIds
            .map((u) => <IgnoredUser userId={u} onUnignored={this._onUserUnignored} key={u} />);

        return (

                {_t('Ignored users')}

                    {userIds}

        );
    }

    _renderManageInvites() {
        if (this.state.invitedRoomAmt === 0) {
            return null;
        }

        const invitedRooms = this._getInvitedRooms();
        const InlineSpinner = sdk.getComponent('elements.InlineSpinner');
        const onClickAccept = this._onAcceptAllInvitesClicked.bind(this, invitedRooms);
        const onClickReject = this._onRejectAllInvitesClicked.bind(this, invitedRooms);
        return (

                {_t('Bulk options')}
                <AccessibleButton onClick={onClickAccept} kind='primary' disabled={this.state.managingInvites}>
                    {_t("Accept all %(invitedRooms)s invites", {invitedRooms: this.state.invitedRoomAmt})}
                </AccessibleButton>
                <AccessibleButton onClick={onClickReject} kind='danger' disabled={this.state.managingInvites}>
                    {_t("Reject all %(invitedRooms)s invites", {invitedRooms: this.state.invitedRoomAmt})}
                </AccessibleButton>
                {this.state.managingInvites ? <InlineSpinner /> :
}

        );
    }

    render() {
        const DevicesPanel = sdk.getComponent('views.settings.DevicesPanel');
        const SettingsFlag = sdk.getComponent('views.elements.SettingsFlag');
        const EventIndexPanel = sdk.getComponent('views.settings.EventIndexPanel');

        const KeyBackupPanel = sdk.getComponent('views.settings.KeyBackupPanel');
        const keyBackup = (

                {_t("Key backup")}

                    <KeyBackupPanel />

        );

        let eventIndex;
        if (SettingsStore.isFeatureEnabled("feature_event_indexing")) {
            eventIndex = (

                    {_t("Message search")}
                    <EventIndexPanel />

            );
        }

        // XXX: There's no such panel in the current cross-signing designs, but
        // it's useful to have for testing the feature. If there's no interest
        // in having advanced details here once all flows are implemented, we
        // can remove this.
        const CrossSigningPanel = sdk.getComponent('views.settings.CrossSigningPanel');
        let crossSigning;
        if (SettingsStore.getValue("feature_cross_signing")) {
            crossSigning = (

                    {_t("Cross-signing")}

                        <CrossSigningPanel />

            );
        }

        const E2eAdvancedPanel = sdk.getComponent('views.settings.E2eAdvancedPanel');

        return (

{_t("Security & Privacy")}

                    {_t("Sessions")}

                        {_t("A session's public name is visible to people you communicate with")}
                        <DevicesPanel />

                {keyBackup}
                {eventIndex}
                {crossSigning}
                {this._renderCurrentDeviceInfo()}

                    {_t("Analytics")}

                        {_t("Riot collects anonymous analytics to allow us to improve the application.")}

                        {_t("Privacy is important to us, so we don't collect any personal or " +
                            "identifiable data for our analytics.")}
                        <AccessibleButton className="mx_SettingsTab_linkBtn" onClick={Analytics.showDetailsModal}>
                            {_t("Learn more about how we use analytics.")}
                        </AccessibleButton>

                    <SettingsFlag name='analyticsOptIn' level={SettingLevel.DEVICE}
                                  onChange={this._updateAnalytics} />

                {this._renderIgnoredUsers()}
                {this._renderManageInvites()}
                <E2eAdvancedPanel />

        );
    }
}
<commit_msg>Sync settings ignoredUsers with global state<commit_after>/*
Copyright 2019 New Vector Ltd

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

    http://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.
*/

import React from 'react';
import PropTypes from 'prop-types';
import {_t} from "../../../../../languageHandler";
import SettingsStore, {SettingLevel} from "../../../../../settings/SettingsStore";
import {MatrixClientPeg} from "../../../../../MatrixClientPeg";
import * as FormattingUtils from "../../../../../utils/FormattingUtils";
import AccessibleButton from "../../../elements/AccessibleButton";
import Analytics from "../../../../../Analytics";
import Modal from "../../../../../Modal";
import * as sdk from "../../../../..";
import {sleep} from "../../../../../utils/promise";
import dis from "../../../../../dispatcher"

export class IgnoredUser extends React.Component {
    static propTypes = {
        userId: PropTypes.string.isRequired,
        onUnignored: PropTypes.func.isRequired,
    };

    _onUnignoreClicked = (e) => {
        this.props.onUnignored(this.props.userId);
    };

    render() {
        const id = `mx_SecurityUserSettingsTab_ignoredUser_${this.props.userId}`;
        return (

                <AccessibleButton onClick={this._onUnignoreClicked} kind='primary_sm' aria-describedby={id}>
                    { _t('Unignore') }
                </AccessibleButton>
                { this.props.userId }

        );
    }
}

export default class SecurityUserSettingsTab extends React.Component {
    constructor() {
        super();

        // Get number of rooms we're invited to
        const invitedRooms = this._getInvitedRooms();

        this.state = {
            ignoredUserIds: MatrixClientPeg.get().getIgnoredUsers(),
            managingInvites: false,
            invitedRoomAmt: invitedRooms.length,
        };

        this._onAction = this._onAction.bind(this);
    }

    _onAction({action}) {
        if (action === "ignore_state_changed"){
            const ignoredUserIds =  MatrixClientPeg.get().getIgnoredUsers();
            this.setState({ignoredUserIds})
        }
    }

    componentDidMount() {
        this.dispatcherRef = dis.register(this._onAction)
    }

    componentWillUnmount() {
        dis.unregister(this.dispatcherRef);
    }

    _updateBlacklistDevicesFlag = (checked) => {
        MatrixClientPeg.get().setGlobalBlacklistUnverifiedDevices(checked);
    };

    _updateAnalytics = (checked) => {
        checked ? Analytics.enable() : Analytics.disable();
    };

    _onExportE2eKeysClicked = () => {
        Modal.createTrackedDialogAsync('Export E2E Keys', '',
            import('../../../../../async-components/views/dialogs/ExportE2eKeysDialog'),
            {matrixClient: MatrixClientPeg.get()},
        );
    };

    _onImportE2eKeysClicked = () => {
        Modal.createTrackedDialogAsync('Import E2E Keys', '',
            import('../../../../../async-components/views/dialogs/ImportE2eKeysDialog'),
            {matrixClient: MatrixClientPeg.get()},
        );
    };

    _onUserUnignored = async (userId) => {
        // Don't use this.state to get the ignored user list as it might be
        // ever so slightly outdated. Instead, prefer to get a fresh list and
        // update that.
        const ignoredUserIds = this.state.ignoredUserIds;
        const index = ignoredUserIds.indexOf(userId);
        if (index !== -1) {
            ignoredUserIds.splice(index, 1);
            MatrixClientPeg.get().setIgnoredUsers(ignoredUserIds);
        }

    };

    _getInvitedRooms = () => {
        return MatrixClientPeg.get().getRooms().filter((r) => {
            return r.hasMembershipState(MatrixClientPeg.get().getUserId(), "invite");
        });
    };

    _manageInvites = async (accept) => {
        this.setState({
            managingInvites: true,
        });

        // Compile array of invitation room ids
        const invitedRoomIds = this._getInvitedRooms().map((room) => {
            return room.roomId;
        });

        // Execute all acceptances/rejections sequentially
        const self = this;
        const cli = MatrixClientPeg.get();
        const action = accept ? cli.joinRoom.bind(cli) : cli.leave.bind(cli);
        for (let i = 0; i < invitedRoomIds.length; i++) {
            const roomId = invitedRoomIds[i];

            // Accept/reject invite
            await action(roomId).then(() => {
                // No error, update invited rooms button
                this.setState({invitedRoomAmt: self.state.invitedRoomAmt - 1});
            }, async (e) => {
                // Action failure
                if (e.errcode === "M_LIMIT_EXCEEDED") {
                    // Add a delay between each invite change in order to avoid rate
                    // limiting by the server.
                    await sleep(e.retry_after_ms || 2500);

                    // Redo last action
                    i--;
                } else {
                    // Print out error with joining/leaving room
                    console.warn(e);
                }
            });
        }

        this.setState({
            managingInvites: false,
        });
    };

    _onAcceptAllInvitesClicked = (ev) => {
        this._manageInvites(true);
    };

    _onRejectAllInvitesClicked = (ev) => {
        this._manageInvites(false);
    };

    _renderCurrentDeviceInfo() {
        const SettingsFlag = sdk.getComponent('views.elements.SettingsFlag');

        const client = MatrixClientPeg.get();
        const deviceId = client.deviceId;
        let identityKey = client.getDeviceEd25519Key();
        if (!identityKey) {
            identityKey = _t("<not supported>");
        } else {
            identityKey = FormattingUtils.formatCryptoKey(identityKey);
        }

        let importExportButtons = null;
        if (client.isCryptoEnabled()) {
            importExportButtons = (

                    <AccessibleButton kind='primary' onClick={this._onExportE2eKeysClicked}>
                        {_t("Export E2E room keys")}
                    </AccessibleButton>
                    <AccessibleButton kind='primary' onClick={this._onImportE2eKeysClicked}>
                        {_t("Import E2E room keys")}
                    </AccessibleButton>

            );
        }

        return (

                {_t("Cryptography")}

                        {_t("Session ID:")}
                        {deviceId}

                        {_t("Session key:")}
                        {identityKey}

                {importExportButtons}
                <SettingsFlag name='blacklistUnverifiedDevices' level={SettingLevel.DEVICE}
                              onChange={this._updateBlacklistDevicesFlag} />

        );
    }

    _renderIgnoredUsers() {
        if (!this.state.ignoredUserIds || this.state.ignoredUserIds.length === 0) return null;

        const userIds = this.state.ignoredUserIds
            .map((u) => <IgnoredUser userId={u} onUnignored={this._onUserUnignored} key={u} />);

        return (

                {_t('Ignored users')}

                    {userIds}

        );
    }

    _renderManageInvites() {
        if (this.state.invitedRoomAmt === 0) {
            return null;
        }

        const invitedRooms = this._getInvitedRooms();
        const InlineSpinner = sdk.getComponent('elements.InlineSpinner');
        const onClickAccept = this._onAcceptAllInvitesClicked.bind(this, invitedRooms);
        const onClickReject = this._onRejectAllInvitesClicked.bind(this, invitedRooms);
        return (

                {_t('Bulk options')}
                <AccessibleButton onClick={onClickAccept} kind='primary' disabled={this.state.managingInvites}>
                    {_t("Accept all %(invitedRooms)s invites", {invitedRooms: this.state.invitedRoomAmt})}
                </AccessibleButton>
                <AccessibleButton onClick={onClickReject} kind='danger' disabled={this.state.managingInvites}>
                    {_t("Reject all %(invitedRooms)s invites", {invitedRooms: this.state.invitedRoomAmt})}
                </AccessibleButton>
                {this.state.managingInvites ? <InlineSpinner /> :
}

        );
    }

    render() {
        const DevicesPanel = sdk.getComponent('views.settings.DevicesPanel');
        const SettingsFlag = sdk.getComponent('views.elements.SettingsFlag');
        const EventIndexPanel = sdk.getComponent('views.settings.EventIndexPanel');

        const KeyBackupPanel = sdk.getComponent('views.settings.KeyBackupPanel');
        const keyBackup = (

                {_t("Key backup")}

                    <KeyBackupPanel />

        );

        let eventIndex;
        if (SettingsStore.isFeatureEnabled("feature_event_indexing")) {
            eventIndex = (

                    {_t("Message search")}
                    <EventIndexPanel />

            );
        }

        // XXX: There's no such panel in the current cross-signing designs, but
        // it's useful to have for testing the feature. If there's no interest
        // in having advanced details here once all flows are implemented, we
        // can remove this.
        const CrossSigningPanel = sdk.getComponent('views.settings.CrossSigningPanel');
        let crossSigning;
        if (SettingsStore.getValue("feature_cross_signing")) {
            crossSigning = (

                    {_t("Cross-signing")}

                        <CrossSigningPanel />

            );
        }

        const E2eAdvancedPanel = sdk.getComponent('views.settings.E2eAdvancedPanel');

        return (

{_t("Security & Privacy")}

                    {_t("Sessions")}

                        {_t("A session's public name is visible to people you communicate with")}
                        <DevicesPanel />

                {keyBackup}
                {eventIndex}
                {crossSigning}
                {this._renderCurrentDeviceInfo()}

                    {_t("Analytics")}

                        {_t("Riot collects anonymous analytics to allow us to improve the application.")}

                        {_t("Privacy is important to us, so we don't collect any personal or " +
                            "identifiable data for our analytics.")}
                        <AccessibleButton className="mx_SettingsTab_linkBtn" onClick={Analytics.showDetailsModal}>
                            {_t("Learn more about how we use analytics.")}
                        </AccessibleButton>

                    <SettingsFlag name='analyticsOptIn' level={SettingLevel.DEVICE}
                                  onChange={this._updateAnalytics} />

                {this._renderIgnoredUsers()}
                {this._renderManageInvites()}
                <E2eAdvancedPanel />

        );
    }
}
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
    User = mongoose.model('User');

/**
 * Auth callback
 */
exports.authCallback = function(req, res) {
    res.redirect('/');
};

/**
 * Show login form
 */
exports.signin = function(req, res) {
    if(req.isAuthenticated()) {
        return res.redirect('/');
    }
    res.redirect('#!/login');
};

/**
 * Logout
 */
exports.signout = function(req, res) {
    req.logout();
    res.redirect('/');
};

/**
 * Session
 */
exports.session = function(req, res) {
    res.redirect('/');
};

/**
 * Create user
 */
exports.create = function(req, res, next) {
    var user = new User(req.body);

    user.provider = 'local';

    // because we set our user.provider to local our models/user.js validation will always be true
    req.assert('name', 'You must enter a name').notEmpty();
    req.assert('email', 'You must enter a valid email address').isEmail();
    req.assert('password', 'Password must be between 8-20 characters long').len(8, 20);
    req.assert('username', 'Username cannot be more than 20 characters').len(1,20);
    req.assert('confirmPassword', 'Passwords do not match').equals(req.body.password);

    var errors = req.validationErrors();
    if (errors) {
        return res.status(400).send(errors);
    }

    // Hard coded for now. Will address this with the user permissions system in v0.3.5
    user.roles = ['authenticated'];
    user.save(function(err) {
        if (err) {
            switch (err.code) {
                case 11000:
                case 11001:
                    res.status(400).send('Username already taken');
                    break;
                default:
                    res.status(400).send('Please fill all the required fields');
            }

            return res.status(400);
        }
        req.logIn(user, function(err) {
            if (err) return next(err);
            return res.redirect('/');
        });
        res.status(200);
    });
};
/**
 * Send User
 */
exports.me = function(req, res) {
    res.jsonp(req.user || null);
};

/**
 * Find user by id
 */
exports.user = function(req, res, next, id) {
    User
        .findOne({
            _id: id
        })
        .exec(function(err, user) {
            if (err) return next(err);
            if (!user) return next(new Error('Failed to load User ' + id));
            req.profile = user;
            next();
        });
};
<commit_msg>fixed pre save validations to return error objects as angular expects them. fixes also validation error for 'username already taken' which was not showing up to the user previously<commit_after>'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
    User = mongoose.model('User');

/**
 * Auth callback
 */
exports.authCallback = function(req, res) {
    res.redirect('/');
};

/**
 * Show login form
 */
exports.signin = function(req, res) {
    if(req.isAuthenticated()) {
        return res.redirect('/');
    }
    res.redirect('#!/login');
};

/**
 * Logout
 */
exports.signout = function(req, res) {
    req.logout();
    res.redirect('/');
};

/**
 * Session
 */
exports.session = function(req, res) {
    res.redirect('/');
};

/**
 * Create user
 */
exports.create = function(req, res, next) {
    var user = new User(req.body);

    user.provider = 'local';

    // because we set our user.provider to local our models/user.js validation will always be true
    req.assert('name', 'You must enter a name').notEmpty();
    req.assert('email', 'You must enter a valid email address').isEmail();
    req.assert('password', 'Password must be between 8-20 characters long').len(8, 20);
    req.assert('username', 'Username cannot be more than 20 characters').len(1,20);
    req.assert('confirmPassword', 'Passwords do not match').equals(req.body.password);

    var errors = req.validationErrors();
    if (errors) {
        return res.status(400).send(errors);
    }

    // Hard coded for now. Will address this with the user permissions system in v0.3.5
    user.roles = ['authenticated'];
    user.save(function(err) {
        if (err) {
            switch (err.code) {
                case 11000:
                case 11001:
                    res.status(400).send([{
                        msg: 'Username already taken',
                        param: 'username'
                    }]);
                    break;
                default:
                    var modelErrors = [];

                    if (err.errors) {

                        for (var x in err.errors) {
                            modelErrors.push({
                                param: x,
                                msg: err.errors[x].message,
                                value: err.errors[x].value
                            });
                        }

                        res.status(400).send(modelErrors);
                    }
            }

            return res.status(400);
        }
        req.logIn(user, function(err) {
            if (err) return next(err);
            return res.redirect('/');
        });
        res.status(200);
    });
};
/**
 * Send User
 */
exports.me = function(req, res) {
    res.jsonp(req.user || null);
};

/**
 * Find user by id
 */
exports.user = function(req, res, next, id) {
    User
        .findOne({
            _id: id
        })
        .exec(function(err, user) {
            if (err) return next(err);
            if (!user) return next(new Error('Failed to load User ' + id));
            req.profile = user;
            next();
        });
};
<|endoftext|>


<commit_before>/*
* mvcController
* author: ronglin
* create date: 2014.6.24
*/

'use strict';

var utils = require('./utilities'),
    mvcAction = require('./mvcAction'),
    mvcInjector = require('./mvcInjector'),
    mvcHelperUrl = require('./mvcHelperUrl'),
    mvcViewData = require('./mvcViewData'),
    mvcTempData = require('./mvcTempData'),
    mvcTempDataStore = require('./mvcTempDataStore'),
    mvcActionResultApi = require('./mvcActionResultApi');

var mvcController = module.exports = function(set) {
    utils.extend(this, set);
};

var defined;
mvcController.define = function() {
    var name, attr, impl;
    var len = arguments.length, arg0 = arguments[0];
    //
    if (len === 1 && utils.isFunction(arg0)) {
        impl = arg0;
    } else if (len === 1 && utils.isObject(arg0)) {
        name = arg0.name;
        attr = arg0.attr;
        impl = arg0.impl;
    } else if (len === 2) {
        attr = arg0;
        impl = arguments[1];
    } else {
        name = arg0;
        attr = arguments[1];
        impl = arguments[2];
    }
    //
    var ret = new mvcController({
        _name: name,
        _attr: attr,
        _impl: impl
    });
    if (defined) {
        defined.push(ret);
    }
    return ret;
};

mvcController.loadfile = function(fileName) {
    defined = [];
    delete require.cache[fileName];
    require(fileName);
    var t = defined;
    defined = null;
    return t;
};

mvcController.prototype = {

    _name: null, _path: null, _attr: null, _impl: null,

    actions: null,  url: null,

    viewData: null, tempData: null,

    resultApi: null, implScope: null,

    httpContext: null, attributes: null,

    constructor: mvcController, className: 'mvcController',

    name: function(p) { return (p === undefined) ? (this._name) : (this._name = p, this); },
    path: function(p) { return (p === undefined) ? (this._path) : (this._path = p, this); },
    attr: function(p) { return (p === undefined) ? (this._attr) : (this._attr = p, this); },
    impl: function(p) { return (p === undefined) ? (this._impl) : (this._impl = p, this); },

    clone: function() {
        return new mvcController({
            _name: this._name,
            _path: this._path,
            _attr: this._attr,
            _impl: this._impl
        });
    },

    destroy: function() {
        if (this.attributes) {
            this.attributes.emitSync(this, { eventName: 'onControllerDestroy' });
            this.attributes = null;
        }
        if (this.actions) {
            utils.each(this.actions, function() { this.destroy(); });
            this.actions = null;
        }
        if (this.url) {
            this.url.httpContext = null;
            this.url = null;
        }
        if (this.viewData) {
            this.viewData.httpContext = null;
            this.viewdata = null;
        }
        if (this.resultApi) {
            this.resultApi.httpContext = null;
            this.resultApi = null;
        }
        if (this.httpContext) {
            this.httpContext.destroy();
            this.httpContext = null;
        }
        if (this.implScope) {
            this.implScope.controller = null;
            this.implScope = null;
        }
        // clear reference types
        this._impl = null;
        this._attr = null;
        this.tempData = null;
    },

    initialize: function(httpContext) {
        this.actions = [];
        this.httpContext = httpContext;
        //
        this.url = new mvcHelperUrl({ httpContext: this.httpContext });
        this.viewData = new mvcViewData({ httpContext: this.httpContext });
        this.tempData = new mvcTempData({ provider: mvcTempDataStore.sessionProvider });
        //
        this.resultApi = new mvcActionResultApi({ httpContext: this.httpContext, sync: false });
        this.implScope = new controllerImplementationScope(this);
        //
        this.attributes = httpContext.app.attributes.resolveConfig(this.attr());
        this.attributes.append(httpContext.app.attributes.resolveConfig('handleError, validateInput(true)'));
        this.attributes.append(this.implScope);
    },

    injectImpl: function(ctx) {
        var annotated = mvcInjector.annotate(this.impl());
        var params = annotated.params = [];
        if (!annotated.args || annotated.args.length === 0) { return annotated; }
        //
        var self = this;
        utils.each(annotated.args, function(i, name) {
            var loweName = name.toLowerCase();
            if (loweName.charAt(0) === '$') {
                loweName = loweName.substr(1);
            }
            switch(loweName) {
                case 'ctx':      params.push(ctx); break;
                case 'req':      params.push(ctx.request); break;
                case 'res':      params.push(ctx.response); break;
                case 'context':  params.push(ctx); break;
                case 'request':  params.push(ctx.request); break;
                case 'response': params.push(ctx.response); break;
                case 'session':  params.push(ctx.rulee.request.session); break;
                case 'query':    params.push(ctx.rulee.request.query); break;
                case 'form':     params.push(ctx.rulee.request.form); break;
                //
                case 'tempdata': params.push(self.tempData); break;
                case 'viewdata': params.push(self.viewData); break;
                case 'end':      params.push(self.resultApi); break;
                case 'url':      params.push(self.url); break;
                //
                default: params.push(null); break;
            }
        });
        //
        return annotated;
    },

    executeImpl: function() {
        var annotated = this.injectImpl(this.httpContext);
        if (!utils.isFunction(annotated.func)) { return; }
        annotated.func.apply(this.implScope, annotated.params);
        this.appendInlineActions(this.implScope);
        this.attributes.emitSync(this, { eventName: 'onControllerInitialized' });
    },

    appendInlineActions: function(scope) {
        if (!(scope instanceof controllerImplementationScope)) { return; }
        var proto = controllerImplementationScope.prototype;
        for (var name in scope) {
            if (!utils.hasOwn(scope, name)) { continue; }
            if (!utils.isFunction(scope[name])) { continue; }
            if (!(name in proto) || name === 'action') {
                var impl = scope[name], attr = impl.attr;
                this.actions.push(new mvcAction({
                    _name: name,
                    _attr: attr,
                    _impl: impl
                }));
            }
        }
    },

    action: function() {
        var len = arguments.length, act;
        if (len === 0) {
            act = new mvcAction();
        } else if (len === 1) {
            act = new mvcAction({
                _name: arguments[0]
            });
        } else if (len === 2) {
            act = new mvcAction({
                _name: arguments[0],
                _impl: arguments[1]
            });
        } else {
            act = new mvcAction({
                _name: arguments[0],
                _attr: arguments[1],
                _impl: arguments[2]
            });
        }
        this.actions.push(act);
        return act; //  for chain
    },

    findAction: function(actionName) {
        var acts = [], self = this;
        utils.each(this.actions, function() {
            this.initialize(self);
            var ret = this.isValidName(actionName);
            if (ret.deft || ret.attr) { acts.push(this); }
        });
        //
        var actsByAttr = [], actsByDeft = [];
        utils.each(acts, function() {
            var ret = this.isValidRequest();
            if (ret.deft) { actsByDeft.push(this); }
            else if (ret.attr) { actsByAttr.push(this); }
        });
        acts = (actsByAttr.length > 0) ? actsByAttr : actsByDeft;
        // ret
        switch(acts.length) {
            case 0: return null;
            case 1: return acts[0];
            default: throw this.createAmbiguousActionsError(acts, actionName);
        }
    },

    createAmbiguousActionsError: function(ambiguousActions, actionName) {
        var message = [];
        utils.each(ambiguousActions, function() {
            var match = this.impl().toString().match(/^function\s*\([^\)]*/ig);
            var fnStr = match ? (match[0] + ')') : this.impl().toString();
            message.push(utils.format('{0} [{1}] {2}', this.name(), this.attr().toString(), fnStr));
        });
        return new Error(utils.format('The current request for action "{0}" on controller type "{1}" is ambiguous between the following action methods:
{2}', actionName, this.name(), message.join('
')));
    }
};

var controllerKeyInScope = 'dont_use_me(random:' + utils.unique(8) + ')';

var controllerImplementationScope = function(controller) {
    this[controllerKeyInScope] = controller;
};

controllerImplementationScope.prototype = {

    constructor: controllerImplementationScope, className: 'controllerImplementationScope',

    action: function() { return this[controllerKeyInScope].action.apply(this[controllerKeyInScope], arguments); },

    /************ controller events **************/
    onControllerInitialized: function(controller) {},
    onControllerDestroy: function(controller) {},

    /************ authorize event **************/
    onAuthorization: function(authorizationContext) {},

    /************ action filter events **************/
    onActionExecuting: function(actionExecutingContext, next) { next(); },
    onActionExecuted: function(actionExecutedContext, next) { next(); },
    onResultExecuting: function(resultExecutingContext, next) { next(); },
    onResultExecuted: function(resultExecutedContext, next) { next(); },

    /************ exception event **************/
    onException: function(exceptionContext) {}
};
<commit_msg>update<commit_after>/*
* mvcController
* author: ronglin
* create date: 2014.6.24
*/

'use strict';

var utils = require('./utilities'),
    mvcAction = require('./mvcAction'),
    mvcInjector = require('./mvcInjector'),
    mvcHelperUrl = require('./mvcHelperUrl'),
    mvcViewData = require('./mvcViewData'),
    mvcTempData = require('./mvcTempData'),
    mvcTempDataStore = require('./mvcTempDataStore'),
    mvcActionResultApi = require('./mvcActionResultApi');

var mvcController = module.exports = function(set) {
    utils.extend(this, set);
};

var defined;
var controllerKeyInScope = 'dont_use_me(random:' + utils.unique(8) + ')';

mvcController.define = function() {
    var name, attr, impl;
    var len = arguments.length, arg0 = arguments[0];
    //
    if (len === 1 && utils.isFunction(arg0)) {
        impl = arg0;
    } else if (len === 1 && utils.isObject(arg0)) {
        name = arg0.name;
        attr = arg0.attr;
        impl = arg0.impl;
    } else if (len === 2) {
        attr = arg0;
        impl = arguments[1];
    } else {
        name = arg0;
        attr = arguments[1];
        impl = arguments[2];
    }
    //
    var ret = new mvcController({
        _name: name,
        _attr: attr,
        _impl: impl
    });
    if (defined) {
        defined.push(ret);
    }
    return ret;
};

mvcController.loadfile = function(fileName) {
    defined = [];
    delete require.cache[fileName];
    require(fileName);
    var t = defined;
    defined = null;
    return t;
};

mvcController.prototype = {

    _name: null, _path: null, _attr: null, _impl: null,

    actions: null,  url: null,

    viewData: null, tempData: null,

    resultApi: null, implScope: null,

    httpContext: null, attributes: null,

    constructor: mvcController, className: 'mvcController',

    name: function(p) { return (p === undefined) ? (this._name) : (this._name = p, this); },
    path: function(p) { return (p === undefined) ? (this._path) : (this._path = p, this); },
    attr: function(p) { return (p === undefined) ? (this._attr) : (this._attr = p, this); },
    impl: function(p) { return (p === undefined) ? (this._impl) : (this._impl = p, this); },

    clone: function() {
        return new mvcController({
            _name: this._name,
            _path: this._path,
            _attr: this._attr,
            _impl: this._impl
        });
    },

    destroy: function() {
        if (this.attributes) {
            this.attributes.emitSync(this, { eventName: 'onControllerDestroy' });
            this.attributes = null;
        }
        if (this.actions) {
            utils.each(this.actions, function() { this.destroy(); });
            this.actions = null;
        }
        if (this.url) {
            this.url.httpContext = null;
            this.url = null;
        }
        if (this.viewData) {
            this.viewData.httpContext = null;
            this.viewdata = null;
        }
        if (this.resultApi) {
            this.resultApi.httpContext = null;
            this.resultApi = null;
        }
        if (this.httpContext) {
            this.httpContext.destroy();
            this.httpContext = null;
        }
        if (this.implScope) {
            this.implScope[controllerKeyInScope] = null;
            this.implScope = null;
        }
        // clear reference types
        this._impl = null;
        this._attr = null;
        this.tempData = null;
    },

    initialize: function(httpContext) {
        this.actions = [];
        this.httpContext = httpContext;
        //
        this.url = new mvcHelperUrl({ httpContext: this.httpContext });
        this.viewData = new mvcViewData({ httpContext: this.httpContext });
        this.tempData = new mvcTempData({ provider: mvcTempDataStore.sessionProvider });
        //
        this.resultApi = new mvcActionResultApi({ httpContext: this.httpContext, sync: false });
        this.implScope = new controllerImplementationScope(this);
        //
        this.attributes = httpContext.app.attributes.resolveConfig(this.attr());
        this.attributes.append(httpContext.app.attributes.resolveConfig('handleError, validateInput(true)'));
        this.attributes.append(this.implScope);
    },

    injectImpl: function(ctx) {
        var annotated = mvcInjector.annotate(this.impl());
        var params = annotated.params = [];
        if (!annotated.args || annotated.args.length === 0) { return annotated; }
        //
        var self = this;
        utils.each(annotated.args, function(i, name) {
            var loweName = name.toLowerCase();
            if (loweName.charAt(0) === '$') {
                loweName = loweName.substr(1);
            }
            switch(loweName) {
                case 'ctx':      params.push(ctx); break;
                case 'req':      params.push(ctx.request); break;
                case 'res':      params.push(ctx.response); break;
                case 'context':  params.push(ctx); break;
                case 'request':  params.push(ctx.request); break;
                case 'response': params.push(ctx.response); break;
                case 'session':  params.push(ctx.rulee.request.session); break;
                case 'query':    params.push(ctx.rulee.request.query); break;
                case 'form':     params.push(ctx.rulee.request.form); break;
                //
                case 'tempdata': params.push(self.tempData); break;
                case 'viewdata': params.push(self.viewData); break;
                case 'end':      params.push(self.resultApi); break;
                case 'url':      params.push(self.url); break;
                //
                default: params.push(null); break;
            }
        });
        //
        return annotated;
    },

    executeImpl: function() {
        var annotated = this.injectImpl(this.httpContext);
        if (!utils.isFunction(annotated.func)) { return; }
        annotated.func.apply(this.implScope, annotated.params);
        this.appendInlineActions(this.implScope);
        this.attributes.emitSync(this, { eventName: 'onControllerInitialized' });
    },

    appendInlineActions: function(scope) {
        if (!(scope instanceof controllerImplementationScope)) { return; }
        var proto = controllerImplementationScope.prototype;
        for (var name in scope) {
            if (!utils.hasOwn(scope, name)) { continue; }
            if (!utils.isFunction(scope[name])) { continue; }
            if (!(name in proto) || name === 'action') {
                var impl = scope[name], attr = impl.attr;
                this.actions.push(new mvcAction({
                    _name: name,
                    _attr: attr,
                    _impl: impl
                }));
            }
        }
    },

    action: function() {
        var len = arguments.length, act;
        if (len === 0) {
            act = new mvcAction();
        } else if (len === 1) {
            act = new mvcAction({
                _name: arguments[0]
            });
        } else if (len === 2) {
            act = new mvcAction({
                _name: arguments[0],
                _impl: arguments[1]
            });
        } else {
            act = new mvcAction({
                _name: arguments[0],
                _attr: arguments[1],
                _impl: arguments[2]
            });
        }
        this.actions.push(act);
        return act; //  for chain
    },

    findAction: function(actionName) {
        var acts = [], self = this;
        utils.each(this.actions, function() {
            this.initialize(self);
            var ret = this.isValidName(actionName);
            if (ret.deft || ret.attr) { acts.push(this); }
        });
        //
        var actsByAttr = [], actsByDeft = [];
        utils.each(acts, function() {
            var ret = this.isValidRequest();
            if (ret.deft) { actsByDeft.push(this); }
            else if (ret.attr) { actsByAttr.push(this); }
        });
        acts = (actsByAttr.length > 0) ? actsByAttr : actsByDeft;
        // ret
        switch(acts.length) {
            case 0: return null;
            case 1: return acts[0];
            default: throw this.createAmbiguousActionsError(acts, actionName);
        }
    },

    createAmbiguousActionsError: function(ambiguousActions, actionName) {
        var message = [];
        utils.each(ambiguousActions, function() {
            var match = this.impl().toString().match(/^function\s*\([^\)]*/ig);
            var fnStr = match ? (match[0] + ')') : this.impl().toString();
            message.push(utils.format('{0} [{1}] {2}', this.name(), this.attr().toString(), fnStr));
        });
        return new Error(utils.format('The current request for action "{0}" on controller type "{1}" is ambiguous between the following action methods:
{2}', actionName, this.name(), message.join('
')));
    }
};

var controllerImplementationScope = function(controller) {
    this[controllerKeyInScope] = controller;
};

controllerImplementationScope.prototype = {

    constructor: controllerImplementationScope, className: 'controllerImplementationScope',

    action: function() { return this[controllerKeyInScope].action.apply(this[controllerKeyInScope], arguments); },

    /************ controller events **************/
    onControllerInitialized: function(controller) {},
    onControllerDestroy: function(controller) {},

    /************ authorize event **************/
    onAuthorization: function(authorizationContext) {},

    /************ action filter events **************/
    onActionExecuting: function(actionExecutingContext, next) { next(); },
    onActionExecuted: function(actionExecutedContext, next) { next(); },
    onResultExecuting: function(resultExecutingContext, next) { next(); },
    onResultExecuted: function(resultExecutedContext, next) { next(); },

    /************ exception event **************/
    onException: function(exceptionContext) {}
};
<|endoftext|>


<commit_before>'use strict';

var request = require('request');
var Url = require('url'),
util = require('util'),
EventEmitter = require('events').EventEmitter,
httpProxy = require('http-proxy'),
_ = require('lodash'),
proxy = new httpProxy.createProxyServer(),
ProxyKeystone = function(customOptions){
  var self = this;

  self.options = {
    token: 'user.token',
    userId: 'user.userId',
    catalog: 'user.serviceCatalog',
    userAgent: ''
  };

  if(customOptions){
    for(var i in customOptions){
      self.options[i] = customOptions[i];
    }
  }

  self.getValueByString = function (o, s) {
    var a = s.split('.');
    while (a.length) {
      var n = a.shift();
      if (n in o) {
          o = o[n];
      } else {
          return false;
      }
    }
    return o;
  };

  self.parseService = function (service) {
    var segments = service.split(','),
    data = {
      name: segments[0]
    };

    if (segments.length === 2) {
      data.region = segments[1];
    }

    self.emit('log:parseService', data);
    return data;
  };

  self.getServiceByName = function (name, catalog) {
    if (catalog instanceof Array) {
      return _.find(catalog, function(item) {
        return name === item.name;
      });
    } else {
      return catalog[name];
    }
  };

  self.findEndpoint = function (serviceInfo, service) {
    if (serviceInfo.region){
      return _.find(service.endpoints, function(endpoint) {
        return serviceInfo.region === endpoint.region;
      });
    } else {
      return service.endpoints[0];
    }
  };

  self.middleware = function (req, res, next) {
    var error, token, catalog, serviceParams, service,
    endpoint, endpointInfo, target, serviceInfo, userId,
    proxyUrl = req.route.path.replace(/\*$/, '');

    // Handle body parser issues
    req.removeAllListeners('data');
    req.removeAllListeners('end');
    process.nextTick(function () {
      if(req.body) {
        req.emit('data', JSON.stringify(req.body));
      }
      req.emit('end');
    });

    // set token and serviceCatalog
    token = self.getValueByString(req, self.options.token);
    userId = self.getValueByString(req, self.options.userId);
    catalog = self.getValueByString(req, self.options.catalog);

    if(!token && !userId){
      error = new Error('Missing token/userId');
      self.emit('proxyError', error);
      return next(error);
    }
    if (!catalog) {
      error = new Error('Missing Service Catalog');
      self.emit('proxyError', error);
      return next(error);
    }

    // begin req.url transformation
    req.url = req.url.split(proxyUrl)[1]; // remove /proxy/
    if (req.service) {
      serviceParams = req.service;
    }
    else {
      serviceParams = req.url.split('/')[0]; // grabs 'catalogItem,[region]'
      req.url = req.url.split(serviceParams)[1]; // transform req.url
    }

    serviceInfo = self.parseService(serviceParams);

    // grab service from catalog based on name
    service = self.getServiceByName(serviceInfo.name, catalog);

    // check if service exists
    if (!service){
      error = new Error('Service Catalog Item Not Found');
      self.emit('proxyError', error);
      return next(error);
    }

    endpoint = self.findEndpoint(serviceInfo, service);

    if (!endpoint) {
      error = new Error('Endpoint Not Found In ' + service.name);
      self.emit('proxyError', error);
      return next(error);
    }

    // url.parse creates an object
    endpointInfo = Url.parse(endpoint.publicURL);
    if (endpointInfo.path != '/') {
      target = endpoint.publicURL.split(endpointInfo.path)[0];
    }
    else {
      target = endpoint.publicURL;
    }
    req.url = endpointInfo.pathname + req.url;

    // Set headers
    req.headers = {};
    req.headers['X-Auth-Token'] = token;
    req.headers['X-Auth-User'] = userId;
    req.headers['Accept'] = 'application/json';
    req.headers['Content-Type'] = 'application/json';
    if (self.options.userAgent){
      req.headers['User-Agent'] = self.options.userAgent;
    }

    if (req.method == 'POST' || req.method == 'PUT') {
      request({
        method: req.method,
        url: target + req.url,
        headers: req.headers,
        json: req.body
      }, function(error, response, body) {
        res.json(body);
      });
    }
    else {
      proxy.on('start', function(req, res, target){
        self.emit('proxyStart', req, res, target);
      });

      proxy.on('end', function(req, res, proxyRes){
        self.emit('proxyEnd', req, res, proxyRes);
      });

      proxy.on('error', function (err) {
        self.emit('proxyError', err);
        next(err);
      });

      proxy.web(req, res, {
        target: target
      });

    }
  };

};

util.inherits(ProxyKeystone, EventEmitter);

module.exports = ProxyKeystone;
<commit_msg>Add error handling for proxied request<commit_after>'use strict';

var request = require('request');
var Url = require('url'),
util = require('util'),
EventEmitter = require('events').EventEmitter,
httpProxy = require('http-proxy'),
_ = require('lodash'),
proxy = new httpProxy.createProxyServer(),
ProxyKeystone = function(customOptions){
  var self = this;

  self.options = {
    token: 'user.token',
    userId: 'user.userId',
    catalog: 'user.serviceCatalog',
    userAgent: ''
  };

  if(customOptions){
    for(var i in customOptions){
      self.options[i] = customOptions[i];
    }
  }

  self.getValueByString = function (o, s) {
    var a = s.split('.');
    while (a.length) {
      var n = a.shift();
      if (n in o) {
          o = o[n];
      } else {
          return false;
      }
    }
    return o;
  };

  self.parseService = function (service) {
    var segments = service.split(','),
    data = {
      name: segments[0]
    };

    if (segments.length === 2) {
      data.region = segments[1];
    }

    self.emit('log:parseService', data);
    return data;
  };

  self.getServiceByName = function (name, catalog) {
    if (catalog instanceof Array) {
      return _.find(catalog, function(item) {
        return name === item.name;
      });
    } else {
      return catalog[name];
    }
  };

  self.findEndpoint = function (serviceInfo, service) {
    if (serviceInfo.region){
      return _.find(service.endpoints, function(endpoint) {
        return serviceInfo.region === endpoint.region;
      });
    } else {
      return service.endpoints[0];
    }
  };

  self.middleware = function (req, res, next) {
    var error, token, catalog, serviceParams, service,
    endpoint, endpointInfo, target, serviceInfo, userId,
    proxyUrl = req.route.path.replace(/\*$/, '');

    // Handle body parser issues
    req.removeAllListeners('data');
    req.removeAllListeners('end');
    process.nextTick(function () {
      if(req.body) {
        req.emit('data', JSON.stringify(req.body));
      }
      req.emit('end');
    });

    // set token and serviceCatalog
    token = self.getValueByString(req, self.options.token);
    userId = self.getValueByString(req, self.options.userId);
    catalog = self.getValueByString(req, self.options.catalog);

    if(!token && !userId){
      error = new Error('Missing token/userId');
      self.emit('proxyError', error);
      return next(error);
    }
    if (!catalog) {
      error = new Error('Missing Service Catalog');
      self.emit('proxyError', error);
      return next(error);
    }

    // begin req.url transformation
    req.url = req.url.split(proxyUrl)[1]; // remove /proxy/
    if (req.service) {
      serviceParams = req.service;
    }
    else {
      serviceParams = req.url.split('/')[0]; // grabs 'catalogItem,[region]'
      req.url = req.url.split(serviceParams)[1]; // transform req.url
    }

    serviceInfo = self.parseService(serviceParams);

    // grab service from catalog based on name
    service = self.getServiceByName(serviceInfo.name, catalog);

    // check if service exists
    if (!service){
      error = new Error('Service Catalog Item Not Found');
      self.emit('proxyError', error);
      return next(error);
    }

    endpoint = self.findEndpoint(serviceInfo, service);

    if (!endpoint) {
      error = new Error('Endpoint Not Found In ' + service.name);
      self.emit('proxyError', error);
      return next(error);
    }

    // url.parse creates an object
    endpointInfo = Url.parse(endpoint.publicURL);
    if (endpointInfo.path != '/') {
      target = endpoint.publicURL.split(endpointInfo.path)[0];
    }
    else {
      target = endpoint.publicURL;
    }
    req.url = endpointInfo.pathname + req.url;

    // Set headers
    req.headers = {};
    req.headers['X-Auth-Token'] = token;
    req.headers['X-Auth-User'] = userId;
    req.headers['Accept'] = 'application/json';
    req.headers['Content-Type'] = 'application/json';
    if (self.options.userAgent){
      req.headers['User-Agent'] = self.options.userAgent;
    }

    // dirty hacks for POST/PUT requests
    if (req.method == 'POST' || req.method == 'PUT') {
      request({
        method: req.method,
        url: target + req.url,
        headers: req.headers,
        json: req.body
      }, function(error, response, body) {
        if (error) {
          res.json({status: 500, data: error});
        }
        else {
          res.json(body);
        }
      });
    }
    else {
      proxy.on('start', function(req, res, target){
        self.emit('proxyStart', req, res, target);
      });

      proxy.on('end', function(req, res, proxyRes){
        self.emit('proxyEnd', req, res, proxyRes);
      });

      proxy.on('error', function (err) {
        self.emit('proxyError', err);
        next(err);
      });

      proxy.web(req, res, {
        target: target
      });

    }
  };

};

util.inherits(ProxyKeystone, EventEmitter);

module.exports = ProxyKeystone;
<|endoftext|>


<commit_before>import React from 'react';
import { connect } from 'react-redux';

class Status extends React.Component {
  render() {
    const {errorUrl, topologiesLoaded, topology, websocketClosed} = this.props;

    let title = '';
    let text = 'Trying to reconnect...';
    let showWarningIcon = false;
    let classNames = 'status sidebar-item';

    if (errorUrl) {
      title = `Cannot reach Scope. Make sure the following URL is reachable: ${errorUrl}`;
      classNames += ' status-loading';
      showWarningIcon = true;
    } else if (!topologiesLoaded) {
      text = 'Connecting to Scope...';
      classNames += ' status-loading';
      showWarningIcon = true;
    } else if (websocketClosed) {
      classNames += ' status-loading';
      showWarningIcon = true;
    } else if (topology) {
      const stats = topology.get('stats');
      text = `${stats.get('node_count')} nodes`;
      if (stats.get('filtered_nodes')) {
        text = `${text} (${stats.get('filtered_nodes')} filtered)`;
      }
      classNames += ' status-stats';
      showWarningIcon = false;
    }

    return (

        {showWarningIcon && }
        {text}

    );
  }
}

function mapStateToProps(state) {
  return {
    errorUrl: state.get('errorUrl'),
    topologiesLoaded: state.get('topologiesLoaded'),
    topology: state.get('currentTopology'),
    websocketClosed: state.get('websocketClosed')
  };
}

export default connect(
  mapStateToProps
)(Status);
<commit_msg>Subtract pinned search-filtered nodes from status node count<commit_after>import React from 'react';
import { connect } from 'react-redux';

class Status extends React.Component {
  render() {
    const {errorUrl, filteredNodeCount, topologiesLoaded, topology,
      websocketClosed} = this.props;

    let title = '';
    let text = 'Trying to reconnect...';
    let showWarningIcon = false;
    let classNames = 'status sidebar-item';

    if (errorUrl) {
      title = `Cannot reach Scope. Make sure the following URL is reachable: ${errorUrl}`;
      classNames += ' status-loading';
      showWarningIcon = true;
    } else if (!topologiesLoaded) {
      text = 'Connecting to Scope...';
      classNames += ' status-loading';
      showWarningIcon = true;
    } else if (websocketClosed) {
      classNames += ' status-loading';
      showWarningIcon = true;
    } else if (topology) {
      const stats = topology.get('stats');
      text = `${stats.get('node_count') - filteredNodeCount} nodes`;
      if (stats.get('filtered_nodes')) {
        text = `${text} (${stats.get('filtered_nodes') + filteredNodeCount} filtered)`;
      }
      classNames += ' status-stats';
      showWarningIcon = false;
    }

    return (

        {showWarningIcon && }
        {text}

    );
  }
}

function mapStateToProps(state) {
  return {
    errorUrl: state.get('errorUrl'),
    filteredNodeCount: state.get('nodes').filter(node => node.get('filtered')).size,
    topologiesLoaded: state.get('topologiesLoaded'),
    topology: state.get('currentTopology'),
    websocketClosed: state.get('websocketClosed')
  };
}

export default connect(
  mapStateToProps
)(Status);
<|endoftext|>


<commit_before>/* global $state, $location */
describe('State: 404', () => {
  beforeEach(module('app.states'))

  describe('route', () => {
    beforeEach(() => {
      bard.inject('$location', '$state')
    })

    it('should map /404 route to 404 View template', () => {
      expect($state.get('404').template).to.match(/blank-slate-pf/) // 404.html topmost classname
    })

    it('should work with $state.go', () => {
      $state.go('404')
      expect($state.is('404'))
    })

    it('should route /invalid to the otherwise (404) route', () => {
      $location.path('/invalid')
      expect($state.current.template).to.match(/blank-slate-pf/) // 404.html topmost classname
    })
  })
})
<commit_msg>404 spec - /invalid *redirects* to 404, doesn't display the template directly<commit_after>/* global $state, $location */
describe('State: 404', () => {
  beforeEach(module('app.states'))

  describe('route', () => {
    beforeEach(() => {
      bard.inject('$location', '$state')
    })

    it('should map /404 route to 404 View template', () => {
      expect($state.get('404').template).to.match(/blank-slate-pf/) // 404.html topmost classname
    })

    it('should work with $state.go', () => {
      $state.go('404')
      expect($state.is('404'))
    })
  })
})
<|endoftext|>


<commit_before>/**
 * @flow
 */

import MetaDomain from './meta-domain'
import getRegistration from './get-registration'
import { get, set, merge, createOrClone } from './utils'
import { castPath, type KeyPath } from './key-path'

import type Action from './action'
import type Microcosm from './microcosm'

type DomainList = Array<[KeyPath, Domain]>
type Registry = { [action: string]: Registrations }

/**
 * Reduce down a list of values.
 */
function reduce(steps: Handler[], payload: *, start: *, scope: any) {
  var next = start

  for (var i = 0, len = steps.length; i < len; i++) {
    next = steps[i].call(scope, next, payload)
  }

  return next
}

class DomainEngine {
  repo: Microcosm
  registry: Registry
  domains: DomainList

  constructor(repo: Microcosm) {
    this.repo = repo
    this.registry = {}
    this.domains = []

    // All realms contain a meta domain for basic Microcosm operations
    this.add([], MetaDomain)
  }

  getRepoHandlers(action: Action): Registrations {
    let { command, status } = action

    let steps = getRegistration(this.repo.register(), command, status)

    return steps.length ? [{ key: [], scope: this.repo, steps }] : []
  }

  getHandlers(action: Action): Registrations {
    let handlers = this.getRepoHandlers(action)

    let { command, status } = action

    for (var i = 0; i < this.domains.length; i++) {
      var [key, scope] = this.domains[i]

      if (scope.register) {
        let steps = getRegistration(scope.register(), command, status)

        if (steps.length) {
          handlers.push({ key, scope, steps })
        }
      }
    }

    return handlers
  }

  register(action: Action): Registrations {
    let type = action.type

    if (!this.registry[type]) {
      this.registry[type] = this.getHandlers(action)
    }

    return this.registry[type]
  }

  add(key: string, config: *, options?: Object) {
    console.assert(
      !options || options.constructor === Object,
      `repo.addDomain("${key}", domain, options) expected a plain object.`,
      'Instead got',
      get(options, 'constructor.name', 'Unknown')
    )

    let deepOptions = merge(
      this.repo.options,
      config.defaults,
      { key },
      options
    )
    let domain: Domain = createOrClone(config, deepOptions, this.repo)
    let keyPath: KeyPath = castPath(key)

    this.domains.push([keyPath, domain])

    // Reset the registry
    this.registry = {}

    if (domain.setup) {
      domain.setup(this.repo, deepOptions)
    }

    if (domain.teardown) {
      this.repo.on('teardown', domain.teardown, domain)
    }

    return domain
  }

  dispatch(action: Action, state: Object, snapshot: Snapshot) {
    let handlers = this.register(action)
    let result = state

    for (var i = 0; i < handlers.length; i++) {
      var { key, scope, steps } = handlers[i]

      var base = get(result, key, null)
      var head = get(snapshot.last, key, null)

      if (
        // If the reference to the prior state changed
        base !== head ||
        // Or the payload is different
        action.payload !== snapshot.payload ||
        // or the status is different
        action.status !== snapshot.status
      ) {
        // Yes: recalculate state from the base
        result = set(result, key, reduce(steps, action.payload, base, scope))
      } else {
        // No: use the existing snapshot value (memoizing the domain handler)
        result = set(result, key, get(snapshot.next, key))
      }
    }

    return result
  }

  deserialize(payload: Object): Object {
    let next = payload

    for (var i = 0; i < this.domains.length; i++) {
      var [key, domain] = this.domains[i]

      if (domain.deserialize) {
        next = set(next, key, domain.deserialize(get(payload, key)))
      }
    }

    return next
  }

  serialize(state: Object, payload: Object): Object {
    let next = payload

    for (var i = 0; i < this.domains.length; i++) {
      var [key, domain] = this.domains[i]

      if (domain.serialize) {
        next = set(next, key, domain.serialize(get(state, key)))
      }
    }

    return next
  }
}

export default DomainEngine
<commit_msg>Fix flow coverage<commit_after>/**
 * @flow
 */

import MetaDomain from './meta-domain'
import getRegistration from './get-registration'
import { get, set, merge, createOrClone } from './utils'
import { castPath, type KeyPath } from './key-path'

import type Action from './action'
import type Microcosm from './microcosm'

type DomainList = Array<[KeyPath, Domain]>
type Registry = { [action: string]: Registrations }

/**
 * Reduce down a list of values.
 */
function reduce(steps: Handler[], payload: *, start: *, scope: any) {
  var next = start

  for (var i = 0, len = steps.length; i < len; i++) {
    next = steps[i].call(scope, next, payload)
  }

  return next
}

class DomainEngine {
  repo: Microcosm
  registry: Registry
  domains: DomainList

  constructor(repo: Microcosm) {
    this.repo = repo
    this.registry = {}
    this.domains = []

    // All realms contain a meta domain for basic Microcosm operations
    this.add([], MetaDomain)
  }

  getRepoHandlers(action: Action): Registrations {
    let { command, status } = action

    let steps = getRegistration(this.repo.register(), command, status)

    return steps.length ? [{ key: [], scope: this.repo, steps }] : []
  }

  getHandlers(action: Action): Registrations {
    let handlers = this.getRepoHandlers(action)

    let { command, status } = action

    for (var i = 0; i < this.domains.length; i++) {
      var [key, scope] = this.domains[i]

      if (scope.register) {
        let steps = getRegistration(scope.register(), command, status)

        if (steps.length) {
          handlers.push({ key, scope, steps })
        }
      }
    }

    return handlers
  }

  register(action: Action): Registrations {
    let type = action.type

    if (!this.registry[type]) {
      this.registry[type] = this.getHandlers(action)
    }

    return this.registry[type]
  }

  add(key: string | KeyPath, config: *, options?: Object) {
    let keyPath: KeyPath = castPath(key)

    console.assert(
      !options || options.constructor === Object,
      `repo.addDomain("${keyPath.join('.')}", domain, options) expected a plain object.`,
      'Instead got',
      get(options, 'constructor.name', 'Unknown')
    )

    let deepOptions = merge(
      this.repo.options,
      config.defaults,
      { key },
      options
    )

    let domain: Domain = createOrClone(config, deepOptions, this.repo)

    this.domains.push([keyPath, domain])

    // Reset the registry
    this.registry = {}

    if (domain.setup) {
      domain.setup(this.repo, deepOptions)
    }

    if (domain.teardown) {
      this.repo.on('teardown', domain.teardown, domain)
    }

    return domain
  }

  dispatch(action: Action, state: Object, snapshot: Snapshot) {
    let handlers = this.register(action)
    let result = state

    for (var i = 0; i < handlers.length; i++) {
      var { key, scope, steps } = handlers[i]

      var base = get(result, key, null)
      var head = get(snapshot.last, key, null)

      if (
        // If the reference to the prior state changed
        base !== head ||
        // Or the payload is different
        action.payload !== snapshot.payload ||
        // or the status is different
        action.status !== snapshot.status
      ) {
        // Yes: recalculate state from the base
        result = set(result, key, reduce(steps, action.payload, base, scope))
      } else {
        // No: use the existing snapshot value (memoizing the domain handler)
        result = set(result, key, get(snapshot.next, key))
      }
    }

    return result
  }

  deserialize(payload: Object): Object {
    let next = payload

    for (var i = 0; i < this.domains.length; i++) {
      var [key, domain] = this.domains[i]

      if (domain.deserialize) {
        next = set(next, key, domain.deserialize(get(payload, key)))
      }
    }

    return next
  }

  serialize(state: Object, payload: Object): Object {
    let next = payload

    for (var i = 0; i < this.domains.length; i++) {
      var [key, domain] = this.domains[i]

      if (domain.serialize) {
        next = set(next, key, domain.serialize(get(state, key)))
      }
    }

    return next
  }
}

export default DomainEngine
<|endoftext|>


<commit_before>// mono core template ids
var dbName = 'mono';
var ids = {
    templates: {
        applications: '528f78dc197ef1c23714a04d',
        modules: '528f78f1197ef1c23714a04e',
        roles: '528f7902197ef1c23714a04f',
        miids: '52923eb6ea5c6526b8870cde'
    },
    roles: {
        proxy: '52923d79ea5c6526b8870cdd'
    }
};

// mono core templates
var templates = {
    applications: {
        _id: ids.templates.applications,
        _tp: [/*Add template id*/],
        db: dbName,
        collection: 'm_applications',
        name: 'm_applications',
        options: {
            label: 'Applications'
        },
        roles: {},
        schema: {
            name: {
                type: 'string',
                required: true
            },
            domains: [{
                type: 'string',
                required: true
            }],
            routes: {
                type: 'object',
                required: true
            }
        }
    },
    modules: {
        _id: ids.templates.modules,
        _tp: [/*Add template id*/],
        db: dbName,
        collection: 'm_modules',
        name: 'm_modules',
        options: {
            label: 'Modules'
        },
        roles: {},
        schema: {
            name: {
                type: 'string',
                required: true
            }
        }
    },
    roles: {
        _id: ids.templates.roles,
        _tp: [/*Add template id*/],
        db: dbName,
        collection: 'm_roles',
        name: 'm_roles',
        options: {
            label: 'Roles'
        },
        roles: {},
        schema: {
            name: {
                type: 'string',
                required: true
            }
        }
    },
    miids: {
        _id: ids.templates.miids,
        _tp: [/*Add template id*/],
        db: dbName,
        collection: 'm_miids',
        name: 'm_miids',
        options: {
            label: 'Module instances'
        },
        roles: {},
        schema: {
            miid: {
                type: 'string',
                required: true
            }
        }
    }
};

var roles = {
    proxy: {
        _id: ids.roles.proxy,
        _tp: [/*Add template id*/],
        name: 'mono_proxy'
    },
    admin: {
        _id: ids.roles.proxy,
        _tp: [/*Add template id*/],
        name: 'mono_admin'
    },
    user: {
        _id: ids.roles.proxy,
        _tp: [/*Add template id*/],
        name: 'mono_user'
    }
};<commit_msg>renamed role "proxy" to "server"<commit_after>// mono core template ids
var dbName = 'mono';
var ids = {
    templates: {
        applications: '528f78dc197ef1c23714a04d',
        modules: '528f78f1197ef1c23714a04e',
        roles: '528f7902197ef1c23714a04f',
        miids: '52923eb6ea5c6526b8870cde'
    },
    roles: {
        server: '52923d79ea5c6526b8870cdd'
    }
};

// mono core templates
var templates = {
    applications: {
        _id: ids.templates.applications,
        _tp: [/*Add template id*/],
        db: dbName,
        collection: 'm_applications',
        name: 'm_applications',
        options: {
            label: 'Applications'
        },
        roles: {},
        schema: {
            name: {
                type: 'string',
                required: true
            },
            domains: [{
                type: 'string',
                required: true
            }],
            routes: {
                type: 'object',
                required: true
            },
            process: {
                host: {
                    type: 'string',
                    required: true
                },
                // port for http
                http: {
                    type: 'number',
                    required: true
                },
                // port for websockets
                ws: {
                    type: 'number',
                    required: true
                }
            }
        }
    },
    modules: {
        _id: ids.templates.modules,
        _tp: [/*Add template id*/],
        db: dbName,
        collection: 'm_modules',
        name: 'm_modules',
        options: {
            label: 'Modules'
        },
        roles: {},
        schema: {
            name: {
                type: 'string',
                required: true
            }
        }
    },
    roles: {
        _id: ids.templates.roles,
        _tp: [/*Add template id*/],
        db: dbName,
        collection: 'm_roles',
        name: 'm_roles',
        options: {
            label: 'Roles'
        },
        roles: {},
        schema: {
            name: {
                type: 'string',
                required: true
            }
        }
    },
    miids: {
        _id: ids.templates.miids,
        _tp: [/*Add template id*/],
        db: dbName,
        collection: 'm_miids',
        name: 'm_miids',
        options: {
            label: 'Module instances'
        },
        roles: {},
        schema: {
            miid: {
                type: 'string',
                required: true
            }
        }
    }
};

var roles = {
    server: {
        _id: ids.roles.server,
        _tp: [/*Add template id*/],
        name: 'mono_server'
    },
    admin: {
        _id: ids.roles.proxy,
        _tp: [/*Add template id*/],
        name: 'mono_admin'
    },
    user: {
        _id: ids.roles.proxy,
        _tp: [/*Add template id*/],
        name: 'mono_user'
    }
};<|endoftext|>


<commit_before>#!/usr/bin/env node

'use strict';
var log              =  require('npmlog')
  , resolveGitRemote =  require('resolve-git-remote')
  , getConfig        =  require('../lib/get-config')
  , updatePackage    =  require('../lib/update-package')
  , createHook       =  require('../lib/create-testling-hook')
  , testHook         =  require('../lib/test-testling-hook')
  ;

var task = (function () {
  var arg = process.argv[2];
  if (!arg) return 'hook';

  arg = arg.toLowerCase();
  if (arg === 'test' || arg === 'badge') return arg;

  if (arg === "-h" || arg === "--help") {
    return console.log("usage:\n" +
      "run testlingify to add hooks.\n" +
      "run testlingify test to test the hook")
  }

  log.error('testlingify', 'unknown task: ' + arg);
  process.exit(1);
})();

if (task === 'hook') {
  log.info('testlingify', 'Adding testling config to your package and creating testling hook on your github repository');
}
if (task === 'test') {
  log.info('testlingify', 'Testing testling hook on your github repository');
}

resolveGitRemote(function (err, remote) {
  if (err) {
    log.error('testlingify', err);
    log.error('testlingify', 'Sorry, testingify has to be executed from inside a git repository');
    process.exit(1);
  }
  gotRemote(remote);
});

function gotRemote(remote) {
  var ownerRepo = remote.split('/')
    , owner = ownerRepo[0]
    , repo = ownerRepo[1]
    ;

  if (task === 'badge')
    return console.log(
      '[![testling badge](https://ci.testling.com/' + owner + '/' + repo + '.png)]' +
      '(https://ci.testling.com/' + owner + '/' + repo + ')'
    );

  getConfig(function (err, config) {
    if (err) {
      log.error('testlingify', err);
      process.exit(1);
    }
    checkConfig(config);
    gotRemoteAndConfig(config, owner, repo);
  });
}

function gotRemoteAndConfig(config, owner, repo) {
  if (config.github.username !== owner)
    log.warn('testlingify', 'github username found in config: "%s", does not match username of repository: "%s"', config.github.username, owner);

  if (task === 'hook')
    return updatePackage(config, createTestlingHook.bind(null, config, owner, repo));
  if (task === 'test')
    return testTestlingHook(config, owner, repo);

  log.error('testlingify', 'Unkown task: %s. Try "testlingify" or "testlignify test" or "testlingify badge"', task);
}

function createTestlingHook(config, owner, repo) {
  var gh = config.github;
  createHook(gh.username, gh.password, owner, repo, function (err, hook) {
    if (err) {
      log.error('testlingify', 'Encountered error when testling hook for %s/%s as %s', owner, repo, config.github.username);
      return log.error('testlingify', err);
    }

    return hook.created
      ? log.info('testlingify', 'Successfully created testling hook for %s/%s as %s', owner, repo, config.github.username)
      : log.warn('testlingify', 'Did not create testling hook for %s/%s as %s because it already exists', owner, repo, config.github.username);
  });
}

function testTestlingHook(config, owner, repo) {
  var gh = config.github;
  testHook(gh.username, gh.password, owner, repo, function (err, hook) {
    if (err) return log.error('testlingify', err.message);
    if (hook.sent) return log.info('testlingify', hook.message);
    log.warn('testlingify', 'Although no error occurred, a post to your testling hook could not be properly sent');
  });
}

function checkConfig(config) {
  function tellToEditAndExit(problem) {
    log.error('testlingify', problem);
    log.error('testlingify', 'Please edit the testlingify config at %s to correct this.', config.location);
    process.exit(1);
  }

  var github = config.github;
  if (!github) tellToEditAndExit('No github config found!');
  if (!github.username || github.username.length === 0) tellToEditAndExit('github username missing!');
  if (!github.password || github.password.length === 0) tellToEditAndExit('github password missing!');
  if (!config.testling) tellToEditAndExit('testling config missing!');
}
<commit_msg>improving help output and exiting immediately<commit_after>#!/usr/bin/env node

'use strict';
var log              =  require('npmlog')
  , resolveGitRemote =  require('resolve-git-remote')
  , getConfig        =  require('../lib/get-config')
  , updatePackage    =  require('../lib/update-package')
  , createHook       =  require('../lib/create-testling-hook')
  , testHook         =  require('../lib/test-testling-hook')
  ;

var task = (function () {
  var arg = process.argv[2];
  if (!arg) return 'hook';

  arg = arg.toLowerCase();
  if (arg === 'test' || arg === 'badge') return arg;

  if (arg === "-h" || arg === "--help") {
    console.log(
      'usage: testlingify            (adds testling hook to github and testling config to package.json)\n' +
      '       testlingify test       (tests testling github hook on)\n' +
      '       testlingify badge      (prints testling badge)');

    process.exit(0);
  }

  log.error('testlingify', 'unknown task: ' + arg);
  process.exit(1);
})();

if (task === 'hook') {
  log.info('testlingify', 'Adding testling config to your package and creating testling hook on your github repository');
}
if (task === 'test') {
  log.info('testlingify', 'Testing testling hook on your github repository');
}

resolveGitRemote(function (err, remote) {
  if (err) {
    log.error('testlingify', err);
    log.error('testlingify', 'Sorry, testingify has to be executed from inside a git repository');
    process.exit(1);
  }
  gotRemote(remote);
});

function gotRemote(remote) {
  var ownerRepo = remote.split('/')
    , owner = ownerRepo[0]
    , repo = ownerRepo[1]
    ;

  if (task === 'badge')
    return console.log(
      '[![testling badge](https://ci.testling.com/' + owner + '/' + repo + '.png)]' +
      '(https://ci.testling.com/' + owner + '/' + repo + ')'
    );

  getConfig(function (err, config) {
    if (err) {
      log.error('testlingify', err);
      process.exit(1);
    }
    checkConfig(config);
    gotRemoteAndConfig(config, owner, repo);
  });
}

function gotRemoteAndConfig(config, owner, repo) {
  if (config.github.username !== owner)
    log.warn('testlingify', 'github username found in config: "%s", does not match username of repository: "%s"', config.github.username, owner);

  if (task === 'hook')
    return updatePackage(config, createTestlingHook.bind(null, config, owner, repo));
  if (task === 'test')
    return testTestlingHook(config, owner, repo);

  log.error('testlingify', 'Unkown task: %s. Try "testlingify" or "testlignify test" or "testlingify badge"', task);
}

function createTestlingHook(config, owner, repo) {
  var gh = config.github;
  createHook(gh.username, gh.password, owner, repo, function (err, hook) {
    if (err) {
      log.error('testlingify', 'Encountered error when testling hook for %s/%s as %s', owner, repo, config.github.username);
      return log.error('testlingify', err);
    }

    return hook.created
      ? log.info('testlingify', 'Successfully created testling hook for %s/%s as %s', owner, repo, config.github.username)
      : log.warn('testlingify', 'Did not create testling hook for %s/%s as %s because it already exists', owner, repo, config.github.username);
  });
}

function testTestlingHook(config, owner, repo) {
  var gh = config.github;
  testHook(gh.username, gh.password, owner, repo, function (err, hook) {
    if (err) return log.error('testlingify', err.message);
    if (hook.sent) return log.info('testlingify', hook.message);
    log.warn('testlingify', 'Although no error occurred, a post to your testling hook could not be properly sent');
  });
}

function checkConfig(config) {
  function tellToEditAndExit(problem) {
    log.error('testlingify', problem);
    log.error('testlingify', 'Please edit the testlingify config at %s to correct this.', config.location);
    process.exit(1);
  }

  var github = config.github;
  if (!github) tellToEditAndExit('No github config found!');
  if (!github.username || github.username.length === 0) tellToEditAndExit('github username missing!');
  if (!github.password || github.password.length === 0) tellToEditAndExit('github password missing!');
  if (!config.testling) tellToEditAndExit('testling config missing!');
}
<|endoftext|>


<commit_before>jQuery(document).ready(function($) {
    hashtagger(window.location.hash, '.firstactive');
    $(window).bind('hashchange', function() {
        hashtagger(window.location.hash);
    });
    pooraccordion();
});

function pooraccordion(animate) {
    animate = typeof animate !== 'undefined' ? animate : true;
    jQuery('.poor-accordion').hide().prev()
        .css('cursor', 'pointer')
        .click(function() {
            if (true == animate) {
                jQuery(this).next().slideToggle();
            } else {
                jQuery(this).next().toggle();
            }
        }
    );
}

function hashtagger (hash, exception) {
    //hashspliter: prefill "GET parameter"-like value string to inputs
    var gets = hash.slice('1').split('&') ;
    if (gets.length != 1) {
        for (var i = 0; i < gets.length; i++) {
            var getkeyparam = gets[i].split('=')
            $('#' + getkeyparam[0]).val( getkeyparam[1] )
        }
        return
    }
    // poor mans tab
    jQuery('.hashtagger > div, .hashtabber').not( exception ).hide();
    jQuery(hash).show();
    jQuery(hash).click(); // to use with jQuery UI Accordion etc

    // special actions
    switch (hash) {
        case "#alert": // example
            alert('fork me at github.com/klml/usefulclassroomphrases')
        break;
        default:
        case "#":

        break;
    }

}
<commit_msg>Bugfixes<commit_after>jQuery(document).ready(function($) {
    hashtagger(window.location.hash, '.firstactive');
    $(window).bind('hashchange', function() {
        hashtagger(window.location.hash);
    });
    pooraccordion();
});

function pooraccordion(animate) {
    animate = typeof animate !== 'undefined' ? animate : true;
    jQuery('.poor-accordion').hide().prev()
        .css('cursor', 'pointer')
        .click(function() {
            if (true == animate) {
                jQuery(this).next().slideToggle();
            } else {
                jQuery(this).next().toggle();
            }
        }
    );
}

function hashtagger (hash, exception) {
    //hashspliter: prefill "GET parameter"-like value string to inputs
    var gets = hash.slice('1').split('&');
    if (gets.indexOf('=') > -1) {
        for (var i = 0; i < gets.length; i++) {
            var getkeyparam = gets[i].split('=');
            $('#' + getkeyparam[0]).val( getkeyparam[1] );
        }
    } else {
        // poor mans tab
        jQuery('.hashtagger > div, .hashtabber').not( exception ).hide();
        jQuery(hash).show();
        jQuery(hash).click(); // to use with jQuery UI Accordion etc

        // special actions
        switch (hash) {
            case "#alert": // example
                alert('fork me at github.com/klml/usefulclassroomphrases');
            break;
            default:
            case "#":

            break;
        }
    }
}
<|endoftext|>