<commit_before>// New client start file
// by PokerDaddy

const network = require('./network.js');
const Display = require('./interface.js');
const Persistence = require('./persistence.js');

const help = `
scaling-potato help by PokerDaddy:
Commands:
/login <server> <nick>      - Asks <server> for a new token associated with <nick>.
/forcelogin <server> <nick> - Gets a new token from the server even if the server accepts your current one with <nick>.
/connect <server>           - Connects to a server using a previously set token. Best used for reconnecting.
/token <server> <token>	    - Connect to <server> using <token>
/nick <nick>                - Sets your current connected user's nickname to <nick>.
/disconnect                 - Disconnects from the current server.
/help                       - Prints this help message.
/msg <id> <msg>             - Send <msg> to user with id <id>
/msgn <nick> <msg>          - Send <msg> to all users with nick <nick>
`;

class CurrentServerdata {
  constructor(serverName) {
    this.servername = serverName;
    this.lastMessageTime = 0;
  }
}

const pers = new Persistence(process.argv[2] || 'default', ['settings', 'servers']);

let result = pers.load();
if (result != 'Success.') {
  console.log(result);
  process.exit(1);
}

const dis = new Display;

let currentServer = null;
let currentSession = null;
let currentServerData = {};

let updateCheckerId = null;

dis.on('input', (line) => {
  if (line.startsWith('/')) {
    let cmd = line.split(' ');
    switch (cmd[0]) {
      case '/login':
        loginToServer(cmd[1], cmd[2]);
        break;
      case '/forcelogin':
        forceLogin(cmd[1], cmd[2]);
        break;
      case '/connect':
        connectToServer(cmd[1]);
        break;
      case '/token':
	connectByToken(cmd[1], cmd[2])
      case '/msg':
        {
          if (cmd.length < 3) {
            console.log('/msg <user-id> <message>');
            break;
          }
          let str = cmd[2];
          for (let index = 3; index < cmd.length; index++) {
            str += ' ' + cmd[index];
          }
          sendPrivateMessageById(cmd[1], str);
        }
        break;
      case '/msgn':
        {
          if (cmd.length < 3) {
            console.log('/msgn <nick> <message>');
            break;
          }
          let str = cmd[2];
          for (let index = 3; index < cmd.length; index++) {
            str += ' ' + cmd[index];
          }
          sendPrivateMessageByNick(cmd[1], str);
        }
        break;
      case '/nick':
        changeNickname(cmd[1]);
        break;
      case '/disconnect':
        disconnectFromServer();
        break;
      case '/help':
        printHelp();
        break;
      default:
        console.log('Unrecognized command: ' + cmd[0]);
        console.log('Use /help to list commands.');
        break;
    }
  } else {
    sendMessage(line);
  }
}).on('quit', () => {
  pers.save();
  stopUpdateChecker();
  process.exit(0);
});

process.on('uncaughtException', (error) => {
  console.log(error);
  pers.save();
  process.exit(1);
});

function printHelp() {
  console.log(help);
}

function _connectToServer(serverData, serverUrl, server) {
  if (serverData) {
    network.getUser(serverUrl, {
      token: serverData.session.token
    }).on('user', (user) => {
      if (user) {
        console.log('Reconnection successful.');
        user.token = serverData.session.token;
        pers.files.servers[server] = {
          session: user
        };
        currentSession = user;
        currentServer = serverUrl;
        currentServerData[serverUrl] = new CurrentServerdata(server);
        startUpdateChecker();
      } else {
        console.log("This server doesn't remember you.");
        console.log('You might want to /login');
      }
    }).on('error', (error) => {
      console.log('Error connecting to ' + server);
    });
  } else {
    console.log('You have never logged into this server before.');
    console.log('Maybe you will want to /login');
  }
}

function connectToServer(server) {
  let serverData = pers.files.servers[server];
  let serverUrl = `http://${server}:8080`;
  _connectToServer(serverData, serverUrl, server)
}

function connectByToken(server, token) {
  let serverData = {session: { token: token }};
  let serverUrl = `http://${server}:8080`;
  _connectToServer(serverData, serverUrl, server);
}

function forceLogin(server, nick) {
  login(server, nick);
}

function loginToServer(server, nick) {
  let serverData = pers.files.servers[server];
  let serverUrl = `http://${server}:8080`;

  if (serverData) {
    network.getUser(serverUrl, {
      token: serverData.session.token
    }).on('user', (user) => {
      if (user) {
        console.log('This server remembers you. You can just /connect or login again with /forcelogin');
      } else {
        login(server, nick);
      }
    }).on('error', (error) => {
      console.log('Error connecting to ' + server);
    });
  } else {
    login(server, nick);
  }
}

function login(server, nick) {
  let serverUrl = `http://${server}:8080`
  console.log('Logging into: ' + server);
  network.login(serverUrl, nick).on('login', (session) => {
    console.log('You are now logged in as: ' + session.nick + '#' + session.id);
    pers.files.servers[server] = {
      session
    };
    currentSession = session;
    currentServer = serverUrl;
    currentServerData[serverUrl] = new CurrentServerdata(server);
    startUpdateChecker();
  }).on('error', (error) => {
    console.log('Login error.');
  });
}

function disconnectFromServer() {
  stopUpdateChecker();
  currentSession = null;
  currentServer = null;
  console.log('Disconnected.');
}

function sendMessage(message) {
  if (currentSession) {
    network.sendMessage(currentServer, currentSession, message).on('error', (error) => {
      console.log('Error sending the message.');
    });
  } else {
    console.log('You must be connected to a server to send messages.');
  }
}

function startUpdateChecker() {
  if (!updateCheckerId) {
    updateCheckerId = setInterval(checkForUpdates, 1000);
  }
}

function stopUpdateChecker() {
  if (updateCheckerId) {
    clearInterval(updateCheckerId);
    updateCheckerId = null;
  }
}

function checkForUpdates() {
  network.update(currentServer, currentServerData[currentServer].lastMessageTime).on('response', (publicMessages) => {
    network.updateDirects(currentServer, currentSession, currentServerData[currentServer].lastMessageTime).on('response', (directMessages) => {
      let messages;
      if ((publicMessages && publicMessages.length > 0) && (directMessages && directMessages.length > 0)) {
        messages = publicMessages.concat(directMessages.map((e) => {
          e.direct = true;
          return e;
        }));
      } else if (publicMessages && publicMessages.length > 0) {
        messages = publicMessages;
      } else if (directMessages && directMessages.length > 0) {
        messages = directMessages;
      }
      if (messages && typeof(messages) == 'object') {
        messages.sort((a, b) => {
          if (a.timestamp > b.timestamp) return 1;
          else if (a.timestamp < b.timestamp) return -1;
          else return 0;
        });
        messages.forEach((message) => {
          if (message.direct) {
            dis.recieveDirect(message.timestamp, message.nick, message.id, message.body);
          } else {
            dis.recieve(message.timestamp, message.nick, message.id, message.body);
          }
        });
        currentServerData[currentServer].lastMessageTime = messages[messages.length - 1].timestamp;
      }
    }).on('error', (error) => {
      console.log('Server timed out.');
      disconnectFromServer();
    });
  }).on('error', (error) => {
    console.log('Server timed out.');
    disconnectFromServer();
  });
}

function changeNickname(newNickname) {
  if (currentSession) {
    currentSession.nick = newNickname;
    network.changeNickname(currentServer, currentSession).on('response', (response) => {
      console.log(`Nickname set to ${response.nick}`);
    }).on('error', (error) => {
      console.log('Error setting nickname.');
    });
  } else {
    console.log('You must be logged into a server to have a nickname.');
  }
}

function sendPrivateMessageByNick(recipient, message) {
  if (currentSession) {
    network.getUsers(currentServer, {
      nick: recipient
    }).on('users', (users) => {
      if (users && users.length > 0) {
        if (users.length > 1) {
          console.log('Found ' + users.length + ' users with the nick: ' + recipient);
        }
        users.forEach((user) => {
          network.sendDirectMessage(currentServer, currentSession, user.id, message).on('response', (messageObj) => {
            console.log('You sent to [' + user.nick + '#' + user.id + ']: ' + message);
          }).on('error', (error) => {
            console.log('Error sending to: ' + user.nick + '#' + user.id);
          });
        });
      } else {
        console.log('No user with the nick: ' + recipient);
      }
    }).on('error', (error) => {
      console.log('Error getting users from the server.');
    });
  } else {
    console.log('You must be connected to a server to send messages.');
  }
}

function sendPrivateMessageById(recipientId, message) {
  if (currentSession) {
    network.sendDirectMessage(currentServer, currentSession, recipientId, message).on('response', (messageObj) => {
      network.getUser(currentServer, {
        id: recipientId
      }).on('user', (user) => {
        if (user) {
          console.log('You sent to [' + user.nick + '#' + user.id + ']: ' + message);
        } else {
          console.log('No user with the id: ' + recipientId);
        }
      }).on('error', (error) => {
        console.log('You sent to [' + recipientId + '] (they might not exist): ' + message);
      });
    }).on('error', (error) => {
      console.log('Error sending to: ' + recipientId);
    });
  } else {
    console.log('You must be connected to a server to send messages.');
  }
}
<commit_msg>client/index.js: Add basic admin functionality<commit_after>// New client start file
// by PokerDaddy

