<commit_before>
import './field_group';
import '../dom';

frappe.provide('frappe.ui');

window.cur_dialog = null;

frappe.ui.open_dialogs = [];

frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup {
	constructor(opts) {
		super();
		this.display = false;
		this.is_dialog = true;

		$.extend(this, { animate: true, size: null }, opts);
		this.make();
	}

	make() {
		this.$wrapper = frappe.get_modal("", "");

		if(this.static) {
			this.$wrapper.modal({
				backdrop: 'static',
				keyboard: false
			});
			this.get_close_btn().hide();
		}

		this.wrapper = this.$wrapper.find('.modal-dialog')
			.get(0);
		if ( this.size == "small" )
			$(this.wrapper).addClass("modal-sm");
		else if ( this.size == "large" )
			$(this.wrapper).addClass("modal-lg");

		this.make_head();
		this.modal_body = this.$wrapper.find(".modal-body");
		this.$body = $('

').appendTo(this.modal_body);
		this.body = this.$body.get(0);
		this.$message = $('

').appendTo(this.modal_body);
		this.header = this.$wrapper.find(".modal-header");

		// make fields (if any)
		super.make();

		// show footer
		this.action = this.action || { primary: { }, secondary: { } };
		if(this.primary_action || (this.action.primary && this.action.primary.onsubmit)) {
			this.set_primary_action(this.primary_action_label || this.action.primary.label || __("Submit"),
				this.primary_action || this.action.primary.onsubmit);
		}

		if(this.secondary_action) {
			this.set_secondary_action(this.secondary_action);
		}

		if (this.secondary_action_label || (this.action.secondary && this.action.secondary.label)) {
			this.get_close_btn().html(this.secondary_action_label || this.action.secondary.label);
		}

		var me = this;
		this.$wrapper
			.on("hide.bs.modal", function() {
				me.display = false;
				me.secondary_action && me.secondary_action();

				if(frappe.ui.open_dialogs[frappe.ui.open_dialogs.length-1]===me) {
					frappe.ui.open_dialogs.pop();
					if(frappe.ui.open_dialogs.length) {
						window.cur_dialog = frappe.ui.open_dialogs[frappe.ui.open_dialogs.length-1];
					} else {
						window.cur_dialog = null;
					}
				}
				me.onhide && me.onhide();
				me.on_hide && me.on_hide();
			})
			.on("shown.bs.modal", function() {
				// focus on first input
				me.display = true;
				window.cur_dialog = me;
				frappe.ui.open_dialogs.push(me);
				me.focus_on_first_input();
				me.on_page_show && me.on_page_show();
			})
			.on('scroll', function() {
				var $input = $('input:focus');
				if($input.length && ['Date', 'Datetime',
					'Time'].includes($input.attr('data-fieldtype'))) {
					$input.blur();
				}
			});

	}

	get_primary_btn() {
		return this.$wrapper.find(".modal-header .btn-primary");
	}

	set_message(text) {
		this.$message.removeClass('hide');
		this.$body.addClass('hide');
		this.$message.text(text);
	}

	clear_message() {
		this.$message.addClass('hide');
		this.$body.removeClass('hide');
	}

	set_primary_action(label, click) {
		this.has_primary_action = true;
		var me = this;
		return this.get_primary_btn()
			.removeClass("hide")
			.html(label)
			.click(function() {
				me.primary_action_fulfilled = true;
				// get values and send it
				// as first parameter to click callback
				// if no values then return
				var values = me.get_values();
				if(!values) return;
				click && click.apply(me, [values]);
			});
	}

	set_secondary_action(click) {
		this.get_close_btn().on('click', click);
	}

	disable_primary_action() {
		this.get_primary_btn().addClass('disabled');
	}
	enable_primary_action() {
		this.get_primary_btn().removeClass('disabled');
	}
	make_head() {
		this.set_title(this.title);
	}
	set_title(t) {
		this.$wrapper.find(".modal-title").html(t);
	}
	show() {
		// show it
		if ( this.animate ) {
			this.$wrapper.addClass('fade');
		} else {
			this.$wrapper.removeClass('fade');
		}
		this.$wrapper.modal("show");
		this.primary_action_fulfilled = false;
		this.is_visible = true;
		return this;
	}
	hide() {
		this.$wrapper.modal("hide");
		this.is_visible = false;
	}
	get_close_btn() {
		return this.$wrapper.find(".btn-modal-close");
	}
	no_cancel() {
		this.get_close_btn().toggle(false);
	}
	cancel() {
		this.get_close_btn().trigger("click");
	}
};

<commit_msg>fix(dialog): clear message before show incase the dialog is being reused<commit_after>
import './field_group';
import '../dom';

frappe.provide('frappe.ui');

window.cur_dialog = null;

frappe.ui.open_dialogs = [];

frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup {
	constructor(opts) {
		super();
		this.display = false;
		this.is_dialog = true;

		$.extend(this, { animate: true, size: null }, opts);
		this.make();
	}

	make() {
		this.$wrapper = frappe.get_modal("", "");

		if(this.static) {
			this.$wrapper.modal({
				backdrop: 'static',
				keyboard: false
			});
			this.get_close_btn().hide();
		}

		this.wrapper = this.$wrapper.find('.modal-dialog')
			.get(0);
		if ( this.size == "small" )
			$(this.wrapper).addClass("modal-sm");
		else if ( this.size == "large" )
			$(this.wrapper).addClass("modal-lg");

		this.make_head();
		this.modal_body = this.$wrapper.find(".modal-body");
		this.$body = $('

').appendTo(this.modal_body);
		this.body = this.$body.get(0);
		this.$message = $('

').appendTo(this.modal_body);
		this.header = this.$wrapper.find(".modal-header");

		// make fields (if any)
		super.make();

		// show footer
		this.action = this.action || { primary: { }, secondary: { } };
		if(this.primary_action || (this.action.primary && this.action.primary.onsubmit)) {
			this.set_primary_action(this.primary_action_label || this.action.primary.label || __("Submit"),
				this.primary_action || this.action.primary.onsubmit);
		}

		if(this.secondary_action) {
			this.set_secondary_action(this.secondary_action);
		}

		if (this.secondary_action_label || (this.action.secondary && this.action.secondary.label)) {
			this.get_close_btn().html(this.secondary_action_label || this.action.secondary.label);
		}

		var me = this;
		this.$wrapper
			.on("hide.bs.modal", function() {
				me.display = false;
				me.secondary_action && me.secondary_action();

				if(frappe.ui.open_dialogs[frappe.ui.open_dialogs.length-1]===me) {
					frappe.ui.open_dialogs.pop();
					if(frappe.ui.open_dialogs.length) {
						window.cur_dialog = frappe.ui.open_dialogs[frappe.ui.open_dialogs.length-1];
					} else {
						window.cur_dialog = null;
					}
				}
				me.onhide && me.onhide();
				me.on_hide && me.on_hide();
			})
			.on("shown.bs.modal", function() {
				// focus on first input
				me.display = true;
				window.cur_dialog = me;
				frappe.ui.open_dialogs.push(me);
				me.focus_on_first_input();
				me.on_page_show && me.on_page_show();
			})
			.on('scroll', function() {
				var $input = $('input:focus');
				if($input.length && ['Date', 'Datetime',
					'Time'].includes($input.attr('data-fieldtype'))) {
					$input.blur();
				}
			});

	}

	get_primary_btn() {
		return this.$wrapper.find(".modal-header .btn-primary");
	}

	set_message(text) {
		this.$message.removeClass('hide');
		this.$body.addClass('hide');
		this.$message.text(text);
	}

	clear_message() {
		this.$message.addClass('hide');
		this.$body.removeClass('hide');
	}

	set_primary_action(label, click) {
		this.has_primary_action = true;
		var me = this;
		return this.get_primary_btn()
			.removeClass("hide")
			.html(label)
			.click(function() {
				me.primary_action_fulfilled = true;
				// get values and send it
				// as first parameter to click callback
				// if no values then return
				var values = me.get_values();
				if(!values) return;
				click && click.apply(me, [values]);
			});
	}

	set_secondary_action(click) {
		this.get_close_btn().on('click', click);
	}

	disable_primary_action() {
		this.get_primary_btn().addClass('disabled');
	}
	enable_primary_action() {
		this.get_primary_btn().removeClass('disabled');
	}
	make_head() {
		this.set_title(this.title);
	}
	set_title(t) {
		this.$wrapper.find(".modal-title").html(t);
	}
	show() {
		// show it
		if ( this.animate ) {
			this.$wrapper.addClass('fade');
		} else {
			this.$wrapper.removeClass('fade');
		}
		this.$wrapper.modal("show");

		// clear any message
		this.clear_message();

		this.primary_action_fulfilled = false;
		this.is_visible = true;
		return this;
	}
	hide() {
		this.$wrapper.modal("hide");
		this.is_visible = false;
	}
	get_close_btn() {
		return this.$wrapper.find(".btn-modal-close");
	}
	no_cancel() {
		this.get_close_btn().toggle(false);
	}
	cancel() {
		this.get_close_btn().trigger("click");
	}
};

<|endoftext|>


<commit_before>// Description:
//   Control the LED strip below our office couch
// Configuration:
//   OPENFAAS_URL,
// Commands
//   hubot couch on - Turn on the LED strip
//   hubot couch off - Turn off the LED strip
//   hubot couch lock - Lock the power state of the LED strip so it cannot be changed by member presence
//   hubot couch unlock - Unlock the power state of the LED strip so it can be changed by member presence
//   hubot couch red|green|yellow|blue|magenta|cyan - Change the color of the LED strip

const _ = require('lodash');
const fetch = require('node-fetch');
const openFaas = require('../lib/openfaas');

function sendCommand(command, color = null) {
  payload = {
    command
  };
  if (color !== null) {
    payload['color'] = color;
  }

  return openFaas('office-couch-api', {
    method: 'POST',
    body: JSON.stringify(payload)
  }).then(response => {
    return;
  });
}

module.exports = robot => {
  robot.respond(/couch off/i, msg => {
    const send = msg.send.bind(msg);
    sendCommand('power_off').catch(error => send(error.message));
  });
  robot.respond(/couch on/i, msg => {
    const send = msg.send.bind(msg);
    sendCommand('power_on').catch(error => send(error.message));
  });
  robot.respond(/couch lock/i, msg => {
    const send = msg.send.bind(msg);
    sendCommand('power_lock').catch(error => send(error.message));
  });
  robot.respond(/couch unlock/i, msg => {
    const send = msg.send.bind(msg);
    sendCommand('power_lock').catch(error => send(error.message));
  });

  robot.respond(/couch (red|green|yellow|blue|magenta|cyan)/i, msg => {
    const send = msg.send.bind(msg);
    const color = msg.match[1].trim();
    sendCommand('set_color', color).catch(error => send(error.message));
  });
};
<commit_msg>Use correct API command to unlock power state for couch<commit_after>// Description:
//   Control the LED strip below our office couch
// Configuration:
//   OPENFAAS_URL,
// Commands
//   hubot couch on - Turn on the LED strip
//   hubot couch off - Turn off the LED strip
//   hubot couch lock - Lock the power state of the LED strip so it cannot be changed by member presence
//   hubot couch unlock - Unlock the power state of the LED strip so it can be changed by member presence
//   hubot couch red|green|yellow|blue|magenta|cyan - Change the color of the LED strip

const _ = require('lodash');
const fetch = require('node-fetch');
const openFaas = require('../lib/openfaas');

function sendCommand(command, color = null) {
  payload = {
    command
  };
  if (color !== null) {
    payload['color'] = color;
  }

  return openFaas('office-couch-api', {
    method: 'POST',
    body: JSON.stringify(payload)
  }).then(response => {
    return;
  });
}

module.exports = robot => {
  robot.respond(/couch off/i, msg => {
    const send = msg.send.bind(msg);
    sendCommand('power_off').catch(error => send(error.message));
  });
  robot.respond(/couch on/i, msg => {
    const send = msg.send.bind(msg);
    sendCommand('power_on').catch(error => send(error.message));
  });
  robot.respond(/couch lock/i, msg => {
    const send = msg.send.bind(msg);
    sendCommand('power_lock').catch(error => send(error.message));
  });
  robot.respond(/couch unlock/i, msg => {
    const send = msg.send.bind(msg);
    sendCommand('power_unlock').catch(error => send(error.message));
  });

  robot.respond(/couch (red|green|yellow|blue|magenta|cyan)/i, msg => {
    const send = msg.send.bind(msg);
    const color = msg.match[1].trim();
    sendCommand('set_color', color).catch(error => send(error.message));
  });
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import unionClassNames from 'union-class-names';

// Get a component's display name
const getDisplayName = (WrappedComponent) => {
  const component = WrappedComponent.WrappedComponent || WrappedComponent;
  return component.displayName || component.name || 'Component';
};

const findParentNode = (node, filter) => {
  if (!node) return null;
  return node.parentElement && filter(node.parentElement)
    ? node.parentElement
    : findParentNode(node.parentElement, filter);
};

export default ({ theme, store }) => (WrappedComponent) => class BlockFocusDecorator extends Component {

  static displayName = `BlockFocus(${getDisplayName(WrappedComponent)})`;
  static WrappedComponent = WrappedComponent.WrappedComponent || WrappedComponent;

  componentDidMount() {
    store.addType(this.props.block.type);
    this.componentDidUpdate();
  }

  componentWillUpdate() {
    document.removeEventListener('keydown', this.releaseOnArrowKey);
    if (this.ReactRoot) {
      this.ReactRoot.removeEventListener('mousedown', this.releaseOnMouseDown);
    }
  }

  componentDidUpdate() {
    // eslint-disable-next-line react/no-find-dom-node
    this.DOMNode = ReactDOM.findDOMNode(this);
    this.ReactRoot = document.querySelector('[data-reactroot]');
    const { pluginEditor, isFocused } = this.props.blockProps;
    const { getReadOnly } = pluginEditor;
    if (!getReadOnly()) {
      document.addEventListener('keydown', this.releaseOnArrowKey);
    }

    if (this.DOMNode && !getReadOnly() && isFocused && this.ReactRoot) {
      this.ReactRoot.addEventListener('mousedown', this.releaseOnMouseDown);
    }
  }

  componentWillUnmount() {
    const { isFocused } = this.props.blockProps;
    this.componentWillUpdate();
    if (isFocused) {
      this.unsetFocus();
    }
  }

  releaseOnArrowKey = (event) => {
    if (event.keyCode === 38) {
      this.props.blockProps.unsetFocus('up', event);
    } else if (event.keyCode === 40) {
      this.props.blockProps.unsetFocus('down', event);
    } else if (event.keyCode === 8) {
      // TODO fix backspace for removing the block
      this.props.blockProps.unsetFocus('down', event);
      this.props.blockProps.removeBlock();
    }
  }

  releaseOnMouseDown = () => {
    if (!findParentNode(event.target, (x) => x === this.DOMNode)) {
      this.props.blockProps.unsetFocus();
    }
  }

  onClick = () => {
    const { isFocused } = this.props.blockProps;
    if (isFocused) return;
    this.props.blockProps.setFocus();
  };

  render() {
    const { blockProps, className } = this.props;
    const { isFocused } = blockProps;
    const combinedClassName = isFocused ? unionClassNames(className, theme.focused) : className;
    return (
      <WrappedComponent
        {...this.props}
        onClick={this.onClick}
        className={combinedClassName}
      />
    );
  }
};
<commit_msg>further focus plugin cleanup<commit_after>import React, { Component } from 'react';
import unionClassNames from 'union-class-names';

// Get a component's display name
const getDisplayName = (WrappedComponent) => {
  const component = WrappedComponent.WrappedComponent || WrappedComponent;
  return component.displayName || component.name || 'Component';
};

// TODO remove if not necessary
// const findParentNode = (node, filter) => {
//   if (!node) return null;
//   return node.parentElement && filter(node.parentElement)
//     ? node.parentElement
//     : findParentNode(node.parentElement, filter);
// };

export default ({ theme, store }) => (WrappedComponent) => class BlockFocusDecorator extends Component {

  static displayName = `BlockFocus(${getDisplayName(WrappedComponent)})`;
  static WrappedComponent = WrappedComponent.WrappedComponent || WrappedComponent;

  componentDidMount() {
    store.addType(this.props.block.type);
    this.componentDidUpdate();
  }

  componentWillUpdate() {
    document.removeEventListener('keydown', this.releaseOnKeyDown);
    document.removeEventListener('click', this.releaseOnClick);
  }

  componentDidUpdate() {
    const { pluginEditor, isFocused } = this.props.blockProps;
    const { getReadOnly } = pluginEditor;
    if (!getReadOnly()) {
      document.addEventListener('keydown', this.releaseOnKeyDown);
      if (isFocused) {
        document.addEventListener('click', this.releaseOnClick);
      }
    }
  }

  componentWillUnmount() {
    const { isFocused } = this.props.blockProps;
    this.componentWillUpdate();
    if (isFocused) {
      this.props.blockProps.unsetFocus();
    }
  }

  releaseOnKeyDown = (event) => {
    if (event.keyCode === 38) {
      this.props.blockProps.unsetFocus('up', event);
    } else if (event.keyCode === 40) {
      this.props.blockProps.unsetFocus('down', event);
    } else if (event.keyCode === 8) {
      // TODO fix backspace for removing the block
      this.props.blockProps.unsetFocus('down', event);
      this.props.blockProps.removeBlock();
    }
  }

  releaseOnClick = () => {
    // TODO don't release in case it's inside this component
    this.props.blockProps.unsetFocus();
  }

  onClick = () => {
    const { isFocused } = this.props.blockProps;
    if (isFocused) return;
    this.props.blockProps.setFocus();
  };

  render() {
    const { blockProps, className } = this.props;
    const { isFocused } = blockProps;
    const combinedClassName = isFocused ? unionClassNames(className, theme.focused) : className;
    return (
      <WrappedComponent
        {...this.props}
        onClick={this.onClick}
        className={combinedClassName}
      />
    );
  }
};
<|endoftext|>


<commit_before>//
// Letschatbro Chat Server
//

var _ = require('underscore');
var hash = require('node_hash');
var moment = require('moment');

var parseCookie = require('connect').utils.parseCookie;
var Session = require('connect').middleware.session.Session;

var models = require('./models/models.js');

var ChatServer = function (app, sessionStore) {

    var self = this;

    // Set moment date formatting
    moment.calendar.sameDay = 'LT';

    this.rooms = {};

    this.getUserList = function(room) {
        var users = {};
        var clients = self.io.sockets.clients(room);
        clients.forEach(function(client) {
            client.get('profile', function(err, profile)  {
                if (err) {
                    // No profile?
                    return;
                }
                users[profile.cid] = profile;
            });
        });
        return users;
    };

    this.listen = function () {

        //
        // Setup
        //
        this.io = require('socket.io').listen(app);
        this.io.set('log level', 0);
        this.io.set('authorization', function (data, accept) {
            // This function, courtesy of danielbaulig.de, will parse out session
            // info for connections.
            if (data.headers.cookie) {
                // if there is, parse the cookie
                data.cookie = parseCookie(data.headers.cookie);
                data.sessionID = data.cookie['express.sid'];
                data.sessionStore = sessionStore;
                sessionStore.get(data.sessionID, function (err, session) {
                    if (err || !session) {
                        accept('Error with Sessions', false);
                    } else {
                        data.session = new Session(data, session);
                        accept(null, true);
                    }
                });
            } else {
                // if there isn't, turn down the connection
                return accept('No cookie transmitted.', false);
            }
        });

        this.io.sockets.on('connection', function(client) {

            var hs = client.handshake;
            var userData = hs.session.user;

            var sessionTouchInterval = setInterval(function () {
              hs.session.reload( function () {
                hs.session.touch().save();
              });
            }, 60 * 1000);

            //
            // Assign Client Profile
            //
            client.set('profile', {
                cid: hash.md5(client.id),
                id: userData._id,
                email: userData.email,
                firstName: userData.firstName,
                lastName: userData.lastName,
                displayName: userData.displayName,
                joined: userData.joined,
                avatar: hash.md5(userData.email)
            });

            //
            // Message History
            //
            client.on('room:messages:get', function(query) {
                var today = new Date()
                query.from = query.from || new Date(today).setDate(today.getDate() - 7)
                query.room = query.room || '';
                models.message.where('posted').gte(query.from)
                    .where('room').equals(query.room)
                    .sort({ posted: -1 }).populate('owner')
                    .limit(150)
                    .exec(function (err, docs) {
                        if (err) {
                            // Couldn't get message or something
                            return;
                        }
                        var messages = [];
                        if (docs) {
                            docs.forEach(function (message) {
                                messages.push({
                                    room: message.room,
                                    id: message._id,
                                    owner: message.owner._id,
                                    avatar: hash.md5(message.owner.email),
                                    name: message.owner.displayName,
                                    text: message.text,
                                    posted: message.posted,
                                    time: moment(message.posted).calendar()
                                });
                            });
                        }
                        messages.reverse();
                        client.emit('room:messages:new', messages);
                });
            });

            //
            // New Message
            //
            client.on('room:messages:new', function(data) {
                var message = new models.message({
                    room: data.room,
                    owner: userData._id,
                    text: data.text
                });
                message.save(function(err, message) {
                    if (err) {
                        // Shit we're on fire!
                        return;
                    }
                    var outgoingMessage = {
                        id: message._id,
                        owner: message.owner,
                        avatar: hash.md5(userData.email),
                        name: userData.displayName,
                        text: message.text,
                        posted: message.posted,
                        time: moment(message.posted).calendar(),
                        room: message.room
                    }
                    self.io.sockets.in(message.room).emit('room:messages:new', outgoingMessage);
                });
            });

            //
            // Join Room
            //
            client.on('room:join', function(id, fn) {
                models.room.findById(id, function(err, room) {
                    if (err) {
                        // Oh shit
                        return;
                    }
                    if (!room) {
                        // No room bro
                        return;
                    }
                    client.join(id);
                    // Send back Room meta to client
                    fn({
                        id: room._id,
                        name: room.name,
                        description: room.description
                    });
                    // Hey everyone, look who it is
                    client.get('profile', function(err, profile) {
                        if (err) {
                            // Oh shit
                            return;
                        }
                        var user = {
                            room: id,
                            id: hash.md5(client.id),
                            avatar: profile.avatar,
                            name: profile.displayName,
                            safeName: profile.displayName.replace(/\W/g, '')
                        }
                        self.io.sockets.in(id).emit('room:users:new', user);
                        self.io.sockets.emit('rooms:users:new', user)
                    });
                });
            });

            //
            // Get Room Users
            //
            client.on('room:users:get', function(query) {
                _.each(self.io.sockets.clients(query.room), function(user) {
                    user.get('profile', function(err, profile) {
                        if (err) {
                            // What the what
                            return;
                        }
                        client.emit('room:users:new', {
                            room: query.room,
                            id: hash.md5(user.id),
                            avatar: profile.avatar,
                            name: profile.displayName,
                            safeName: profile.displayName.replace(/\W/g, '')
                        });
                    });
                });

            });

            //
            // Create Room
            //
            client.on('rooms:create', function(room, fn) {
              var newroom = new models.room({
                name: room.name,
                description: room.description,
                owner: userData._id
              });
              newroom.save(function (err, room) {
                if (err) {
                  // We derped somehow
                  return;
                }
                self.io.sockets.emit('rooms:new', {
                    id: room._id,
                    name: room.name,
                    description: room.description,
                    owner: room.owner
                });
              });
            });

            //
            // Roomlist request
            //
            client.on('rooms:get', function (query) {
                models.room.find().exec(function(err, rooms) {
                    if (err) {
                        // Couldn't get rooms
                        return;
                    }
                    _.each(rooms, function(room) {
                        client.emit('rooms:new', {
                            id: room._id,
                            name: room.name,
                            description: room.description,
                            owner: room.owner
                        });
                         _.each(self.io.sockets.clients(room._id), function(user) {
                            user.get('profile', function(err, profile) {
                                if (err) {
                                    // What the what
                                    return;
                                }
                                client.emit('rooms:users:new', {
                                    room: room._id,
                                    id: hash.md5(user.id),
                                    avatar: profile.avatar,
                                    name: profile.displayName,
                                    safeName: profile.displayName.replace(/\W/g, '')
                                });
                            });
                        });
                    });
                });
            });

            //
            // Leave Room
            //
            client.on('room:leave', function(room) {
                var user = {
                    id: hash.md5(client.id),
                    room: room
                }
                self.io.sockets.in(room).emit('room:users:leave', user);
                self.io.sockets.emit('rooms:users:leave', user)
            });

            //
            // Delete Room
            //
            client.on('room:delete', function(id) {
                models.room.findOne({
                    _id: id
                }).exec(function (err, room) {
                    if (err) {
                        // Oh damn
                        return;
                    }
                    if (!room) {
                        // What happened to our room?
                        return;
                    }
                    self.io.sockets.in(id).emit('room:remove', id);
                    self.io.sockets.emit('rooms:remove', id)
                    room.remove();
                });
            });

            //
            // Disconnect
            //
            client.on('disconnect', function() {
                var rooms = self.io.sockets.manager.roomClients[client.id];
                _.each(rooms, function(status, room) {
                    room = room.replace('/', '');
                    var user = {
                        id: hash.md5(client.id),
                        room: room
                    }
                    self.io.sockets.in(room).emit('room:users:leave', user);
                    self.io.sockets.emit('rooms:users:leave', user)
                });
              clearInterval(sessionTouchInterval)
            });

        });

    };

    this.start = function () {
        // Setup listeners
        this.listen();
		return this;
    };

};

module.exports = ChatServer;
<commit_msg>Prevent invalid sessions from crashing server<commit_after>//
// Letschatbro Chat Server
//

var _ = require('underscore');
var hash = require('node_hash');
var moment = require('moment');

var parseCookie = require('connect').utils.parseCookie;
var Session = require('connect').middleware.session.Session;

var models = require('./models/models.js');

var ChatServer = function (app, sessionStore) {

    var self = this;

    // Set moment date formatting
    moment.calendar.sameDay = 'LT';

    this.rooms = {};

    this.getUserList = function(room) {
        var users = {};
        var clients = self.io.sockets.clients(room);
        clients.forEach(function(client) {
            client.get('profile', function(err, profile)  {
                if (err) {
                    // No profile?
                    return;
                }
                users[profile.cid] = profile;
            });
        });
        return users;
    };

    this.listen = function () {

        //
        // Setup
        //
        this.io = require('socket.io').listen(app);
        this.io.set('log level', 0);
        this.io.set('authorization', function (data, accept) {
            // This function, courtesy of danielbaulig.de, will parse out session
            // info for connections.
            if (data.headers.cookie) {
                // if there is, parse the cookie
                data.cookie = parseCookie(data.headers.cookie);
                data.sessionID = data.cookie['express.sid'];
                data.sessionStore = sessionStore;
                sessionStore.get(data.sessionID, function (err, session) {
                    if (err || !session) {
                        accept('Error with Sessions', false);
                    } else {
                        data.session = new Session(data, session);
                        accept(null, true);
                    }
                });
            } else {
                // if there isn't, turn down the connection
                return accept('No cookie transmitted.', false);
            }
        });

        this.io.sockets.on('connection', function(client) {

            var hs = client.handshake;
            var userData = hs.session.user;

            if (!userData || !hs) {
                //
                // Sessions be messin' up bro
                //
                return;
            }

            var sessionTouchInterval = setInterval(function () {
              hs.session.reload( function () {
                hs.session.touch().save();
              });
            }, 60 * 1000);

            //
            // Assign Client Profile
            //
            client.set('profile', {
                cid: hash.md5(client.id),
                id: userData._id,
                email: userData.email,
                firstName: userData.firstName,
                lastName: userData.lastName,
                displayName: userData.displayName,
                joined: userData.joined,
                avatar: hash.md5(userData.email)
            });

            //
            // Message History
            //
            client.on('room:messages:get', function(query) {
                var today = new Date()
                query.from = query.from || new Date(today).setDate(today.getDate() - 7)
                query.room = query.room || '';
                models.message.where('posted').gte(query.from)
                    .where('room').equals(query.room)
                    .sort({ posted: -1 }).populate('owner')
                    .limit(150)
                    .exec(function (err, docs) {
                        if (err) {
                            // Couldn't get message or something
                            return;
                        }
                        var messages = [];
                        if (docs) {
                            docs.forEach(function (message) {
                                messages.push({
                                    room: message.room,
                                    id: message._id,
                                    owner: message.owner._id,
                                    avatar: hash.md5(message.owner.email),
                                    name: message.owner.displayName,
                                    text: message.text,
                                    posted: message.posted,
                                    time: moment(message.posted).calendar()
                                });
                            });
                        }
                        messages.reverse();
                        client.emit('room:messages:new', messages);
                });
            });

            //
            // New Message
            //
            client.on('room:messages:new', function(data) {
                var message = new models.message({
                    room: data.room,
                    owner: userData._id,
                    text: data.text
                });
                message.save(function(err, message) {
                    if (err) {
                        // Shit we're on fire!
                        return;
                    }
                    var outgoingMessage = {
                        id: message._id,
                        owner: message.owner,
                        avatar: hash.md5(userData.email),
                        name: userData.displayName,
                        text: message.text,
                        posted: message.posted,
                        time: moment(message.posted).calendar(),
                        room: message.room
                    }
                    self.io.sockets.in(message.room).emit('room:messages:new', outgoingMessage);
                });
            });

            //
            // Join Room
            //
            client.on('room:join', function(id, fn) {
                models.room.findById(id, function(err, room) {
                    if (err) {
                        // Oh shit
                        return;
                    }
                    if (!room) {
                        // No room bro
                        return;
                    }
                    client.join(id);
                    // Send back Room meta to client
                    fn({
                        id: room._id,
                        name: room.name,
                        description: room.description
                    });
                    // Hey everyone, look who it is
                    client.get('profile', function(err, profile) {
                        if (err) {
                            // Oh shit
                            return;
                        }
                        var user = {
                            room: id,
                            id: hash.md5(client.id),
                            avatar: profile.avatar,
                            name: profile.displayName,
                            safeName: profile.displayName.replace(/\W/g, '')
                        }
                        self.io.sockets.in(id).emit('room:users:new', user);
                        self.io.sockets.emit('rooms:users:new', user)
                    });
                });
            });

            //
            // Get Room Users
            //
            client.on('room:users:get', function(query) {
                _.each(self.io.sockets.clients(query.room), function(user) {
                    user.get('profile', function(err, profile) {
                        if (err) {
                            // What the what
                            return;
                        }
                        client.emit('room:users:new', {
                            room: query.room,
                            id: hash.md5(user.id),
                            avatar: profile.avatar,
                            name: profile.displayName,
                            safeName: profile.displayName.replace(/\W/g, '')
                        });
                    });
                });

            });

            //
            // Create Room
            //
            client.on('rooms:create', function(room, fn) {
              var newroom = new models.room({
                name: room.name,
                description: room.description,
                owner: userData._id
              });
              newroom.save(function (err, room) {
                if (err) {
                  // We derped somehow
                  return;
                }
                self.io.sockets.emit('rooms:new', {
                    id: room._id,
                    name: room.name,
                    description: room.description,
                    owner: room.owner
                });
              });
            });

            //
            // Roomlist request
            //
            client.on('rooms:get', function (query) {
                models.room.find().exec(function(err, rooms) {
                    if (err) {
                        // Couldn't get rooms
                        return;
                    }
                    _.each(rooms, function(room) {
                        client.emit('rooms:new', {
                            id: room._id,
                            name: room.name,
                            description: room.description,
                            owner: room.owner
                        });
                         _.each(self.io.sockets.clients(room._id), function(user) {
                            user.get('profile', function(err, profile) {
                                if (err) {
                                    // What the what
                                    return;
                                }
                                client.emit('rooms:users:new', {
                                    room: room._id,
                                    id: hash.md5(user.id),
                                    avatar: profile.avatar,
                                    name: profile.displayName,
                                    safeName: profile.displayName.replace(/\W/g, '')
                                });
                            });
                        });
                    });
                });
            });

            //
            // Leave Room
            //
            client.on('room:leave', function(room) {
                var user = {
                    id: hash.md5(client.id),
                    room: room
                }
                self.io.sockets.in(room).emit('room:users:leave', user);
                self.io.sockets.emit('rooms:users:leave', user)
            });

            //
            // Delete Room
            //
            client.on('room:delete', function(id) {
                models.room.findOne({
                    _id: id
                }).exec(function (err, room) {
                    if (err) {
                        // Oh damn
                        return;
                    }
                    if (!room) {
                        // What happened to our room?
                        return;
                    }
                    self.io.sockets.in(id).emit('room:remove', id);
                    self.io.sockets.emit('rooms:remove', id)
                    room.remove();
                });
            });

            //
            // Disconnect
            //
            client.on('disconnect', function() {
                var rooms = self.io.sockets.manager.roomClients[client.id];
                _.each(rooms, function(status, room) {
                    room = room.replace('/', '');
                    var user = {
                        id: hash.md5(client.id),
                        room: room
                    }
                    self.io.sockets.in(room).emit('room:users:leave', user);
                    self.io.sockets.emit('rooms:users:leave', user)
                });
              clearInterval(sessionTouchInterval)
            });

        });

    };

    this.start = function () {
        // Setup listeners
        this.listen();
		return this;
    };

};

module.exports = ChatServer;
<|endoftext|>


<commit_before>"use strict";

function FirebaseRefNotProvidedError() {
  this.name = 'FirebaseRefNotProvidedError';
  this.message = 'No Firebase URL registered. Use firebaseRefProvider.registerUrl() in the config phase to set up a root reference.';
  this.stack = (new Error()).stack;
}
FirebaseRefNotProvidedError.prototype = Object.create(Error.prototype);
FirebaseRefNotProvidedError.prototype.constructor = FirebaseRefNotProvidedError;

function FirebaseRef() {
  this.urls = null;
  this.singleUrl = false;
  this.registerUrl = function registerUrl(urlOrConfig) {

    if (typeof urlOrConfig === 'string') {
      this.urls = {};
      this.urls.default = urlOrConfig;
      this.singleUrl = true;
    }

    if (angular.isObject(urlOrConfig)) {
      this.urls = urlOrConfig;
      this.singleUrl = false;
    }

  };

  this.$$checkUrls = function $$checkUrls(urlConfig) {
    if (!urlConfig) {
      return new FirebaseRefNotProvidedError();
    }
  };

  this.$$createSingleRef = function $$createSingleRef(defaultUrl) {
    var error = this.$$checkUrls(defaultUrl);
    if (error) { throw error; }
    return new Firebase(defaultUrl);
  };

  this.$$createMultipleRefs = function $$createMultipleRefs(urlConfig) {
    var error = this.$$checkUrls(urlConfig);
    if (error) { throw error; }
    var defaultUrl = urlConfig.default;
    var defaultRef = new Firebase(defaultUrl);
    delete urlConfig.default;
    angular.forEach(urlConfig, function(value, key) {
      if (!defaultRef.hasOwnProperty(key)) {
        defaultRef[key] = new Firebase(value);
      } else {
        throw new Error(key + ' is a reserved property name on firebaseRef.');
      }
    });
    return defaultRef;
  };

  this.$get = function FirebaseRef_$get() {

    if (this.singleUrl) {
      return this.$$createSingleRef(this.urls.default);
    } else {
      return this.$$createMultipleRefs(this.urls);
    }

  };
}

angular.module('firebase')
  .provider('firebaseRef', FirebaseRef);
<commit_msg>Use a single ref creator function<commit_after>"use strict";

function FirebaseRefNotProvidedError() {
  this.name = 'FirebaseRefNotProvidedError';
  this.message = 'No Firebase URL registered. Use firebaseRefProvider.registerUrl() in the config phase to set up a root reference.';
  this.stack = (new Error()).stack;
}
FirebaseRefNotProvidedError.prototype = Object.create(Error.prototype);
FirebaseRefNotProvidedError.prototype.constructor = FirebaseRefNotProvidedError;

function FirebaseRef() {
  this.urls = null;
  this.registerUrl = function registerUrl(urlOrConfig) {

    if (typeof urlOrConfig === 'string') {
      this.urls = {};
      this.urls.default = urlOrConfig;
    }

    if (angular.isObject(urlOrConfig)) {
      this.urls = urlOrConfig;
    }

  };

  this.$$checkUrls = function $$checkUrls(urlConfig) {
    if (!urlConfig) {
      return new FirebaseRefNotProvidedError();
    }
  };

  this.$$createRefsFromUrlConfig = function $$createMultipleRefs(urlConfig) {
    var error = this.$$checkUrls(urlConfig);
    if (error) { throw error; }
    var defaultUrl = urlConfig.default;
    var defaultRef = new Firebase(defaultUrl);
    delete urlConfig.default;
    angular.forEach(urlConfig, function(value, key) {
      if (!defaultRef.hasOwnProperty(key)) {
        defaultRef[key] = new Firebase(value);
      } else {
        throw new Error(key + ' is a reserved property name on firebaseRef.');
      }
    });
    return defaultRef;
  };

  this.$get = function FirebaseRef_$get() {
    return this.$$createRefsFromUrlConfig(this.urls);
  };
}

angular.module('firebase')
  .provider('firebaseRef', FirebaseRef);
<|endoftext|>


<commit_before>import request from 'request'

const apiUrl = 'https://graph.facebook.com/v2.6/'

/** Class representing a Facebook Messenger App. */
class Messenger {
  /**
   * Create a Messenger.
   *
   * @param {string} [token=null] - The Facebook Page Access Token.
   * @param {string} [notificationType=REGULAR] - The default message notification type.
   */
  constructor (token = null, notificationType = 'REGULAR') {
    this.token = token
    this.notificationType = notificationType

    if (!this.token) throw new Error('Facebook Page access token is missing.')
  }

  /**
  * This method will subscribe App via API
  *
  * @callback [cb] - The callback function
  */
  subscribeApp (cb) {
    const req = {
      url: `${apiUrl}me/subscribed_apps`,
      qs: {
        access_token: this.token
      },
      method: 'POST',
      json: true
    }
    sendRequest(req, cb)
  }

  /**
  * This method will send a plain Text Message.
  *
  * @param {string} recipient - The user id that will receive the message
  * @param {string} text - The text message (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendTextMessage (recipient, text, notificationType, cb) {
    const message = {
      text: message
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a Quick Replies Message.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object[]} quickReplies - The quick replies to be sent with messages
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendQuickMessage (recipient, quickReplies, notificationType, cb) {
    const message = {
      quick_replies: quickReplies
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Attachment Message.
  *
  * @param {string} recipient - The user id that will receive the message
  * @param {string} type - The attachment type
  * @param {object} payload - The attachment payload
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendAttachmentMessage (recipient, type, payload, notificationType, cb) {
    const message = {
      attachment: {
        type: type, // image, audio, video, file, location, template
        payload: payload
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a file attachment. The file type must be image, audio, video or file).
  * Image supported formats [jpg, png and gifs]
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} type - The file type ['image', 'audio', 'video' or 'file']
  * @param {string} fileUrl - The file url where it is hosted (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendFileMessage (recipient, type, fileUrl, notificationType, cb) {
    const payload = {
      url: fileUrl
    }
    this.sendAttachmentMessage(recipient, type, payload, notificationType, cb)
  }

  /**
  * This method will send a text and buttons attachment to request input from the user.
  * The buttons can open a URL, or make a back-end call to your webhook.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} text - The head text of the button message
  * @param {object[]} buttons - The Set of call-to-action buttons
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendButtonMessage (recipient, text, buttons, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: {
          template_type: 'button',
          text: text,
          buttons: buttons
        }
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a Structured Generic Message, to send a horizontal scrollable carousel of items,
  * each composed of an image attachment, short description and buttons to request input from the user.
  * The buttons can open a URL, or make a back-end call to your webhook.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object[]} elements - The Data for each bubble in message
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendGenericMessage (recipient, elements, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: {
          template_type: 'generic',
          elements: elements
        }
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a Receipt Message, to send a order confirmation,
  * with the transaction summary and description for each item.
  *
  * @param {string} recipient - The receipient user id.
  * @param {object} receipt - The Receipt Template
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendReceiptMessage (recipient, receipt, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: receipt
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Airplane Itinerary Message, that contains the itinerary and receipt.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} itinerary - The payload of itinerary template (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendItineraryMessage (recipient, itinerary, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: itinerary
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Airplane Check-In Reminder Message.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} checkin - The payload of checkin template (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendCheckinMessage (recipient, checkin, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: checkin
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Airplane Boarding Pass Message, that contains boarding
  * passes for one or more flights or one more passengers
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} boardingpass - The payload of boarding pass template (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendBoardingpassMessage (recipient, boardingpass, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: boardingpass
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Airplane Flight Update Message.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} flightupdate - The payload of flight update template (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendFlightupdateMessage (recipient, flightupdate, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: flightupdate
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a message to the user.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} message - The message object (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendApiMessage (recipient, message, notificationType, cb) {
    if (typeof notificationType === 'function') {
      cb = notificationType
      notificationType = this.notificationType
    }
    const req = {
      url: `${apiUrl}me/messages`,
      qs: {
        access_token: this.token
      },
      method: 'POST',
      json: {
        recipient: {
          id: recipient
        },
        message: message,
        notification_type: notificationType
      }
    }
    sendRequest(req, cb)
  }

  /**
  * This method will send Sender Actions, this are typing indicators or send read receipts,
  * to let the user know you are processing their request
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} senderAction - The action typing indicator (required)
  * @callback [cb] - The callback function
  */
  sendSenderAction (recipient, senderAction, cb) {
    const req = {
      url: `${apiUrl}me/messages`,
      qs: {
        access_token: this.token
      },
      method: 'POST',
      json: {
        recipient: {
          id: recipient
        },
        sender_action: senderAction
      }
    }
    sendRequest(req, cb)
  }

  /**
  * This method will set a Greeting Text.
  *
  * @param {(object|string)} text - The greeting text
  * @callback [cb] - The callback function
  */
  setGreetingText (text, cb) {
    if (typeof text === 'string') {
      text = {text: text}
    }
    const method = 'POST'
    const params = {
      setting_type: 'greeting',
      greeting: text
    }
    this.sendThreadSettingsRequest(method, params, cb)
  }

  /**
  * This method will set a Get Started Button, in the welcome screen.
  *
  * @param {(object[]|string)} payload - The string payloads
  * @callback [cb] - The callback function
  */
  setGetStartedButton (payload, cb) {
    if (typeof payload === 'string') {  // Case a string is entered
      payload = [{
        payload: payload
      }]
    }
    const method = 'POST'
    const params = {
      setting_type: 'call_to_actions',
      thread_state: 'new_thread',
      call_to_actions: payload // max 1
    }
    this.sendThreadSettingsRequest(method, params, cb)
  }

  /**
  * This method will set a Persistent Menu, always available to the user.
  *
  * @param {object[]} menuItems - The menu items in the menu
  * @callback [cb] - The callback function
  */
  setPersistentMenu (menuItems, cb) {
    const method = 'POST'
    const params = {
      setting_type: 'call_to_actions',
      thread_state: 'existing_thread',
      call_to_actions: menuItems
    }
    this.sendThreadSettingsRequest(method, params, cb)
  }

  /**
  * This method will delete a Thread Setting. Get Started Button('new_thread')
  * or Persistent Menu('existing_thread')
  *
  * @param {string} threadType - The thread type to be deleted
  * @callback [cb] - The callback function
  */
  deleteThreadSetting (threadType, cb) {
    const method = 'DELETE'
    const params = {
      setting_type: 'call_to_actions',
      thread_state: threadType
    }
    this.sendThreadSettingsRequest(method, params, cb)
  }

  /**
  * This method will Configure the Thread Setting on Messenger.
  *
  * @param {string} method - The call request (POST or DELETE)
  * @param {object} params - The configuration parameters
  * @callback [cb] - The callback function
  */
  sendThreadSettingsRequest (method, params, cb) {
    const req = {
      url: `${apiUrl}me/thread_settings`,
      qs: {
        access_token: this.token
      },
      method: method,
      json: params
    }
    sendRequest(req, cb)
  }

  /**
  * This method will send an account linking call-2-action to the user.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} title - The title of the account linking CTA
  * @param {string} imageUrl - The URL of the image in the account linking CTA
  * @param {string} authUrl - The Authentication callback URL
  * @callback [cb] - The callback function
  */
  sendAccountLinkingMessage (recipient, title, imageUrl, authUrl, cb) {
    const message = {
      attachment: {
        type: 'tempalte',
        payload: {
          template_type: 'generic',
          elements: [{
            title: title,
            image_url: imageUrl,
            buttons: [{
              type: 'account_link',
              url: authUrl
            }]
          }]
        }
      }
    }
    this.sendApiMessage(recipient, message, cb)
  }

  /**
  * This method will retrieve the user page-scoped ID (PSID) using the account
  * linking endpoint.
  *
  * @param {string} token - The account linking token
  * @callback [cb] - The callback function
  */
  getUserPsid (token, cb) {
    const req = {
      url: `${apiUrl}me`,
      qs: {
        access_token: this.token,
        fields: 'recipient',
        account_linking_token: token
      },
      method: 'GET',
      json: true
    }
    sendRequest(req, cb)
  }

  /**
  * This method will send an account unlinking call-2-action to the user.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} title - The title of the account linking CTA
  * @param {string} imageUrl - The URL of the image in the account linking CTA
  * @callback [cb] - The callback function
  */
  sendAccountUnlinkingMessage (recipient, title, imageUrl, cb) {
    const message = {
      attachment: {
        type: 'tempalte',
        payload: {
          template_type: 'generic',
          elements: [{
            title: title,
            image_url: imageUrl,
            buttons: [{
              type: 'account_unlink'
            }]
          }]
        }
      }
    }
    this.sendApiMessage(recipient, message, cb)
  }

  /**
  * This method will unlink the user account.
  *
  * @param {string} psid - A valid page-scoped ID (PSID)
  * @callback [cb] - The callback function
  */
  unlinkAccount (psid, cb) {
    const req = {
      url: `${apiUrl}me/unlink_accounts`,
      qs: {
        access_token: this.token
      },
      method: 'POST',
      json: {
        psid: psid
      }
    }
    sendRequest(req, cb)
  }

  /**
  * This method will get the User Profile, used to query more information about
  * the user, and personalize the experience further.
  *
  * @param {string} userId - The user id
  * @callback [cb] - The callback function
  */
  getUserProfile (userId, cb) {
    const req = {
      url: `${apiUrl}${userId}`,
      qs: {
        access_token: this.token,
        fields: 'first_name,last_name,profile_pic,locale,timezone,gender'
      },
      method: 'GET',
      json: true
    }
    sendRequest(req, cb)
  }
}

/**
* This method will send a Request to the Send API.
*
* @param {object} req - The request being send
* @callback [cb] - The callback function
*/
const sendRequest = (req, cb) => {
  request(req, (error, response, body) => {
    if (!cb) return
    if (error) return cb(error)
    if (response.body.error) return cb(response.body.error)
    cb(null, response.body)
  })
}

export default Messenger
<commit_msg>style(src/app.js): one-liner objects literals with one param<commit_after>import request from 'request'

const apiUrl = 'https://graph.facebook.com/v2.6/'

/** Class representing a Facebook Messenger App. */
class Messenger {
  /**
   * Create a Messenger.
   *
   * @param {string} [token=null] - The Facebook Page Access Token.
   * @param {string} [notificationType=REGULAR] - The default message notification type.
   */
  constructor (token = null, notificationType = 'REGULAR') {
    this.token = token
    this.notificationType = notificationType

    if (!this.token) throw new Error('Facebook Page access token is missing.')
  }

  /**
  * This method will subscribe App via API
  *
  * @callback [cb] - The callback function
  */
  subscribeApp (cb) {
    const req = {
      url: `${apiUrl}me/subscribed_apps`,
      qs: {
        access_token: this.token
      },
      method: 'POST',
      json: true
    }
    sendRequest(req, cb)
  }

  /**
  * This method will send a plain Text Message.
  *
  * @param {string} recipient - The user id that will receive the message
  * @param {string} text - The text message (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendTextMessage (recipient, text, notificationType, cb) {
    const message = { text: message }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a Quick Replies Message.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object[]} quickReplies - The quick replies to be sent with messages
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendQuickMessage (recipient, quickReplies, notificationType, cb) {
    const message = { quick_replies: quickReplies }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Attachment Message.
  *
  * @param {string} recipient - The user id that will receive the message
  * @param {string} type - The attachment type
  * @param {object} payload - The attachment payload
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendAttachmentMessage (recipient, type, payload, notificationType, cb) {
    const message = {
      attachment: {
        type: type, // image, audio, video, file, location, template
        payload: payload
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a file attachment. The file type must be image, audio, video or file).
  * Image supported formats [jpg, png and gifs]
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} type - The file type ['image', 'audio', 'video' or 'file']
  * @param {string} fileUrl - The file url where it is hosted (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendFileMessage (recipient, type, fileUrl, notificationType, cb) {
    const payload = { url: fileUrl }
    this.sendAttachmentMessage(recipient, type, payload, notificationType, cb)
  }

  /**
  * This method will send a text and buttons attachment to request input from the user.
  * The buttons can open a URL, or make a back-end call to your webhook.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} text - The head text of the button message
  * @param {object[]} buttons - The Set of call-to-action buttons
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendButtonMessage (recipient, text, buttons, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: {
          template_type: 'button',
          text: text,
          buttons: buttons
        }
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a Structured Generic Message, to send a horizontal scrollable carousel of items,
  * each composed of an image attachment, short description and buttons to request input from the user.
  * The buttons can open a URL, or make a back-end call to your webhook.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object[]} elements - The Data for each bubble in message
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendGenericMessage (recipient, elements, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: {
          template_type: 'generic',
          elements: elements
        }
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a Receipt Message, to send a order confirmation,
  * with the transaction summary and description for each item.
  *
  * @param {string} recipient - The receipient user id.
  * @param {object} receipt - The Receipt Template
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendReceiptMessage (recipient, receipt, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: receipt
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Airplane Itinerary Message, that contains the itinerary and receipt.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} itinerary - The payload of itinerary template (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendItineraryMessage (recipient, itinerary, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: itinerary
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Airplane Check-In Reminder Message.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} checkin - The payload of checkin template (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendCheckinMessage (recipient, checkin, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: checkin
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Airplane Boarding Pass Message, that contains boarding
  * passes for one or more flights or one more passengers
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} boardingpass - The payload of boarding pass template (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendBoardingpassMessage (recipient, boardingpass, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: boardingpass
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send an Airplane Flight Update Message.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} flightupdate - The payload of flight update template (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendFlightupdateMessage (recipient, flightupdate, notificationType, cb) {
    const message = {
      attachment: {
        type: 'template',
        payload: flightupdate
      }
    }
    this.sendApiMessage(recipient, message, notificationType, cb)
  }

  /**
  * This method will send a message to the user.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {object} message - The message object (required)
  * @param {string} [notificationType] - The notification type
  * @callback [cb] - The callback function
  */
  sendApiMessage (recipient, message, notificationType, cb) {
    if (typeof notificationType === 'function') {
      cb = notificationType
      notificationType = this.notificationType
    }
    const req = {
      url: `${apiUrl}me/messages`,
      qs: {
        access_token: this.token
      },
      method: 'POST',
      json: {
        recipient: {
          id: recipient
        },
        message: message,
        notification_type: notificationType
      }
    }
    sendRequest(req, cb)
  }

  /**
  * This method will send Sender Actions, this are typing indicators or send read receipts,
  * to let the user know you are processing their request
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} senderAction - The action typing indicator (required)
  * @callback [cb] - The callback function
  */
  sendSenderAction (recipient, senderAction, cb) {
    const req = {
      url: `${apiUrl}me/messages`,
      qs: {
        access_token: this.token
      },
      method: 'POST',
      json: {
        recipient: {
          id: recipient
        },
        sender_action: senderAction
      }
    }
    sendRequest(req, cb)
  }

  /**
  * This method will set a Greeting Text.
  *
  * @param {(object|string)} text - The greeting text
  * @callback [cb] - The callback function
  */
  setGreetingText (text, cb) {
    if (typeof text === 'string') {
      text = {text: text}
    }
    const method = 'POST'
    const params = {
      setting_type: 'greeting',
      greeting: text
    }
    this.sendThreadSettingsRequest(method, params, cb)
  }

  /**
  * This method will set a Get Started Button, in the welcome screen.
  *
  * @param {(object[]|string)} payload - The string payloads
  * @callback [cb] - The callback function
  */
  setGetStartedButton (payload, cb) {
    if (typeof payload === 'string') {  // Case a string is entered
      payload = [{
        payload: payload
      }]
    }
    const method = 'POST'
    const params = {
      setting_type: 'call_to_actions',
      thread_state: 'new_thread',
      call_to_actions: payload // max 1
    }
    this.sendThreadSettingsRequest(method, params, cb)
  }

  /**
  * This method will set a Persistent Menu, always available to the user.
  *
  * @param {object[]} menuItems - The menu items in the menu
  * @callback [cb] - The callback function
  */
  setPersistentMenu (menuItems, cb) {
    const method = 'POST'
    const params = {
      setting_type: 'call_to_actions',
      thread_state: 'existing_thread',
      call_to_actions: menuItems
    }
    this.sendThreadSettingsRequest(method, params, cb)
  }

  /**
  * This method will delete a Thread Setting. Get Started Button('new_thread')
  * or Persistent Menu('existing_thread')
  *
  * @param {string} threadType - The thread type to be deleted
  * @callback [cb] - The callback function
  */
  deleteThreadSetting (threadType, cb) {
    const method = 'DELETE'
    const params = {
      setting_type: 'call_to_actions',
      thread_state: threadType
    }
    this.sendThreadSettingsRequest(method, params, cb)
  }

  /**
  * This method will Configure the Thread Setting on Messenger.
  *
  * @param {string} method - The call request (POST or DELETE)
  * @param {object} params - The configuration parameters
  * @callback [cb] - The callback function
  */
  sendThreadSettingsRequest (method, params, cb) {
    const req = {
      url: `${apiUrl}me/thread_settings`,
      qs: {
        access_token: this.token
      },
      method: method,
      json: params
    }
    sendRequest(req, cb)
  }

  /**
  * This method will send an account linking call-2-action to the user.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} title - The title of the account linking CTA
  * @param {string} imageUrl - The URL of the image in the account linking CTA
  * @param {string} authUrl - The Authentication callback URL
  * @callback [cb] - The callback function
  */
  sendAccountLinkingMessage (recipient, title, imageUrl, authUrl, cb) {
    const message = {
      attachment: {
        type: 'tempalte',
        payload: {
          template_type: 'generic',
          elements: [{
            title: title,
            image_url: imageUrl,
            buttons: [{
              type: 'account_link',
              url: authUrl
            }]
          }]
        }
      }
    }
    this.sendApiMessage(recipient, message, cb)
  }

  /**
  * This method will retrieve the user page-scoped ID (PSID) using the account
  * linking endpoint.
  *
  * @param {string} token - The account linking token
  * @callback [cb] - The callback function
  */
  getUserPsid (token, cb) {
    const req = {
      url: `${apiUrl}me`,
      qs: {
        access_token: this.token,
        fields: 'recipient',
        account_linking_token: token
      },
      method: 'GET',
      json: true
    }
    sendRequest(req, cb)
  }

  /**
  * This method will send an account unlinking call-2-action to the user.
  *
  * @param {string} recipient - The user id to whom we're sending the text message
  * @param {string} title - The title of the account linking CTA
  * @param {string} imageUrl - The URL of the image in the account linking CTA
  * @callback [cb] - The callback function
  */
  sendAccountUnlinkingMessage (recipient, title, imageUrl, cb) {
    const message = {
      attachment: {
        type: 'tempalte',
        payload: {
          template_type: 'generic',
          elements: [{
            title: title,
            image_url: imageUrl,
            buttons: [{
              type: 'account_unlink'
            }]
          }]
        }
      }
    }
    this.sendApiMessage(recipient, message, cb)
  }

  /**
  * This method will unlink the user account.
  *
  * @param {string} psid - A valid page-scoped ID (PSID)
  * @callback [cb] - The callback function
  */
  unlinkAccount (psid, cb) {
    const req = {
      url: `${apiUrl}me/unlink_accounts`,
      qs: {
        access_token: this.token
      },
      method: 'POST',
      json: {
        psid: psid
      }
    }
    sendRequest(req, cb)
  }

  /**
  * This method will get the User Profile, used to query more information about
  * the user, and personalize the experience further.
  *
  * @param {string} userId - The user id
  * @callback [cb] - The callback function
  */
  getUserProfile (userId, cb) {
    const req = {
      url: `${apiUrl}${userId}`,
      qs: {
        access_token: this.token,
        fields: 'first_name,last_name,profile_pic,locale,timezone,gender'
      },
      method: 'GET',
      json: true
    }
    sendRequest(req, cb)
  }
}

/**
* This method will send a Request to the Send API.
*
* @param {object} req - The request being send
* @callback [cb] - The callback function
*/
const sendRequest = (req, cb) => {
  request(req, (error, response, body) => {
    if (!cb) return
    if (error) return cb(error)
    if (response.body.error) return cb(response.body.error)
    cb(null, response.body)
  })
}

export default Messenger
<|endoftext|>


<commit_before>jQuery(function($) {
  var htmlElement = $('html');
  var editor = $('textarea.wiki-edit');
  var preview = $('div#preview');
  var preview_link = $('input[name=commit]').next();

  var disable_side_by_side_mode = function() {
    htmlElement.removeClass('side_by_side');

    editor.off('scroll');
    editor.off('mouseup');

    $('#content').append(preview);
  };

  var disable_writing_mode = function() {
    htmlElement.removeClass('writing_mode');
  }

  var enable_side_by_side_mode = function() {
    htmlElement.addClass('side_by_side');

    editor.before(preview);
    resize_preview_to_editor_height();

    editor.scroll(preview, scroll_preview);
    editor.mouseup(resize_preview_if_required);
    editor.scroll();

    if($('fieldset.preview').length === 0) {
      preview_link.click();
    }
  };

  var enable_writing_mode = function() {
    htmlElement.addClass('writing_mode');
  }

  var resize_preview_if_required = function() {
    var newEditorHeight = editor.outerHeight();

    if(newEditorHeight != editor.data('height')) {
      editor.data('height', newEditorHeight);
      resize_preview_to_editor_height();
    }
  }

  var resize_preview_to_editor_height = function() {
    preview.height(editor.height() + 6);
  }

  var scroll_preview = function(event) {
    var source_position = this.scrollTop / (this.scrollHeight - $(this).innerHeight());
    var target = $(event.data);

    target.scrollTop(source_position * (target[0].scrollHeight - target.innerHeight()));
  };

  var toggle_side_by_side_mode = function() {
    if(this.checked) {
      enable_side_by_side_mode();
    } else {
      disable_side_by_side_mode();
    }
  };

  var toggle_writing_mode = function() {
    if(this.checked) {
      enable_writing_mode();
    } else {
      disable_writing_mode();
    }
  };

  preview_link.after($('Show editor and preview side-by-side'))
              .after($('<input id="side_by_side_mode" type="checkbox" />'))
              .after($('Writing mode'))
              .after($('<input id="writing_mode" type="checkbox" />'));
  $('#side_by_side_mode').click(toggle_side_by_side_mode);
  $('#writing_mode').click(toggle_writing_mode);

  editor.data('height', editor.outerHeight());
});
<commit_msg>Do not show extension mode selectors when not on edit page<commit_after>jQuery(function($) {
  var htmlElement = $('html');
  var editor = $('textarea.wiki-edit');
  var preview = $('div#preview');
  var preview_link = $('#wiki_form input[name=commit]').next();

  var disable_side_by_side_mode = function() {
    htmlElement.removeClass('side_by_side');

    editor.off('scroll');
    editor.off('mouseup');

    $('#content').append(preview);
  };

  var disable_writing_mode = function() {
    htmlElement.removeClass('writing_mode');
  }

  var enable_side_by_side_mode = function() {
    htmlElement.addClass('side_by_side');

    editor.before(preview);
    resize_preview_to_editor_height();

    editor.scroll(preview, scroll_preview);
    editor.mouseup(resize_preview_if_required);
    editor.scroll();

    if($('fieldset.preview').length === 0) {
      preview_link.click();
    }
  };

  var enable_writing_mode = function() {
    htmlElement.addClass('writing_mode');
  }

  var resize_preview_if_required = function() {
    var newEditorHeight = editor.outerHeight();

    if(newEditorHeight != editor.data('height')) {
      editor.data('height', newEditorHeight);
      resize_preview_to_editor_height();
    }
  }

  var resize_preview_to_editor_height = function() {
    preview.height(editor.height() + 6);
  }

  var scroll_preview = function(event) {
    var source_position = this.scrollTop / (this.scrollHeight - $(this).innerHeight());
    var target = $(event.data);

    target.scrollTop(source_position * (target[0].scrollHeight - target.innerHeight()));
  };

  var toggle_side_by_side_mode = function() {
    if(this.checked) {
      enable_side_by_side_mode();
    } else {
      disable_side_by_side_mode();
    }
  };

  var toggle_writing_mode = function() {
    if(this.checked) {
      enable_writing_mode();
    } else {
      disable_writing_mode();
    }
  };

  preview_link.after($('Show editor and preview side-by-side'))
              .after($('<input id="side_by_side_mode" type="checkbox" />'))
              .after($('Writing mode'))
              .after($('<input id="writing_mode" type="checkbox" />'));
  $('#side_by_side_mode').click(toggle_side_by_side_mode);
  $('#writing_mode').click(toggle_writing_mode);

  editor.data('height', editor.outerHeight());
});
<|endoftext|>


<commit_before>function show(state) {

	document.getElementById('window').style.display = state;
	document.getElementById('wrap').style.display = state;
}
<commit_msg>Update debug.js<commit_after>function show(state) {
	document.getElementById('window').style.display = state;
	document.getElementById('wrap').style.display = state;
}
<|endoftext|>