示例#1
0
    def perform_actions(self, item, data):
        """Execute all the rule's actions against the item."""
        for key, target in self.targets.iteritems():
            target_item = self.get_target_item(item, data, key)
            target.perform_actions(target_item, data)

        if self.comment:
            comment = self.build_message(self.comment, item, data, disclaimer=True)

            # TODO: shouldn't have to do all this manually
            if isinstance(item, Comment):
                link = data["link"]
                parent_comment = item
            else:
                link = item
                parent_comment = None
            new_comment, inbox_rel = Comment._new(
                ACCOUNT, link, parent_comment, comment, None)
            new_comment.distinguished = "yes"
            new_comment._commit()
            queries.queue_vote(ACCOUNT, new_comment, True, None)
            queries.new_comment(new_comment, inbox_rel)

            g.stats.simple_event("automoderator.comment")

        if self.modmail:
            message = self.build_message(self.modmail, item, data, permalink=True)
            subject = replace_placeholders(
                self.modmail_subject, data, self.matches)
            subject = subject[:100]

            new_message, inbox_rel = Message._new(ACCOUNT, data["subreddit"],
                subject, message, None)
            new_message.distinguished = "yes"
            new_message._commit()
            queries.new_message(new_message, inbox_rel)

            g.stats.simple_event("automoderator.modmail")

        if self.message and not data["author"]._deleted:
            message = self.build_message(self.message, item, data,
                disclaimer=True, permalink=True)
            subject = replace_placeholders(
                self.message_subject, data, self.matches)
            subject = subject[:100]

            new_message, inbox_rel = Message._new(ACCOUNT, data["author"],
                subject, message, None)
            queries.new_message(new_message, inbox_rel)

            g.stats.simple_event("automoderator.message")

        PerformedRulesByThing.mark_performed(item, self)
示例#2
0
def notify_user_added(rel_type, author, user, target):
    msgs = user_added_messages.get(rel_type)
    if not msgs:
        return

    srname = target.path.rstrip("/")
    d = {
        "url": srname,
        "title": "%s: %s" % (srname, target.title),
        "author": "/u/" + author.name,
        "user": "******" + user.name,
    }

    if "pm" in msgs and author != user:
        subject = msgs["pm"]["subject"] % d
        msg = msgs["pm"]["msg"] % d

        if rel_type in ("moderator_invite", "contributor"):
            # send the message from the subreddit
            item, inbox_rel = Message._new(
                author, user, subject, msg, request.ip, sr=target, from_sr=True,
                can_send_email=False, is_auto_modmail=True)
        else:
            item, inbox_rel = Message._new(
                author, user, subject, msg, request.ip, can_send_email=False)

        queries.new_message(item, inbox_rel, update_modmail=False)

    if "modmail" in msgs:
        subject = msgs["modmail"]["subject"] % d
        msg = msgs["modmail"]["msg"] % d

        if rel_type == "moderator_invite":
            # Don't send the separate moderator invite message from the
            # system user to new modmail, since the one sent to the invitee
            # will already show up in there.
            # TODO: when new modmail is fully deployed, the "modmail" dict
            # should be completely removed from the moderator_invite section
            # of user_added_messages, and this check removed.
            if feature.is_enabled('new_modmail', subreddit=target.name):
                return

            modmail_author = Account.system_user()
        else:
            modmail_author = author

        item, inbox_rel = Message._new(modmail_author, target, subject, msg,
                                       request.ip, sr=target,
                                       is_auto_modmail=True)
        queries.new_message(item, inbox_rel)
示例#3
0
def _conversation(trees, parent):
    from r2.models import Message
    if parent._id in trees:
        convo = trees[parent._id]
        if convo:
            m = Message._byID(convo[0], data=True)
        if not convo or m.first_message == m.parent_id:
            return [(parent._id, convo)]

    # if we get to this point, either we didn't find the conversation,
    # or the first child of the result was not the actual first child.
    # To the database!
    m = Message._query(Message.c.first_message == parent._id, data=True)
    return compute_message_trees([parent] + list(m))
示例#4
0
 def process_message(msg):
     msg_dict = json.loads(msg.body)
     if msg_dict["event"] == "new_message":
         message_id36 = msg_dict["message_id36"]
         message = Message._byID36(message_id36, data=True)
         send_modmail_email(message)
     elif msg_dict["event"] == "blocked_muted":
         subreddit_id36 = msg_dict["subreddit_id36"]
         sr = Subreddit._byID36(subreddit_id36, data=True)
         parent_id36 = msg_dict["parent_id36"]
         parent = Message._byID36(parent_id36, data=True)
         sender_email = msg_dict["sender_email"]
         incoming_email_id = msg_dict["incoming_email_id"]
         send_blocked_muted_email(sr, parent, sender_email, incoming_email_id)
示例#5
0
def get_email_ids(message):
    parent_email_id = None
    other_email_ids = []
    if message.parent_id:
        parent = Message._byID(message.parent_id, data=True)
        if parent.email_id:
            other_email_ids.append(parent.email_id)
            parent_email_id = parent.email_id

    if message.first_message:
        first_message = Message._byID(message.first_message, data=True)
        if first_message.email_id:
            other_email_ids.append(first_message.email_id)

    return parent_email_id, other_email_ids
示例#6
0
    def __init__(self, thing, delete = False, report = True):
        was_comment = getattr(thing, 'was_comment', False)
        permalink = thing.permalink
        # don't allow replying to self unless it's modmail
        valid_recipient = (thing.author_id != c.user._id or
                           thing.sr_id)

        can_reply = (c.user_is_loggedin and
                     getattr(thing, "repliable", True) and
                     valid_recipient)
        can_block = True
        can_mute = False
        is_admin_message = False
        del_on_recipient = (isinstance(thing, Message) and
                            thing.del_on_recipient)

        if not was_comment:
            first_message = thing
            if getattr(thing, 'first_message', False):
                first_message = Message._byID(thing.first_message, data=True)

            if thing.sr_id:
                sr = thing.subreddit_slow
                is_admin_message = '/r/%s' % sr.name == g.admin_message_acct

                if (sr.is_muted(first_message.author_slow) or
                        (first_message.to_id and
                            sr.is_muted(first_message.recipient_slow))):
                    can_reply = False

                can_mute = sr.can_mute(c.user, thing.author_slow)

        if not was_comment and thing.display_author:
            can_block = False

        if was_comment:
            link = thing.link_slow
            if link.archived or link.locked:
                can_reply = False

        # Allow comment-reply messages to have links to the full thread.
        if was_comment:
            self.full_comment_path = thing.link_permalink
            self.full_comment_count = thing.full_comment_count

        PrintableButtons.__init__(self, "messagebuttons", thing,
                                  profilepage = c.profilepage,
                                  permalink = permalink,
                                  was_comment = was_comment,
                                  unread = thing.new,
                                  user_is_recipient = thing.user_is_recipient,
                                  can_reply = can_reply,
                                  parent_id = getattr(thing, "parent_id", None),
                                  show_report = True,
                                  show_delete = False,
                                  can_block = can_block,
                                  can_mute = can_mute,
                                  is_admin_message = is_admin_message,
                                  del_on_recipient=del_on_recipient,
                                 )
示例#7
0
def compute_message_trees(messages):
    from r2.models import Message
    roots = set()
    threads = {}
    mdict = {}
    messages = sorted(messages, key = lambda m: m._date, reverse = True)

    for m in messages:
        if not m._loaded:
            m._load()
        mdict[m._id] = m
        if m.first_message:
            roots.add(m.first_message)
            threads.setdefault(m.first_message, set()).add(m._id)
        else:
            roots.add(m._id)

    # load any top-level messages which are not in the original list
    missing = [m for m in roots if m not in mdict]
    if missing:
        mdict.update(Message._byID(tup(missing),
                                   return_dict = True, data = True))

    # sort threads in chrono order
    for k in threads:
        threads[k] = list(sorted(threads[k]))

    tree = [(root, threads.get(root, [])) for root in roots]
    tree.sort(key = tree_sort_fn, reverse = True)

    return tree