const network = require('./network.js');
const Display = require('./interface.js');
const Persistence = require('./persistence.js');

const help = `
scaling-potato help by PokerDaddy:
Commands:
/login <server> <nick>      - Asks <server> for a new token associated with <nick>.
/forcelogin <server> <nick> - Gets a new token from the server even if the server accepts your current one with <nick>.
/connect <server>           - Connects to a server using a previously set token. Best used for reconnecting.
/auth <token>		    - Login as system user using <token>
/announce <msg>		    - Send a message as system user
/token <server> <token>	    - Connect to <server> using <token>
/nick <nick>                - Sets your current connected user's nickname to <nick>.
/disconnect                 - Disconnects from the current server.
/help                       - Prints this help message.
/msg <id> <msg>             - Send <msg> to user with id <id>
/msgn <nick> <msg>          - Send <msg> to all users with nick <nick>
`;

class CurrentServerdata {
  constructor(serverName) {
    this.servername = serverName;
    this.lastMessageTime = 0;
  }
}

const pers = new Persistence(process.argv[2] || 'default', ['settings', 'servers']);

let result = pers.load();
if (result != 'Success.') {
  console.log(result);
  process.exit(1);
}

const dis = new Display;

let currentServer = null;
let currentSession = null;
let currentServerData = {};
let adminToken = null;

let updateCheckerId = null;

dis.on('input', (line) => {
  if (line.startsWith('/')) {
    let cmd = line.split(' ');
    switch (cmd[0]) {
      case '/login':
        loginToServer(cmd[1], cmd[2]);
        break;
      case '/forcelogin':
        forceLogin(cmd[1], cmd[2]);
        break;
      case '/connect':
        connectToServer(cmd[1]);
        break;
      case '/token':
	connectByToken(cmd[1], cmd[2])
      case '/msg':
        {
          if (cmd.length < 3) {
            console.log('/msg <user-id> <message>');
            break;
          }
          let str = cmd[2];
          for (let index = 3; index < cmd.length; index++) {
            str += ' ' + cmd[index];
          }
          sendPrivateMessageById(cmd[1], str);
        }
        break;
      case '/auth':
	{
	  authenticateAdmin(cmd[1]);
	}
      case '/announce':
	{
	  let str = cmd[1];
	  for (let index = 2; index < cmd.length; index++) {
            str += ' ' + cmd[index];
	  }
	  sendAnnouncement(str);
	}
      case '/msgn':
        {
          if (cmd.length < 3) {
            console.log('/msgn <nick> <message>');
            break;
          }
          let str = cmd[2];
          for (let index = 3; index < cmd.length; index++) {
            str += ' ' + cmd[index];
          }
          sendPrivateMessageByNick(cmd[1], str);
        }
        break;
      case '/nick':
        changeNickname(cmd[1]);
        break;
      case '/disconnect':
        disconnectFromServer();
        break;
      case '/help':
        printHelp();
        break;
      default:
        console.log('Unrecognized command: ' + cmd[0]);
        console.log('Use /help to list commands.');
        break;
    }
  } else {
    sendMessage(line);
  }
}).on('quit', () => {
  pers.save();
  stopUpdateChecker();
  process.exit(0);
});

process.on('uncaughtException', (error) => {
  console.log(error);
  pers.save();
  process.exit(1);
});

function printHelp() {
  console.log(help);
}

function _connectToServer(serverData, serverUrl, server) {
  if (serverData) {
    network.getUser(serverUrl, {
      token: serverData.session.token
    }).on('user', (user) => {
      if (user) {
        console.log('Reconnection successful.');
        user.token = serverData.session.token;
        pers.files.servers[server] = {
          session: user
        };
        currentSession = user;
        currentServer = serverUrl;
        currentServerData[serverUrl] = new CurrentServerdata(server);
        startUpdateChecker();
      } else {
        console.log("This server doesn't remember you.");
        console.log('You might want to /login');
      }
    }).on('error', (error) => {
      console.log('Error connecting to ' + server);
    });
  } else {
    console.log('You have never logged into this server before.');
    console.log('Maybe you will want to /login');
  }
}

function connectToServer(server) {
  let serverData = pers.files.servers[server];
  let serverUrl = `http://${server}:8080`;
  _connectToServer(serverData, serverUrl, server)
}

function connectByToken(server, token) {
  let serverData = {session: { token: token }};
  let serverUrl = `http://${server}:8080`;
  _connectToServer(serverData, serverUrl, server);
}

function forceLogin(server, nick) {
  login(server, nick);
}

function loginToServer(server, nick) {
  let serverData = pers.files.servers[server];
  let serverUrl = `http://${server}:8080`;

  if (serverData) {
    network.getUser(serverUrl, {
      token: serverData.session.token
    }).on('user', (user) => {
      if (user) {
        console.log('This server remembers you. You can just /connect or login again with /forcelogin');
      } else {
        login(server, nick);
      }
    }).on('error', (error) => {
      console.log('Error connecting to ' + server);
    });
  } else {
    login(server, nick);
  }
}

function login(server, nick) {
  let serverUrl = `http://${server}:8080`
  console.log('Logging into: ' + server);
  network.login(serverUrl, nick).on('login', (session) => {
    console.log('You are now logged in as: ' + session.nick + '#' + session.id);
    pers.files.servers[server] = {
      session
    };
    currentSession = session;
    currentServer = serverUrl;
    currentServerData[serverUrl] = new CurrentServerdata(server);
    startUpdateChecker();
  }).on('error', (error) => {
    console.log('Login error.');
  });
}

function disconnectFromServer() {
  stopUpdateChecker();
  currentSession = null;
  currentServer = null;
  console.log('Disconnected.');
}

function authenticateAdmin(token) {
  if (currentSession) {
    network.getUser(currentServer, {token:token}).on('user', (user) => {
      if (user.id === "0000") {
        adminToken = token;
        console.log('Now authenticated as admin.')
      } else {
        console.log('Invalid admin token.');
      }});
  } else {
    console.log('You must be connected to a server to become admin.');
  }
}

function sendAnnouncement(message) {
  if (currentSession && adminToken) {
    network.sendMessage(currentServer, {token:adminToken}, message).on('error', (error) => {
      console.log('Error sending the message.');
    });
  } else if (currentSession) {
    console.log('You are not an admin.');
  } else {
    console.log('You must be connected to a server to send messages.');
  }
}

function sendMessage(message) {
  if (currentSession) {
    network.sendMessage(currentServer, currentSession, message).on('error', (error) => {
      console.log('Error sending the message.');
    });
  } else {
    console.log('You must be connected to a server to send messages.');
  }
}

function startUpdateChecker() {
  if (!updateCheckerId) {
    updateCheckerId = setInterval(checkForUpdates, 1000);
  }
}

function stopUpdateChecker() {
  if (updateCheckerId) {
    clearInterval(updateCheckerId);
    updateCheckerId = null;
  }
}

function checkForUpdates() {
  network.update(currentServer, currentServerData[currentServer].lastMessageTime).on('response', (publicMessages) => {
    network.updateDirects(currentServer, currentSession, currentServerData[currentServer].lastMessageTime).on('response', (directMessages) => {
      let messages;
      if ((publicMessages && publicMessages.length > 0) && (directMessages && directMessages.length > 0)) {
        messages = publicMessages.concat(directMessages.map((e) => {
          e.direct = true;
          return e;
        }));
      } else if (publicMessages && publicMessages.length > 0) {
        messages = publicMessages;
      } else if (directMessages && directMessages.length > 0) {
        messages = directMessages;
      }
      if (messages && typeof(messages) == 'object') {
        messages.sort((a, b) => {
          if (a.timestamp > b.timestamp) return 1;
          else if (a.timestamp < b.timestamp) return -1;
          else return 0;
        });
        messages.forEach((message) => {
          if (message.direct) {
            dis.recieveDirect(message.timestamp, message.nick, message.id, message.body);
          } else {
            dis.recieve(message.timestamp, message.nick, message.id, message.body);
          }
        });
        currentServerData[currentServer].lastMessageTime = messages[messages.length - 1].timestamp;
      }
    }).on('error', (error) => {
      console.log('Server timed out.');
      disconnectFromServer();
    });
  }).on('error', (error) => {
    console.log('Server timed out.');
    disconnectFromServer();
  });
}

function changeNickname(newNickname) {
  if (currentSession) {
    currentSession.nick = newNickname;
    network.changeNickname(currentServer, currentSession).on('response', (response) => {
      console.log(`Nickname set to ${response.nick}`);
    }).on('error', (error) => {
      console.log('Error setting nickname.');
    });
  } else {
    console.log('You must be logged into a server to have a nickname.');
  }
}

