def _renderReportResponses(self, request, convId, convMeta, args): reportId = convMeta.get('reportId', None) args['convMeta'] = convMeta script = args["script"] myId = args["myId"] landing = not self._ajax if script: t.renderScriptBlock(request, "item-report.mako", "item_report", landing, "#report-contents", "set", **args) if reportId: reportResponses = yield db.get_slice(reportId, "itemResponses") reportResponseKeys, toFetchEntities = [], [] reportResponseActions = {} for response in reportResponses: userKey, responseKey, action = response.column.value.split(":") reportResponseKeys.append(responseKey) reportResponseActions[responseKey] = action fetchedResponses = yield db.multiget_slice(reportResponseKeys, "items", ["meta"]) fetchedResponses = utils.multiSuperColumnsToDict(fetchedResponses) args["reportId"] = reportId args["reportItems"] = fetchedResponses args["responseKeys"] = reportResponseKeys args["reportResponseActions"] = reportResponseActions #Show comments from report only if I am the owner or the reporter if script and myId in [convMeta["owner"], convMeta["reportedBy"]]: t.renderScriptBlock(request, "item-report.mako", 'report_comments', landing, '#report-comments', 'set', **args)
def getLatestCounts(request, asJSON=True): authinfo = yield defer.maybeDeferred(request.getSession, IAuthInfo) myId = authinfo.username myOrgId = authinfo.organization latest = yield db.get_slice(myId, "latest") latest = supercolumnsToDict(latest) counts = dict([(key, len(latest[key])) for key in latest]) # Default keys for which counts should be set defaultKeys = ["notifications", "messages", "groups", "tags"] for key in defaultKeys: counts[key] = counts[key] if key in counts else 0 groups = yield db.get_slice(myId, "entities", ["adminOfGroups"]) groups = supercolumnsToDict(groups).get("adminOfGroups", {}).keys() if groups: counts.setdefault("groups", 0) cols = yield db.multiget_slice(groups, "latest") cols = multiSuperColumnsToDict(cols) for groupId in cols: for key in cols[groupId]: counts["groups"] += len(cols[groupId][key]) if asJSON: defer.returnValue(json.dumps(counts)) else: defer.returnValue(counts)
def fetchData(self, columns=None): if not columns: columns = ['basic'] entities = yield db.multiget_slice(self.ids, "entities", columns) entities = utils.multiSuperColumnsToDict(entities) for entityId in entities: entity = Entity(entityId, entities[entityId]) self.data[entityId] = entity
def _compute_weights(userIds, myGroups, type): followers = yield db.multiget_slice(userIds, "followers", count=50) subscriptions = yield db.multiget_slice(userIds, "subscriptions", count=50) groups = yield db.multiget_slice(userIds, "entityGroupsMap") followers = utils.multiColumnsToDict(followers) subscriptions = utils.multiColumnsToDict(subscriptions) groups = utils.multiColumnsToDict(groups) for userId in followers: for follower in followers[userId]: people[follower] = people.setdefault(follower, defaultWeight) + weights[type]['follower'] for userId in subscriptions: for subscription in subscriptions[userId]: people[subscription] = people.setdefault(subscription, defaultWeight) + weights[type]['subscription'] for userId in groups: groupIds = [x.split(':', 1)[1] for x in groups[userId]] for groupId in groupIds: if groupId in myGroups: people[userId] = people.setdefault(userId, defaultWeight) + weights[type]['group']
def delete(self, myId, convId, conv): log.debug("plugin:delete", convId) user_tuids = {} # Get the list of every user who responded to this event res = yield db.get_slice(convId, "eventResponses") attendees = [x.column.name.split(":", 1)[1] for x in res] # Add all the invited people of the item res = yield db.get_slice(convId, "items", ['invitees']) res = utils.supercolumnsToDict(res) attendees.extend(res["invitees"].keys()) invitedPeople = res["invitees"].keys() log.debug("Maps", ["%s:%s"%(uId, convId) for \ uId in attendees]) # Get the Org and GroupIds if any. convMeta = conv["meta"] groupIds = convMeta["target"].split(",") if "target" in convMeta else [] attendees.extend(groupIds+[convMeta["org"]]) log.debug("Attendees", attendees) # Get the timeuuids that were inserted for this user res = yield db.multiget_slice(["%s:%s"%(uId, convId) for \ uId in attendees], "userAgendaMap") res = utils.multiColumnsToDict(res) for k, v in res.iteritems(): uid = k.split(":", 1)[0] tuids = v.keys() if tuids: user_tuids[uid] = tuids log.debug("userAgenda Removal", user_tuids) # Delete their entries in the user's list of event entries for attendee in user_tuids: yield db.batch_remove({'userAgenda': [attendee]}, names=user_tuids[attendee]) # Delete invitation entries for invited people invited_tuids = dict([[x, user_tuids[x]] for x in invitedPeople]) log.debug("userAgenda Invitation Removal", invited_tuids) for attendee in invited_tuids: yield db.batch_remove({'userAgenda': ['%s:%s' %(attendee, 'I')]}, names=invited_tuids[attendee]) log.debug("eventResponses Removal", convId) # Delete the event's entry in eventResponses yield db.remove(convId, "eventResponses") log.debug("userAgendaMap Removal", user_tuids) # Delete their entries in userAgendaMap for attendee in user_tuids: yield db.batch_remove({'userAgendaMap': ["%s:%s"%(attendee, convId)]}, names=user_tuids[attendee])
def getGroups(me, entity, start='', count=PEOPLE_PER_PAGE): """get the groups of entity. (either groups of an organization or groups of an user) keyword params: @me: @entity: org/user start: fetch group from @start count: no.of groups to fetch. """ toFetchCount = count + 1 groups = {} groupIds = [] myGroupsIds = [] groupFollowers = {} pendingConnections = {} toFetchGroups = set() nextPageStart = '' prevPageStart = '' #TODO: list the groups in sorted order. cols = yield db.get_slice(entity.id, 'entityGroupsMap', start=start, count=toFetchCount) groupIds = [x.column.name for x in cols] if len(groupIds) > count: nextPageStart = utils.encodeKey(groupIds[-1]) groupIds = groupIds[0:count] toFetchGroups.update(set([y.split(':', 1)[1] for y in groupIds])) if entity.id == me.id: myGroupsIds = [x.split(':', 1)[1] for x in groupIds] elif groupIds: cols = yield db.get_slice(me.id, "entityGroupsMap", groupIds) myGroupsIds = [x.column.name.split(':', 1)[1] for x in cols] groupIds = [x.split(':', 1)[1] for x in groupIds] if start: cols = yield db.get_slice(entity.id, 'entityGroupsMap', start=start, count=toFetchCount, reverse=True) if len(cols) > 1: prevPageStart = utils.encodeKey(cols[-1].column.name) if toFetchGroups: groups = base.EntitySet(toFetchGroups) yield groups.fetchData() groupFollowers = yield db.multiget_slice(toFetchGroups, "followers", names=[me.id]) groupFollowers = utils.multiColumnsToDict(groupFollowers) columns = reduce(lambda x, y: x + y, [["GO:%s" % (x), "GI:%s" % (x)] for x in toFetchGroups]) cols = yield db.get_slice(me.id, 'pendingConnections', columns) pendingConnections = utils.columnsToDict(cols) data = {"entities": groups, "groupIds": groupIds, "pendingConnections": pendingConnections, "myGroups": myGroupsIds, "groupFollowers": groupFollowers, "nextPageStart": nextPageStart, "prevPageStart": prevPageStart} defer.returnValue(data)
def responses(myId, itemId, item, start=''): toFetchEntities = set() itemResponses = yield db.get_slice(itemId, "itemResponses", start=start, reverse=True, count=constants.COMMENTS_PER_PAGE + 1) nextPageStart = itemResponses[-1].column.name\ if len(itemResponses) > constants.COMMENTS_PER_PAGE\ else None itemResponses = itemResponses[:-1] \ if len(itemResponses) > constants.COMMENTS_PER_PAGE\ else itemResponses responseKeys = [] for response in itemResponses: userKey, responseKey = response.column.value.split(":") responseKeys.append(responseKey) toFetchEntities.add(userKey) responseKeys.reverse() entities = base.EntitySet(toFetchEntities) d3 = db.multiget_slice(responseKeys + [itemId], "itemLikes", [myId]) d2 = db.multiget_slice(responseKeys + [itemId], "items", ["meta", "attachments"]) d1 = entities.fetchData() fetchedItems = yield d2 myLikes = yield d3 yield d1 fetchedItems = utils.multiSuperColumnsToDict(fetchedItems) fetchedLikes = utils.multiColumnsToDict(myLikes) # Do some error correction/consistency checking to ensure that the # response items actually exist. I don't know of any reason why these # items may not exist. missingIds = [x for x, y in fetchedItems.items() if not y] if missingIds: yield _cleanupMissingComments(itemId, missingIds, itemResponses) ret = {'items': fetchedItems, 'entities': entities, 'myLikes': myLikes, 'responses': {itemId: responseKeys}} if nextPageStart: ret['oldest'] = utils.encodeKey(nextPageStart) defer.returnValue(ret)
def sendInvitations(sender): cols = yield db.get_slice(sender, "userAuth") senderInfo = utils.columnsToDict(cols) senderOrgId = senderInfo["org"] senderId = senderInfo["user"] cols = yield db.multiget_slice([senderId, senderOrgId], "entities", ["basic"]) entities = utils.multiSuperColumnsToDict(cols) emails = sys.stdin.readlines() emails = [x.strip() for x in emails] yield people._sendInvitations([], emails, entities[senderId], senderId, entities[senderOrgId])
def notify(userIds, notifyId, value, timeUUID=None, **kwargs): if not userIds: return defer.succeed([]) timeUUID = timeUUID or uuid.uuid1().bytes notifyIdParts = notifyId.split(':') notifyType = notifyIdParts[1] if not notifyIdParts[0] else notifyIdParts[3] plugin = _notificationPlugins.get(notifyType, None) if not plugin: return defer.succeed([]) deferreds = [] # Delete existing notifications for the same item/activiy if plugin.notifyOnWeb: d1 = db.multiget_slice(userIds, "notificationItems", super_column=notifyId, count=3, reverse=True) def deleteOlderNotifications(results): mutations = {} timestamp = int(time.time() * 1e6) for key, cols in results.iteritems(): names = [col.column.name for col in cols if col.column.name != timeUUID] if names: colmap = dict([(x, None) for x in names]) deletion = ttypes.Deletion(timestamp, 'notifications', ttypes.SlicePredicate(column_names=names)) mutations[key] = {'notifications': colmap, 'latest': [deletion]} if mutations: return db.batch_mutate(mutations) else: return defer.succeed([]) d1.addCallback(deleteOlderNotifications) deferreds.append(d1) # Create new notifications mutations = {} for userId in userIds: colmap = {timeUUID: notifyId} mutations[userId] = {'notifications': colmap, 'latest': {'notifications': colmap}, 'notificationItems': {notifyId: {timeUUID: value}}} deferreds.append(db.batch_mutate(mutations)) for handler in notificationHandlers: d = handler.notify(userIds, notifyIdParts, value, **kwargs) deferreds.append(d) return defer.DeferredList(deferreds)
def getManagedGroups(me, start, count=PEOPLE_PER_PAGE): """get all groups managed by me Keyword params: @me: @start: get groups from @start. @count: no.of groups to be fetched. """ groups = {} groupIds = [] myGroupsIds = [] nextPageStart = '' prevPageStart = '' toFetchCount = count + 1 toFetchGroups = set() groupFollowers = {} pendingConnections = {} try: cols = yield db.get_slice(me.id, "entities", super_column='adminOfGroups', start=start, count=toFetchCount) groupIds = [x.column.name for x in cols] toFetchGroups.update(set(groupIds)) myGroupsIds = groupIds if len(groupIds) > count: nextPageStart = utils.encodeKey(groupIds[-1]) groupIds = groupIds[0:count] except ttypes.NotFoundException: pass if start: cols = yield db.get_slice(me.id, "entities", super_column='adminOfGroups', start=start, count=toFetchCount, reverse=True) if len(cols) > 1: prevPageStart = utils.encodeKey(cols[-1].column.name) if toFetchGroups: groups = base.EntitySet(toFetchGroups) yield groups.fetchData() groupFollowers = yield db.multiget_slice(toFetchGroups, "followers", names=[me.id]) groupFollowers = utils.multiColumnsToDict(groupFollowers) columns = reduce(lambda x, y: x + y, [["GO:%s" % (x), "GI:%s" % (x)] for x in toFetchGroups]) cols = yield db.get_slice(me.id, 'pendingConnections', columns) pendingConnections = utils.columnsToDict(cols) data = {"entities": groups, "groupIds": groupIds, "pendingConnections": pendingConnections, "myGroups": myGroupsIds, "groupFollowers": groupFollowers, "nextPageStart": nextPageStart, "prevPageStart": prevPageStart} defer.returnValue(data)
def _renderDeleteUser(self, request, data=None): myId = request.getSession(IAuthInfo).username user = data['id'] # Admin cannot block himself. if user.id == myId: error_str = "You are the only administrator, you can not delete yourself" request.write("$$.dialog.close('removeuser-dlg');\ $$.alerts.error('%s')" % error_str) else: orgAdminNewGroups = [] affectedGroups = [] groups = yield db.get_slice(user.id, "entityGroupsMap") groupIds = [x.column.name.split(':')[1] for x in groups] groupAdmins = yield db.multiget_slice(groupIds, "entities", ['admins']) groupAdmins = utils.multiSuperColumnsToDict(groupAdmins) for group in groups: name, groupId = group.column.name.split(':') if len(groupAdmins[groupId].get('admins', {})) == 1 and user.id in groupAdmins[groupId]['admins']: orgAdminNewGroups.append((groupId, name)) affectedGroups.append((groupId, name)) apiKeys = yield db.get_slice(user.id, "entities", ['apikeys']) apiKeys = utils.supercolumnsToDict(apiKeys) if apiKeys.get('apikeys', {}).keys(): apps = yield db.multiget_slice(apiKeys['apikeys'].keys(), "apps", ['meta']) apps = utils.multiSuperColumnsToDict(apps) else: apps = {} entities = base.EntitySet(user) args = {'affectedGroups': affectedGroups} args['orgAdminNewGroups'] = orgAdminNewGroups args['apps'] = apps args['userId'] = user.id args["entities"] = entities t.renderScriptBlock(request, 'admin.mako', "confirm_remove_user", False, "#removeuser-dlg", "set", **args)
def _moveConversation(self, request, convIds, toFolder): """Move a conversation or conversations from one folder to another. Keyword Arguments: convIds: List of conversation ids which need to be moved. toFolder: The final destination of the above conversations CF Changes: mConvFolders mUnreadConversations mAllConversations mDeletedConversations """ myId = request.getSession(IAuthInfo).username convs = yield db.multiget_slice(convIds, "mConversations") convs = utils.multiSuperColumnsToDict(convs) for convId in convs: conv = convs.get(convId, {}) if not conv: raise errors.InvalidMessage(convId) if myId not in conv.get('participants', {}): raise errors.MessageAccessDenied(convId) timeUUID = conv['meta']['uuid'] val = "%s:%s" % ('u' if toFolder == 'unread' else 'r', convId) cols = yield db.get_slice(convId, 'mConvFolders', [myId]) cols = utils.supercolumnsToDict(cols) for folder in cols[myId]: cf = self._folders[folder] if folder in self._folders else folder if toFolder != 'unread': if folder != 'mUnreadConversations': col = yield db.get(myId, cf, timeUUID) val = col.column.value yield db.remove(myId, cf, timeUUID) yield db.remove(convId, "mConvFolders", cf, myId) else: yield db.insert(myId, cf, "u:%s" % (convId), timeUUID) if toFolder == 'unread': val = "u:%s" % (convId) yield db.insert(convId, 'mConvFolders', '', 'mUnreadConversations', myId) yield db.insert(myId, 'mUnreadConversations', val, timeUUID) else: folder = self._folders[toFolder] yield db.insert(myId, folder, val, timeUUID) yield db.insert(convId, 'mConvFolders', '', folder, myId)
def getReason(self, convId, requesters, userId): conv = yield db.get_slice(convId, "items", ["meta"]) conv = utils.supercolumnsToDict(conv) cols = yield db.multiget_slice(requesters, "entities", ["basic"]) entities = utils.multiSuperColumnsToDict(cols) foo = requesters[0] if conv["meta"]["subType"] == "connection": reasonStr = '%s accepted your friend request' \ %(utils.userName(foo, entities[foo])) elif conv["meta"]["subType"] == "pendingConnection": reasonStr = "%s sent a friend request." \ "Click <a href='/profile?id=%s'>here </a> to respond" \ %(utils.userName(foo, entities[foo]), foo) defer.returnValue(reasonStr)
def _upload_files(owner, tmp_fileIds): attachments = {} if tmp_fileIds: cols = yield db.multiget_slice(tmp_fileIds, "tmp_files", ["fileId"]) cols = multiColumnsToDict(cols) for tmpFileId in cols: attachmentId = getUniqueKey() timeuuid = uuid.uuid1().bytes val = cols[tmpFileId]["fileId"] fileId, name, size, ftype = val.split(":") meta = {"meta": {"uri": tmpFileId, "name": name, "fileType": ftype, "owner": owner}} yield db.batch_insert(tmpFileId, "files", meta) yield db.remove(tmpFileId, "tmp_files") yield db.insert(attachmentId, "attachmentVersions", val, timeuuid) attachments[attachmentId] = (fileId, name, size, ftype) defer.returnValue(attachments)
def expandAcl(userId, orgId, acl, convId, convOwnerId=None, allItemFollowers=False): keys = set() acl = pickle.loads(acl) accept = acl.get("accept", {}) deny = acl.get("deny", {}) deniedUsers = deny.get("users", []) if not allItemFollowers: unfollowed_d = ( db.get_slice(convId, "items", super_column="unfollowed", count=INFINITY) if convId else defer.succeed([]) ) # When users are explicitly selected, they always # get items in their feeds if "users" in accept: for uid in accept["users"]: if uid not in deniedUsers: keys.add(uid) # Posted to a group if "groups" in accept: groups = accept["groups"][:] for groupId in groups[:]: if groupId in deny.get("groups", []): groups.remove(groupId) groupMembers = yield db.multiget_slice(groups, "followers") groupMembers = multiColumnsToDict(groupMembers) for groupId in groupMembers: keys.update([uid for uid in groupMembers[groupId].keys() if uid not in deniedUsers]) keys.update(groups) # See if followers and the company feed should get this update. if any([typ in ["orgs", "public"] for typ in accept]): followers = yield getFollowers(userId, count=INFINITY) keys.update([uid for uid in followers if uid not in deniedUsers]) keys.add(orgId) # Remove keys of people who unfollowed the item. if not allItemFollowers: unfollowed = yield unfollowed_d unfollowed = set(columnsToDict(unfollowed).keys()) defer.returnValue(keys.difference(unfollowed)) else: defer.returnValue(keys)
def _render(self, request): (appchange, script, args, myId) = yield self._getBasicArgs(request) landing = not self._ajax title = "Applications" args["title"] = title args["detail"] = "apps" if script and landing: t.render(request, "apps.mako", **args) if appchange and script: t.renderScriptBlock(request, "apps.mako", "layout", landing, "#mainbar", "set", **args) if script: self.setTitle(request, title) # XXX: Currently fetching all available apps under each category. # In future implement pagination here. appIds = yield db.get_slice(myId, "entities", ["apikeys", "apps"], count=100) appIds = utils.supercolumnsToDict(appIds, timestamps=True) appsByMe = yield db.get_slice(myId, "appsByOwner", count=100) appIds["my"] = utils.columnsToDict(appsByMe) toFetchClients = set() for val in appIds.values(): toFetchClients.update(val.keys()) clients = yield db.multiget_slice(toFetchClients, "apps") clients = utils.multiSuperColumnsToDict(clients) toFetchEntities = set([x.author for x in clients if "author" in x]) entities = base.EntitySet(toFetchEntities) yield entities.fetchData() args.update({"entities": entities, "clients": clients, "apps": appIds}) if script: t.renderScriptBlock(request, "apps.mako", "appListing", landing, "#apps-contents", "set", **args) else: t.render(request, "apps.mako", **args)
def fetchAndFilterConvs(ids, relation, items, myId, orgId, isOrgAdmin=False, supercols=None): """Fetch items represented by ids and check if the authenticated user has access to them. Since the data is already fetched, cache it. Keyword arguments: @ids - List of conversation Ids that need to be fetched @relation - Relation object for the authenticated user @items - Dictionary into which the fetched data is stored @myId - Id of the authenticated user @orgId - Id of the authenticated user's org. """ retIds = [] deleted = set() if not ids: defer.returnValue((retIds, deleted)) supercols = supercols or ["meta", "tags", "attachments"] cols = yield db.multiget_slice(ids, "items", supercols) items.update(multiSuperColumnsToDict(cols)) # Filter the items (checkAcl only for conversations) for convId in ids: if convId not in items: continue # Ignore if it is a comment meta = items.get(convId, {}).get("meta", {}) if not meta or "parent" in meta: continue # Check if the conversation was already deleted if "state" in meta and meta["state"] == "deleted": deleted.add(convId) continue # Check ACL if checkAcl(myId, orgId, isOrgAdmin, relation, meta): retIds.append(convId) defer.returnValue((retIds, deleted))
def _gotConvs(results): docs = results.data.get('response', {}).get('docs', []) highlight.update(results.data.get('highlighting')) for index, item in enumerate(docs): itemId = item['id'] parentId = item.get('parent', None) if parentId: toFetchItems.add(itemId) toFetchItems.add(parentId) matchedItemIds.append(itemId) else: toFetchItems.add(itemId) matchedItemIds.append(itemId) if toFetchItems and matchedItemIds: fetchedItems = yield db.multiget_slice(toFetchItems, "items", ["meta", "tags", "attachments"]) fetchedItems = utils.multiSuperColumnsToDict(fetchedItems) for itemId, item in fetchedItems.items(): toFetchEntities.add(item['meta']['owner']) if 'target' in item['meta']: toFetchEntities.update(item['meta']['target'].split(',')) items.update(fetchedItems) extraDataDeferreds = [] for itemId in toFetchItems: if itemId in matchedItemIds and itemId in items: meta = items[itemId]['meta'] itemType = meta.get('type', 'status') if itemType in plugins: d = plugins[itemType].fetchData(args, itemId) extraDataDeferreds.append(d) result = yield defer.DeferredList(extraDataDeferreds) for success, ret in result: if success: toFetchEntities.update(ret) args['matchedItemCount'] = results.data.get('response', {}).get('numFound', 0)
def updateData(): def _getAllFiles(): SKey = config.get('CloudFiles', 'SecretKey') AKey = config.get('CloudFiles', 'AccessKey') bucket = config.get('CloudFiles', 'Bucket') conn = S3Connection(AKey, SKey) bucket = conn.get_bucket(bucket) files = [] for key in bucket.list(): if not key.name.endswith('/'): files.append(key.name) return files files = yield threads.deferToThread(_getAllFiles) S3fileIds = [x.split("/")[2] for x in files] log.msg("Fetched %d files" %(len(S3fileIds))) log.msg("Fetching info about all the files") d = db.multiget_slice(S3fileIds, "files") files_map = {} for f in files: org, owner, fileId = f.split("/") files_map[fileId] = (owner, org) res = yield d ids = utils.multiSuperColumnsToDict(res) fileIds = [x for x in ids.keys() if ids[x] and "owner" not in ids[x]["meta"]] log.msg("Out of %d S3 files, found %d files in \'files\' in old format" %( len(S3fileIds), len(fileIds))) updated_file_meta = {} for fileId in fileIds: owner, org = files_map[fileId] updated_file_meta[fileId] = {"files":{"meta":{"owner": owner}}} log.msg(updated_file_meta) yield db.batch_mutate(updated_file_meta)
def _renderChatArchives(self, request): (appchange, script, args, myId) = yield self._getBasicArgs(request) orgId = args['orgId'] landing = not self._ajax start = utils.getRequestArg(request, 'start') or '' start = utils.decodeKey(start) count = constants.CHATS_PER_PAGE if script and landing: t.render(request, "chat.mako", **args) if appchange and script: t.renderScriptBlock(request, "chat.mako", "layout", landing, "#mainbar", "set", **args) chats = {} chatParticipants = {} prevPageStart = '' nextPageStart = '' cols = yield db.get_slice(myId, "chatArchiveList", start=start, count=count + 1, reverse=True) chatIds = [col.column.value for col in cols] if len(cols) == count + 1: chatIds = chatIds[:count] nextPageStart = utils.encodeKey(cols[-1].column.name) cols = yield db.get_slice(myId, "chatArchiveList", start=start, count=count + 1) if len(cols) > 1 and start: prevPageStart = utils.encodeKey(cols[-1].column.name) if chatIds: cols = yield db.multiget_slice(chatIds, "chatLogs", reverse=False) chats = OrderedDict() for chatId in cols: chats[chatId] = [] for col in cols[chatId]: entityId, comment = col.column.value.split(':', 1) chats[chatId] = (entityId, comment, col.column.timestamp / 1e6) participants = yield db.multiget_slice(chatIds, "chatParticipants") participants = utils.multiColumnsToDict(participants) entityIds = set([]) for chatId in participants: entityIds.update(participants[chatId]) entities = base.EntitySet(entityIds) yield entities.fetchData() entities.update(args['me']) args.update({'chatParticipants': participants, 'entities': entities, 'chats': chats, 'chatIds': chatIds, 'nextPageStart': nextPageStart, 'prevPageStart': prevPageStart, 'view': 'list', 'menuId': 'chats'}) if script: onload = """ $$.menu.selectItem('chats'); """ t.renderScriptBlock(request, "chat.mako", "chatList", landing, '.center-contents', "set", True, handlers={"onload": onload}, **args) else: t.render(request, "chat.mako", **args)
def _actions(self, request): """Perform an action on a conversation or a group of conversations. Update the UI based on the folder and the view that the user is in. Keyword arguments: convIds: A list of conversations upon which an action is to be taken. filterType: The folder view in which this action was taken. trash: A presence of this argument indicates that the action is to delete the selected conversations. archive: A presence of this argument indicates that the action is to archive the selected conversations. unread: A presence of this argument indicates that the action is to mark the selected conversations as unread. inbox: A presence of this argument indicates that the action is to move the selected conversations to inbox. view: one of [message, messages] indicates whether the user is performing action on a single conversation or multiple conversations. action: The actual action that the user wants to peform. One of ["inbox", "archive", "trash", "read", "unread"]. This is used if none of the above are mentioned. CF Changes: mConvFolders mUnreadConversations latest mAllConversations mDeletedConversations """ (appchange, script, args, myId) = yield self._getBasicArgs(request) convIds = utils.getRequestArg(request, 'selected', multiValued=True) or [] filterType = utils.getRequestArg(request, "filterType") or "all" trash = utils.getRequestArg(request, "trash") or None archive = utils.getRequestArg(request, "archive") or None unread = utils.getRequestArg(request, "unread") or None inbox = utils.getRequestArg(request, "inbox") or None view = utils.getRequestArg(request, "view") or "messages" if trash: action = "trash" elif archive: action = "archive" elif unread: action = "unread" elif inbox: action = "inbox" else: action = utils.getRequestArg(request, "action") if convIds: #Move the conversations based on action and update the CFs. if action in self._folders.keys(): yield self._moveConversation(request, convIds, action) elif action == "read": #Remove it from unreadIndex and mark it as unread in all other # folders cols = yield db.multiget_slice(convIds, "mConversations") convs = utils.multiSuperColumnsToDict(cols) for convId in convs: conv = convs[convId] if not conv: raise errors.InvalidMessage(convId) if myId not in conv.get('participants', {}): raise errors.MessageAccessDenied(convId) timeUUID = conv['meta']['uuid'] yield db.remove(myId, "mUnreadConversations", timeUUID) yield db.remove(convId, "mConvFolders", 'mUnreadConversations', myId) yield db.remove(myId, "latest", timeUUID, "messages") cols = yield db.get_slice(convId, "mConvFolders", [myId]) cols = utils.supercolumnsToDict(cols) for folder in cols[myId]: if folder in self._folders: folder = self._folders[folder] yield db.insert(myId, folder, "r:%s" % (convId), timeUUID) count = yield utils.render_LatestCounts(request) #XXX:Actions are not supported in non js mode so this check is unncessary. if not self._ajax: #Not all actions on message(s) happen over ajax, for them do a redirect request.redirect("/messages?type=%s" % filterType) request.finish() elif self._ajax and len(convIds) > 0: #Update the UI based on the actions and folder view. #For all actions other than read/unread, since the action won't be # available to the user in same view; i.e, archive won't be on # archive view, we can simply remove the conv. if action in ["inbox", "archive", "trash"]: if filterType != "unread": request.write("$('%s').remove();" % ','.join(['#thread-%s' % convId for convId in convIds])) if view == "message": reason = _("Message moved to %s" % (action.capitalize())) if action == "archive": reason = _("Message archived") request.write("""$$.fetchUri('/messages?type=%s');$$.alerts.info("%s");""" % (filterType, _(reason))) elif action == "unread": query_template = """ $('#thread-%s').removeClass('row-read').addClass('row-unread'); $('#thread-%s .messaging-read-icon').removeClass('messaging-read-icon').addClass('messaging-unread-icon'); $('#thread-%s .messaging-unread-icon').attr("title", "Mark this conversation as read"); $('#thread-%s .messaging-unread-icon')[0].onclick = function(event) { $.post('/ajax/messages/thread', 'action=read&selected=%s&filterType=%s', null, 'script') }; """ query = "".join([query_template % (convId, convId, convId, convId, convId, filterType) for convId in convIds]) if view == "message": request.write("""$$.fetchUri('/messages');$$.alerts.info("%s");""" % ("Message marked as unread")) else: request.write(query) elif action == "read": # If we are in unread view, remove the conv else swap the styles if filterType != "unread": query_template = """ $('#thread-%s').removeClass('row-unread').addClass('row-read'); $('#thread-%s .messaging-unread-icon').removeClass('messaging-unread-icon').addClass('messaging-read-icon'); $('#thread-%s .messaging-read-icon').attr("title", "Mark this conversation as unread") $('#thread-%s .messaging-read-icon')[0].onclick = function(event) { $.post('/ajax/messages/thread', 'action=unread&selected=%s&filterType=%s', null, 'script') } """ query = "".join([query_template % (convId, convId, convId, convId, convId, filterType) for convId in convIds]) request.write(query) else: request.write("$('%s').remove()" % ','.join(['#thread-%s' % convId for convId in convIds]))
def _removeMembers(self, request): """This method allows the current user to remove another participant to this conversation. Keyword Arguments: newMembers: A list of members who will be added to this conversation. convId: The id of the conversation to which these new members will be added as participants. CF Changes: mConversations latest """ myId = request.getSession(IAuthInfo).username orgId = request.getSession(IAuthInfo).organization members, body, subject, convId = self._parseComposerArgs(request) if not (convId and members): raise errors.MissingParams([]) conv = yield db.get_slice(convId, "mConversations") conv = utils.supercolumnsToDict(conv) subject = conv['meta'].get('subject', None) participants = conv.get('participants', {}).keys() if not conv: raise errors.InvalidMessage(convId) if myId not in participants: raise errors.MessageAccessDenied(convId) cols = yield db.multiget_slice(members, "entities", ['basic']) people = utils.multiSuperColumnsToDict(cols) members = set([userId for userId in people if people[userId] and \ people[userId]["basic"]["org"] == orgId]) members = members.intersection(participants) if len(members) == len(participants): members.remove(conv['meta']['owner']) deferreds = [] if members: d = db.batch_remove({"mConversations": [convId]}, names=members, supercolumn='participants') deferreds.append(d) cols = yield db.get_slice(convId, 'mConvFolders', members) cols = utils.supercolumnsToDict(cols) for recipient in cols: for folder in cols[recipient]: cf = self._folders[folder] if folder in self._folders else folder d = db.remove(recipient, cf, conv['meta']['uuid']) deferreds.append(d) #update latest- messages-count deferreds.append(db.batch_remove({"latest": members}, names=[conv['meta']['uuid']], supercolumn='messages')) if deferreds: yield deferreds mailNotificants = set(participants) - members - set([myId]) if mailNotificants and members: toFetchEntities = mailNotificants.union([myId, orgId]).union(members) entities = base.EntitySet(toFetchEntities) yield entities.fetchData() data = {"entities": entities} data["orgId"] = orgId data["convId"] = convId data["removedMembers"] = members data["subject"] = subject data["_fromName"] = entities[myId].basic['name'] yield notifications.notify(mailNotificants, ":MA", myId, **data)
def _listConversations(self, request): """Renders a time sorted list of coversations in a particular view. Keyword Arguments: filerType: The folder view which is to rendered. One of ['unread', 'all', 'archive', 'trash']. start: The base64 encoded timeUUID of the starting conversation id of the page that needs to be rendered. """ (appchange, script, args, myId) = yield self._getBasicArgs(request) landing = not self._ajax filterType = utils.getRequestArg(request, 'type') folder = self._folders[filterType] if filterType in self._folders else\ self._folders['inbox'] start = utils.getRequestArg(request, "start") or '' start = utils.decodeKey(start) if script and landing: t.render(request, "message.mako", **args) if appchange and script: t.renderScriptBlock(request, "message.mako", "layout", landing, "#mainbar", "set", **args) unread = [] convs = [] users = set() count = 10 fetchCount = count + 1 nextPageStart = '' prevPageStart = '' cols = yield db.get_slice(myId, folder, reverse=True, start=start, count=fetchCount) for col in cols: x, convId = col.column.value.split(':') convs.append(convId) if x == 'u': unread.append(convId) if len(cols) == fetchCount: nextPageStart = utils.encodeKey(col.column.name) convs = convs[:count] ###XXX: try to avoid extra fetch cols = yield db.get_slice(myId, folder, count=fetchCount, start=start) if cols and len(cols) > 1 and start: prevPageStart = utils.encodeKey(cols[-1].column.name) cols = yield db.multiget_slice(convs, 'mConversations') conversations = utils.multiSuperColumnsToDict(cols) m = {} for convId in conversations: if not conversations[convId]: continue participants = conversations[convId]['participants'].keys() users.update(participants) conversations[convId]['people'] = participants conversations[convId]['read'] = str(int(convId not in unread)) messageCount = yield db.get_count(convId, "mConvMessages") conversations[convId]['count'] = messageCount m[convId] = conversations[convId] users = base.EntitySet(users) yield users.fetchData() args.update({"view": "messages"}) args.update({"messages": m}) args.update({"people": users}) args.update({"mids": convs}) args.update({"menuId": "messages"}) args.update({"filterType": filterType or "all"}) args['nextPageStart'] = nextPageStart args['prevPageStart'] = prevPageStart if script: onload = """ $$.menu.selectItem('%s'); $('#mainbar .contents').removeClass("has-right"); """ % args["menuId"] t.renderScriptBlock(request, "message.mako", "render_conversations", landing, ".center-contents", "set", True, handlers={"onload": onload}, **args) yield utils.render_LatestCounts(request, landing) else: t.render(request, "message.mako", **args)
def _reply(self, request): """Commit a new message in reply to an existing conversation. Creates a new message, uploads any attachments, updates the conversation meta info and finally renders the message for the user. Keyword Arguments: convId: conversation id to which this user is replying to. body: The content of the reply. CF Changes: mConversations mConvMessages attachmentVersions """ (appchange, script, args, myId) = yield self._getBasicArgs(request) landing = not self._ajax myOrgId = args['orgId'] convId = utils.getRequestArg(request, 'id') recipients, body, subject, convId = self._parseComposerArgs(request) epoch = int(time.time()) if not convId: raise errors.MissingParams([]) cols = yield db.get_slice(convId, "mConversations", ['meta', 'participants']) cols = utils.supercolumnsToDict(cols) subject = cols['meta'].get('subject', None) participants = cols.get('participants', {}).keys() if not cols: raise errors.InvalidMessage(convId) if myId not in participants: raise errors.MessageAccessDenied(convId) timeUUID = uuid.uuid1().bytes snippet = self._fetchSnippet(body) meta = {'uuid': timeUUID, 'date_epoch': str(epoch), "snippet": snippet} attachments = yield self._handleAttachments(request) attach_meta = self._formatAttachMeta(attachments) messageId = yield self._newMessage(myId, timeUUID, body, epoch) yield self._deliverMessage(convId, participants, timeUUID, myId) yield db.insert(convId, "mConvMessages", messageId, timeUUID) yield db.batch_insert(convId, "mConversations", {'meta': meta, 'attachments': attach_meta}) # Currently, we don't support searching for private messages # self._indexMessage(convId, messageId, myOrgId, meta, attachments, body) #XXX:We currently only fetch the message we inserted. Later we may fetch # all messages delivered since we last rendered the conversation cols = yield db.get_slice(convId, "mConversations") conv = utils.supercolumnsToDict(cols) participants = set(conv['participants']) mids = [messageId] messages = yield db.multiget_slice(mids, "messages", ["meta"]) messages = utils.multiSuperColumnsToDict(messages) participants.update([messages[mid]['meta']['owner'] for mid in messages]) people = base.EntitySet(participants) yield people.fetchData() value = myId data = {"entities": people} data["entities"].update({args['orgId']: args["org"]}) data["orgId"] = args["orgId"] data["convId"] = convId data["message"] = body data["subject"] = subject data["_fromName"] = people[value].basic['name'] users = participants - set([myId]) if users: yield notifications.notify(users, ":MR", value, timeUUID, **data) args.update({"people": people}) args.update({"messageIds": mids}) args.update({'messages': messages}) if script: onload = """ $('.conversation-reply').attr('value', ''); $('#msgreply-attach-uploaded').empty(); """ t.renderScriptBlock(request, "message.mako", "render_conversation_messages", landing, ".conversation-messages-wrapper", "append", True, handlers={"onload": onload}, **args) #Update the right side bar with any attachments the user uploaded args.update({"conv": conv}) people = base.EntitySet(set(conv['participants'])) yield people.fetchData() args.update({"people": people}) args.update({"conv": conv}) args.update({"id": convId}) args.update({"view": "message"}) if script: onload = """ $('#conversation_add_member').autocomplete({ source: '/auto/users', minLength: 2, select: function( event, ui ) { $('#conversation_recipients').attr('value', ui.item.uid) } }); """ t.renderScriptBlock(request, "message.mako", "right", landing, ".right-contents", "set", True, handlers={"onload": onload}, **args) else: request.redirect('/messages') request.finish()
def _renderConversation(self, request): """Render a conversation. Keyword arguments: convId: The id of the conversation that needs to be rendered. """ (appchange, script, args, myId) = yield self._getBasicArgs(request) landing = not self._ajax convId = utils.getRequestArg(request, 'id', sanitize=False) if not convId: raise errors.MissingParams([]) if script and landing: t.render(request, "message.mako", **args) if appchange and script: t.renderScriptBlock(request, "message.mako", "layout", landing, "#mainbar", "set", **args) cols = yield db.get_slice(convId, "mConversations") conv = utils.supercolumnsToDict(cols) participants = set(conv.get('participants', {}).keys()) if not conv: raise errors.InvalidMessage(convId) if myId not in participants: raise errors.MessageAccessDenied(convId) timeUUID = conv['meta']['uuid'] d1 = db.remove(myId, "mUnreadConversations", timeUUID) d2 = db.remove(convId, "mConvFolders", 'mUnreadConversations', myId) d3 = db.remove(myId, "latest", timeUUID, "messages") deferreds = [d1, d2, d3] yield defer.DeferredList(deferreds) deferreds = [] cols = yield db.get_slice(convId, "mConvFolders", [myId]) cols = utils.supercolumnsToDict(cols) for folder in cols[myId]: if folder in self._folders: folder = self._folders[folder] d = db.insert(myId, folder, "r:%s" % (convId), timeUUID) deferreds.append(d) inFolders = cols[myId].keys() #FIX: make sure that there will be an entry of convId in mConvFolders cols = yield db.get_slice(convId, "mConvMessages") mids = [col.column.value for col in cols] messages = yield db.multiget_slice(mids, "messages", ["meta"]) messages = utils.multiSuperColumnsToDict(messages) s = yield defer.DeferredList(deferreds) participants.update([messages[mid]['meta']['owner'] for mid in messages]) people = base.EntitySet(participants) yield people.fetchData() args.update({"people": people}) args.update({"conv": conv}) args.update({"messageIds": mids}) args.update({'messages': messages}) args.update({"id": convId}) args.update({"flags": {}}) args.update({"view": "message"}) args.update({"menuId": "messages"}) args.update({"inFolders": inFolders}) if script: onload = """ $$.menu.selectItem("messages"); $('#mainbar .contents').addClass("has-right"); $('.conversation-reply').autogrow(); $('#message-reply-form').html5form({messages: 'en'}); """ t.renderScriptBlock(request, "message.mako", "render_conversation", landing, ".center-contents", "set", True, handlers={"onload": onload}, **args) onload = """ $$.files.init('msgreply-attach'); $('#conversation_add_member').autocomplete({ source: '/auto/users', minLength: 2, select: function( event, ui ) { $('#conversation_recipients').attr('value', ui.item.uid) } }); """ t.renderScriptBlock(request, "message.mako", "right", landing, ".right-contents", "set", True, handlers={"onload": onload}, **args) yield utils.render_LatestCounts(request, landing) else: t.render(request, "message.mako", **args)
def _getUserItems(self, request, userId, start='', count=10): authinfo = request.getSession(IAuthInfo) myId = authinfo.username myOrgId = authinfo.organization toFetchItems = set() toFetchEntities = set() toFetchTags = set() toFetchResponses = set() toFetchCount = count + 1 toFetchStart = utils.decodeKey(start) if start else '' fetchedUserItem = [] responses = {} convs = [] userItemsRaw = [] userItems = [] reasonStr = {} timestamps = {} items = {} nextPageStart = None args = {'myId': myId} relation = Relation(myId, []) yield relation.initGroupsList() toFetchEntities.add(userId) while len(convs) < toFetchCount: cols = yield db.get_slice(userId, "userItems", start=toFetchStart, reverse=True, count=toFetchCount) tmpIds = [] for col in cols: convId = col.column.value.split(":")[2] if convId not in tmpIds and convId not in convs: tmpIds.append(convId) (filteredConvs, deletedConvs) = yield utils.fetchAndFilterConvs\ (tmpIds, relation, items, myId, myOrgId) for col in cols[0:count]: convId = col.column.value.split(":")[2] if len(convs) == count or len(fetchedUserItem) == count*2: nextPageStart = col.column.name break if convId not in filteredConvs and convId not in convs: continue fetchedUserItem.append(col) if convId not in convs: convs.append(convId) if len(cols) < toFetchCount or nextPageStart: break if cols: toFetchStart = cols[-1].column.name if nextPageStart: nextPageStart = utils.encodeKey(nextPageStart) for col in fetchedUserItem: value = tuple(col.column.value.split(":")) timestamps[value] = col.column.timestamp/1e6 rtype, itemId, convId, convType, convOwnerId, commentSnippet = value commentSnippet = """<span class="snippet">"%s"</span>""" %(_(commentSnippet)) toFetchEntities.add(convOwnerId) if rtype == 'I': toFetchItems.add(convId) toFetchResponses.add(convId) userItems.append(value) elif rtype == "L" and itemId == convId and convOwnerId != userId: reasonStr[value] = _("liked %s's %s") userItems.append(value) elif rtype == "L" and convOwnerId != userId: r = "answer" if convType == 'question' else 'comment' reasonStr[value] = _("liked") + " %s " %(commentSnippet) + _("%s "%r) + _("on %s's %s") userItems.append(value) elif rtype in ["C", 'Q'] and convOwnerId != userId: reasonStr[value] = "%s"%(commentSnippet) + _(" on %s's %s") userItems.append(value) itemResponses = yield db.multiget_slice(toFetchResponses, "itemResponses", count=2, reverse=True) for convId, comments in itemResponses.items(): responses[convId] = [] for comment in comments: userId_, itemKey = comment.column.value.split(':') if itemKey not in toFetchItems: responses[convId].insert(0,itemKey) toFetchItems.add(itemKey) toFetchEntities.add(userId_) items = yield db.multiget_slice(toFetchItems, "items", ["meta", "tags", "attachments"]) items = utils.multiSuperColumnsToDict(items) args["items"] = items extraDataDeferreds = [] for convId in convs: if convId not in items: continue meta = items[convId]["meta"] itemType = meta["type"] toFetchEntities.add(meta["owner"]) if "target" in meta: toFetchEntities.update(meta["target"].split(',')) toFetchTags.update(items[convId].get("tags", {}).keys()) if itemType in plugins: d = plugins[itemType].fetchData(args, convId) extraDataDeferreds.append(d) result = yield defer.DeferredList(extraDataDeferreds) for success, ret in result: if success: toFetchEntities.update(ret) entities = base.EntitySet(toFetchEntities) yield entities.fetchData() tags = {} if toFetchTags: userOrgId = entities[userId].basic["org"] fetchedTags = yield db.get_slice(userOrgId, "orgTags", toFetchTags) tags = utils.supercolumnsToDict(fetchedTags) fetchedLikes = yield db.multiget(toFetchItems, "itemLikes", myId) myLikes = utils.multiColumnsToDict(fetchedLikes) data = {"entities": entities, "reasonStr": reasonStr, "tags": tags, "myLikes": myLikes, "userItems": userItems, "responses": responses, "nextPageStart": nextPageStart, "timestamps": timestamps } del args['myId'] args.update(data) defer.returnValue(args)
def _render(self, request): (appchange, script, args, myId) = yield self._getBasicArgs(request) # We are setting an empty value to 'cu' here just to make sure that # any errors when looking validating the entity should not leave us # in a bad state. request.addCookie('cu', '', path="/ajax/profile") if request.args.get("id", None): userId, ign = yield utils.getValidEntityId(request, "id", "user") else: userId = myId # XXX: We should use getValidEntityId to fetch the entire user # info instead of another call to the database. request.addCookie('cu', userId, path="/ajax/profile") user = base.Entity(userId) yield user.fetchData([]) if user._data: args['user'] = user detail = utils.getRequestArg(request, "dt") or "activity" args["detail"] = detail args["userId"] = userId args["menuId"] = "people" args["entities"] = base.EntitySet({myId:args['me'], userId:user}) # When scripts are enabled, updates are sent to the page as # and when we get the required data from the database. # When we are the landing page, we also render the page header # and all updates are wrapped in <script> blocks. landing = not self._ajax # User entered the URL directly # Render the header. Other things will follow. if script and landing: t.render(request, "profile.mako", **args) # Start with displaying the template and navigation menu if script and appchange: t.renderScriptBlock(request, "profile.mako", "layout", landing, "#mainbar", "set", **args) # Prefetch some data about how I am related to the user. # This is required in order to reliably filter our profile details # that I don't have access to. relation = Relation(myId, [userId]) args["relations"] = relation yield defer.DeferredList([relation.initSubscriptionsList(), relation.initGroupsList()]) # Reload all user-depended blocks if the currently displayed user is # not the same as the user for which new data is being requested. if script: t.renderScriptBlock(request, "profile.mako", "summary", landing, "#profile-summary", "set", **args) t.renderScriptBlock(request, "profile.mako", "user_subactions", landing, "#user-subactions", "set", **args) fetchedEntities = set() start = utils.getRequestArg(request, "start") or '' fromFetchMore = ((not landing) and (not appchange) and start) if detail == "activity": userItems = yield self._getUserItems(request, userId, start=start) args.update(userItems) elif detail == 'files': end = utils.getRequestArg(request, "end") or '' end = utils.decodeKey(end) start = utils.decodeKey(start) userFiles = yield files.userFiles(myId, userId, args['orgId'], start, end, fromFeed=False) args['userfiles'] = userFiles args['fromProfile'] = True if script: t.renderScriptBlock(request, "profile.mako", "tabs", landing, "#profile-tabs", "set", **args) handlers = {} if detail != "activity" \ else {"onload": "(function(obj){$$.convs.load(obj);})(this);"} if fromFetchMore and detail == "activity": t.renderScriptBlock(request, "profile.mako", "content", landing, "#next-load-wrapper", "replace", True, handlers=handlers, **args) else: t.renderScriptBlock(request, "profile.mako", "content", landing, "#profile-content", "set", True, handlers=handlers, **args) # List the user's subscriptions cols = yield db.get_slice(userId, "subscriptions", count=11) subscriptions = set(utils.columnsToDict(cols).keys()) args["subscriptions"] = subscriptions # List the user's followers cols = yield db.get_slice(userId, "followers", count=11) followers = set(utils.columnsToDict(cols).keys()) args["followers"] = followers # Fetch item data (name and avatar) for subscriptions, followers, # user groups and common items. entitiesToFetch = followers.union(subscriptions)\ .difference(fetchedEntities) # List the user's groups (and look for groups common with me) cols = yield db.multiget_slice([myId, userId], "entityGroupsMap") myGroups = set([x.column.name.split(':', 1)[1] for x in cols[myId]]) userGroups = set([x.column.name.split(':', 1)[1] for x in cols[userId]]) commonGroups = myGroups.intersection(userGroups) if len(userGroups) > 10: userGroups = sample(userGroups, 10) args["userGroups"] = userGroups args["commonGroups"] = commonGroups groupsToFetch = commonGroups.union(userGroups) entitiesToFetch = entitiesToFetch.union(groupsToFetch) entities = base.EntitySet(entitiesToFetch) yield entities.fetchData() for entityId, entity in entities.items(): if not entity._data: del entities[entityId] args["entities"].update(entities) if script: t.renderScriptBlock(request, "profile.mako", "user_subscriptions", landing, "#user-subscriptions", "set", **args) t.renderScriptBlock(request, "profile.mako", "user_followers", landing, "#user-followers", "set", **args) t.renderScriptBlock(request, "profile.mako", "user_me", landing, "#user-me", "set", **args) t.renderScriptBlock(request, "profile.mako", "user_groups", landing, "#user-groups", "set", **args) if script and landing: request.write("</body></html>") if not script: t.render(request, "profile.mako", **args)
def updateData(): yield db.truncate('user_files') try: yield db.get('asdf', 'entityFeed_files', uuid.uuid1().bytes) except ttypes.InvalidRequestException as exception: log.msg(exception) raise Exception('entityFeed_files CF missing, create the CF') except ttypes.NotFoundException: pass entities = {} items = {} rows = yield db.get_range_slice('items', count=10000, reverse=True) for row in rows: itemId = row.key item = utils.supercolumnsToDict(row.columns) items[itemId]=item for itemId in items: item = items[itemId] log.msg(itemId) if 'meta' not in item: continue # Add org to all items try: owner = item['meta']['owner'] col = yield db.get(owner, "entities", 'org', 'basic') ownerOrgId = col.column.value yield db.insert(itemId, 'items', ownerOrgId, 'org', 'meta') except Exception as e: if item['meta'].get('type', '') == 'feedback': yield db.insert(itemId, 'items', owner, 'org', 'meta') # Fix ACLs if 'parent' not in item['meta']: acl = item['meta']['acl'] convOwner = item['meta']['owner'] convId = itemId if acl == 'company': col = yield db.get(convOwner, "entities", "org", "basic") ownerOrgId = col.column.value acl = pickle.dumps({"accept":{"orgs":[ownerOrgId]}}) yield db.insert(convId, 'items', acl, 'acl', 'meta') else: try: acl = pickle.loads(acl) if 'accept' in acl and 'friends' in acl['accept'] and isinstance(acl['accept']['friends'], bool): del acl['accept']['friends'] acl = pickle.dumps(acl) yield db.insert(convId, 'items', acl, 'acl', 'meta') except : log.msg('cannot unpack acl', acl) # Migrate files # truncate user_files # update user_files and entityFeed_files if 'owner' in item['meta'] and 'attachments' in item: ownerId = item['meta']['owner'] if ownerId not in entities: cols = yield db.get_slice(ownerId, 'entities', ['basic']) entities.update({ownerId: utils.supercolumnsToDict(cols)}) for attachmentId in item['attachments']: orgId = entities[ownerId]['basic']['org'] timeuuid, name = item['attachments'][attachmentId].split(':')[:2] timeuuid = utils.decodeKey(timeuuid) val = '%s:%s:%s:%s' % (attachmentId, name, itemId, ownerId) yield db.insert(ownerId, "user_files", val, timeuuid) if 'parent' not in item['meta'] and item['meta'].get('acl', ''): _entities = yield utils.expandAcl(ownerId, orgId, item['meta']['acl'], itemId, ownerId, True) for entityId in _entities: yield db.insert(entityId, "entityFeed_files", val, timeuuid) # Migrate items # Meta fields in "link", "event" and "poll" if item['meta'].get('type', None) in ['link', 'poll', 'event']: itemMeta = item['meta'] itemType = itemMeta['type'] updated = {} if itemType == "link": if 'url' in itemMeta: updated['link_url'] = itemMeta['url'] if 'title' in itemMeta: updated['link_title'] = itemMeta['title'] if 'summary' in itemMeta: updated['link_summary'] = itemMeta['summary'] if 'imgSrc' in itemMeta: updated['link_imgSrc'] = itemMeta['imgSrc'] if 'embedType' in itemMeta: updated['link_embedType'] = itemMeta['embedType'] if 'embedSrc' in itemMeta: updated['link_embedSrc'] = itemMeta['embedSrc'] if 'embedHeight' in itemMeta: updated['link_embedHeight'] = itemMeta['embedHeight'] if 'embedWidth' in itemMeta: updated['link_embedWidth'] = itemMeta['embedWidth'] elif itemType == 'poll': if 'question' in itemMeta: updated['comment'] = itemMeta['question'] else: print 'Found an event:', itemId if updated: yield db.batch_insert(itemId, 'items', {'meta': updated}) # # Create poll indexes for feed and userItems # rows = yield db.get_range_slice('entities', count=10000, reverse=True) mutations = {} for row in rows: entityId = row.key entity = utils.supercolumnsToDict(row.columns) if entity['basic']['type'] != 'user': continue d1 = db.get_slice(entityId, 'feed', count=10000) d2 = db.get_slice(entityId, 'userItems', count=10000) results = yield d1 for col in results: value = col.column.value if value in items: if items.get(value, {}).get('meta', {}).get('type', '') == 'poll': mutations.setdefault(entityId, {}).setdefault('feed_poll', {}).update({col.column.name: value}) results = yield d2 for col in results: value = col.column.value responseType, itemId, convId, convType, others = value.split(':', 4) if convType == 'poll': mutations.setdefault(entityId, {}).setdefault('userItems_poll', {}).update({col.column.name: value}) yield db.batch_mutate(mutations) #Group type changed from public-private to open-closed. rows = yield db.get_range_slice('entityGroupsMap', count=1000) groupIds = set() for row in rows: for col in row.columns: name_, groupId = col.column.name.split(':') groupIds.add(groupId) cols = yield db.multiget_slice(groupIds, "entities") groups = utils.multiSuperColumnsToDict(cols) for groupId in groups: access = groups[groupId]['basic']['access'].lower() if access == 'public': yield db.insert(groupId, 'entities', 'open', 'access', 'basic') elif access.lower() == 'private': yield db.insert(groupId, 'entities', 'closed', 'access', 'basic') #Fix entityGroupsMap rows = yield db.get_range_slice('entityGroupsMap', count=1000) for row in rows: entityId = row.key for col in row.columns: name_, groupId = col.column.name.split(':') if col.column.name != '%s:%s'%(groups[groupId]['basic']['name'].lower(), groupId): yield db.remove(entityId, 'entityGroupsMap', col.column.name) yield db.insert(entityId, 'entityGroupsMap', '', '%s:%s' %(groups[groupId]['basic']['name'].lower(), groupId))
try: yield comet.publish('/notify/%s' % (myId), data) yield comet.publish('/notify/%s' % (recipientId), data) except Exception, e: self.setResponseCodeAndWrite(request, 200, {'error': 'The message could not be sent!'}) return yield db.insert(channelId, 'channelSubscribers', '', myId) yield db.insert(channelId, 'channelSubscribers', '', recipientId) channelSubscribers = set([myId, recipientId]) start = utils.uuid1(timestamp=time.time() - 3600).bytes cols = yield db.get_slice(myId, 'chatArchiveList', start=start, ) chatIds = [col.column.value for col in cols] participants = yield db.multiget_slice(chatIds, "chatParticipants") participants = utils.multiColumnsToDict(participants) oldTimeuuid = None chatId = None timeuuid = uuid.uuid1().bytes for col in cols: _participants = participants[col.column.value].keys() if not set(_participants).difference(channelSubscribers): chatId = col.column.value oldTimeuuid = col.column.name if not chatId: chatId = utils.getUniqueKey() for userId in channelSubscribers: yield db.insert(chatId, "chatParticipants", '', userId) for userId in channelSubscribers: yield db.insert(chatId, "chatLogs", '%s:%s' % (myId, comment),
def _listGroups(self, request): appchange, script, args, myId = yield self._getBasicArgs(request) landing = not self._ajax me = args['me'] viewType = utils.getRequestArg(request, 'type') or 'myGroups' start = utils.getRequestArg(request, 'start') or '' start = utils.decodeKey(start) viewTypes = ['myGroups', 'allGroups', 'adminGroups', 'pendingRequests', 'invitations'] viewType = 'myGroups' if viewType not in viewTypes else viewType args["menuId"] = "groups" args['viewType'] = viewType cols = yield db.get_slice(myId, "entities", super_column='adminOfGroups') managedGroupIds = [col.column.name for col in cols] ##TODO: can we use getLatestCounts instead of fetching pendingConnections? cols = yield db.multiget_slice(managedGroupIds, "pendingConnections", count=1) cols = utils.multiColumnsToDict(cols) showPendingRequestsTab = sum([len(cols[groupId]) for groupId in cols]) > 0 args["showPendingRequestsTab"] = showPendingRequestsTab if viewType == 'pendingRequests' and not showPendingRequestsTab: viewType = 'myGroups' args["viewType"] = viewType cols = yield db.get_slice(myId, "pendingConnections", start="GI:", count=1) args["showInvitationsTab"] = bool(len([col for col in cols if col.column.name.startswith('GI:')])) if viewType == 'invitations' and not args["showInvitationsTab"]: viewType = 'myGroups' args['viewType'] = viewType counts = yield utils.getLatestCounts(request, False) groupRequestCount = args["groupRequestCount"] = counts["groups"] if script and landing: t.render(request, "groups.mako", **args) if script and appchange: t.renderScriptBlock(request, "groups.mako", "layout", landing, "#mainbar", "set", **args) if viewType not in ['pendingRequests', 'invitations']: if viewType == 'myGroups': data = yield Group.getGroups(me, me, start) elif viewType == 'allGroups': data = yield Group.getGroups(me, args['org'], start) else: data = yield Group.getManagedGroups(me, start) args.update(data) elif viewType == 'pendingRequests': data = yield Group.getGroupRequests(me, start) args.update(data) args['tab'] = 'pending' elif viewType == 'invitations': data = yield Group.getAllInvitations(me, start) args.update(data) if script: t.renderScriptBlock(request, "groups.mako", "titlebar", landing, "#titlebar", "set", **args) t.renderScriptBlock(request, "groups.mako", "viewOptions", landing, "#groups-view", "set", args=[viewType], showPendingRequestsTab=showPendingRequestsTab, showInvitationsTab=args['showInvitationsTab'], groupRequestCount=groupRequestCount) if viewType == "pendingRequests": t.renderScriptBlock(request, "groups.mako", "allPendingRequests", landing, "#groups-wrapper", "set", **args) else: t.renderScriptBlock(request, "groups.mako", "listGroups", landing, "#groups-wrapper", "set", **args) t.renderScriptBlock(request, "groups.mako", "paging", landing, "#groups-paging", "set", **args) if not script: t.render(request, "groups.mako", **args)