示例#1
0
    def _addMembers(self, request):
        """This method add a new user 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

        """
        myId = request.getSession(IAuthInfo).username
        orgId = request.getSession(IAuthInfo).organization
        newMembers, body, subject, convId = self._parseComposerArgs(request)

        if not (convId and newMembers):
            raise errors.MissingParams(['Recipient'])

        conv = yield db.get_slice(convId, "mConversations")
        conv = utils.supercolumnsToDict(conv)
        subject = conv['meta'].get('subject', None)
        participants = set(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(newMembers, "entities", ['basic'])
        #people = utils.multiSuperColumnsToDict(cols)
        people = base.EntitySet(newMembers)
        yield people.fetchData()
        newMembers = set([userId for userId in people.keys() \
                            if people[userId].basic and \
                               people[userId].basic["org"] == orgId])
        newMembers = newMembers - participants

        mailNotificants = participants - set([myId])
        toFetchEntities = mailNotificants.union([myId, orgId]).union(newMembers)
        entities = base.EntitySet(toFetchEntities)
        yield entities.fetchData()
        data = {"entities": entities}
        data["orgId"] = orgId
        data["convId"] = convId
        data["subject"] = subject
        data["_fromName"] = entities[myId].basic['name']
        if newMembers:
            data["message"] = conv["meta"]["snippet"]
            newMembers = dict([(userId, '') for userId in newMembers])
            yield db.batch_insert(convId, "mConversations", {'participants': newMembers})
            yield self._deliverMessage(convId, newMembers, conv['meta']['uuid'], conv['meta']['owner'])
            yield notifications.notify(newMembers, ":NM", myId, **data)
        if mailNotificants and newMembers:
            data["addedMembers"] = newMembers
            yield notifications.notify(mailNotificants, ":MA", myId, **data)
示例#2
0
def invite(group, me, user):
    """Invite an user to join a group.
    Only group-member can invite others to the group. Ignore if invited user
    is already a member of the group.

    Keyword params:
    @me:
    @user: user object
    @group: group object
    """
    try:
        yield db.get(group.id, "groupMembers", me.id)
    except ttypes.NotFoundException as e:
        raise e

    try:
        yield db.get(group.id, "groupMembers", user.id)
    except ttypes.NotFoundException:
        try:
            yield db.get(user.id, "pendingConnections", "GO:%s" % (group.id))
        except ttypes.NotFoundException:
            cols = yield db.get_slice(user.id, "pendingConnections",
                                      ["GI:%s" % (group.id)])
            invited_by = set()
            if cols:
                invited_by.update(cols[0].column.value.split(','))
            invited_by.add(me.id)
            yield db.insert(user.id, "pendingConnections",
                            ",".join(invited_by), "GI:%s" % (group.id))
            data = {"entities": {group.id: group, user.id: user, me.id: me},
                    "groupName": group.basic["name"]}
            yield notifications.notify([user.id], ":GI:%s" % (group.id),
                                        me.id, **data)
示例#3
0
def approveRequest(request, group, user, me):
    """accept a group-join request. Add the user to group-members.
    Only group-admin can perform this action.

    Keyword params:
    @me:
    @user: user object
    @group: group object
    @request:
    """
    if me.id not in group.admins:
        raise errors.PermissionDenied('Access Denied')

    try:
        yield db.get(group.id, "pendingConnections", "GI:%s" % (user.id))
        d1 = _removeFromPending(group, user)
        d2 = _addMember(request, group, user)

        data = {"entities": {group.id: group, user.id: user, me.id: me}}
        d3 = notifications.notify([user.id], ":GA", group.id, **data)

        yield defer.DeferredList([d1, d2, d3])
        defer.returnValue(True)

    except ttypes.NotFoundException:
        pass
    defer.returnValue(False)
示例#4
0
def subscribe(request, group, user, org):
    """Open group: add user to the group.
    Closed group: add a pending request, send a notification to group-admins.
    Raise an exception if user is blocked from joining the group.

    Keyword params:
    @org: org object
    @user: user object
    @group: group object
    @request:

    """
    cols = yield db.get_slice(group.id, "blockedUsers", [user.id])
    if cols:
        raise errors.PermissionDenied(_("You are banned from joining the group."))

    isNewMember = False
    pendingRequests = {}
    try:
        cols = yield db.get(group.id, "groupMembers", user.id)
    except ttypes.NotFoundException:
        if group.basic['access'] == "open":
            yield _addMember(request, group, user)
            yield _removeFromPending(group, user)
            isNewMember = True
        else:
            # Add to pending connections
            yield db.insert(user.id, "pendingConnections",
                            '', "GO:%s" % (group.id))
            yield db.insert(group.id, "pendingConnections",
                            '', "GI:%s" % (user.id))

            yield _notify(group, user)
            pendingRequests["GO:%s" % (group.id)] = user.id

            entities = base.EntitySet(group.admins.keys())
            yield entities.fetchData()

            entities.update({group.id: group, org.id: org, user.id: user})
            data = {"entities": entities, "groupName": group.basic['name']}
            yield notifications.notify(group.admins, ":GR", user.id, **data)
    defer.returnValue((isNewMember, pendingRequests))
示例#5
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)
示例#6
0
    def _createConversation(self, request):
        """Create a new conversation including committing meta info about the
        conversation and the message.

        Keyword Arguments:
        recipients: A list of user ids who also receive this conversation.
        body: Text of the first message in this conversation.
        subject: Subject of the conversation.

        CF Changes:
        mConvMessages
        attachmentVersions

        """
        (appchange, script, args, myId) = yield self._getBasicArgs(request)
        landing = not self._ajax
        myOrgId = args['orgId']
        epoch = int(time.time())

        recipients, body, subject, parent = self._parseComposerArgs(request)
        filterType = utils.getRequestArg(request, "filterType") or None

        if not parent and not recipients:
            raise errors.MissingParams(['Recipients'])

        if not subject and not body:
            raise errors.MissingParams(['Both subject and message'])

        recipients = base.EntitySet(recipients)
        yield recipients.fetchData()
        recipients = set([userId for userId in recipients.keys() if not recipients[userId].isEmpty()])
        if not recipients:
            raise errors.MissingParams(['Recipients'])

        recipients.add(myId)
        participants = list(recipients)

        timeUUID = uuid.uuid1().bytes
        snippet = self._fetchSnippet(body)
        meta = {'uuid': timeUUID, 'date_epoch': str(epoch), "snippet": snippet,
                'subject': subject, "owner": myId,
                "timestamp": str(int(time.time()))}
        attachments = yield self._handleAttachments(request)

        convId = yield self._newConversation(myId, participants, meta, attachments)
        messageId = yield self._newMessage(myId, timeUUID, body, epoch)
        yield self._deliverMessage(convId, participants, timeUUID, myId)
        yield db.insert(convId, "mConvMessages", messageId, timeUUID)

        self._indexMessage(convId, messageId, myOrgId, meta, attachments, body)

        #XXX: Is this a duplicate batch insert?
        #yield db.batch_insert(convId, "mConversations", {'meta':meta})
        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 = set(participants) - set([myId])
        if users:
            yield notifications.notify(users, ":NM", myId, timeUUID, **data)

        if script:
            request.write("$$.dialog.close('msgcompose-dlg', true);$$.fetchUri('/messages');")