示例#8
0
def _add_message_nolock(key, message):
    from r2.models import Account, Message
    trees = g.permacache.get(key)
    if not trees:
        # in case an empty list got written at some point, delete it to
        # force a recompute
        if trees is not None:
            g.permacache.delete(key)
        # no point computing it now.  We'll do it when they go to
        # their message page.
        return

    # if it is a new root message, easy enough
    if message.first_message is None:
        trees.insert(0, (message._id, []))
    else:
        tree_dict = dict(trees)

        # if the tree already has the first message, update the list
        if message.first_message in tree_dict:
            if message._id not in tree_dict[message.first_message]:
                tree_dict[message.first_message].append(message._id)
                tree_dict[message.first_message].sort()
        # we have to regenerate the conversation :/
        else:
            m = Message._query(Message.c.first_message == message.first_message,
                               data = True)
            new_tree = compute_message_trees(m)
            if new_tree:
                trees.append(new_tree[0])
        trees.sort(key = tree_sort_fn, reverse = True)

    # done!
    g.permacache.set(key, trees)
示例#9
0
def send_system_message(user, subject, body, system_user=None,
                        distinguished='admin', repliable=False,
                        add_to_sent=True, author=None):
    from r2.lib.db import queries

    if system_user is None:
        system_user = Account.system_user()
    if not system_user:
        g.log.warning("Can't send system message "
                      "- invalid system_user or g.system_user setting")
        return
    if not author:
        author = system_user

    item, inbox_rel = Message._new(author, user, subject, body,
                                   ip='0.0.0.0')
    item.distinguished = distinguished
    item.repliable = repliable
    item.display_author = system_user._id
    item._commit()

    try:
        queries.new_message(item, inbox_rel, add_to_sent=add_to_sent)
    except MemcachedError:
        raise MessageError('reddit_inbox')
示例#10
0
def get_reply_to_address(message):
    """Construct a reply-to address that encodes the message id.

    The address is of the form:
        zendeskreply+{message_id36}-{email_mac}

    where the mac is generated from {message_id36} using the
    `modmail_email_secret`

    The reply address should be configured with the inbound email service so
    that replies to our messages are routed back to the app somehow. For mailgun
    this involves adding a Routes filter for messages sent to
    "zendeskreply\+*@". to be forwarded to POST /api/zendeskreply.

    """

    # all email replies are treated as replies to the first message in the
    # conversation. this is to get around some peculiarities of zendesk
    if message.first_message:
        first_message = Message._byID(message.first_message, data=True)
    else:
        first_message = message
    email_id = first_message._id36

    email_mac = hmac.new(
        g.secrets['modmail_email_secret'], email_id, hashlib.sha256).hexdigest()
    reply_id = "zendeskreply+{email_id}-{email_mac}".format(
        email_id=email_id, email_mac=email_mac)

    sr = Subreddit._byID(message.sr_id, data=True)
    return "r/{subreddit} mail <{reply_id}@{domain}>".format(
        subreddit=sr.name, reply_id=reply_id, domain=g.modmail_email_domain)
示例#11
0
    def POST_traffic_viewer(self, form, jquery, user, thing):
        """
        Adds a user to the list of users allowed to view a promoted
        link's traffic page.
        """
        if not form.has_errors("name",
                               errors.USER_DOESNT_EXIST, errors.NO_USER):
            form.set_inputs(name="")
            form.set_html(".status:first", _("added"))
            if promote.add_traffic_viewer(thing, user):
                user_row = TrafficViewerList(thing).user_row('traffic_viewer', user)
                jquery(".traffic_viewer-table").show(
                    ).find("table").insert_table_rows(user_row)

                # send the user a message
                msg = user_added_messages['traffic']['pm']['msg']
                subj = user_added_messages['traffic']['pm']['subject']
                if msg and subj:
                    d = dict(url=thing.make_permalink_slow(),
                             traffic_url=promote.promo_traffic_url(thing),
                             title=thing.title)
                    msg = msg % d
                    item, inbox_rel = Message._new(c.user, user,
                                                   subj, msg, request.ip)
                    queries.new_message(item, inbox_rel)
示例#12
0
def send_ban_message(subreddit, mod, user, note=None, days=None, new=True):
    sr_name = "/r/" + subreddit.name
    if days:
        subject = "you've been temporarily banned from %(subreddit)s"
        message = ("you have been temporarily banned from posting to "
            "%(subreddit)s. this ban will last for %(duration)s days.")
    else:
        subject = "you've been banned from %(subreddit)s"
        message = "you have been banned from posting to %(subreddit)s."

    if not new:
        subject = "Your ban from %(subreddit)s has changed"

    subject %= {"subreddit": sr_name}
    message %= {"subreddit": sr_name, "duration": days}

    if note:
        message += "\n\n" + 'note from the moderators:'
        message += "\n\n" + blockquote_text(note)

    message += "\n\n" + ("you can contact the moderators regarding your ban "
        "by replying to this message. **warning**: using other accounts to "
        "circumvent a subreddit ban is considered a violation of reddit's "
        "[site rules](/help/contentpolicy#section_prohibited_behavior) "
        "and can result in the "
        "[suspension](https://reddit.zendesk.com/hc/articles/205687686) "
        "of your reddit account.")

    item, inbox_rel = Message._new(mod, user, subject, message, request.ip,
        sr=subreddit, from_sr=True)
    queries.new_message(item, inbox_rel, update_modmail=False)
示例#13
0
def send_ban_message(subreddit, mod, user, note=None, days=None, new=True):
    sr_name = "/r/" + subreddit.name
    if days:
        subject = "you've been temporarily banned from %(subreddit)s"
        message = ("you have been temporarily banned from posting to "
            "%(subreddit)s. this ban will last for %(duration)s days.")
    else:
        subject = "you've been banned from %(subreddit)s"
        message = "you have been banned from posting to %(subreddit)s."

    if not new:
        subject = "Your ban from %(subreddit)s has changed"

    subject %= {"subreddit": sr_name}
    message %= {"subreddit": sr_name, "duration": days}

    if note:
        message += "\n\n" + 'note from the moderators:'
        message += "\n\n" + blockquote_text(note)

    message += "\n\n" + ("you can contact the moderators regarding your ban "
        "by replying to this message. **warning**: using other accounts to "
        "circumvent a subreddit ban is considered a violation of reddit's "
        "[site rules](/rules) and can result in being banned from reddit "
        "entirely.")

    item, inbox_rel = Message._new(
        mod, user, subject, message, request.ip, sr=subreddit, from_sr=True,
        can_send_email=False)
    queries.new_message(item, inbox_rel, update_modmail=False)
示例#14
0
    def _mock_message(id=1, author_id=1, **kwargs):
        kwargs['id'] = id
        kwargs['author_id'] = author_id

        message = Message(**kwargs)
        VByName.run = MagicMock(return_value=message)

        return message
示例#15
0
def _load_messages(mlist):
    from r2.models import Message
    m = {}
    ids = [x for x in mlist if not isinstance(x, Message)]
    if ids:
        m = Message._by_fullname(ids, return_dict = True, data = True)
    messages = [m.get(x, x) for x in mlist]
    return messages
示例#16
0
def _load_messages(mlist):
    from r2.models import Message
    m = {}
    ids = [x for x in mlist if not isinstance(x, Message)]
    if ids:
        m = Message._by_fullname(ids, return_dict=True, data=True)
    messages = [m.get(x, x) for x in mlist]
    return messages
示例#17
0
文件: things.py 项目: ruivop/reddit
    def __init__(self, thing, delete=False, report=True):
        was_comment = getattr(thing, 'was_comment', False)
        permalink = thing.permalink
        # don't allow replying to self unless it's modmail
        valid_recipient = (thing.author_id != c.user._id or thing.sr_id)

        can_reply = (c.user_is_loggedin and getattr(thing, "repliable", True)
                     and valid_recipient)
        can_block = True
        can_mute = False

        if not was_comment:
            first_message = thing
            if getattr(thing, 'first_message', False):
                first_message = Message._byID(thing.first_message, data=True)

            if thing.sr_id:
                sr = thing.subreddit_slow
                if feature.is_enabled('modmail_muting', subreddit=sr.name):
                    if (sr.is_muted(first_message.author_slow) or
                        (first_message.to_id
                         and sr.is_muted(first_message.recipient_slow))):
                        can_reply = False

                    if (not sr.is_moderator(thing.author_slow)
                            and sr.is_moderator_with_perms(
                                c.user, 'access', 'mail')):
                        can_mute = True

        if not was_comment and thing.display_author:
            can_block = False

        if was_comment:
            link = thing.link_slow
            if link.archived or link.locked:
                can_reply = False

        # Allow comment-reply messages to have links to the full thread.
        if was_comment:
            self.full_comment_path = thing.link_permalink
            self.full_comment_count = thing.full_comment_count

        PrintableButtons.__init__(
            self,
            "messagebuttons",
            thing,
            profilepage=c.profilepage,
            permalink=permalink,
            was_comment=was_comment,
            unread=thing.new,
            user_is_recipient=thing.user_is_recipient,
            can_reply=can_reply,
            parent_id=getattr(thing, "parent_id", None),
            show_report=True,
            show_delete=False,
            can_block=can_block,
            can_mute=can_mute,
        )