function sendPrivateMessageByNick(recipient, message) {
  if (currentSession) {
    network.getUsers(currentServer, {
      nick: recipient
    }).on('users', (users) => {
      if (users && users.length > 0) {
        if (users.length > 1) {
          console.log('Found ' + users.length + ' users with the nick: ' + recipient);
        }
        users.forEach((user) => {
          network.sendDirectMessage(currentServer, currentSession, user.id, message).on('response', (messageObj) => {
            console.log('You sent to [' + user.nick + '#' + user.id + ']: ' + message);
          }).on('error', (error) => {
            console.log('Error sending to: ' + user.nick + '#' + user.id);
          });
        });
      } else {
        console.log('No user with the nick: ' + recipient);
      }
    }).on('error', (error) => {
      console.log('Error getting users from the server.');
    });
  } else {
    console.log('You must be connected to a server to send messages.');
  }
}

function sendPrivateMessageById(recipientId, message) {
  if (currentSession) {
    network.sendDirectMessage(currentServer, currentSession, recipientId, message).on('response', (messageObj) => {
      network.getUser(currentServer, {
        id: recipientId
      }).on('user', (user) => {
        if (user) {
          console.log('You sent to [' + user.nick + '#' + user.id + ']: ' + message);
        } else {
          console.log('No user with the id: ' + recipientId);
        }
      }).on('error', (error) => {
        console.log('You sent to [' + recipientId + '] (they might not exist): ' + message);
      });
    }).on('error', (error) => {
      console.log('Error sending to: ' + recipientId);
    });
  } else {
    console.log('You must be connected to a server to send messages.');
  }
}
<|endoftext|>


<commit_before>/**
 *
 * draw rect
 * 画矩形
 *
 * User: bastengao
 * Date: 12-9-3  Time: 上午9:33
 * dependency : jQuery, underscore
 */