示例#7
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()
示例#8
0
 def notifyFollow(res):
     data = {'entities': entities}
     return notifications.notify([targetId], ":NF", myId, **data)
示例#9
0
    def _addUser(self, request):
        emailId = utils.getRequestArg(request, 'email')
        existingUser = db.get_count(emailId, "userAuth")

        localpart, domain = emailId.split("@")
        displayName = utils.getRequestArg(request, 'name')
        jobTitle = utils.getRequestArg(request, 'jobTitle')
        timezone = utils.getRequestArg(request, 'timezone')
        passwd = utils.getRequestArg(request, 'password', sanitize=False)
        pwdrepeat = utils.getRequestArg(request, 'pwdrepeat', sanitize=False)
        if not displayName or not jobTitle or not timezone or not passwd:
            raise errors.MissingParams([_("All fields are required to create the user")])

        if passwd != pwdrepeat:
            raise PasswordsNoMatch()

        args = {'emailId': emailId, 'view': 'invite'}

        existingUser = yield existingUser
        if not existingUser:
            authinfo = yield defer.maybeDeferred(request.getSession, IAuthInfo)
            orgId = yield getOrgId(domain)
            if not orgId:
                orgId = utils.getUniqueKey()
                domains = {domain: ''}
                basic = {"name": domain, "type": "org"}
                yield db.batch_insert(orgId, "entities", {"basic": basic,
                                                          "domains": domains})
                yield db.insert(domain, "domainOrgMap", '', orgId)

            userId = yield utils.addUser(emailId, displayName, passwd,
                                         orgId, jobTitle, timezone)
            authinfo.username = userId
            authinfo.organization = orgId
            authinfo.isAdmin = False
            yield request._saveSessionToDB()

            cols = yield db.get_slice(domain, "invitations", [emailId])
            cols = utils.supercolumnsToDict(cols)

            userIds = cols.get(emailId, {}).values()
            if userIds:
                db.batch_remove({'invitationsSent': userIds}, names=[emailId])

            yield db.remove(domain, "invitations", super_column=emailId)
            t.render(request, "signup.mako", **args)

            # Notify all invitees about this user.
            token = utils.getRequestArg(request, "token")
            acceptedInvitationSender = cols.get(emailId, {}).get(token)
            otherInvitees = [x for x in userIds
                             if x not in (acceptedInvitationSender, emailId)]

            entities = base.EntitySet(userIds + [orgId, userId])
            yield entities.fetchData()
            data = {"entities": entities, 'orgId': orgId}

            yield notifications.notify([acceptedInvitationSender], ":IA", userId, **data)
            yield notifications.notify(otherInvitees, ":NU", userId, **data)
        else:
            raise InvalidRegistration("A user with this e-mail already exists! Already registered?")