示例#18
0
def notify_user_added(rel_type, author, user, target, message=None):
    msgs = user_added_messages.get(rel_type)
    if not msgs:
        return

    srname = target.path.rstrip("/")
    d = {
        "url": srname,
        "title": "%s: %s" % (srname, target.title),
        "author": "/u/" + author.name,
        "user": "******" + user.name,
    }

    if "pm" in msgs and author != user:
        subject = msgs["pm"]["subject"] % d
        msg = msgs["pm"]["msg"] % d

        if rel_type == "banned" and not user.has_interacted_with(target):
            return

        if rel_type == "banned" and message:
            msg += "\n\n" + N_("note from the moderators:\n\n\"%(message)s\"")
            msg %= {'message': message}

        if rel_type in ("banned", "moderator_invite"):
            # send the message from the subreddit
            item, inbox_rel = Message._new(author, user, subject, msg, request.ip,
                                           sr=target, from_sr=True)
        else:
            item, inbox_rel = Message._new(author, user, subject, msg, request.ip)

        queries.new_message(item, inbox_rel, update_modmail=False)

    if "modmail" in msgs:
        subject = msgs["modmail"]["subject"] % d
        msg = msgs["modmail"]["msg"] % d

        if rel_type == "moderator_invite":
            modmail_author = Account.system_user()
        else:
            modmail_author = author

        item, inbox_rel = Message._new(modmail_author, target, subject, msg,
                                       request.ip, sr=target)
        queries.new_message(item, inbox_rel, update_modmail=False)
示例#19
0
def _conversation(trees, parent):
    from r2.models import Message
    if parent._id in trees:
        convo = trees[parent._id]
        if convo:
            m = Message._byID(convo[0], data=True)
        if not convo or m.first_message == m.parent_id:
            return [(parent._id, convo)]

    # if we get to this point, either we didn't find the conversation,
    # or the first child of the result was not the actual first child.
    # To the database!
    rules = [Message.c.first_message == parent._id]
    if c.user_is_admin:
        rules.append(Message.c._spam == (True, False))
        rules.append(Message.c._deleted == (True, False))
    m = Message._query(*rules, data=True)
    return compute_message_trees([parent] + list(m))
示例#20
0
def _conversation(trees, parent):
    from r2.models import Message
    if parent._id in trees:
        convo = trees[parent._id]
        if convo:
            m = Message._byID(convo[0], data = True)
        if not convo or m.first_message == m.parent_id:
            return [(parent._id, convo)]

    # if we get to this point, either we didn't find the conversation,
    # or the first child of the result was not the actual first child.
    # To the database!
    rules = [Message.c.first_message == parent._id]
    if c.user_is_admin:
        rules.append(Message.c._spam == (True, False))
        rules.append(Message.c._deleted == (True, False))
    m = Message._query(*rules, data=True)
    return compute_message_trees([parent] + list(m))
示例#21
0
def get_message_subject(message):
    sr = Subreddit._byID(message.sr_id, data=True)

    if message.first_message:
        first_message = Message._byID(message.first_message, data=True)
        conversation_subject = first_message.subject
    else:
        conversation_subject = message.subject

    return u"[r/{subreddit} mail]: {subject}".format(
        subreddit=sr.name, subject=_force_unicode(conversation_subject))
示例#22
0
def get_message_subject(message):
    sr = Subreddit._byID(message.sr_id, data=True)

    if message.first_message:
        first_message = Message._byID(message.first_message, data=True)
        conversation_subject = first_message.subject
    else:
        conversation_subject = message.subject

    return u"[{brander_community_abbr}/{subreddit} mail]: {subject}".format(
        subreddit=sr.name, subject=_force_unicode(conversation_subject, brander_community_abbr=g.brander_community_abbr))
示例#23
0
def notify_user_added(rel_type, author, user, target):
    msgs = user_added_messages.get(rel_type)
    if not msgs:
        return

    srname = target.path.rstrip("/")
    d = {
        "url": srname,
        "title": "%s: %s" % (srname, target.title),
        "author": "/u/" + author.name,
        "user": "******" + user.name,
    }

    if "pm" in msgs and author != user:
        subject = msgs["pm"]["subject"] % d
        msg = msgs["pm"]["msg"] % d

        if rel_type == "banned" and not user.has_interacted_with(target):
            return

        if rel_type in ("banned", "moderator_invite"):
            # send the message from the subreddit
            item, inbox_rel = Message._new(author, user, subject, msg, request.ip,
                                           sr=target, from_sr=True)
        else:
            item, inbox_rel = Message._new(author, user, subject, msg, request.ip)

        queries.new_message(item, inbox_rel)

    if "modmail" in msgs:
        subject = msgs["modmail"]["subject"] % d
        msg = msgs["modmail"]["msg"] % d

        if rel_type == "moderator_invite":
            modmail_author = Account.system_user()
        else:
            modmail_author = author

        item, inbox_rel = Message._new(modmail_author, target, subject, msg,
                                       request.ip, sr=target)
        queries.new_message(item, inbox_rel)
示例#24
0
def notify_user_added(rel_type, author, user, target):
    msgs = user_added_messages.get(rel_type)
    if not msgs:
        return

    srname = target.path.rstrip("/")
    d = {
        "url": srname,
        "title": "%s: %s" % (srname, target.title),
        "author": "/u/" + author.name,
        "user": "******" + user.name,
    }

    if "pm" in msgs and author != user:
        subject = msgs["pm"]["subject"] % d
        msg = msgs["pm"]["msg"] % d

        if rel_type in ("moderator_invite", "contributor"):
            # send the message from the subreddit
            item, inbox_rel = Message._new(
                author, user, subject, msg, request.ip, sr=target, from_sr=True,
                can_send_email=False)
        else:
            item, inbox_rel = Message._new(
                author, user, subject, msg, request.ip, can_send_email=False)

        queries.new_message(item, inbox_rel, update_modmail=False)

    if "modmail" in msgs:
        subject = msgs["modmail"]["subject"] % d
        msg = msgs["modmail"]["msg"] % d

        if rel_type == "moderator_invite":
            modmail_author = Account.system_user()
        else:
            modmail_author = author

        item, inbox_rel = Message._new(modmail_author, target, subject, msg,
                                       request.ip, sr=target)
        queries.new_message(item, inbox_rel)
示例#25
0
文件: things.py 项目: saisai/reddit
    def __init__(self, thing, delete = False, report = True):
        was_comment = getattr(thing, 'was_comment', False)
        permalink = thing.permalink
        # don't allow replying to self unless it's modmail
        valid_recipient = (thing.author_id != c.user._id or
                           thing.sr_id)
        is_muted = False
        can_mute = False
        if not was_comment:
            first_message = thing
            if getattr(thing, 'first_message', False):
                first_message = Message._byID(thing.first_message, data=True)

            if thing.sr_id:
                sr = thing.subreddit_slow
                if feature.is_enabled('modmail_muting', subreddit=sr.name):
                    if (sr.is_muted(first_message.author_slow) or
                            (first_message.to_id and
                                sr.is_muted(first_message.recipient_slow))):
                        is_muted = True

                    if (not sr.is_moderator(thing.author_slow) and
                            sr.is_moderator_with_perms(c.user, 'access', 'mail')):
                        can_mute = True

        can_reply = (c.user_is_loggedin and
                     getattr(thing, "repliable", True) and
                     valid_recipient and
                     not is_muted)
        can_block = True

        if not thing.was_comment and thing.display_author:
            can_block = False

        # Allow comment-reply messages to have links to the full thread.
        if was_comment:
            self.full_comment_path = thing.link_permalink
            self.full_comment_count = thing.full_comment_count

        PrintableButtons.__init__(self, "messagebuttons", thing,
                                  profilepage = c.profilepage,
                                  permalink = permalink,
                                  was_comment = was_comment,
                                  unread = thing.new,
                                  user_is_recipient = thing.user_is_recipient,
                                  can_reply = can_reply,
                                  parent_id = getattr(thing, "parent_id", None),
                                  show_report = True,
                                  show_delete = False,
                                  can_block = can_block,
                                  can_mute = can_mute,
                                 )