(function ($) {
    //画家是最大的名称空间
    //init Painter
    var Painter = (function () {
        if (_.isObject(window.Painter)) {
            return window.Painter;
        } else {
            window.Painter = {};
            return window.Painter;
        }
    })();

    //代表一个矩形
    function Rect(ele) {
        var that = this;
        this.ele = ele;
        this.$ele = $(ele);
        //左上角位置(Rect 元素的位置是相对于 playground 的位置)
        this.offsetX = 0;
        this.offsetY = 0;
        //宽高
        this.width = 0;
        this.height = 0;

        this._onPgMouseMoveCallbacks = {};
        this._onPgMouseUpCallbacks = {};

        //初始化
        this.init = function () {
            //默认可以拖
            that.dragable();
        };

        this._sendEvent = function (event, callbacks) {
            _.each(callbacks, function (callback) {
                that._callWhenFunction(callback, event);
            });
        };

        this._callWhenFunction = function(func, args){
            if(_.isFunction(func)){
                func(args);
            }
        };

        //playground 上鼠标移动时, Playground 会调用此方法
        this.playgroundMouseMove = function (event) {
            that._sendEvent(event, that._onPgMouseMoveCallbacks);
        };

        //注册 Playground 鼠标移动 回调
        this.onPgMouseMove = function (name, func) {
            that._onPgMouseMoveCallbacks[name] = func;
        };

        //playground 上鼠标弹起时，Playground 会调用此方法
        this.playgroundMouseUp = function (event) {
            that._sendEvent(event, that._onPgMouseUpCallbacks);
        };

        //注册 Playground 鼠标弹起 回调
        this.onPgMouseUp = function (name, func) {
            that._onPgMouseUpCallbacks[name] = func;
        };

        //注册拖动回调
        this.onDrag = function (func) {
            that._onDragCallbakc = func;
        };

        //可以拖
        this.dragable = function () {
            //拖拽开始时，Rect 元素在 document 中的位置
            var startOffset = null;
            //起点在 document 中的位置
            var startX = null;
            var startY = null;
            var dragging = false;
            that.$ele.bind('mousedown.drag', function (event) {
                startOffset = {x:that.offsetX, y:that.offsetY};
                startX = event.pageX;
                startY = event.pageY;
                dragging = true;

                //fix bug dragging on image at FireFox
                event.preventDefault();
            });

            that.onPgMouseMove('drag', function (event) {
                //如果开始拖拽
                if (dragging) {
                    var deltaX = event.pageX - startX;
                    var deltaY = event.pageY - startY;
                    that.setX(startOffset.x + deltaX);
                    that.setY(startOffset.y + deltaY);

                    that._callWhenFunction(that._onDragCallbakc, event);
                }
            });

            that.onPgMouseUp('drag', function (event) {
                if (dragging) {
                    dragging = false;
                    //清空
                    startOffset = null;
                    startX = null;
                    startY = null;
                }
            });

            that.$ele.css('cursor', 'move');
        };

        //取消拖拽
        this.undrag = function () {
            //消除绑定的事件
            that.$ele.unbind("mousedown.drag");
            delete that._onPgMouseMoveCallbacks['drag'];
            delete that._onPgMouseUpCallbacks['drag'];

            that.$ele.css('cursor', 'default');
            return that;
        };

        //可以改变大小
        this.resizable = function () {
            var $mover = that.$ele.append('').find('i');
            var moving = false;
            var startBox = null;
            var topLeftPoint = null; //左上角
            var bottomRightPoint = null; //右下角
            var startOffset = null;
            var endOffset = null;
            $mover.mousedown(function (event) {
                moving = true;
                startBox = that.box();
                topLeftPoint = {x:startBox.x, y:startBox.y};
                bottomRightPoint = {
                    x:startBox.x + startBox.width,
                    y:startBox.y + startBox.height
                };
                startOffset = {x:event.pageX, y:event.pageY};
            });

            that.onPgMouseMove('resize', function (event) {
                if (moving) {
                    endOffset = {x:event.pageX, y:event.pageY};

                    var deltaX = endOffset.x - startOffset.x;
                    var deltaY = endOffset.y - startOffset.y;

                    var newEndPointX = bottomRightPoint.x + deltaX;
                    var newEndPointY = bottomRightPoint.y + deltaY;

                    var newX = Math.min(topLeftPoint.x, newEndPointX);
                    var newY = Math.min(topLeftPoint.y, newEndPointY);
                    that.setX(newX);
                    that.setY(newY);

                    that.setWidth(Math.abs(topLeftPoint.x - newEndPointX));
                    that.setHeight(Math.abs(topLeftPoint.y - newEndPointY));

                    $mover.removeClass('mover-nw mover-ne mover-sw mover-sw');
                    var direction = 0; // 小方块在 Rect 中的位置，初始在右下角
                    if (newY < topLeftPoint.y) {
                        direction = direction + 0; //上
                    } else {
                        direction = direction + 2; //下
                    }

                    if (newX < topLeftPoint.x) {
                        direction = direction + 0; //左
                    } else {
                        direction = direction + 1; //右
                    }

                    switch (direction) {
                        case 0:
                            $mover.addClass('mover-nw');
                            break;
                        case 1:
                            $mover.addClass('mover-ne');
                            break;
                        case 2:
                            $mover.addClass('mover-sw');
                            break;
                        case 3:
                            $mover.addClass('mover-se');
                            break;
                    }
                }
            });
            that.onPgMouseUp('resize', function (event) {
                if (moving) {
                    moving = false;
                    $mover.removeClass('mover-nw mover-ne mover-sw mover-sw');
                }
            });

            return that;
        };

        //取消改变大小
        this.unresize = function () {
            that.$ele.find('i').remove();
            delete that._onPgMouseMoveCallbacks['resize'];
            delete that._onPgMouseUpCallbacks['resize'];
        };

        //将自己删除
        this.remove = function () {
            that._callWhenFunction(that._onRemoveCallback, that);

            that.$ele.remove();
        };

        //注册删除回调
        this.onRemove = function (func) {
            that._onRemoveCallback = func;
        };

        /**
         * 返回矩形的位置及宽高
         * 如下：
         * {
         *    x: 左上角 x
         *    y: 左上角 y
         *    width: 宽度
         *    height: 高度
         * }
         */
        this.box = function () {
            return {x:that.offsetX, y:that.offsetY, width:that.width, height:that.height};
        };

        this.setX = function (x) {
            that.offsetX = x;
            that.$ele.css('left', x);
        };

        this.setY = function (y) {
            that.offsetY = y;
            that.$ele.css('top', y);
        };

        this.setOffset = function (x, y) {
            that.setX(x);
            that.setY(y);
        };

        this.setWidth = function (width) {
            that.width = width;
            that.$ele.width(width);
        };

        this.setHeight = function (height) {
            that.height = height;
            that.$ele.height(height);
        };

        this.setDimension = function (width, height) {
            that.setWidth(width);
            that.setHeight(height);
        };

        this.setColor = function (color) {
            that.$ele.css('border-color', color);
            return that;
        };
    }

    //创建新的 Rect
    Rect.build = function (playground) {
        var $rectEle = $(playground).append('

')
            .children().last();

        var rect = new Rect($rectEle[0]);
        rect.init();
        return rect;
    };

    //代表操场, 可以在里面画各种矩形
    function Playground(ele, options) {
        var that = this;
        //原生元素
        this.ele = ele;
        //jQuery 对象
        this.$ele = $(ele);
        this.$ele.addClass("playground");

        //保存所有的 Rect
        this.rects = [];
        (function () {
            //当画完一个新矩形时的回调
            that.onPaintRectComplete = null;
            if (_.has(options, 'rectComplete')) {
                that.onPaintRectComplete = options['rectComplete'];
            }

            //mouse moving
            that.$ele.bind('mousemove.onPgMouseMove', function (event) {
                _.each(that.rects, function (rect) {
                    rect.playgroundMouseMove(event);
                });
            });

            //mouse up
            that.$ele.bind('mouseup.onPgMouseUp', function (event) {
                _.each(that.rects, function (rect) {
                    rect.playgroundMouseUp(event);
                });
            });
        })();

        //画矩形
        this.paintRect = function (x, y, width, height) {
            var rect = Rect.build(that.ele);
            that.rects.push(rect);
            rect.onRemove(function (removingRect) {
                var index = _.indexOf(that.rects, removingRect);
                that.rects.splice(index, 1);
            });
            rect.setOffset(x, y);
            rect.setDimension(width, height);
            return rect;
        };

        //可以画矩形
        this.drawable = function () {
            var $ele = that.$ele;
            //新画矩形
            var newRect = null;
            //鼠标的起始点坐标(相对于 playground)
            var startOffset = null;
            //鼠标的终点坐标(相对于 playground)
            var endOffset = null;

            //开始画新的矩形
            $ele.bind('mousedown.draw', function (event) {
                //如果事件源来自 rect 或者 mover, 则忽略
                if (that.isEventFromRect(event)) {
                    return;
                }
                if (that.isEventFromMover(event)) {
                    return;
                }
                //如何事件源不是来自 rect
                startOffset = Painter.positionRelativeTo(event.pageX, event.pageY, $ele[0]);
                newRect = that.paintRect(startOffset.x, startOffset.y, 0, 0);
            });
            $ele.bind('mousemove.draw', function (event) {
                if (!_.isNull(startOffset)) { //如果是画矩形
                    endOffset = Painter.positionRelativeTo(event.pageX, event.pageY, $ele[0]);

                    newRect.setX(Math.min(startOffset.x, endOffset.x));
                    newRect.setY(Math.min(startOffset.y, endOffset.y));

                    newRect.setWidth(Math.abs(endOffset.x - startOffset.x));
                    newRect.setHeight(Math.abs(endOffset.y - startOffset.y));
                }
            });
            //结束画矩形
            $ele.bind('mouseup.draw', function () {
                if (!_.isNull(startOffset)) { //如果是画矩形
                    //调用矩形完成的回调
                    if (_.isFunction(that.onPaintRectComplete)) {
                        that.onPaintRectComplete(newRect);
                    }
                    //清空
                    startOffset = null;
                    endOffset = null;
                    newRect = null;
                }
            });
        };

        //取消可以画图
        this.undrawable = function () {
            //取消画图的鼠标事件
            that.$ele.unbind('.draw');
        };

        //判断此事件是否来自 Rect
        this.isEventFromRect = function (event) {
            return  $(event.target).hasClass('rect');
        };
        //判断此事件是否来自 Rect 的 mover
        this.isEventFromMover = function (event) {
            return $(event.target).hasClass('mover');
        };

        //init
        (function () {
            that.drawable();
        })();
    }

    /**
     * 创建操场
     *
     * 参数:
     * id : 绑定的元素的id
     * ele : 绑定的 dom element(元素)
     * rectComplete : 画完新矩形的回调, 会传入新画的矩形(Rect)的对象
     */
    Painter.playground = function (options) {
        var $ele = null;
        if (_.has(options, 'ele')) {
            $ele = $(options['ele']);
        } else if (_.has(options, 'id')) {
            $ele = $(options['id'])
        }

        return new Playground($ele[0], options);
    };

    //相对于某一个元素的坐标
    Painter.positionRelativeTo = function (pageX, pageY, element) {
        var offset = $(element).offset();
        return {x:pageX - offset.left, y:pageY - offset.top};
    };
})(jQuery);

<commit_msg>refactor<commit_after>/**
 *
 * draw rect
 * 画矩形
 *
 * User: bastengao
 * Date: 12-9-3  Time: 上午9:33
 * dependency : jQuery, underscore
 */
(function ($) {
    //画家是最大的名称空间
    //init Painter
    var Painter = (function () {
        if (_.isObject(window.Painter)) {
            return window.Painter;
        } else {
            window.Painter = {};
            return window.Painter;
        }
    })();

    //代表一个矩形
    function Rect(ele) {
        var that = this;
        this.ele = ele;
        this.$ele = $(ele);
        //左上角位置(Rect 元素的位置是相对于 playground 的位置)
        this.offsetX = 0;
        this.offsetY = 0;
        //宽高
        this.width = 0;
        this.height = 0;

        this._onPgMouseMoveCallbacks = {};
        this._onPgMouseUpCallbacks = {};

        //初始化
        this.init = function () {
            //默认可以拖
            that.dragable();
        };

        //playground 上鼠标移动时, Playground 会调用此方法
        this.playgroundMouseMove = function (event) {
            that._sendEvent(event, that._onPgMouseMoveCallbacks);
        };

        //注册 Playground 鼠标移动 回调
        this.onPgMouseMove = function (name, func) {
            that._onPgMouseMoveCallbacks[name] = func;
        };

        //playground 上鼠标弹起时，Playground 会调用此方法
        this.playgroundMouseUp = function (event) {
            that._sendEvent(event, that._onPgMouseUpCallbacks);
        };

        //注册 Playground 鼠标弹起 回调
        this.onPgMouseUp = function (name, func) {
            that._onPgMouseUpCallbacks[name] = func;
        };

        //注册拖动回调
        this.onDrag = function (func) {
            that._onDragCallbakc = func;
        };

        //可以拖
        this.dragable = function () {
            //拖拽开始时，Rect 元素在 document 中的位置
            var startOffset = null;
            //起点在 document 中的位置
            var startX = null;
            var startY = null;
            var dragging = false;
            that.$ele.bind('mousedown.drag', function (event) {
                startOffset = {x:that.offsetX, y:that.offsetY};
                startX = event.pageX;
                startY = event.pageY;
                dragging = true;

                //fix bug dragging on image at FireFox
                event.preventDefault();
            });

            that.onPgMouseMove('drag', function (event) {
                //如果开始拖拽
                if (dragging) {
                    var deltaX = event.pageX - startX;
                    var deltaY = event.pageY - startY;
                    that.setX(startOffset.x + deltaX);
                    that.setY(startOffset.y + deltaY);

                    Painter._callWhenFunction(that._onDragCallbakc, event);
                }
            });

            that.onPgMouseUp('drag', function (event) {
                if (dragging) {
                    dragging = false;
                    //清空
                    startOffset = null;
                    startX = null;
                    startY = null;
                }
            });

            that.$ele.css('cursor', 'move');
        };

        //取消拖拽
        this.undrag = function () {
            //消除绑定的事件
            that.$ele.unbind("mousedown.drag");
            delete that._onPgMouseMoveCallbacks['drag'];
            delete that._onPgMouseUpCallbacks['drag'];

            that.$ele.css('cursor', 'default');
            return that;
        };

        //可以改变大小
        this.resizable = function () {
            var $mover = that.$ele.append('').find('i');
            var moving = false;
            var startBox = null;
            var topLeftPoint = null; //左上角
            var bottomRightPoint = null; //右下角
            var startOffset = null;
            var endOffset = null;
            $mover.mousedown(function (event) {
                moving = true;
                startBox = that.box();
                topLeftPoint = {x:startBox.x, y:startBox.y};
                bottomRightPoint = {
                    x:startBox.x + startBox.width,
                    y:startBox.y + startBox.height
                };
                startOffset = {x:event.pageX, y:event.pageY};
            });

            that.onPgMouseMove('resize', function (event) {
                if (moving) {
                    endOffset = {x:event.pageX, y:event.pageY};

                    var deltaX = endOffset.x - startOffset.x;
                    var deltaY = endOffset.y - startOffset.y;

                    var newEndPointX = bottomRightPoint.x + deltaX;
                    var newEndPointY = bottomRightPoint.y + deltaY;

                    var newX = Math.min(topLeftPoint.x, newEndPointX);
                    var newY = Math.min(topLeftPoint.y, newEndPointY);
                    that.setX(newX);
                    that.setY(newY);

                    that.setWidth(Math.abs(topLeftPoint.x - newEndPointX));
                    that.setHeight(Math.abs(topLeftPoint.y - newEndPointY));

                    $mover.removeClass('mover-nw mover-ne mover-sw mover-sw');
                    var direction = 0; // 小方块在 Rect 中的位置，初始在右下角
                    if (newY < topLeftPoint.y) {
                        direction = direction + 0; //上
                    } else {
                        direction = direction + 2; //下
                    }

                    if (newX < topLeftPoint.x) {
                        direction = direction + 0; //左
                    } else {
                        direction = direction + 1; //右
                    }

                    switch (direction) {
                        case 0:
                            $mover.addClass('mover-nw');
                            break;
                        case 1:
                            $mover.addClass('mover-ne');
                            break;
                        case 2:
                            $mover.addClass('mover-sw');
                            break;
                        case 3:
                            $mover.addClass('mover-se');
                            break;
                    }
                }
            });
            that.onPgMouseUp('resize', function (event) {
                if (moving) {
                    moving = false;
                    $mover.removeClass('mover-nw mover-ne mover-sw mover-sw');
                }
            });

            return that;
        };

        //取消改变大小
        this.unresize = function () {
            that.$ele.find('i').remove();
            delete that._onPgMouseMoveCallbacks['resize'];
            delete that._onPgMouseUpCallbacks['resize'];
        };

        //将自己删除
        this.remove = function () {
            Painter._callWhenFunction(that._onRemoveCallback, that);

            that.$ele.remove();
        };

        //注册删除回调
        this.onRemove = function (func) {
            that._onRemoveCallback = func;
        };

        /**
         * 返回矩形的位置及宽高
         * 如下：
         * {
         *    x: 左上角 x
         *    y: 左上角 y
         *    width: 宽度
         *    height: 高度
         * }
         */
        this.box = function () {
            return {x:that.offsetX, y:that.offsetY, width:that.width, height:that.height};
        };

        this.setX = function (x) {
            that.offsetX = x;
            that.$ele.css('left', x);
        };

        this.setY = function (y) {
            that.offsetY = y;
            that.$ele.css('top', y);
        };

        this.setOffset = function (x, y) {
            that.setX(x);
            that.setY(y);
        };

        this.setWidth = function (width) {
            that.width = width;
            that.$ele.width(width);
        };

        this.setHeight = function (height) {
            that.height = height;
            that.$ele.height(height);
        };

        this.setDimension = function (width, height) {
            that.setWidth(width);
            that.setHeight(height);
        };

        this.setColor = function (color) {
            that.$ele.css('border-color', color);
            return that;
        };

        //遍历回调集合
        this._sendEvent = function (event, callbacks) {
            _.each(callbacks, function (callback) {
                Painter._callWhenFunction(callback, event);
            });
        };
    }

    //创建新的 Rect
    Rect.build = function (playground) {
        var $rectEle = $(playground).append('

')
            .children().last();

        var rect = new Rect($rectEle[0]);
        rect.init();
        return rect;
    };

    //代表操场, 可以在里面画各种矩形
    function Playground(ele, options) {
        var that = this;
        //原生元素
        this.ele = ele;
        //jQuery 对象
        this.$ele = $(ele);
        this.$ele.addClass("playground");

        //保存所有的 Rect
        this.rects = [];
        (function () {
            //当画完一个新矩形时的回调
            that.onPaintRectComplete = null;
            if (_.has(options, 'rectComplete')) {
                that.onPaintRectComplete = options['rectComplete'];
            }

            //mouse moving
            that.$ele.bind('mousemove.onPgMouseMove', function (event) {
                _.each(that.rects, function (rect) {
                    rect.playgroundMouseMove(event);
                });
            });

            //mouse up
            that.$ele.bind('mouseup.onPgMouseUp', function (event) {
                _.each(that.rects, function (rect) {
                    rect.playgroundMouseUp(event);
                });
            });
        })();

        //画矩形
        this.paintRect = function (x, y, width, height) {
            var rect = Rect.build(that.ele);
            that.rects.push(rect);
            rect.onRemove(function (removingRect) {
                var index = _.indexOf(that.rects, removingRect);
                that.rects.splice(index, 1);
            });
            rect.setOffset(x, y);
            rect.setDimension(width, height);
            return rect;
        };

        //可以画矩形
        this.drawable = function () {
            var $ele = that.$ele;
            //新画矩形
            var newRect = null;
            //鼠标的起始点坐标(相对于 playground)
            var startOffset = null;
            //鼠标的终点坐标(相对于 playground)
            var endOffset = null;
            var drawing = false;

            //开始画新的矩形
            $ele.bind('mousedown.draw', function (event) {
                //如果事件源来自 rect 或者 mover, 则忽略
                if (that.isEventFromRect(event)) {
                    return;
                }
                if (that.isEventFromMover(event)) {
                    return;
                }
                //如何事件源不是来自 rect
                startOffset = Painter.positionRelativeTo(event.pageX, event.pageY, $ele[0]);
                newRect = that.paintRect(startOffset.x, startOffset.y, 0, 0);
                drawing = true;
            });
            $ele.bind('mousemove.draw', function (event) {
                if (drawing) { //如果是画矩形
                    endOffset = Painter.positionRelativeTo(event.pageX, event.pageY, $ele[0]);

                    newRect.setX(Math.min(startOffset.x, endOffset.x));
                    newRect.setY(Math.min(startOffset.y, endOffset.y));

                    newRect.setWidth(Math.abs(endOffset.x - startOffset.x));
                    newRect.setHeight(Math.abs(endOffset.y - startOffset.y));
                }
            });
            //结束画矩形
            $ele.bind('mouseup.draw', function () {
                if (drawing) { //如果是画矩形
                    drawing = false;
                    //调用矩形完成的回调
                    Painter._callWhenFunction(that.onPaintRectComplete, newRect);

                    //清空
                    startOffset = null;
                    endOffset = null;
                    newRect = null;
                }
            });
        };

        //取消可以画图
        this.undrawable = function () {
            //取消画图的鼠标事件
            that.$ele.unbind('.draw');
        };

        //判断此事件是否来自 Rect
        this.isEventFromRect = function (event) {
            return  $(event.target).hasClass('rect');
        };
        //判断此事件是否来自 Rect 的 mover
        this.isEventFromMover = function (event) {
            return $(event.target).hasClass('mover');
        };

        //init
        (function () {
            that.drawable();
        })();
    }

    /**
     * 创建操场
     *
     * 参数:
     * id : 绑定的元素的id
     * ele : 绑定的 dom element(元素)
     * rectComplete : 画完新矩形的回调, 会传入新画的矩形(Rect)的对象
     */
    Painter.playground = function (options) {
        var $ele = null;
        if (_.has(options, 'ele')) {
            $ele = $(options['ele']);
        } else if (_.has(options, 'id')) {
            $ele = $(options['id'])
        }

        return new Playground($ele[0], options);
    };

    //相对于某一个元素的坐标
    Painter.positionRelativeTo = function (pageX, pageY, element) {
        var offset = $(element).offset();
        return {x:pageX - offset.left, y:pageY - offset.top};
    };

    //调用，如果能调用
    Painter._callWhenFunction = function (func, args) {
        if (_.isFunction(func)) {
            func(args);
        }
    };
})(jQuery);

<|endoftext|>


<commit_before>// @flow
import storage from 'electron-json-storage'
import { wallet } from 'neon-js'
import { isEmpty } from 'lodash-es'

import {
  showErrorNotification,
  showInfoNotification,
  hideNotification
} from './notifications'

import { validatePassphraseLength } from '../core/wallet'
import { ROUTES, DEFAULT_WALLET } from '../core/constants'
import { Account } from '../core/schemas'

// Actions
import { saveAccountActions, getWallet } from '../actions/accountsActions'

// Constants
export const NEW_WALLET_ACCOUNT = 'NEW_WALLET_ACCOUNT'
export const RESET_WALLET_ACCOUNT = 'RESET_WALLET_ACCOUNT'

export function newWalletAccount({
  account,
  isImport
}: {
  account: Object,
  isImport: boolean
}) {
  return {
    type: NEW_WALLET_ACCOUNT,
    payload: {
      wif: account.wif,
      address: account.address,
      passphrase: account.passphrase,
      encryptedWIF: account.encryptedWIF,
      walletName: account.walletName,
      isImport
    }
  }
}

export function resetKey() {
  return {
    type: RESET_WALLET_ACCOUNT
  }
}

// Utils
export const walletHasKey = (wallet: Object, key: string) =>
  wallet.accounts.some(account => account.key === key)

export const walletHasLabel = (wallet: Object, label: string) =>
  wallet.accounts.some(account => account.label === label)

export const convertOldWalletAccount = (
  label: string,
  key: string,
  isDefault: boolean
) => {
  if (!key || typeof key !== 'string') return
  return new Account({
    address: '', // Unfortunately all we have is the encrypted private keys, so no way to get this for now.
    label,
    isDefault, // Make the first account the default
    key
  })
}

export const upgradeUserWalletNEP6 = (): Promise<*> =>
  new Promise((resolve, reject) => {
    storage.get('userWallet', (readNEP6Error, data) => {
      if (readNEP6Error) {
        reject(readNEP6Error)
      }

      if (isEmpty(data)) {
        storage.get('keys', (readLegacyError, keyData) => {
          if (readLegacyError) {
            reject(readLegacyError)
          }
          const wallet = { ...DEFAULT_WALLET }

          if (isEmpty(keyData)) {
            // create empty nep-6 wallet
            storage.set('userWallet', wallet)
          } else {
            const accounts = []
            // eslint-disable-next-line
            Object.keys(keyData).map((label: string) => {
              const newAccount = convertOldWalletAccount(
                label,
                keyData[label],
                accounts.length === 0
              )
              if (newAccount) {
                accounts.push(newAccount)
              }
            })

            wallet.accounts = accounts

            storage.set('userWallet', wallet, saveError => {
              if (saveError) {
                reject(saveError)
              } else {
                resolve()
              }
            })
          }
        })
      } else {
        resolve()
      }
    })
  })

export const recoverWallet = (wallet: Object): Promise<*> =>
  new Promise((resolve, reject) => {
    storage.get('userWallet', (readError, data) => {
      if (readError) {
        reject(readError)
      }

      let accounts: Array<any> = []

      // If for some reason we have no NEP-6 wallet stored, create a default.
      if (!data) {
        data = { ...DEFAULT_WALLET } // eslint-disable-line no-param-reassign
      }

      if (!wallet.accounts) {
        // Load the old wallet type
        // eslint-disable-next-line
        Object.keys(wallet).map((label: string) => {
          const isDefault = accounts.length === 0 && wallet.length === 0
          const newAccount = convertOldWalletAccount(
            label,
            wallet[label],
            isDefault
          )
          if (newAccount && newAccount.key) {
            accounts.push(newAccount)
          }
        })
      } else {
        accounts = wallet.accounts // eslint-disable-line
      }

      if (!accounts.length) {
        reject(Error('No accounts found in recovery file.'))
      }

      // eslint-disable-next-line
      accounts.some(account => {
        if (account.key && !walletHasKey(data, account.key)) {
          data.accounts.push(account)
        }
      })

      storage.set('userWallet', data, saveError => {
        if (saveError) {
          reject(saveError)
        } else {
          resolve(data)
        }
      })
    })
  })

export const generateNewWalletAccount = (
  passphrase: string,
  passphrase2: string,
  wif?: string,
  history: Object,
  walletName: string,
  authenticated: boolean = false,
  onFailure: () => any = () => undefined
) => (dispatch: DispatchType) => {
  const isImport = !!wif
  const dispatchError = (message: string) => {
    dispatch(showErrorNotification({ message }))
    return false
  }
  if (passphrase !== passphrase2) {
    onFailure()
    return dispatchError('Passphrases do not match')
  }
  if (!validatePassphraseLength(passphrase)) {
    onFailure()
    return dispatchError('Please choose a longer passphrase')
  }
  if (wif && !wallet.isWIF(wif)) {
    onFailure()
    return dispatchError('The private key is not valid')
  }
  const infoNotificationId: any = dispatch(
    showInfoNotification({
      message: 'Generating encoded key...',
      autoDismiss: 0
    })
  )
  setTimeout(async () => {
    try {
      const account = new wallet.Account(wif || wallet.generatePrivateKey())
      const { WIF, address } = account
      const encryptedWIF = wallet.encrypt(WIF, passphrase)

      const storedWallet = await getWallet()
      if (walletName && walletHasLabel(storedWallet, walletName)) {
        onFailure()
        return dispatchError('A wallet with this name already exists locally')
      }

      dispatch(
        saveAccountActions.call({
          isImport,
          label: walletName,
          address,
          key: encryptedWIF
        })
      )

      dispatch(hideNotification(infoNotificationId))
      dispatch(
        newWalletAccount({
          account: {
            wif: WIF,
            address,
            passphrase,
            encryptedWIF,
            walletName
          },
          isImport
        })
      )

      if (wif) history.push(ROUTES.HOME)
      if (authenticated) history.push(ROUTES.DISPLAY_WALLET_KEYS_AUTHENTICATED)
      else history.push(ROUTES.DISPLAY_WALLET_KEYS)
      return true
    } catch (e) {
      onFailure()
      console.error(e)
      return dispatchError(
        `An error occured while trying to ${
          isImport ? 'import' : 'generate'
        } a new wallet`
      )
    }
  }, 500)
}

// state getters
export const getWIF = (state: Object) => state.generateWallet.wif
export const getAddress = (state: Object) => state.generateWallet.address
export const getPassphrase = (state: Object) => state.generateWallet.passphrase
export const getWalletName = (state: Object) => state.generateWallet.walletName
export const getEncryptedWIF = (state: Object) =>
  state.generateWallet.encryptedWIF
export const getIsImport = (state: Object) => state.generateWallet.isImport

const initialState = {
  wif: null,
  address: null,
  passphrase: null,
  encryptedWIF: null,
  walletName: null,
  isImport: null
}

export default (state: Object = initialState, action: ReduxAction) => {
  switch (action.type) {
    case NEW_WALLET_ACCOUNT: {
      const {
        passphrase,
        wif,
        address,
        encryptedWIF,
        walletName,
        isImport
      } = action.payload
      return {
        ...state,
        wif,
        address,
        passphrase,
        encryptedWIF,
        walletName,
        isImport
      }
    }
    case RESET_WALLET_ACCOUNT: {
      return { ...initialState }
    }
    default:
      return state
  }
}
<commit_msg>[#1640] Added wallet import name duplication validation (#1697)<commit_after>// @flow
import storage from 'electron-json-storage'
import { wallet } from 'neon-js'
import { isEmpty, intersectionBy } from 'lodash-es'

import {
  showErrorNotification,
  showInfoNotification,
  hideNotification
} from './notifications'

import { validatePassphraseLength } from '../core/wallet'
import { ROUTES, DEFAULT_WALLET } from '../core/constants'
import { Account } from '../core/schemas'

// Actions
import { saveAccountActions, getWallet } from '../actions/accountsActions'

// Constants
export const NEW_WALLET_ACCOUNT = 'NEW_WALLET_ACCOUNT'
export const RESET_WALLET_ACCOUNT = 'RESET_WALLET_ACCOUNT'

export function newWalletAccount({
  account,
  isImport
}: {
  account: Object,
  isImport: boolean
}) {
  return {
    type: NEW_WALLET_ACCOUNT,
    payload: {
      wif: account.wif,
      address: account.address,
      passphrase: account.passphrase,
      encryptedWIF: account.encryptedWIF,
      walletName: account.walletName,
      isImport
    }
  }
}

export function resetKey() {
  return {
    type: RESET_WALLET_ACCOUNT
  }
}

// Utils
export const walletHasKey = (wallet: Object, key: string) =>
  wallet.accounts.some(account => account.key === key)

export const walletHasLabel = (wallet: Object, label: string) =>
  wallet.accounts.some(account => account.label === label)

export const convertOldWalletAccount = (
  label: string,
  key: string,
  isDefault: boolean
) => {
  if (!key || typeof key !== 'string') return
  return new Account({
    address: '', // Unfortunately all we have is the encrypted private keys, so no way to get this for now.
    label,
    isDefault, // Make the first account the default
    key
  })
}

export const upgradeUserWalletNEP6 = (): Promise<*> =>
  new Promise((resolve, reject) => {
    storage.get('userWallet', (readNEP6Error, data) => {
      if (readNEP6Error) {
        reject(readNEP6Error)
      }

      if (isEmpty(data)) {
        storage.get('keys', (readLegacyError, keyData) => {
          if (readLegacyError) {
            reject(readLegacyError)
          }
          const wallet = { ...DEFAULT_WALLET }

          if (isEmpty(keyData)) {
            // create empty nep-6 wallet
            storage.set('userWallet', wallet)
          } else {
            const accounts = []
            // eslint-disable-next-line
            Object.keys(keyData).map((label: string) => {
              const newAccount = convertOldWalletAccount(
                label,
                keyData[label],
                accounts.length === 0
              )
              if (newAccount) {
                accounts.push(newAccount)
              }
            })

            wallet.accounts = accounts

            storage.set('userWallet', wallet, saveError => {
              if (saveError) {
                reject(saveError)
              } else {
                resolve()
              }
            })
          }
        })
      } else {
        resolve()
      }
    })
  })

export const recoverWallet = (wallet: Object): Promise<*> =>
  new Promise((resolve, reject) => {
    storage.get('userWallet', (readError, data) => {
      if (readError) {
        reject(readError)
      }

      let accounts: Array<any> = []

      // If for some reason we have no NEP-6 wallet stored, create a default.
      if (!data) {
        data = { ...DEFAULT_WALLET } // eslint-disable-line no-param-reassign
      }

      if (!wallet.accounts) {
        // Load the old wallet type
        // eslint-disable-next-line
        Object.keys(wallet).map((label: string) => {
          const isDefault = accounts.length === 0 && wallet.length === 0
          const newAccount = convertOldWalletAccount(
            label,
            wallet[label],
            isDefault
          )
          if (newAccount && newAccount.key) {
            accounts.push(newAccount)
          }
        })
      } else {
        accounts = wallet.accounts // eslint-disable-line
      }

      if (!accounts.length) {
        reject(Error('No accounts found in recovery file.'))
      }

      // check if wallet label already exists
      const duplicateLabels = intersectionBy(data.accounts, accounts, 'label')

      if (duplicateLabels.length > 0) {
        reject(Error('A wallet with this name already exists locally.'))
      }

      // eslint-disable-next-line
      accounts.some(account => {
        if (account.key && !walletHasKey(data, account.key)) {
          data.accounts.push(account)
        }
      })

      storage.set('userWallet', data, saveError => {
        if (saveError) {
          reject(saveError)
        } else {
          resolve(data)
        }
      })
    })
  })

export const generateNewWalletAccount = (
  passphrase: string,
  passphrase2: string,
  wif?: string,
  history: Object,
  walletName: string,
  authenticated: boolean = false,
  onFailure: () => any = () => undefined
) => (dispatch: DispatchType) => {
  const isImport = !!wif
  const dispatchError = (message: string) => {
    dispatch(showErrorNotification({ message }))
    return false
  }
  if (passphrase !== passphrase2) {
    onFailure()
    return dispatchError('Passphrases do not match')
  }
  if (!validatePassphraseLength(passphrase)) {
    onFailure()
    return dispatchError('Please choose a longer passphrase')
  }
  if (wif && !wallet.isWIF(wif)) {
    onFailure()
    return dispatchError('The private key is not valid')
  }
  const infoNotificationId: any = dispatch(
    showInfoNotification({
      message: 'Generating encoded key...',
      autoDismiss: 0
    })
  )
  setTimeout(async () => {
    try {
      const account = new wallet.Account(wif || wallet.generatePrivateKey())
      const { WIF, address } = account
      const encryptedWIF = wallet.encrypt(WIF, passphrase)

      const storedWallet = await getWallet()
      if (walletName && walletHasLabel(storedWallet, walletName)) {
        onFailure()
        return dispatchError('A wallet with this name already exists locally')
      }

      dispatch(
        saveAccountActions.call({
          isImport,
          label: walletName,
          address,
          key: encryptedWIF
        })
      )

      dispatch(hideNotification(infoNotificationId))
      dispatch(
        newWalletAccount({
          account: {
            wif: WIF,
            address,
            passphrase,
            encryptedWIF,
            walletName
          },
          isImport
        })
      )

      if (wif) history.push(ROUTES.HOME)
      if (authenticated) history.push(ROUTES.DISPLAY_WALLET_KEYS_AUTHENTICATED)
      else history.push(ROUTES.DISPLAY_WALLET_KEYS)
      return true
    } catch (e) {
      onFailure()
      console.error(e)
      return dispatchError(
        `An error occured while trying to ${
          isImport ? 'import' : 'generate'
        } a new wallet`
      )
    }
  }, 500)
}

// state getters
export const getWIF = (state: Object) => state.generateWallet.wif
export const getAddress = (state: Object) => state.generateWallet.address
export const getPassphrase = (state: Object) => state.generateWallet.passphrase
export const getWalletName = (state: Object) => state.generateWallet.walletName
export const getEncryptedWIF = (state: Object) =>
  state.generateWallet.encryptedWIF
export const getIsImport = (state: Object) => state.generateWallet.isImport

const initialState = {
  wif: null,
  address: null,
  passphrase: null,
  encryptedWIF: null,
  walletName: null,
  isImport: null
}

export default (state: Object = initialState, action: ReduxAction) => {
  switch (action.type) {
    case NEW_WALLET_ACCOUNT: {
      const {
        passphrase,
        wif,
        address,
        encryptedWIF,
        walletName,
        isImport
      } = action.payload
      return {
        ...state,
        wif,
        address,
        passphrase,
        encryptedWIF,
        walletName,
        isImport
      }
    }
    case RESET_WALLET_ACCOUNT: {
      return { ...initialState }
    }
    default:
      return state
  }
}
<|endoftext|>


<commit_before>require('traceur/bin/traceur-runtime.js')

var $ = require('jquery')
  , io = require('socket.io-client')()
  , initWebrtc = require('./init-webrtc')
  , captureFrames = require('./capture-frames')
  , cuid = require('cuid')
  , Fingerprint = require('fingerprintjs')
  , NotificationCounter = require('./notification-counter')
  , StoredSet = require('./stored-set')
  , createCharCounter = require('./char-counter')
  , createDropdown = require('./dropdown')
  , progressSpinner = require('./progress')($('.progress'))
  , muteSet = new StoredSet('mutes')
  , messageList = require('./message')($('#message-list'), muteSet)
  , detectVideoSupport = require('./detect-video-support')

var supportedVideoTypes = detectVideoSupport()

var active = 0
  , meatspaceActive = 0
io.on('connect', function() {
  io.emit('fingerprint', new Fingerprint({ canvas: true }).get())
  // TODO(tec27): detect cases where video isn't supported at all and pick based on performance?
  io.emit('join', supportedVideoTypes.webm ? 'webm' : 'x264')
}).on('disconnect', function() {
  active = 0
  meatspaceActive = 0
  updateActiveUsers()
})

var unreadMessages = 0
io.on('chat', function(chat) {
  var autoScroll = $(window).scrollTop() + $(window).height() + 32 > $(document).height()
  var message = messageList.addMessage(chat, autoScroll)
  if (message && autoScroll) {
    message.elem[0].scrollIntoView()
  }

  if (message && document.hidden) {
    unreadMessages++
    updateNotificationCount()
  }
}).on('active', function(numActive) {
  active = numActive
  updateActiveUsers()
}).on('meatspaceActive', function(numActive) {
  meatspaceActive = numActive
  updateActiveUsers()
}).on('meatspace', function(status) {
  if (status != 'connected') {
    meatspaceActive = 0
    updateActiveUsers()
  }
})

function updateActiveUsers() {
  $('#active-users')
    .text(active + meatspaceActive)
    .attr('title', `${active} active seat.camp users, ${meatspaceActive} meatspace`)
}

createDropdown($('header .dropdown'), {
  unmute: () => muteSet.clear()
})

var messageInput = $('#message')
  , awaitingAck = null

createCharCounter(messageInput, $('#char-counter'), 250)

$('form').on('submit', function(event) {
  event.preventDefault()

  if (awaitingAck) return

  messageInput.prop('readonly', true)
  awaitingAck = cuid()
  progressSpinner.setValue(0).show()

  captureFrames($('#preview')[0], {
    format: 'image/jpeg',
    width: 200,
    height: 150
  }, function(err, frames) {
    setTimeout(() => {
      progressSpinner.hide()
      setTimeout(() => progressSpinner.setValue(0), 400)
    }, 400)
    if (err) {
      messageInput.prop('readonly', false)
      awaitingAck = null
      // TODO(tec27): show to user
      return console.error(err)
    }

    var message = {
      text: messageInput.val(),
      format: 'image/jpeg',
      ack: awaitingAck
    }
    io.emit('chat', message, frames)
    messageInput.val('').change()
  }).on('progress', percentDone => progressSpinner.setValue(percentDone))
})

io.on('ack', function(ack) {
  if (awaitingAck && awaitingAck == ack.key) {
    messageInput.prop('readonly', false)
    awaitingAck = null
    if (ack.err) {
      // TODO(tec27): display to user
      console.log('Error: ' + ack.err)
    }
  }
})

initWebrtc($('#preview')[0], 200, 150, function(err, stream) {
  if (err) {
    // TODO(tec27): display something to user depending on error type
    console.dir(err)
    return
  }

  // TODO(tec27): save stream so it can be stopped later to allow for camera switches
})

$(document).on('visibilitychange', () => {
  if (!document.hidden) {
    unreadMessages = 0
    updateNotificationCount()
  }
})

var notificationCounter = new NotificationCounter()
function updateNotificationCount() {
  if (!unreadMessages) {
    notificationCounter.clear()
  } else {
    notificationCounter.setCount(unreadMessages)
  }
}
<commit_msg>Correct user count for not connected case.<commit_after>require('traceur/bin/traceur-runtime.js')

var $ = require('jquery')
  , io = require('socket.io-client')()
  , initWebrtc = require('./init-webrtc')
  , captureFrames = require('./capture-frames')
  , cuid = require('cuid')
  , Fingerprint = require('fingerprintjs')
  , NotificationCounter = require('./notification-counter')
  , StoredSet = require('./stored-set')
  , createCharCounter = require('./char-counter')
  , createDropdown = require('./dropdown')
  , progressSpinner = require('./progress')($('.progress'))
  , muteSet = new StoredSet('mutes')
  , messageList = require('./message')($('#message-list'), muteSet)
  , detectVideoSupport = require('./detect-video-support')

var supportedVideoTypes = detectVideoSupport()

var active = 0
  , meatspaceActive = 0
io.on('connect', function() {
  io.emit('fingerprint', new Fingerprint({ canvas: true }).get())
  // TODO(tec27): detect cases where video isn't supported at all and pick based on performance?
  io.emit('join', supportedVideoTypes.webm ? 'webm' : 'x264')
}).on('disconnect', function() {
  active = 0
  meatspaceActive = 0
  updateActiveUsers()
})

var unreadMessages = 0
io.on('chat', function(chat) {
  var autoScroll = $(window).scrollTop() + $(window).height() + 32 > $(document).height()
  var message = messageList.addMessage(chat, autoScroll)
  if (message && autoScroll) {
    message.elem[0].scrollIntoView()
  }

  if (message && document.hidden) {
    unreadMessages++
    updateNotificationCount()
  }
}).on('active', function(numActive) {
  active = numActive
  updateActiveUsers()
}).on('meatspaceActive', function(numActive) {
  meatspaceActive = numActive
  updateActiveUsers()
}).on('meatspace', function(status) {
  if (status != 'connected') {
    meatspaceActive = 0
    updateActiveUsers()
  }
})

function updateActiveUsers() {
  if (active + meatspaceActive > 0) {
    $('#active-users')
      .text(active + meatspaceActive)
      .attr('title', `${active} active seat.camp users, ${meatspaceActive} meatspace`)
  } else {
    $('#active-users')
      .text('?')
      .attr('title', 'not connected')
  }
}

createDropdown($('header .dropdown'), {
  unmute: () => muteSet.clear()
})

var messageInput = $('#message')
  , awaitingAck = null

createCharCounter(messageInput, $('#char-counter'), 250)

$('form').on('submit', function(event) {
  event.preventDefault()

  if (awaitingAck) return

  messageInput.prop('readonly', true)
  awaitingAck = cuid()
  progressSpinner.setValue(0).show()

  captureFrames($('#preview')[0], {
    format: 'image/jpeg',
    width: 200,
    height: 150
  }, function(err, frames) {
    setTimeout(() => {
      progressSpinner.hide()
      setTimeout(() => progressSpinner.setValue(0), 400)
    }, 400)
    if (err) {
      messageInput.prop('readonly', false)
      awaitingAck = null
      // TODO(tec27): show to user
      return console.error(err)
    }

    var message = {
      text: messageInput.val(),
      format: 'image/jpeg',
      ack: awaitingAck
    }
    io.emit('chat', message, frames)
    messageInput.val('').change()
  }).on('progress', percentDone => progressSpinner.setValue(percentDone))
})

io.on('ack', function(ack) {
  if (awaitingAck && awaitingAck == ack.key) {
    messageInput.prop('readonly', false)
    awaitingAck = null
    if (ack.err) {
      // TODO(tec27): display to user
      console.log('Error: ' + ack.err)
    }
  }
})

initWebrtc($('#preview')[0], 200, 150, function(err, stream) {
  if (err) {
    // TODO(tec27): display something to user depending on error type
    console.dir(err)
    return
  }

  // TODO(tec27): save stream so it can be stopped later to allow for camera switches
})

$(document).on('visibilitychange', () => {
  if (!document.hidden) {
    unreadMessages = 0
    updateNotificationCount()
  }
})

var notificationCounter = new NotificationCounter()
function updateNotificationCount() {
  if (!unreadMessages) {
    notificationCounter.clear()
  } else {
    notificationCounter.setCount(unreadMessages)
  }
}
<|endoftext|>


<commit_before>'use strict';

const builder = require('botbuilder');
const jira = require('../services/jira');
const lib = new builder.Library('search');

const empty = (arr) => {
    return !arr || arr.length === 0;
};

const find = (...args) => {
    const el = builder.EntityRecognizer.findEntity.call(this, ...args);
    return el ? el.entity : null;
};

lib.dialog('/', [
        (session, args) => {

            if (!session.userData.profile) {
                return session.send(`Looks like you haven't signed in.`).replaceDialog('greet:/');
            } else if (empty.call(this, ...session.userData.jira)) {
                return session.send(`Looks like you don't have JIRA access.`).replaceDialog('greet:/');
            }

            session.beginDialog('/prepare', args);
        },

        (session, results) => {
            if (!results.response) {
                return session.endDialogWithResult({
                    resumed: builder.ResumeReason.notCompleted
                });
            }

            session.dialogData.queries = results.response;
            session.beginDialog('/query', session.dialogData);
        },

        (session, results) => {

            if (!results.response) {
                return session.endDialogWithResult({
                    resumed: builder.ResumeReason.notCompleted
                });
            }
            session.dialogData.results = results.response;
            session.beginDialog('/complete', session.dialogData);
        }
    ])
    .triggerAction({
        matches: ['/search']
    });

lib.dialog('/prepare', [
    (session, args, next) => {
        const query = find.call(this, ...[args.intent.entities, 'query']);
        if (query) {
            next({
                response: query
            });
        } else {
            session.send(`I couldn't figure out what to search (wasntme)`)
                .endDialogWithResult({
                    resumed: builder.ResumeReason.notCompleted
                });
        }
    },

    (session, results) => {
        const query = results.response;

        const queries = session.userData.jira.map((instance) => {
            return {
                criteria: query,
                project: instance
            };
        });

        session.endDialogWithResult({
            response: queries
        });
    }
]);

lib.dialog('/query', [
    (session, args, next) => {

        session.dialogData.queries = args.queries;
        session.dialogData.current = args.current || 0;

        const query = session.dialogData.queries[session.dialogData.current];

        jira.searchIssues(query.project, query.criteria)
            .then((response) => {
                response = response || [];

                query.results = response.map((issue) => {
                        return `* ${issue.key} - ${issue.summary}`;
                    })
                    .join('\n');

                next();
            })
            .catch((error) => {
                query.results = `* Couldn't find anything cause of this error ${error.statusCode}`;
                next();
            });
    },

    (session) => {
        session.dialogData.current++;
        if (session.dialogData.current >= session.dialogData.queries.length) {
            return session.endDialogWithResult({
                response: session.dialogData.queries
            });
        }
        session.replaceDialog('/query', session.dialogData);
    }
]);

lib.dialog('/complete', [
    (session, args) => {

        const {
            response
        } = args;
        let message = '';

        response.map((query) => {
                return `${query.project.account}${'\n'}${query.results}${'\n'}`;
            })
            .join('');

        session.send(message)
            .endDialog();
    }
]);

module.exports = exports = {
    createNew: () => {
        return lib.clone();
    }
};<commit_msg>#17 fixing search results formatting.<commit_after>'use strict';

const builder = require('botbuilder');
const jira = require('../services/jira');
const lib = new builder.Library('search');

const empty = (arr) => {
    return !arr || arr.length === 0;
};

const find = (...args) => {
    const el = builder.EntityRecognizer.findEntity.call(this, ...args);
    return el ? el.entity : null;
};

lib.dialog('/', [
        (session, args) => {

            if (!session.userData.profile) {
                return session.send(`Looks like you haven't signed in.`).replaceDialog('greet:/');
            } else if (empty.call(this, ...session.userData.jira)) {
                return session.send(`Looks like you don't have JIRA access.`).replaceDialog('greet:/');
            }

            session.beginDialog('/prepare', args);
        },

        (session, results) => {

            if (!results.response) {
                return session.endDialogWithResult({
                    resumed: builder.ResumeReason.notCompleted
                });
            }

            session.dialogData.queries = results.response;
            session.beginDialog('/query', session.dialogData);
        },

        (session, results) => {

            if (!results.response) {
                return session.endDialogWithResult({
                    resumed: builder.ResumeReason.notCompleted
                });
            }
            session.dialogData.results = results.response;
            session.beginDialog('/complete', session.dialogData);
        }
    ])
    .triggerAction({
        matches: ['/search']
    });

lib.dialog('/prepare', [
    (session, args, next) => {
        const query = find.call(this, ...[args.intent.entities, 'query']);
        if (query) {
            next({
                response: query
            });
        } else {
            session.send(`I couldn't figure out what to search (wasntme)`)
                .endDialogWithResult({
                    resumed: builder.ResumeReason.notCompleted
                });
        }
    },

    (session, results) => {
        const query = results.response;

        const queries = session.userData.jira.map((instance) => {
            return {
                criteria: query,
                project: instance
            };
        });

        session.endDialogWithResult({
            response: queries
        });
    }
]);

lib.dialog('/query', [
    (session, args, next) => {

        session.dialogData.queries = args.queries;
        session.dialogData.current = args.current || 0;

        const query = session.dialogData.queries[session.dialogData.current];

        jira.searchIssues(query.project, query.criteria)
            .then((response) => {
                response = response || [];

                query.results = response.map((issue) => {
                        return `* ${issue.key} - ${issue.summary}`;
                    })
                    .join('\n');

                next();
            })
            .catch((error) => {
                query.results = `* Couldn't find anything cause of this error ${error.statusCode}`;
                next();
            });
    },

    (session) => {
        session.dialogData.current++;
        if (session.dialogData.current >= session.dialogData.queries.length) {
            return session.endDialogWithResult({
                response: session.dialogData.queries
            });
        }
        session.replaceDialog('/query', session.dialogData);
    }
]);

lib.dialog('/complete', [
    (session, args) => {

        console.log('complete args', JSON.stringify(args.results));

        const {
            results
        } = args;
        const message = results.map((query) => {
                return `${query.project.name}${'\n'}${query.results}${'\n'}`;
            })
            .join('');

        session.send(message)
            .endDialog();
    }
]);

module.exports = exports = {
    createNew: () => {
        return lib.clone();
    }
};<|endoftext|>


<commit_before><commit_msg>Clear Jasmine reporters to avoid exit code issues<commit_after><|endoftext|>