示例#10
0
 def _sendNotifications(ignored):
     return notifications.notify(recipients, notifyId,
                                 myId, timeUUID, **kwargs)
示例#11
0
def new(request, authInfo, convType, richText=False):
    if convType not in plugins:
        raise errors.BaseError('Unsupported item type', 400)
    myId = authInfo.username
    orgId = authInfo.organization
    entities = base.EntitySet([myId, orgId])
    yield entities.fetchData(['basic', 'admins'])

    plugin = plugins[convType]
    convId = utils.getUniqueKey()
    conv = yield plugin.create(request, entities[myId], convId, richText)
    orgAdminIds = entities[orgId].admins.keys()
    if orgAdminIds:
        text = ''
        monitoredFields = getattr(plugin, 'monitoredFields', {})
        for superColumnName in monitoredFields:
            for columnName in monitoredFields[superColumnName]:
                if columnName in conv[superColumnName]:
                    text = " ".join([text, conv[superColumnName][columnName]])
        matchedKeywords = yield utils.watchForKeywords(orgId, text)

        if matchedKeywords:
            reviewOK = utils.getRequestArg(request, "_review") == "1"
            if reviewOK:
                # Add conv to list of items that matched this keyword
                # and notify the administrators about it.
                orgAdmins = base.EntitySet(orgAdminIds)
                yield orgAdmins.fetchData()
                entities.update(orgAdmins)
                for keyword in matchedKeywords:
                    yield db.insert(orgId + ":" + keyword, "keywordItems",
                                    convId, conv['meta']['uuid'])
                    yield notifications.notify(orgAdminIds, ':KW:' + keyword,
                                               myId, entities=entities)
            else:
                # This item contains a few keywords that are being monitored
                # by the admin and cannot be posted unless reviewOK is set.
                defer.returnValue((None, None, matchedKeywords))

    #
    # Save the new item to database and index it.
    #
    yield db.batch_insert(convId, "items", conv)
    yield files.pushfileinfo(myId, orgId, convId, conv)
    search.solr.updateItemIndex(convId, conv, orgId)

    #
    # Push item to feeds and userItems
    #
    timeUUID = conv["meta"]["uuid"]
    convACL = conv["meta"]["acl"]
    deferreds = []
    responseType = 'I'

    # Push to feeds
    feedUpdateVal = "I:%s:%s" % (myId, convId)
    d = Feed.push(myId, orgId, convId, conv, timeUUID,
                  feedUpdateVal, promoteActor=True)
    deferreds.append(d)

    # Save in user items.
    userItemValue = ":".join([responseType, convId, convId, convType, myId, ''])
    d = db.insert(myId, "userItems", userItemValue, timeUUID)
    deferreds.append(d)
    if plugins[convType].hasIndex:
        d = db.insert(myId, "userItems_%s" % (convType), userItemValue, timeUUID)
        deferreds.append(d)

    yield defer.DeferredList(deferreds)
    defer.returnValue((convId, conv, None))