示例#26
0
def send_ban_message(subreddit, mod, user, note=None, days=None, new=True):
    sr_name = "/" + g.brander_community_abbr + "/" + subreddit.name
    if days:
        subject = "You've been temporarily banned from participating in %(subreddit)s"
        message = ("You have been temporarily banned from participating in "
                   "%(subreddit)s. This ban will last for %(duration)s days. ")
    else:
        subject = "You've been banned from participating in %(subreddit)s"
        message = "You have been banned from participating in %(subreddit)s. "

    message += ("You can still view and subscribe to %(subreddit)s, but you "
                "won't be able to post or comment.")

    if not new:
        subject = "Your ban from %(subreddit)s has changed"

    subject %= {"subreddit": sr_name}
    message %= {"subreddit": sr_name, "duration": days}

    if note:
        message += "\n\n" + 'Note from the moderators:'
        message += "\n\n" + blockquote_text(note)

    message += "\n\n" + (
        "If you have a question regarding your ban, you can "
        "contact the moderator team for %(subreddit)s by replying to this "
        "message.") % {
            "subreddit": sr_name
        }

    message += "\n\n" + (
        "**Reminder from the %(site_name)s staff**: If you use "
        "another account to circumvent this sub ban, that will be "
        "considered a violation of [the Content Policy](/s/SaidIt/comments/j1/the_saiditnet_terms_and_content_policy/) "
        "and can result in your account being suspended"
        "from the site as a whole.") % {
            "site_name": g.brander_site
        }

    item, inbox_rel = Message._new(mod,
                                   user,
                                   subject,
                                   message,
                                   request.ip,
                                   sr=subreddit,
                                   from_sr=True,
                                   can_send_email=False)
    queries.new_message(item, inbox_rel, update_modmail=False)
示例#27
0
def send_ban_message(subreddit, mod, user, note=None, days=None, new=True):
    sr_name = "/r/" + subreddit.name
    if days:
        subject = "You've been temporarily banned from participating in %(subreddit)s"
        message = ("You have been temporarily banned from participating in "
                   "%(subreddit)s. This ban will last for %(duration)s days. ")
    else:
        subject = "You've been banned from participating in %(subreddit)s"
        message = "You have been banned from participating in %(subreddit)s. "

    message += ("You can still view and subscribe to %(subreddit)s, but you "
                "won't be able to post or comment.")

    if not new:
        subject = "Your ban from %(subreddit)s has changed"

    subject %= {"subreddit": sr_name}
    message %= {"subreddit": sr_name, "duration": days}

    if note:
        message += "\n\n" + 'Note from the moderators:'
        message += "\n\n" + blockquote_text(note)

    message += "\n\n" + (
        "If you have a question regarding your ban, you can "
        "contact the moderator team for %(subreddit)s by replying to this "
        "message.") % {
            "subreddit": sr_name
        }

    message += "\n\n" + (
        "**Reminder from the Reddit staff**: If you use "
        "another account to circumvent this subreddit ban, that will be "
        "considered a violation of [the Content Policy](/help/contentpolicy#section_prohibited_behavior) "
        "and can result in your account being [suspended](https://reddit.zendesk.com/hc/en-us/articles/205687686) "
        "from the site as a whole.")

    item, inbox_rel = Message._new(mod,
                                   user,
                                   subject,
                                   message,
                                   request.ip,
                                   sr=subreddit,
                                   from_sr=True,
                                   can_send_email=False,
                                   is_auto_modmail=True)
    queries.new_message(item, inbox_rel, update_modmail=False)
示例#28
0
def send_system_message(user, subject, body, system_user=None, distinguished="admin", repliable=False):
    from r2.lib.db import queries

    if system_user is None:
        system_user = Account.system_user()
    if not system_user:
        g.log.warning("Can't send system message " "- invalid system_user or g.system_user setting")
        return

    item, inbox_rel = Message._new(system_user, user, subject, body, ip="0.0.0.0")
    item.distinguished = distinguished
    item.repliable = repliable
    item._commit()

    try:
        queries.new_message(item, inbox_rel)
    except MemcachedError:
        raise MessageError("reddit_inbox")
示例#29
0
def send_system_message(user, subject, body):
    from r2.lib.db import queries

    system_user = Account.system_user()
    if not system_user:
        g.log.warning("g.system_user isn't set properly. Can't send system message.")
        return

    item, inbox_rel = Message._new(system_user, user, subject, body,
                                   ip='0.0.0.0')
    item.distinguished = 'admin'
    item.repliable = False
    item._commit()

    try:
        queries.new_message(item, inbox_rel)
    except MemcachedError:
        raise MessageError('reddit_inbox')
示例#30
0
def send_mod_removal_message(subreddit, mod, user):
    sr_name = "/r/" + subreddit.name
    subject = "You've been removed as a moderator from %(subreddit)s"
    message = (
        "You have been removed as a moderator from %(subreddit)s.  "
        "If you have a question regarding your removal, you can "
        "contact the moderator team for %(subreddit)s by replying to this "
        "message."
    )
    subject %= {"subreddit": sr_name}
    message %= {"subreddit": sr_name}

    item, inbox_rel = Message._new(
        mod, user, subject, message, request.ip,
        sr=subreddit,
        from_sr=True,
        can_send_email=False,
    )
    queries.new_message(item, inbox_rel, update_modmail=True)
示例#31
0
def _add_message_nolock(key, message):
    from r2.models import Account, Message
    trees = g.permacache.get(key)
    if not trees:
        # in case an empty list got written at some point, delete it to
        # force a recompute
        if trees is not None:
            g.permacache.delete(key)
        # no point computing it now.  We'll do it when they go to
        # their message page.
        return

    # if it is a new root message, easy enough
    if message.first_message is None:
        trees.insert(0, (message._id, []))
    else:
        tree_dict = dict(trees)

        # if the tree already has the first message, update the list
        if message.first_message in tree_dict:
            if message._id not in tree_dict[message.first_message]:
                tree_dict[message.first_message].append(message._id)
                tree_dict[message.first_message].sort()
        # we have to regenerate the conversation :/
        else:
            m = Message._query(
                Message.c.first_message == message.first_message, data=True)
            new_tree = compute_message_trees(m)
            if new_tree:
                trees.append(new_tree[0])
        trees.sort(key=tree_sort_fn, reverse=True)

    # If we have too many messages in the tree, drop the oldest
    # conversation to avoid the permacache size limit
    tree_size = len(trees) + sum(len(convo[1]) for convo in trees)

    if tree_size > MESSAGE_TREE_SIZE_LIMIT:
        del trees[-1]

    # done!
    g.permacache.set(key, trees)
示例#32
0
def send_system_message(user, subject, body, system_user=None,
                        distinguished='admin', repliable=False):
    from r2.lib.db import queries

    if system_user is None:
        system_user = Account.system_user()
    if not system_user:
        g.log.warning("Can't send system message "
                      "- invalid system_user or g.system_user setting")
        return

    item, inbox_rel = Message._new(system_user, user, subject, body,
                                   ip='0.0.0.0')
    item.distinguished = distinguished
    item.repliable = repliable
    item._commit()

    try:
        queries.new_message(item, inbox_rel)
    except MemcachedError:
        raise MessageError('reddit_inbox')
示例#33
0
def send_mod_removal_message(subreddit, mod, user):
    sr_name = "/r/" + subreddit.name
    subject = "You've been removed as a moderator from %(subreddit)s"
    message = (
        "You have been removed as a moderator from %(subreddit)s.  "
        "If you have a question regarding your removal, you can "
        "contact the moderator team for %(subreddit)s by replying to this "
        "message.")
    subject %= {"subreddit": sr_name}
    message %= {"subreddit": sr_name}

    item, inbox_rel = Message._new(
        mod,
        user,
        subject,
        message,
        request.ip,
        sr=subreddit,
        from_sr=True,
        can_send_email=False,
    )
    queries.new_message(item, inbox_rel, update_modmail=True)
