import {Log} from "fme-logger"; var L = new Log("users"); var _ = require('underscore')._ var _m = require('moment'); var bcrypt = require('bcrypt-nodejs'); var ObjectId = require('mongodb').ObjectId; import {TradechatServer} from "../tradechat-server"; import {TradechatUser,Penalty, FmeUser, LiteUser, LoginLog} from "./user-models" export {TradechatUser} import {Collection} from "mongodb" export class TradechatUserController { usersOnline:TradechatUser[] = []; userDb:Collection = {} as Collection; allUsers:TradechatUser[] = []; bannedUsers:string[] = []; // array of user ids that are banned kickedUsers:string[] = []; constructor(public tradechatServer:TradechatServer){ } init = async () => { this.userDb = this.tradechatServer.db.collection("users"); // await this.fixDb(); } fixDb = async () => { L.info("FIX DB ### FIXING UP STRIPE IDS ######") var users = await this.userDb.find({}).toArray(); for (var i in users) { var user = users[i]; if (user.stripeID) { L.info("## Have a stripeID",user.stripeID); var st = {company:"MRTOPSTEP",isLive:true,stripeId:user.stripeID} if (user.stripeIds && user.stripeIds.constructor == Array) { for (var j in user.stripeIds) { var sid = user.stripeIds[j].stripeId; if (sid == user.stripeID) { L.info("ALREADY CONVERTED THIS STRIPE ID",user.stripeID); continue; } } user.stripeIds.push(st); } else { user.stripeIds = [st]; } } else { user.stripeIds = []; } await this.userDb.update({_id:user._id},user); } } create = async (email:string,password:string,username:string) => { let user = await this.getByEmail(email); if (user) { L.error("create: User already exists!",user,email); return user; } user = new FmeUser() as FmeUser; L.info("Create: New user",email); user.local.email = email; user.local.username = username; user.role.name = "SUBSCRIBER"; user.local.password = bcrypt.hashSync(password, bcrypt.genSaltSync(8), null); await this.update(user); return user; } changePassword = async (user:FmeUser,password:string) => { user.local.password = bcrypt.hashSync(password, bcrypt.genSaltSync(8), null); await this.update(user); return user; } liteUser = (user:FmeUser) => { var lUser = new LiteUser(); lUser._id = user._id; lUser.color = user.color; lUser.company = user.company; lUser.invert_color = user.invert_color; lUser.local.username = user.local.username; lUser.local.email = user.local.email; lUser.isLive = user.isLive; lUser.role = user.role; return lUser } generatePassword = (password:string) => { return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null); } initKickedUsers = async() => { L.info("Getting list of kicked users"); var users = await this.userDb.find({"kick.status":true}).toArray(); this.kickedUsers = users.map( (a) => {return a._id}); L.info("initBannedUsers:Count:",users.length); } initBannedUsers = async() => { L.info("Getting list of baned users"); var users = await this.userDb.find({"ban.status":true}).toArray(); this.bannedUsers = users.map( (a) => {return a._id}); L.info("initBannedUsers:Count:",users.length); } addKickedUser = async(user:TradechatUser,penalty:Penalty) => { if (!user.id) { L.error("Add kicked users called without user.id",user); return; } L.info("Adding a kicked users to the list",user.name,user.id); if (this.isKicked(user)) { L.error("This user is already kicked!"); } else { this.kickedUsers.push(user.id); await this.userDb.update({_id:user.id},{kick:penalty}); } return; } addBannedUser = async(user:TradechatUser,penalty:Penalty) => { if (!user.id) { L.error("Add kicked users called without user.id",user); return; } L.info("Adding a kicked users to the list",user.name,user.id); if (this.isBanned(user)) { L.error("This user is already kicked!"); } else { this.bannedUsers.push(user.id); await this.userDb.update({_id:user.id},{ban:penalty}); } return; } addLoginLog = async(user: TradechatUser,source:string,ippadr:string) => { if (!user.id) { L.error("addLoginLog: user has no id",user); return false; } var m = new LoginLog(); m.ipaddr = ippadr; m.source = source; m.time = new Date(); var fullUser = await this.getById(user.id); fullUser.login_log.push(m); this.update(fullUser); return fullUser; } addAdminLog = async(user: FmeUser,source:string,message:string) => { var m = _m().format("YYYYMMDD-HHMMSS") + ":"+source + ":" + message; user.admin_log.push(m); await this.update(user); return user; } isKicked = (user:TradechatUser) => { if (!user.id) return; return (this.kickedUsers.indexOf(user.id) > -1) } isBanned = (user:TradechatUser) => { if (!user.id) return; return (this.bannedUsers.indexOf(user.id) > -1) } getAllByRoom = async (roomName:string) => { try { var r = await this.userDb.find({rooms:roomName}).toArray() as FmeUser[] | null; if (r == null) { L.info("getAllByRoom: Returned null!") return null } L.debug("getAllByRoom:",r.length) } catch (err) { L.error("getAllByRoom",err) return null; } return r; } get = async( user:FmeUser) => { if (user._id) { return await this.getById(user._id) } else { return this.getByEmail(user.local.email); } } getById = async (id:string) => { var users = await this.userDb.find({_id:ObjectId(id)}).toArray(); if (users.length == 0) { L.error("No user found for request",id); return null } if (users.length > 1) { L.error("More that one user with id! not possible",id); } return users[0] } getByStripeId = async (id:string) => { var user = await this.userDb.findOne({"stripeIds.stripeId":id}) return user; } getByEmail = async (email:string) => { var users = await this.userDb.find({"local.email":email}).toArray() as FmeUser[]; if (users.length == 0) { L.error("No user found for request",email); return null } if (users.length > 1) { L.error("More that one user with email! not possible",email); } return users[0] } checkPassword = (password:string,user:FmeUser) => { if (!user.local.password) return false; return bcrypt.compareSync(password,user.local.password) as boolean; } convertFmeUser = (user:FmeUser) => { var chatUser:TradechatUser = {} as TradechatUser; chatUser.name = user.local.username; chatUser.company = user.company; chatUser.color = user.color; chatUser.id = user._id; chatUser.invert_color = user.invert_color; // chatUser.groups = user.groups; chatUser.rooms = user.rooms; chatUser.role = user.role.name; chatUser.socketIds = []; chatUser.room = ""; return chatUser; } findUserSockets = (user:TradechatUser) => { var foundUser = this.usersOnline.find( (a) => {return a.id == user.id}); if (foundUser) { L.info("findUserSockets: user",foundUser.name,foundUser.socketIds.length) } else { L.error("findUserSocket: No socket found for user",user.id,user.name) } return foundUser; } findUserBySocketIdIndex = (socketId:string) => { return this.usersOnline.findIndex( (a) => {return a.socketIds.indexOf(socketId) > -1 }) } addUserOnline = (user:TradechatUser,socketId:string) => { L.info("addUserOnline: ",user.name,socketId); var index = this.findUserBySocketIdIndex(socketId); if (index > -1) { L.error("addUser: Socket id already on list",user); } else { var userIndex = this.usersOnline.findIndex( (a) => { return user.id == a.id}) if (userIndex > -1 ) { L.info("This user already online, so adding in anoter socket",this.usersOnline[userIndex].socketIds.length); this.usersOnline[userIndex].socketIds.push(socketId) } else { this.usersOnline.push(user) } } L.info("addUserOnline: Call to update Roster"); this.tradechatServer.roster.updateUser(user); return; } removeUserBySocket = (socket:any) => { L.info("removeUserBySocket:",socket.id); var index = this.findUserBySocketIdIndex(socket.id); if (index == -1 ) { L.error("removeUser not online",socket.id) } else { L.info("removeUserBySocket:",this.usersOnline[index].id,"index",index); var u = this.usersOnline[index]; this.tradechatServer.roster.updateUser(u); this.usersOnline.splice(index,1); } return; } update = async (user:FmeUser) => { var ret = await this.userDb.update({"local.email":user.local.email},user,{upsert:true}) return ret } updateById = async (user:FmeUser) => { L.info("Update by Id",user._id) var ret = await this.userDb.update({_id:ObjectId(user._id)},user,{upsert:true}) return ret } isOnline = (user:TradechatUser) => { var index = this.usersOnline.findIndex( (a) => {return a.id == user.id}); if (index == -1) return false; return true; } getOnlineById = (id:string) => { var user = this.usersOnline.find( (a) => {return a.id == id}); if (!user) { L.error("getOnlineById: can't find",id); return null } return user; } sendAddUserToRoom = function (socket:any,room:string) { socket.emit("addRoom", {room: room}); return } bindUserToSocket = (socket:any,user:TradechatUser) => { if (!user.socketIds) user.socketIds = []; user.socketIds.push(socket.id); socket.user = user; this.addUserOnline(user,socket.id); return socket } addSocketToRooms = (socket:any) => { var u = socket.user; socket.user.rooms.push("SUPPORT"); // auto add support socket.user.rooms.push("BROADCAST"); // auto add support var rooms = socket.user.rooms; L.info("Adding",socket.user.name,"to rooms",JSON.stringify(socket.user.rooms)) for (var i in rooms) { var room = rooms[i]; socket.join(room); let data:any = {}; data.room = {}; data.room.name = room; data.room.media_server = "https://mcu1.fortunesrocks.me/"; data.room.audio_server = "https://mcu3.fortunesrocks.me/"; socket.emit("addRoom", data); } L.info("Getting history, message count is",this.tradechatServer.messages.messages.length); var messages = this.tradechatServer.messages.getHistory(u); socket.emit("roomHistories", messages ); messages = this.tradechatServer.messages.getPrivate(u); socket.emit("privateHistoric", messages ); return socket; } kickUser = async (user:TradechatUser,reason:string,penalty:number,admin:TradechatUser) => { var isValid = await this.isValidUser(user); if (isValid) { var p:Penalty = {} as Penalty; p.status = true; p.date = new Date(); p.reason = reason; p.expiration = _m().add(1000*60*10,"minutes").toDate() ; // enforce a 10 minute ban; this.addKickedUser(user,p); this.tradechatServer.messages.sendCommand(user,"kicked",reason); } } banUser = async (user:TradechatUser,reason:string,admin:TradechatUser) => { var isValid = await this.isValidUser(user); if (isValid) { var p:Penalty = {} as Penalty; p.status = true; p.date = new Date(); p.reason = reason; p.banee = admin; this.addBannedUser(user,p); this.tradechatServer.messages.sendCommand(user,"banned",reason); } else { L.error("banUser, user not valid",user); } } isValidUser = async (user:TradechatUser) => { if (!user.id) { L.info("User validator, no id passed",user); return false; } var users = await this.userDb.find({_id:user.id}).toArray(); if (users.length == 0) { L.error("isValidUser: no user found",user); return false; } if (users.length > 1) { L.error("isValidUser: Multiple records",user); } return true; } remove = async (user:FmeUser) => { if (user._id) { return await this.removeById(user._id) } else { return await this.removeByEmail(user.local.email) } } removeByEmail = async (email:string) => { return await this.userDb.remove({"local.email":email}) } removeById = async (id:string) => { return await this.userDb.remove({_id:ObjectId(id)}) } }