示例#12
0
def _comment(convId, conv, comment, snippet, myId, orgId, richText, reviewed, fids=None):
    convType = conv["meta"].get("type", "status")

    # 1. Create the new item
    timeUUID = uuid.uuid1().bytes
    meta = {"owner": myId, "parent": convId, "comment": comment,
            "timestamp": str(int(time.time())), "org": orgId,
            "uuid": timeUUID, "richText": str(richText)}
    item = {'meta':meta}
    followers = {myId: ''}
    itemId = utils.getUniqueKey()
    if snippet:
        meta['snippet'] = snippet

    # 1.5. Check if the comment matches any of the keywords
    entities = base.EntitySet([myId, orgId])
    yield entities.fetchData(['basic', 'admins'])
    orgAdmins = entities[orgId].admins.keys()
    if orgAdmins:
        matchedKeywords = yield utils.watchForKeywords(orgId, comment)
        if matchedKeywords:
            if reviewed:
                # Add item to list of items that matched this keyword
                # and notify the administrators about it.
                for keyword in matchedKeywords:
                    yield db.insert(orgId + ":" + keyword, "keywordItems",
                                    itemId + ":" + convId, timeUUID)
                    yield notifications.notify(orgAdmins, ':KW:' + keyword,
                                               myId, entities=entities)

            else:
                # This item contains a few keywords that are being monitored
                # by the admin and cannot be posted unless reviewOK is set.
                defer.returnValue((None, convId, {convId: conv}, matchedKeywords))

    # 1.9. Actually store the item
    if fids:
        attachments = yield utils._upload_files(myId, fids)
        if attachments:
            item['attachments'] = {}
        for attachmentId in attachments:
            fileId, name, size, ftype = attachments[attachmentId]
            item["attachments"][attachmentId] = "%s:%s:%s" % (name, size, ftype)

    yield db.batch_insert(itemId, "items", item)
    yield files.pushfileinfo(myId, orgId, itemId, item, conv)

    # 2. Update response count and add myself to the followers of conv
    convOwnerId = conv["meta"]["owner"]
    convType = conv["meta"]["type"]
    responseCount = int(conv["meta"].get("responseCount", "0"))
    if responseCount % 5 == 3:
        responseCount = yield db.get_count(convId, "itemResponses")

    responseCount += 1
    conv['meta']['responseCount'] = responseCount
    convUpdates = {"responseCount": str(responseCount)}
    yield db.batch_insert(convId, "items", {"meta": convUpdates,
                                            "followers": followers})

    # 3. Add item as response to parent
    yield db.insert(convId, "itemResponses",
                    "%s:%s" % (myId, itemId), timeUUID)

    # 4. Update userItems and userItems_*
    responseType = "Q" if convType == "question" else 'C'
    commentSnippet = utils.toSnippet(comment, 35, richText)
    userItemValue = ":".join([responseType, itemId, convId, convType,
                              convOwnerId, commentSnippet])
    yield db.insert(myId, "userItems", userItemValue, timeUUID)
    if convType in plugins and plugins[convType].hasIndex:
        yield db.insert(myId, "userItems_" + convType, userItemValue, timeUUID)

    # 5. Update my feed.
    feedItemVal = "%s:%s:%s" % (responseType, myId, itemId)
    yield Feed.push(myId, orgId, convId, conv, timeUUID, feedItemVal)

    yield _notify("C", convId, timeUUID, convType=convType,
                  convOwnerId=convOwnerId, myId=myId, me=entities[myId],
                  comment=comment, richText=richText)
    search.solr.updateItemIndex(itemId, {'meta': meta}, orgId, conv=conv)
    items = {itemId: item, convId: conv}
    defer.returnValue((itemId, convId, items, None))