示例#34
0
def send_ban_message(subreddit, mod, user, note=None, days=None, new=True):
    sr_name = "/r/" + subreddit.name
    if days:
        subject = "You've been temporarily banned from participating in %(subreddit)s"
        message = ("You have been temporarily banned from participating in "
            "%(subreddit)s. This ban will last for %(duration)s days. ")
    else:
        subject = "You've been banned from participating in %(subreddit)s"
        message = "You have been banned from participating in %(subreddit)s. "

    message += ("You can still view and subscribe to %(subreddit)s, but you "
                "won't be able to post or comment.")

    if not new:
        subject = "Your ban from %(subreddit)s has changed"

    subject %= {"subreddit": sr_name}
    message %= {"subreddit": sr_name, "duration": days}

    if note:
        message += "\n\n" + 'Note from the moderators:'
        message += "\n\n" + blockquote_text(note)

    message += "\n\n" + ("If you have a question regarding your ban, you can "
        "contact the moderator team for %(subreddit)s by replying to this "
        "message.") % {"subreddit": sr_name}

    message += "\n\n" + ("**Reminder from the Reddit staff**: If you use "
        "another account to circumvent this subreddit ban, that will be "
        "considered a violation of [the Content Policy](/help/contentpolicy#section_prohibited_behavior) "
        "and can result in your account being [suspended](https://reddit.zendesk.com/hc/en-us/articles/205687686) "
        "from the site as a whole.")

    item, inbox_rel = Message._new(
        mod, user, subject, message, request.ip, sr=subreddit, from_sr=True,
        can_send_email=False, is_auto_modmail=True)
    queries.new_message(item, inbox_rel, update_modmail=False)
示例#35
0
def send_ban_message(subreddit, mod, user, note=None, days=None, new=True):
    sr_name = "/r/" + subreddit.name
    if days:
        subject = "you've been temporarily banned from %(subreddit)s"
        message = ("you have been temporarily banned from posting to "
                   "%(subreddit)s. this ban will last for %(duration)s days.")
    else:
        subject = "you've been banned from %(subreddit)s"
        message = "you have been banned from posting to %(subreddit)s."

    if not new:
        subject = "Your ban from %(subreddit)s has changed"

    subject %= {"subreddit": sr_name}
    message %= {"subreddit": sr_name, "duration": days}

    if note:
        message += "\n\n" + 'note from the moderators:'
        message += "\n\n" + blockquote_text(note)

    message += "\n\n" + (
        "you can contact the moderators regarding your ban "
        "by replying to this message. **warning**: using other accounts to "
        "circumvent a subreddit ban is considered a violation of reddit's "
        "[site rules](/rules) and can result in being banned from reddit "
        "entirely.")

    item, inbox_rel = Message._new(mod,
                                   user,
                                   subject,
                                   message,
                                   request.ip,
                                   sr=subreddit,
                                   from_sr=True,
                                   can_send_email=False)
    queries.new_message(item, inbox_rel, update_modmail=False)
示例#36
0
文件: builder.py 项目: Acceto/reddit
    def get_items(self):
        tree = self.get_tree()

        prev_item = next_item = None
        if not self.parent:
            if self.num is not None:
                if self.after:
                    if self.reverse:
                        tree = filter(
                            self._tree_filter_reverse,
                            tree)
                        next_item = self.after._id
                        if len(tree) > self.num:
                            first = tree[-(self.num+1)]
                            prev_item = first[1][-1] if first[1] else first[0]
                            tree = tree[-self.num:]
                    else:
                        prev_item = self.after._id
                        tree = filter(
                            self._tree_filter,
                            tree)
                if len(tree) > self.num:
                    tree = tree[:self.num]
                    last = tree[-1]
                    next_item = last[1][-1] if last[1] else last[0]

        # generate the set of ids to look up and look them up
        message_ids = []
        for root, thread in tree:
            message_ids.append(root)
            message_ids.extend(thread)
        if prev_item:
            message_ids.append(prev_item)

        messages = Message._byID(message_ids, data = True, return_dict = False)
        wrapped = {}
        for m in self.wrap_items(messages):
            if not self._viewable_message(m):
                g.log.warning("%r is not viewable by %s; path is %s" %
                                 (m, c.user.name, request.fullpath))
                continue
            wrapped[m._id] = m

        if prev_item:
            prev_item = wrapped[prev_item]
        if next_item:
            next_item = wrapped[next_item]

        final = []
        for parent, children in tree:
            if parent not in wrapped:
                continue
            parent = wrapped[parent]
            if children:
                # if no parent is specified, check if any of the messages are
                # uncollapsed, and truncate the thread
                children = [wrapped[child] for child in children
                                           if child in wrapped]
                parent.child = empty_listing()
                # if the parent is new, uncollapsed, or focal we don't
                # want it to become a moremessages wrapper.
                if (self.skip and 
                    not self.parent and not parent.new and parent.is_collapsed 
                    and not (self.focal and self.focal._id == parent._id)):
                    for i, child in enumerate(children):
                        if (child.new or not child.is_collapsed or
                            (self.focal and self.focal._id == child._id)):
                            break
                    else:
                        i = -1
                    parent = Wrapped(MoreMessages(parent, empty_listing()))
                    children = children[i:]

                parent.child.parent_name = parent._fullname
                parent.child.things = []

                for child in children:
                    child.is_child = True
                    if self.focal and child._id == self.focal._id:
                        # focal message is never collapsed
                        child.collapsed = False
                        child.focal = True
                    else:
                        child.collapsed = child.is_collapsed

                    parent.child.things.append(child)
            parent.is_parent = True
            # the parent might be the focal message on a permalink page
            if self.focal and parent._id == self.focal._id:
                parent.collapsed = False
                parent.focal = True
            else:
                parent.collapsed = parent.is_collapsed
            final.append(parent)

        return (final, prev_item, next_item, len(final), len(final))
示例#37
0
    def get_items(self):
        tree = self.get_tree()
        tree, prev_item, next_item = self._apply_pagination(tree)

        message_ids = []
        for parent_id, child_ids in tree:
            message_ids.append(parent_id)
            message_ids.extend(child_ids)

        if prev_item:
            message_ids.append(prev_item)

        messages = Message._byID(message_ids, data=True, return_dict=False)
        wrapped = {m._id: m for m in self.wrap_items(messages)}

        if prev_item:
            prev_item = wrapped[prev_item]
        if next_item:
            next_item = wrapped[next_item]

        final = []
        for parent_id, child_ids in tree:
            if parent_id not in wrapped:
                continue

            parent = wrapped[parent_id]

            if not self._viewable_message(parent):
                continue

            children = [wrapped[child_id] for child_id in child_ids if child_id in wrapped]

            depth = {parent_id: 0}
            substitute_parents = {}

            if (
                children
                and self.skip
                and not self.threaded
                and not self.parent
                and not parent.new
                and parent.is_collapsed
            ):
                for i, child in enumerate(children):
                    if child.new or not child.is_collapsed:
                        break
                else:
                    i = -1
                # in flat view replace collapsed chain with MoreMessages
                add_child_listing(parent)
                parent = Wrapped(MoreMessages(parent, parent.child))
                children = children[i:]

            for child in sorted(children, key=lambda child: child._id):
                # iterate from the root outwards so we can check the depth
                if self.threaded:
                    try:
                        child_parent = wrapped[child.parent_id]
                    except KeyError:
                        # the stored comment tree was missing this message's
                        # parent, treat it as a top level reply
                        child_parent = parent
                else:
                    # for flat view all messages are decendants of the
                    # parent message
                    child_parent = parent
                parent_depth = depth[child_parent._id]
                child_depth = parent_depth + 1
                depth[child._id] = child_depth

                if child_depth == MAX_RECURSION:
                    # current message is at maximum depth level, all its
                    # children will be displayed as children of its parent
                    substitute_parents[child._id] = child_parent._id

                if child_depth > MAX_RECURSION:
                    child_parent_id = substitute_parents[child.parent_id]
                    substitute_parents[child._id] = child_parent_id
                    child_parent = wrapped[child_parent_id]

                if not hasattr(child_parent, "child"):
                    add_child_listing(child_parent)
                child.is_child = True
                child_parent.child.things.append(child)

            for child in children:
                # look over the children again to decide whether they can be
                # collapsed
                child.threaded = self.threaded
                child.collapsed = self.should_collapse(child)

            if self.threaded and children:
                most_recent_child_id = max(child._id for child in children)
                most_recent_child = wrapped[most_recent_child_id]
                most_recent_child.most_recent = True

            parent.is_parent = True
            parent.threaded = self.threaded
            parent.collapsed = self.should_collapse(parent)
            final.append(parent)

        return (final, prev_item, next_item, len(final), len(final))
