def updateAndPublishStatus(userId, orgId, sessionId, status, user=None): # Check if there is a change in the online status results = yield db.get_slice(orgId, 'presence', super_column=userId) results = utils.columnsToDict(results) oldPublishedStatus = getMostAvailablePresence(results.values()) # Update the online status if status != 'offline': yield db.insert(orgId, 'presence', status, sessionId, userId) else: yield db.remove(orgId, 'presence', sessionId, userId) # If status changed broadcast the change # XXX: Currently everyone on the network will get the presence update. # This will not scale well with big networks results[sessionId] = status newPublishedStatus = getMostAvailablePresence(results.values()) if oldPublishedStatus != newPublishedStatus: if not user: user = base.Entity(userId) yield user.fetchData() data = {"userId": userId, 'status': newPublishedStatus, 'name': user.basic['name'], 'title': user.basic['jobTitle'], 'avatar': utils.userAvatar(userId, user, 's')} yield comet.publish('/presence/' + orgId, data)
def _getPresence(self, request): authInfo = request.getSession(IAuthInfo) orgId = authInfo.organization myId = authInfo.username data = [] cols = yield db.get_slice(orgId, "presence") cols = utils.supercolumnsToDict(cols) if myId not in cols: myPresence = yield db.get_slice(orgId, "presence", super_column=myId) cols[myId] = utils.columnsToDict(myPresence) presence = {} for userId in cols: presence[userId] = getMostAvailablePresence(cols[userId].values()) if presence[myId] == PresenceStates.OFFLINE: request.write(json.dumps(data)) return userIds = cols.keys() entities = base.EntitySet(userIds) yield entities.fetchData() for entityId in entities.keys(): entity = entities[entityId] _data = {"userId": entityId, "name": entity.basic['name'], "status": presence.get(entityId, PresenceStates.OFFLINE), "title": entity.basic["jobTitle"], "avatar": utils.userAvatar(entityId, entity, 's')} data.append(_data) request.write(json.dumps(data))
def render(self, parts, value, toOwner=False, getTitle=True, getBody=True, data=None): convId, convType, convOwnerId, notifyType = parts if convType == "question": templates = self._toOthers_A if not toOwner else self._toOwner_A else: templates = self._toOthers_C if not toOwner else self._toOwner_C title, body, html = '', '', '' senderName = data['me'].basic['name'] convOwnerName = data['entities'][convOwnerId].basic['name'] if getTitle: title = templates[0] % locals() if getBody: senderAvatarUrl = utils.userAvatar(data['myId'], data['me'], "medium") convUrl = "%s/item?id=%s" % (rootUrl, convId) comment = data.get('comment', '') body = templates[1] % locals() if 'richComment' in data: comment = data['richComment'] vals = locals().copy() del vals['self'] html = t.getBlock("emails.mako", templates[2], **vals) return (title, body, html)
def _render(self, parts, value, getTitle, getBody, data, args): args.update({'brandName': brandName, 'rootUrl': rootUrl}) if getTitle: title = self._template[0] % args if getBody: args['senderAvatarUrl'] = utils.userAvatar(value, data['entities'][value], "medium") args['senderId'] = value args['senderName'] = data['entities'][value].basic['name'] body = self._template[1] % args html = t.getBlock("emails.mako", self._template[2], **args) return (title, body, html)
def updatePeopleIndex(self, myId, me, orgId): mailId = me.basic['emailId'] fields = [self.elementMaker.field(myId, {"name":"id"}), self.elementMaker.field(orgId, {"name":"org"}), self.elementMaker.field('people', {"name":"_type"}), self.elementMaker.field(mailId, {'name':'email'}) ] for field in ['name', 'lastname', 'firstname', 'jobTitle']: if field in me.basic: fields.append(self.elementMaker.field(_toUnicodeOrText(me.basic[field]), {'name': field})) for field in ['phone', 'mobile']: if field in me.contact: fields.append(self.elementMaker.field(_toUnicodeOrText(me.contact[field]), {'name': field})) for field in ['email', 'phone', 'mobile', 'currentCity']: if field in me.personal: fields.append(self.elementMaker.field(_toUnicodeOrText(me.personal[field]), {'name': field})) schools = set() for school in me.schools.keys(): year, name = school.split(':', 1) schools.add(name) fields.extend([self.elementMaker.field(_toUnicodeOrText(x), {'name': 'school'}) for x in schools]) companies = set() for company in me.companies.keys(): end, start, name = company.split(':', 2) companies.add(name) fields.extend([self.elementMaker.field(_toUnicodeOrText(x), {'name': 'company'}) for x in companies]) skills = ','.join(me.expertise.keys()) if skills: fields.append(self.elementMaker.field(_toUnicodeOrText(skills), {'name': 'expertise'})) fields.append(self.elementMaker.field(str(int(time.time())), {'name': 'timestamp'})) avatarURI = utils.userAvatar(myId, me, 'small') fields.append(self.elementMaker.field(avatarURI, {'name': 'avatar'})) root = self.elementMaker.add(self.elementMaker.doc(*fields)) return self._request("POST", self._updateURL, {}, XMLBodyProducer(root))
def _postChat(self, request): comment = utils.getRequestArg(request, 'message') channelId = utils.getRequestArg(request, 'room') if not comment: # Ignore empty comment return authInfo = request.getSession(IAuthInfo) myId = authInfo.username orgId = authInfo.organization timeuuid = uuid.uuid1().bytes recipientId, recipient = yield utils.getValidEntityId(request, 'to') me = base.Entity(myId) yield me.fetchData() myName = me.basic['name'] myAvatar = utils.userAvatar(myId, me, 's') chatId = utils.getUniqueKey() sessionId = request.getCookie('session') try: col = yield db.get(orgId, 'presence', sessionId, myId) except ttypes.NotFoundException: self.setResponseCodeAndWrite(request, 200, {'error': 'You are currently offline'}) return cols = yield db.get_slice(orgId, "presence", super_column=recipientId) recipientStatus = getMostAvailablePresence( utils.columnsToDict(cols).values()) if recipientStatus == PresenceStates.OFFLINE: self.setResponseCodeAndWrite(request, 200, {'error': 'Cannot send message. User is currently offline'}) return message = {"from": myName, "to": recipientId, "message": comment, "timestamp": time.time(), "avatar": myAvatar} data = {"type": "room", "from": myId, "to": recipientId, "message": message} if channelId: channelSubscribers = yield db.get_slice(channelId, 'channelSubscribers') channelSubscribers = utils.columnsToDict(channelSubscribers) channelSubscribers = set([x.split(':', 1)[0] \ for x in channelSubscribers]) if myId not in channelSubscribers: self.setResponseCodeAndWrite(request, 200, {'error': 'Access denied'}) return yield db.insert(channelId, 'channelSubscribers', '', '%s:%s'\ % (myId, sessionId)) yield db.insert("%s:%s" % (myId, sessionId), "sessionChannelsMap", '', channelId) data["room"] = channelId startKey = '%s:' % recipientId cols = yield db.get_slice(channelId, "channelSubscribers", start=startKey, count=1) count = len([col for col in cols \ if col.column.name.startswith(startKey)]) try: yield comet.publish('/chat/%s' % (channelId), message) if not count: yield comet.publish('/notify/%s' % (recipientId), data) except Exception, e: self.setResponseCodeAndWrite(request, 200, {'error': 'The message could not be sent!'}) return
def render(self, parts, value, toOwner=False, getTitle=True, getBody=True, data=None): convId, convType, convOwnerId, notifyType = parts convTitle, convLocation, convTime = "", "", "" if "convMeta" in data: convMeta = data["convMeta"] me = data['me'] entities = data['entities'] convTitle = convMeta["event_title"] convLocation = convMeta.get("event_location", "") start = convMeta["event_startTime"] end = convMeta["event_endTime"] owner = convMeta["owner"] ownerName = entities[owner].basic["name"] my_tz = timezone(me.basic['timezone']) owner_tz = timezone(entities[owner].basic['timezone']) utc = pytz.utc startdatetime = datetime.datetime.utcfromtimestamp(float(start)).replace(tzinfo=utc) enddatetime = datetime.datetime.utcfromtimestamp(float(end)).replace(tzinfo=utc) utc_dt = utc.normalize(startdatetime) start_dt = my_tz.normalize(startdatetime.astimezone(my_tz)) end_dt = my_tz.normalize(enddatetime.astimezone(my_tz)) if start_dt.date() == end_dt.date(): sameDay = True else: sameDay = False allDay = True if convMeta.get("event_allDay", "0") == "1" else False if not allDay: event_start_fmt = "%a %b %d, %I:%M %p" else: event_start_fmt = "%a %b %d" event_start = start_dt.strftime(event_start_fmt) if allDay: event_end_fmt = "%a %b %d" elif sameDay: event_end_fmt = "%I:%M %p" else: event_end_fmt = "%a %b %d, %I:%M %p" event_end = end_dt.strftime(event_end_fmt) if not allDay: convTime += event_start if sameDay: convTime += " to %s" % (event_end) else: convTime += " -- %s" % (event_end) else: convTime += event_start if sameDay: convTime += _("All Day") else: convTime += " -- %s" % (event_end) if notifyType == "EI": templates = self._toOthers_EI else: templates = self._toOwner_EA title, body, html = '', '', '' senderName = data['me'].basic['name'] convOwnerName = data['entities'][convOwnerId].basic['name'] if getTitle: title = templates[0] % locals() if getBody: senderAvatarUrl = utils.userAvatar(data['myId'], data['me'], "medium") convUrl = "%s/item?id=%s" % (rootUrl, convId) body = templates[1] % locals() vals = locals().copy() del vals['self'] html = t.getBlock("event.mako", templates[2], **vals) return (title, body, html)
def _sendInvitations(myOrgUsers, otherOrgUsers, me, myId, myOrg): rootUrl = config.get('General', 'URL') brandName = config.get('Branding', 'Name') senderName = me.basic["name"] senderOrgName = myOrg.basic["name"] senderAvatarUrl = utils.userAvatar(myId, me, "medium") sentUsers = [] blockedUsers = [] existingUsers = [] myOrgSubject = "%s invited you to %s" % (senderName, brandName) myOrgBody = "Hi,\n\n"\ "%(senderName)s has invited you to %(senderOrgName)s network on %(brandName)s.\n"\ "To activate your account please visit: %(activationUrl)s.\n\n" otherOrgSubject = "%s invited you to %s" % (senderName, brandName) otherOrgBody = "Hi,\n\n"\ "%(senderName)s has invited you to try %(brandName)s.\n"\ "To activate your account please visit: %(activationUrl)s.\n\n" signature = "Flocked.in Team.\n\n\n\n"\ "--\n"\ "To block invitations from %(senderName)s visit %(blockSenderUrl)s\n"\ "To block all invitations from %(brandName)s visit %(blockAllUrl)s" blockSenderTmpl = "%(rootUrl)s/signup/blockSender?email=%(emailId)s&token=%(token)s" blockAllTmpl = "%(rootUrl)s/signup/blockAll?email=%(emailId)s&token=%(token)s" activationTmpl = "%(rootUrl)s/signup?email=%(emailId)s&token=%(token)s" # Combine all users. myOrgUsers.extend(otherOrgUsers) # Ensure that the users do not already exist and that the users are # not in the doNotSpam list (for this sender or globally) d1 = db.multiget(myOrgUsers, "userAuth", "user") d2 = db.multiget_slice(myOrgUsers, "doNotSpam", [myId, '*']) existing = yield d1 existing = utils.multiColumnsToDict(existing) doNotSpam = yield d2 doNotSpam = utils.multiColumnsToDict(doNotSpam) deferreds = [] for emailId in myOrgUsers: if emailId in existing and existing[emailId]: existingUsers.append(emailId) continue token = utils.getRandomKey() # Add invitation to the database localpart, domainpart = emailId.split('@') deferreds.append(db.insert(domainpart, "invitations", myId, token, emailId)) deferreds.append(db.insert(myId, "invitationsSent", '', emailId)) # Mail the invitation if everything is ok. if emailId in doNotSpam and doNotSpam[emailId]: blockedUsers.append(emailId) continue activationUrl = activationTmpl % locals() blockAllUrl = blockAllTmpl % locals() blockSenderUrl = blockSenderTmpl % locals() sameOrg = False if emailId in otherOrgUsers else True if not sameOrg: subject = otherOrgSubject textBody = (otherOrgBody + signature) % locals() else: subject = myOrgSubject textBody = (myOrgBody + signature) % locals() # XXX: getBlock blocks the application for disk reads when reading template htmlBody = t.getBlock("emails.mako", "invite", **locals()) deferreds.append(utils.sendmail(emailId, subject, textBody, htmlBody)) sentUsers.append(emailId) yield defer.DeferredList(deferreds) defer.returnValue((sentUsers, blockedUsers, existingUsers))
def _editBasicInfo(self, request): authInfo = request.getSession(IAuthInfo) myId = authInfo.username orgId = authInfo.organization userInfo = {"basic":{}} to_remove = [] basicUpdatedInfo, basicUpdated = {}, False me = base.Entity(myId) yield me.fetchData([]) # Check if any basic information is being updated. for cn in ("jobTitle", "name", "firstname", "lastname", "timezone"): val = utils.getRequestArg(request, cn) if not val and cn in ['name', 'jobTitle', 'timezone']: request.write("<script>parent.$$.alerts.error('One or more required parameters are missing')</script>") raise errors.MissingParams(_([cn])) if val: userInfo["basic"][cn] = val basicUpdatedInfo[cn] = val elif cn in ["firstname", "lastname"]: to_remove.append(cn) basicUpdatedInfo[cn] = "" if me.basic.get(cn, None) != userInfo['basic'].get(cn, None): basicUpdated = True # Update name indicies of organization. nameIndexKeys = [orgId] nameIndicesDeferreds = [] oldNameParts = [] newNameParts = [] for field in ["name", "lastname", "firstname"]: if field in basicUpdatedInfo: newNameParts.extend(basicUpdatedInfo[field].split()) oldNameParts.extend(me.basic.get(field, '').split()) if field == 'name': d1 = utils.updateDisplayNameIndex(myId, nameIndexKeys, basicUpdatedInfo[field], me.basic.get(field, None)) nameIndicesDeferreds.append(d1) d = utils.updateNameIndex(myId, nameIndexKeys, " ".join(newNameParts), " ".join(oldNameParts)) nameIndicesDeferreds.append(d) # Avatar (display picture) dp = utils.getRequestArg(request, "dp", sanitize=False) if dp: avatar = yield saveAvatarItem(myId, orgId, dp) userInfo["basic"]["avatar"] = avatar me.basic["avatar"] = avatar avatarURI = utils.userAvatar(myId, me) basicUpdatedInfo["avatar"] = avatarURI basicUpdated = True if userInfo["basic"]: yield db.batch_insert(myId, "entities", userInfo) me.basic.update(userInfo['basic']) yield search.solr.updatePeopleIndex(myId, me, orgId) if to_remove: yield db.batch_remove({'entities':[myId]}, names=to_remove, supercolumn='basic') if basicUpdated: response = """ <script> var data = %s; if (data.avatar){ var imageUrl = data.avatar; parent.$('#avatar').css('background-image', 'url(' + imageUrl + ')'); } parent.$('#name').html(data.name + ', ' + data.jobTitle); parent.$$.alerts.info("%s"); </script> """ % (json.dumps(basicUpdatedInfo), _("Profile updated")) request.write(response) # Wait for name indices to be updated. if nameIndicesDeferreds: yield defer.DeferredList(nameIndicesDeferreds) args = {"detail": "", "me": me} suggestedSections = yield self._checkProfileCompleteness(request, myId, args) tmp_suggested_sections = {} for section, items in suggestedSections.iteritems(): if len(suggestedSections[section]) > 0: tmp_suggested_sections[section] = items args.update({'suggested_sections':tmp_suggested_sections}) t.renderScriptBlock(request, "settings.mako", "right", False, ".right-contents", "set", **args)