Beispiel #1
0
    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)
Beispiel #2
0
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)
Beispiel #3
0
 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
Beispiel #4
0
 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']
Beispiel #5
0
    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])
Beispiel #6
0
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)
Beispiel #7
0
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])
Beispiel #9
0
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)
Beispiel #10
0
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)
Beispiel #11
0
    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)
Beispiel #12
0
    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)
Beispiel #13
0
    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)
Beispiel #14
0
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)
Beispiel #15
0
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)
Beispiel #16
0
    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)
Beispiel #17
0
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))
Beispiel #18
0
            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)
Beispiel #20
0
    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)
Beispiel #21
0
    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]))
Beispiel #22
0
    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)
Beispiel #23
0
    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)
Beispiel #24
0
    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()
Beispiel #25
0
    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)
Beispiel #26
0
    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)
Beispiel #27
0
    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))
Beispiel #29
0
            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),
Beispiel #30
0
    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)