示例#38
0
    def POST_zendeskreply(self):
        request_body = request.POST
        recipient = request_body["recipient"]
        sender_email = request_body["sender"]
        from_ = request_body["from"]
        subject = request_body["subject"]
        body_plain = request_body["body-plain"]
        stripped_text = request_body["stripped-text"]
        stripped_signature = request_body["stripped-signature"]
        timestamp = request_body["timestamp"]
        token = request_body["token"]
        signature = request_body["signature"]
        email_id = request_body["Message-Id"]

        if not validate_mailgun_webhook(timestamp, token, signature):
            # per Mailgun docs send a 406 so the message won't be retried
            abort(406, "invalid signature")

        message_id36 = parse_and_validate_reply_to_address(recipient)

        if not message_id36:
            # per Mailgun docs send a 406 so the message won't be retried
            abort(406, "invalid message")

        parent = Message._byID36(message_id36, data=True)
        to = Account._byID(parent.author_id, data=True)
        sr = Subreddit._byID(parent.sr_id, data=True)
        body = self.get_snipped_body(stripped_text, stripped_signature)

        try:
            markdown_souptest(body)
        except SoupError:
            g.log.warning("bad markdown in modmail email: %s", body)
            abort(406, "invalid body")

        if parent.get_muted_user_in_conversation():
            queue_blocked_muted_email(sr, parent, sender_email, email_id)
            return

        # keep the subject consistent
        message_subject = parent.subject
        if not message_subject.startswith("re: "):
            message_subject = "re: " + message_subject

        # from_ is like '"NAME (GROUP)" <*****@*****.**>'
        match = re.search("\"(?P<name>\w+) [\w ()]*\"", from_)
        from_sr = True
        author = Account.system_user()

        if match and match.group("name") in g.live_config['modmail_account_map']:
            zendesk_name = match.group("name")
            moderator_name = g.live_config['modmail_account_map'][zendesk_name]
            moderator = Account._by_name(moderator_name)
            if sr.is_moderator_with_perms(moderator, "mail"):
                author = moderator
                from_sr = False

        message, inbox_rel = Message._new(
            author=author,
            to=to,
            subject=message_subject,
            body=body,
            ip='0.0.0.0',
            parent=parent,
            sr=sr,
            from_sr=from_sr,
            can_send_email=False,
            sent_via_email=True,
            email_id=email_id,
        )
        message._commit()
        queries.new_message(message, inbox_rel)
        g.stats.simple_event("mailgun.incoming.success")
        g.stats.simple_event("modmail_email.incoming_email")
示例#39
0
def get_sent(user):
    q = Message._query(Message.c.author_id == user._id,
                       Message.c._spam == (True, False),
                       sort=desc('_date'))
    return make_results(q)
示例#40
0
def get_sent(user_id):
    return Message._query(Message.c.author_id == user_id,
                          Message.c._spam == (True, False),
                          sort = desc('_date'))
示例#41
0
    def POST_conversations(self, entity, subject, body, is_author_hidden, to):
        """Creates a new conversation for a particular SR

        This endpoint will create a ModmailConversation object as
        well as the first ModmailMessage within the ModmailConversation
        object.

        POST Params:
        srName          -- the human readable name of the subreddit
        subject         -- the subject of the first message in the conversation
        body            -- the body of the first message in the conversation
        isAuthorHidden  -- boolean on whether the mod name should be hidden
                           (only mods can use this flag)
        to              -- name of the user that a mod wants to create a convo
                           with (only mods can use this flag)
        """
        self._feature_enabled_check(entity)

        # make sure the user is not muted when creating a new conversation
        if entity.is_muted(c.user) and not c.user_is_admin:
            return self.send_error(400, errors.USER_MUTED)

        # validate post params
        if (errors.USER_BLOCKED, to) in c.errors:
            return self.send_error(400, errors.USER_BLOCKED, fields='to')
        elif (errors.USER_DOESNT_EXIST, to) in c.errors:
            return self.send_error(404, errors.USER_DOESNT_EXIST, fields='to')

        if to and not isinstance(to, Account):
            return self.send_error(
                422,
                errors.NO_SR_TO_SR_MESSAGE,
                fields='to',
            )

        # only mods can set a 'to' parameter
        if (not entity.is_moderator_with_perms(c.user, 'mail') and to):
            return self.send_error(403, errors.MOD_REQUIRED, fields='to')

        if to and entity.is_muted(to):
            return self.send_error(
                400,
                errors.MUTED_FROM_SUBREDDIT,
                fields='to',
            )

        try:
            conversation = ModmailConversation(
                entity,
                c.user,
                subject,
                body,
                is_author_hidden=is_author_hidden,
                to=to,
            )
        except MustBeAModError:
            return self.send_error(403,
                                   errors.MOD_REQUIRED,
                                   fields='isAuthorHidden')
        except Exception as e:
            g.log.error('Failed to save conversation: {}'.format(e))
            return self.send_error(500, errors.CONVERSATION_NOT_SAVED)

        # Create copy of the message in the legacy messaging system as well
        if to:
            message, inbox_rel = Message._new(
                c.user,
                to,
                subject,
                body,
                request.ip,
                sr=entity,
                from_sr=is_author_hidden,
                create_modmail=False,
            )
        else:
            message, inbox_rel = Message._new(
                c.user,
                entity,
                subject,
                body,
                request.ip,
                create_modmail=False,
            )
        queries.new_message(message, inbox_rel)
        conversation.set_legacy_first_message_id(message._id)

        # Get author associated account object for serialization
        # of the newly created conversation object
        authors = self._try_get_byID(conversation.author_ids,
                                     Account,
                                     ignore_missing=True)

        response.status_code = 201
        serializable_convo = conversation.to_serializable(authors,
                                                          entity,
                                                          all_messages=True,
                                                          current_user=c.user)
        messages = serializable_convo.pop('messages')
        mod_actions = serializable_convo.pop('modActions')

        g.events.new_modmail_event(
            'ss.send_modmail_message',
            conversation,
            message=conversation.messages[0],
            msg_author=c.user,
            sr=entity,
            request=request,
            context=c,
        )

        return simplejson.dumps({
            'conversation': serializable_convo,
            'messages': messages,
            'modActions': mod_actions,
        })
示例#42
0
    def modmail_event(self, message, request=None, context=None):
        """Create a 'modmail' event for event-collector.

        message: An r2.models.Message object
        request: pylons.request of the request that created the message
        context: pylons.tmpl_context of the request that created the message

        """

        from r2.models import Account, Message

        sender = message.author_slow
        sr = message.subreddit_slow
        sender_is_moderator = sr.is_moderator_with_perms(sender, "mail")

        if message.first_message:
            first_message = Message._byID(message.first_message, data=True)
        else:
            first_message = message

        event = EventV2(
            topic="message_events",
            event_type="ss.send_message",
            time=message._date,
            request=request,
            context=context,
            data={
                # set these manually rather than allowing them to be set from
                # the request context because the loggedin user might not
                # be the message sender
                "user_id": sender._id,
                "user_name": sender.name,
            },
        )

        if sender == Account.system_user():
            sender_type = "automated"
        elif sender_is_moderator:
            sender_type = "moderator"
        else:
            sender_type = "user"

        event.add("sender_type", sender_type)
        event.add("sr_id", sr._id)
        event.add("sr_name", sr.name)
        event.add("message_id", message._id)
        event.add("message_fullname", message._fullname)
        event.add("first_message_id", first_message._id)
        event.add("first_message_fullname", first_message._fullname)

        if request and request.POST.get("source", None):
            source = request.POST["source"]
            if source in {"compose", "permalink", "modmail", "usermail"}:
                event.add("page", source)

        if message.sent_via_email:
            event.add("is_third_party", True)
            event.add("third_party_metadata", "mailgun")

        if not message.to_id:
            target = sr
        else:
            target = Account._byID(message.to_id, data=True)

        event.add_target_fields(target)

        self.save_event(event)
示例#43
0
    def __init__(self, thing, delete=False, report=True):
        was_comment = getattr(thing, 'was_comment', False)
        permalink = thing.permalink
        # don't allow replying to self unless it's modmail
        valid_recipient = (thing.author_id != c.user._id or thing.sr_id)

        can_reply = (c.user_is_loggedin and getattr(thing, "repliable", True)
                     and valid_recipient)
        can_block = True
        can_mute = False
        is_admin_message = False
        show_distinguish = c.user.employee and c.user._id == thing.author_id
        del_on_recipient = (isinstance(thing, Message)
                            and thing.del_on_recipient)

        if not was_comment:
            first_message = thing
            if getattr(thing, 'first_message', False):
                first_message = Message._byID(thing.first_message, data=True)

            if thing.sr_id:
                sr = thing.subreddit_slow
                is_admin_message = '/r/%s' % sr.name == g.admin_message_acct

                if (sr.is_muted(first_message.author_slow)
                        or (first_message.to_id
                            and sr.is_muted(first_message.recipient_slow))):
                    can_reply = False

                can_mute = sr.can_mute(c.user, thing.author_slow)

        if not was_comment and thing.display_author:
            can_block = False

        if was_comment:
            link = thing.link_slow
            if link.archived or link.locked:
                can_reply = False

        # Allow comment-reply messages to have links to the full thread.
        if was_comment:
            self.full_comment_path = thing.link_permalink
            self.full_comment_count = thing.full_comment_count

        PrintableButtons.__init__(
            self,
            "messagebuttons",
            thing,
            profilepage=c.profilepage,
            permalink=permalink,
            was_comment=was_comment,
            unread=thing.new,
            user_is_recipient=thing.user_is_recipient,
            can_reply=can_reply,
            parent_id=getattr(thing, "parent_id", None),
            show_report=True,
            show_delete=False,
            can_block=can_block,
            can_mute=can_mute,
            is_admin_message=is_admin_message,
            del_on_recipient=del_on_recipient,
            show_distinguish=show_distinguish,
            distinguished=thing.distinguished,
        )
示例#44
0
    def POST_mod_messages(self, conversation, msg_body, is_author_hidden,
                          is_internal):
        """Creates a new message for a particular ModmailConversation

        URL Params:
        conversation_id -- id of the conversation to post a new message to

        POST Params:
        body            -- this is the message body
        isAuthorHidden  -- boolean on whether to hide author, i.e. respond as
                           the subreddit
        isInternal      -- boolean to signify a moderator only message
        """
        self._validate_vmodconversation()

        sr = Subreddit._by_fullname(conversation.owner_fullname)
        self._feature_enabled_check(sr)

        # make sure the user is not muted before posting a message
        if sr.is_muted(c.user):
            return self.send_error(400, errors.USER_MUTED)

        if conversation.is_internal and not is_internal:
            is_internal = True

        is_mod = sr.is_moderator(c.user)
        if not is_mod and is_author_hidden:
            return self.send_error(
                403,
                errors.MOD_REQUIRED,
                fields='isAuthorHidden',
            )
        elif not is_mod and is_internal:
            return self.send_error(
                403,
                errors.MOD_REQUIRED,
                fields='isInternal',
            )

        try:
            if not conversation.is_internal and not conversation.is_auto:
                participant = conversation.get_participant_account()

                if participant and sr.is_muted(participant):
                    return self.send_error(
                        400,
                        errors.MUTED_FROM_SUBREDDIT,
                    )
        except NotFound:
            pass

        try:
            new_message = conversation.add_message(
                c.user,
                msg_body,
                is_author_hidden=is_author_hidden,
                is_internal=is_internal,
            )
        except:
            return self.send_error(500, errors.MODMAIL_MESSAGE_NOT_SAVED)

        # Add the message to the legacy messaging system as well (unless it's
        # an internal message on a non-internal conversation, since we have no
        # way to hide specific messages from the external participant)
        legacy_incompatible = is_internal and not conversation.is_internal
        if (conversation.legacy_first_message_id and not legacy_incompatible):
            first_message = Message._byID(conversation.legacy_first_message_id)
            subject = conversation.subject
            if not subject.startswith('re: '):
                subject = 're: ' + subject

            # Retrieve the participant to decide whether to send the message
            # to the sr or to the participant. If the currently logged in user
            # is the same as the participant then address the message to the
            # sr.
            recipient = sr
            if not is_internal:
                try:
                    participant = (
                        ModmailConversationParticipant.get_participant(
                            conversation.id))

                    is_participant = (
                        (c.user._id == participant.account_id)
                        and not sr.is_moderator_with_perms(c.user, 'mail'))

                    if not is_participant:
                        recipient = Account._byID(participant.account_id)
                except NotFound:
                    pass

            message, inbox_rel = Message._new(
                c.user,
                recipient,
                subject,
                msg_body,
                request.ip,
                parent=first_message,
                from_sr=is_author_hidden,
                create_modmail=False,
            )
            queries.new_message(message, inbox_rel)

        serializable_convo = conversation.to_serializable(
            entity=sr,
            all_messages=True,
            current_user=c.user,
        )
        messages = serializable_convo.pop('messages')

        g.events.new_modmail_event(
            'ss.send_modmail_message',
            conversation,
            message=new_message,
            msg_author=c.user,
            sr=sr,
            request=request,
            context=c,
        )

        response.status_code = 201
        return simplejson.dumps({
            'conversation': serializable_convo,
            'messages': messages,
        })
示例#45
0
    def message_event(self, message, request=None, context=None):
        """Create a 'message' event for event-collector.

        message: An r2.models.Message object
        request: pylons.request of the request that created the message
        context: pylons.tmpl_context of the request that created the message

        """

        from r2.models import Account, Message

        sender = message.author_slow

        if message.first_message:
            first_message = Message._byID(message.first_message, data=True)
        else:
            first_message = message

        event = Event(
            topic="message_events",
            event_type="ss.send_message",
            time=message._date,
            request=request,
            context=context,
            data={
                # set these manually rather than allowing them to be set from
                # the request context because the loggedin user might not
                # be the message sender
                "user_id": sender._id,
                "user_name": sender.name,
            },
        )

        if sender == Account.system_user():
            sender_type = "automated"
        else:
            sender_type = "user"

        event.add("sender_type", sender_type)
        event.add("message_kind", "message")
        event.add("message_id", message._id)
        event.add("message_fullname", message._fullname)

        event.add_text("message_body", message.body)
        event.add_text("message_subject", message.subject)

        event.add("first_message_id", first_message._id)
        event.add("first_message_fullname", first_message._fullname)

        if request and request.POST.get("source", None):
            source = request.POST["source"]
            if source in {"compose", "permalink", "usermail"}:
                event.add("page", source)

        if message.sent_via_email:
            event.add("is_third_party", True)
            event.add("third_party_metadata", "mailgun")

        target = Account._byID(message.to_id, data=True)

        event.add_target_fields(target)

        self.save_event(event)
示例#46
0
    def POST_zendeskreply(self):
        request_body = request.POST
        recipient = request_body["recipient"]
        sender_email = request_body["sender"]
        from_ = request_body["from"]
        subject = request_body["subject"]
        body_plain = request_body["body-plain"]
        stripped_text = request_body["stripped-text"]
        stripped_signature = request_body["stripped-signature"]
        timestamp = request_body["timestamp"]
        token = request_body["token"]
        signature = request_body["signature"]
        email_id = request_body["Message-Id"]

        if not validate_mailgun_webhook(timestamp, token, signature):
            # per Mailgun docs send a 406 so the message won't be retried
            abort(406, "invalid signature")

        message_id36 = parse_and_validate_reply_to_address(recipient)

        if not message_id36:
            # per Mailgun docs send a 406 so the message won't be retried
            abort(406, "invalid message")

        parent = Message._byID36(message_id36, data=True)
        to = Account._byID(parent.author_id, data=True)
        sr = Subreddit._byID(parent.sr_id, data=True)
        body = self.get_snipped_body(stripped_text, stripped_signature)

        try:
            markdown_souptest(body)
        except SoupError:
            g.log.warning("bad markdown in modmail email: %s", body)
            abort(406, "invalid body")

        if parent.get_muted_user_in_conversation():
            queue_blocked_muted_email(sr, parent, sender_email, email_id)
            return

        # keep the subject consistent
        message_subject = parent.subject
        if not message_subject.startswith("re: "):
            message_subject = "re: " + message_subject

        # from_ is like '"NAME (GROUP)" <*****@*****.**>'
        match = re.search("\"(?P<name>\w+) [\w ()]*\"", from_)
        from_sr = True
        author = Account.system_user()

        if match and match.group(
                "name") in g.live_config['modmail_account_map']:
            zendesk_name = match.group("name")
            moderator_name = g.live_config['modmail_account_map'][zendesk_name]
            moderator = Account._by_name(moderator_name)
            if sr.is_moderator_with_perms(moderator, "mail"):
                author = moderator
                from_sr = False

        message, inbox_rel = Message._new(
            author=author,
            to=to,
            subject=message_subject,
            body=body,
            ip='0.0.0.0',
            parent=parent,
            sr=sr,
            from_sr=from_sr,
            can_send_email=False,
            sent_via_email=True,
            email_id=email_id,
        )
        message._commit()
        queries.new_message(message, inbox_rel)
        g.stats.simple_event("mailgun.incoming.success")
        g.stats.simple_event("modmail_email.incoming_email")
示例#47
0
    return True

resume_id = long(sys.argv[1]) if len(sys.argv) > 1 else None

msg_accounts = Account._query(sort=desc("_date"), data=True)

if resume_id:
    msg_accounts._filter(Account.c._id < resume_id)

for account in progress(fetch_things2(msg_accounts), estimate=resume_id):
    current_inbox_count = account.inbox_count
    unread_messages = list(queries.get_unread_inbox(account))

    if account._id % 100000 == 0:
        g.reset_caches()

    if not len(unread_messages):
        if current_inbox_count:
            account._incr('inbox_count', -current_inbox_count)
    else:
        msgs = Message._by_fullname(
            unread_messages,
            data=True,
            return_dict=False,
            ignore_missing=True,
        )
        kept_msgs = sum(1 for msg in msgs if _keep(msg, account))

        if kept_msgs or current_inbox_count:
            account._incr('inbox_count', kept_msgs - current_inbox_count)
示例#48
0

resume_id = long(sys.argv[1]) if len(sys.argv) > 1 else None

msg_accounts = Account._query(sort=desc("_date"), data=True)

if resume_id:
    msg_accounts._filter(Account.c._id < resume_id)

for account in progress(fetch_things2(msg_accounts), estimate=resume_id):
    current_inbox_count = account.inbox_count
    unread_messages = list(queries.get_unread_inbox(account))

    if account._id % 100000 == 0:
        g.reset_caches()

    if not len(unread_messages):
        if current_inbox_count:
            account._incr('inbox_count', -current_inbox_count)
    else:
        msgs = Message._by_fullname(
            unread_messages,
            data=True,
            return_dict=False,
            ignore_missing=True,
        )
        kept_msgs = sum(1 for msg in msgs if _keep(msg, account))

        if kept_msgs or current_inbox_count:
            account._incr('inbox_count', kept_msgs - current_inbox_count)
示例#49
0
def notify_user_added(rel_type, author, user, target):
    msgs = user_added_messages.get(rel_type)
    if not msgs:
        return

    srname = target.path.rstrip("/")
    d = {
        "url": srname,
        "title": "%s: %s" % (srname, target.title),
        "author": "/u/" + author.name,
        "user": "******" + user.name,
    }

    if "pm" in msgs and author != user:
        subject = msgs["pm"]["subject"] % d
        msg = msgs["pm"]["msg"] % d

        if rel_type in ("moderator_invite", "contributor"):
            # send the message from the subreddit
            item, inbox_rel = Message._new(author,
                                           user,
                                           subject,
                                           msg,
                                           request.ip,
                                           sr=target,
                                           from_sr=True,
                                           can_send_email=False,
                                           is_auto_modmail=True)
        else:
            item, inbox_rel = Message._new(author,
                                           user,
                                           subject,
                                           msg,
                                           request.ip,
                                           can_send_email=False)

        queries.new_message(item, inbox_rel, update_modmail=False)

    if "modmail" in msgs:
        subject = msgs["modmail"]["subject"] % d
        msg = msgs["modmail"]["msg"] % d

        if rel_type == "moderator_invite":
            # Don't send the separate moderator invite message from the
            # system user to new modmail, since the one sent to the invitee
            # will already show up in there.
            # TODO: when new modmail is fully deployed, the "modmail" dict
            # should be completely removed from the moderator_invite section
            # of user_added_messages, and this check removed.
            if feature.is_enabled('new_modmail', subreddit=target.name):
                return

            modmail_author = Account.system_user()
        else:
            modmail_author = author

        item, inbox_rel = Message._new(modmail_author,
                                       target,
                                       subject,
                                       msg,
                                       request.ip,
                                       sr=target,
                                       is_auto_modmail=True)
        queries.new_message(item, inbox_rel)
示例#50
0
def get_sent(user_id):
    return Message._query(Message.c.author_id == user_id,
                          Message.c._spam == (True, False),
                          sort = desc('_date'))
示例#51
0
文件: queries.py 项目: rram/reddit
def get_sent(user):
    q = Message._query(Message.c.author_id == user._id,
                       Message.c._spam == (True, False),
                       sort = desc('_date'))
    return make_results(q)
示例#52
0
    def get_items(self):
        tree = self.get_tree()

        prev_item = next_item = None
        if not self.parent:
            if self.num is not None:
                if self.after:
                    if self.reverse:
                        tree = filter(self._tree_filter_reverse, tree)
                        next_item = self.after._id
                        if len(tree) > self.num:
                            first = tree[-(self.num + 1)]
                            prev_item = first[1][-1] if first[1] else first[0]
                            tree = tree[-self.num:]
                    else:
                        prev_item = self.after._id
                        tree = filter(self._tree_filter, tree)
                if len(tree) > self.num:
                    tree = tree[:self.num]
                    last = tree[-1]
                    next_item = last[1][-1] if last[1] else last[0]

        # generate the set of ids to look up and look them up
        message_ids = []
        for root, thread in tree:
            message_ids.append(root)
            message_ids.extend(thread)
        if prev_item:
            message_ids.append(prev_item)

        messages = Message._byID(message_ids, data=True, return_dict=False)
        wrapped = {m._id: m for m in self.wrap_items(messages)}

        if prev_item:
            prev_item = wrapped[prev_item]
        if next_item:
            next_item = wrapped[next_item]

        final = []
        for parent, children in tree:
            if parent not in wrapped:
                continue

            parent = wrapped[parent]

            if not self._viewable_message(parent):
                continue

            if children:
                # if no parent is specified, check if any of the messages are
                # uncollapsed, and truncate the thread
                children = [
                    wrapped[child] for child in children if child in wrapped
                ]
                add_child_listing(parent)
                # if the parent is new, uncollapsed, or focal we don't
                # want it to become a moremessages wrapper.
                if (self.skip and not self.parent and not parent.new
                        and parent.is_collapsed
                        and not (self.focal and self.focal._id == parent._id)):
                    for i, child in enumerate(children):
                        if (child.new or not child.is_collapsed or
                            (self.focal and self.focal._id == child._id)):
                            break
                    else:
                        i = -1
                    parent = Wrapped(MoreMessages(parent, parent.child))
                    children = children[i:]

                parent.child.parent_name = parent._fullname
                parent.child.things = []

                for child in children:
                    child.is_child = True
                    if self.focal and child._id == self.focal._id:
                        # focal message is never collapsed
                        child.collapsed = False
                        child.focal = True
                    else:
                        child.collapsed = child.is_collapsed

                    parent.child.things.append(child)
            parent.is_parent = True
            # the parent might be the focal message on a permalink page
            if self.focal and parent._id == self.focal._id:
                parent.collapsed = False
                parent.focal = True
            else:
                parent.collapsed = parent.is_collapsed
            final.append(parent)

        return (final, prev_item, next_item, len(final), len(final))