Exemplo n.º 1
0
def upgrade_messages(update_comments=True, update_messages=True, update_trees=True):
    from r2.lib.db import queries
    from r2.lib import comment_tree, cache
    from r2.models import Account
    from pylons import app_globals as g

    accounts = set()

    def batch_fn(items):
        g.reset_caches()
        return items

    if update_messages or update_trees:
        q = Message._query(Message.c.new == True, sort=desc("_date"), data=True)
        for m in fetch_things2(q, batch_fn=batch_fn):
            print m, m._date
            if update_messages:
                accounts = accounts | queries.set_unread(m, m.new)
            else:
                accounts.add(m.to_id)
    if update_comments:
        q = Comment._query(Comment.c.new == True, sort=desc("_date"))
        q._filter(Comment.c._id < 26152162676)

        for m in fetch_things2(q, batch_fn=batch_fn):
            print m, m._date
            queries.set_unread(m, True)

    print "Precomputing comment trees for %d accounts" % len(accounts)

    for i, a in enumerate(accounts):
        if not isinstance(a, Account):
            a = Account._byID(a)
        print i, a
        comment_tree.user_messages(a)
Exemplo n.º 2
0
def readd_mention_notification(mention):
    """Reinsert into inbox after a comment has been unspammed"""
    inbox_owner = mention._thing1
    thing = mention._thing2
    with query_cache.CachedQueryMutator() as m:
        m.insert(queries.get_inbox_comment_mentions(inbox_owner), [mention])
        unread = getattr(mention, 'unread_preremoval', True)
        queries.set_unread(thing, inbox_owner, unread=unread, mutator=m)
Exemplo n.º 3
0
def readd_mention_notification(mention):
    """Reinsert into inbox after a comment has been unspammed"""
    inbox_owner = mention._thing1
    thing = mention._thing2
    with query_cache.CachedQueryMutator() as m:
        m.insert(queries.get_inbox_comment_mentions(inbox_owner), [mention])
        unread = getattr(mention, "unread_preremoval", True)
        queries.set_unread(thing, inbox_owner, unread=unread, mutator=m)
Exemplo n.º 4
0
def notify_mention(user, thing):
    try:
        inbox_rel = Inbox._add(user, thing, "mention")
    except CreationError:
        # this mention was already inserted, ignore it
        g.log.error("duplicate mention for (%s, %s)", user, thing)
        return

    with query_cache.CachedQueryMutator() as m:
        m.insert(queries.get_inbox_comment_mentions(user), [inbox_rel])
        queries.set_unread(thing, user, unread=True, mutator=m)
Exemplo n.º 5
0
def notify_mention(user, thing):
    try:
        inbox_rel = Inbox._add(user, thing, "mention")
    except CreationError:
        # this mention was already inserted, ignore it
        g.log.error("duplicate mention for (%s, %s)", user, thing)
        return

    with query_cache.CachedQueryMutator() as m:
        m.insert(queries.get_inbox_comment_mentions(user), [inbox_rel])
        queries.set_unread(thing, user, unread=True, mutator=m)
Exemplo n.º 6
0
def upgrade_messages(update_comments=True,
                     update_messages=True,
                     update_trees=True):
    from r2.lib.db import queries
    from r2.lib import comment_tree, cache
    from r2.models import Account
    from pylons import app_globals as g
    accounts = set()

    def batch_fn(items):
        g.reset_caches()
        return items

    if update_messages or update_trees:
        q = Message._query(Message.c.new == True,
                           sort=desc("_date"),
                           data=True)
        for m in fetch_things2(q, batch_fn=batch_fn):
            print m, m._date
            if update_messages:
                accounts = accounts | queries.set_unread(m, m.new)
            else:
                accounts.add(m.to_id)
    if update_comments:
        q = Comment._query(Comment.c.new == True, sort=desc("_date"))
        q._filter(Comment.c._id < 26152162676)

        for m in fetch_things2(q, batch_fn=batch_fn):
            print m, m._date
            queries.set_unread(m, True)

    print "Precomputing comment trees for %d accounts" % len(accounts)

    for i, a in enumerate(accounts):
        if not isinstance(a, Account):
            a = Account._byID(a)
        print i, a
        comment_tree.user_messages(a)
Exemplo n.º 7
0
    def add_props(cls, user, wrapped):
        from r2.lib.db import queries
        #TODO global-ish functions that shouldn't be here?
        #reset msgtime after this request
        msgtime = c.have_messages

        # make sure there is a sr_id set:
        for w in wrapped:
            if not hasattr(w, "sr_id"):
                w.sr_id = None

        # load the to fields if one exists
        to_ids = set(w.to_id for w in wrapped if w.to_id is not None)
        tos = Account._byID(to_ids, True) if to_ids else {}

        # load the subreddit field if one exists:
        sr_ids = set(w.sr_id for w in wrapped if w.sr_id is not None)
        m_subreddits = Subreddit._byID(sr_ids, data=True, return_dict=True)

        # load the links and their subreddits (if comment-as-message)
        links = Link._byID(
            set(l.link_id for l in wrapped if l.was_comment),
            data=True,
            return_dict=True)
        # subreddits of the links (for comment-as-message)
        l_subreddits = Subreddit._byID(
            set(l.sr_id for l in links.values()), data=True, return_dict=True)

        parents = Comment._byID(
            set(l.parent_id for l in wrapped if l.parent_id and l.was_comment),
            data=True,
            return_dict=True)

        # load the unread list to determine message newness
        unread = set(queries.get_unread_inbox(user))

        msg_srs = set(
            m_subreddits[x.sr_id] for x in wrapped
            if x.sr_id is not None and isinstance(x.lookups[0], Message))
        # load the unread mod list for the same reason
        mod_unread = set(
            queries.merge_results(
                *[queries.get_unread_subreddit_messages(sr)
                  for sr in msg_srs]))

        for item in wrapped:
            item.to = tos.get(item.to_id)
            if item.sr_id:
                item.recipient = (item.author_id != c.user._id)
            else:
                item.recipient = (item.to_id == c.user._id)

            # new-ness is stored on the relation
            if item.author_id == c.user._id:
                item.new = False
            elif item._fullname in unread:
                item.new = True
                # wipe new messages if preferences say so, and this isn't a feed
                # and it is in the user's personal inbox
                if (item.new and c.user.pref_mark_messages_read
                        and c.extension not in ("rss", "xml", "api", "json")):
                    queries.set_unread(item.lookups[0], c.user, False)
            else:
                item.new = (item._fullname in mod_unread)

            item.score_fmt = Score.none

            item.message_style = ""
            # comment as message:
            if item.was_comment:
                link = links[item.link_id]
                sr = l_subreddits[link.sr_id]
                item.to_collapse = False
                item.author_collapse = False
                item.link_title = link.title
                item.permalink = item.lookups[0].make_permalink(link, sr=sr)
                item.link_permalink = link.make_permalink(sr)
                if item.parent_id:
                    item.subject = _('comment reply')
                    item.message_style = "comment-reply"
                    parent = parents[item.parent_id]
                    item.parent = parent._fullname
                    item.parent_permalink = parent.make_permalink(link, sr)
                else:
                    item.subject = _('post reply')
                    item.message_style = "post-reply"
            elif item.sr_id is not None:
                item.subreddit = m_subreddits[item.sr_id]

            if c.user.pref_no_profanity:
                item.subject = profanity_filter(item.subject)

            item.is_collapsed = None
            if not item.new:
                if item.recipient:
                    item.is_collapsed = item.to_collapse
                if item.author_id == c.user._id:
                    item.is_collapsed = item.author_collapse
                if c.user.pref_collapse_read_messages:
                    item.is_collapsed = (item.is_collapsed is not False)

        # Run this last
        Printable.add_props(user, wrapped)
Exemplo n.º 8
0
def remove_mention_notification(mention):
    inbox_owner = mention._thing1
    thing = mention._thing2
    with query_cache.CachedQueryMutator() as m:
        m.delete(queries.get_inbox_comment_mentions(inbox_owner), [mention])
        queries.set_unread(thing, inbox_owner, unread=False, mutator=m)
Exemplo n.º 9
0
def remove_mention_notification(mention):
    inbox_owner = mention._thing1
    thing = mention._thing2
    with query_cache.CachedQueryMutator() as m:
        m.delete(queries.get_inbox_comment_mentions(inbox_owner), [mention])
        queries.set_unread(thing, inbox_owner, unread=False, mutator=m)
Exemplo n.º 10
0
def notify_mention(user, thing):
    inbox_rel = Inbox._add(user, thing, "mention")
    with query_cache.CachedQueryMutator() as m:
        m.insert(queries.get_inbox_comment_mentions(user), [inbox_rel])
        queries.set_unread(thing, user, unread=True, mutator=m)
Exemplo n.º 11
0
def notify_mention(user, thing):
    inbox_rel = Inbox._add(user, thing, "mention")
    with query_cache.CachedQueryMutator() as m:
        m.insert(queries.get_inbox_comment_mentions(user), [inbox_rel])
        queries.set_unread(thing, user, unread=True, mutator=m)
Exemplo n.º 12
0
    def add_props(cls, user, wrapped):
        from r2.lib.db import queries
        #TODO global-ish functions that shouldn't be here?
        #reset msgtime after this request
        msgtime = c.have_messages

        # make sure there is a sr_id set:
        for w in wrapped:
            if not hasattr(w, "sr_id"):
                w.sr_id = None

        # load the to fields if one exists
        to_ids = set(w.to_id for w in wrapped if w.to_id is not None)
        tos = Account._byID(to_ids, True) if to_ids else {}

        # load the subreddit field if one exists:
        sr_ids = set(w.sr_id for w in wrapped if w.sr_id is not None)
        m_subreddits = Subreddit._byID(sr_ids, data = True, return_dict = True)

        # load the links and their subreddits (if comment-as-message)
        links = Link._byID(set(l.link_id for l in wrapped if l.was_comment),
                           data = True,
                           return_dict = True)
        # subreddits of the links (for comment-as-message)
        l_subreddits = Subreddit._byID(set(l.sr_id for l in links.values()),
                                       data = True, return_dict = True)

        parents = Comment._byID(set(l.parent_id for l in wrapped
                                  if l.parent_id and l.was_comment),
                                data = True, return_dict = True)

        # load the unread list to determine message newness
        unread = set(queries.get_unread_inbox(user))

        msg_srs = set(m_subreddits[x.sr_id]
                      for x in wrapped if x.sr_id is not None
                      and isinstance(x.lookups[0], Message))
        # load the unread mod list for the same reason
        mod_unread = set(queries.get_unread_subreddit_messages_multi(msg_srs))

        for item in wrapped:
            item.to = tos.get(item.to_id)
            if item.sr_id:
                item.recipient = (item.author_id != c.user._id)
            else:
                item.recipient = (item.to_id == c.user._id)
            
            # new-ness is stored on the relation
            if item.author_id == c.user._id:
                item.new = False
            elif item._fullname in unread:
                item.new = True
                # wipe new messages if preferences say so, and this isn't a feed
                # and it is in the user's personal inbox
                if (item.new and c.user.pref_mark_messages_read
                    and c.extension not in ("rss", "xml", "api", "json")):
                    queries.set_unread(item.lookups[0],
                                       c.user, False)
            else:
                item.new = (item._fullname in mod_unread and not item.to_id)

            item.score_fmt = Score.none

            item.message_style = ""
            # comment as message:
            if item.was_comment:
                link = links[item.link_id]
                sr = l_subreddits[link.sr_id]
                item.to_collapse = False
                item.author_collapse = False
                item.link_title = link.title
                item.permalink = item.lookups[0].make_permalink(link, sr=sr)
                item.link_permalink = link.make_permalink(sr)
                if item.parent_id:
                    item.subject = _('comment reply')
                    item.message_style = "comment-reply"
                    parent = parents[item.parent_id]
                    item.parent = parent._fullname
                    item.parent_permalink = parent.make_permalink(link, sr)
                else:
                    item.subject = _('post reply')
                    item.message_style = "post-reply"
            elif item.sr_id is not None:
                item.subreddit = m_subreddits[item.sr_id]
            
            item.hide_author = False
            if getattr(item, "from_sr", False):
                if not (item.subreddit.is_moderator(c.user) or
                        c.user_is_admin):
                    item.author = item.subreddit
                    item.hide_author = True
            
            item.is_collapsed = None
            if not item.new:
                if item.recipient:
                    item.is_collapsed = item.to_collapse
                if item.author_id == c.user._id:
                    item.is_collapsed = item.author_collapse
                if c.user.pref_collapse_read_messages:
                    item.is_collapsed = (item.is_collapsed is not False)
            if item.author_id in c.user.enemies and not item.was_comment:
                item.is_collapsed = True
                if not c.user_is_admin:
                    item.subject = _('[message from blocked user]')
                    item.body = _('[unblock user to see this message]')
            taglinetext = ''
            if item.hide_author:
                taglinetext = _("subreddit message %(author)s sent %(when)s ago")
            elif item.author_id == c.user._id:
                taglinetext = _("to %(dest)s sent %(when)s ago")
            elif item.to_id == c.user._id or item.to_id is None:
                taglinetext = _("from %(author)s sent %(when)s ago")
            else:
                taglinetext = _("to %(dest)s from %(author)s sent %(when)s ago")
            item.taglinetext = taglinetext
            item.dest = item.to.name if item.to else ""
            if item.sr_id:
                if item.hide_author:
                    item.updated_author = _("via %(subreddit)s")
                else:
                    item.updated_author = _("%(author)s via %(subreddit)s")
            else:
                item.updated_author = ''


        # Run this last
        Printable.add_props(user, wrapped)
Exemplo n.º 13
0
    def add_props(cls, user, wrapped):
        from r2.lib.db import queries

        # TODO global-ish functions that shouldn't be here?
        # reset msgtime after this request
        msgtime = c.have_messages

        # make sure there is a sr_id set:
        for w in wrapped:
            if not hasattr(w, "sr_id"):
                w.sr_id = None

        # load the to fields if one exists
        to_ids = set(w.to_id for w in wrapped if w.to_id is not None)
        tos = Account._byID(to_ids, True) if to_ids else {}

        # load the subreddit field if one exists:
        sr_ids = set(w.sr_id for w in wrapped if w.sr_id is not None)
        m_subreddits = Subreddit._byID(sr_ids, data=True, return_dict=True)

        # load the links and their subreddits (if comment-as-message)
        links = Link._byID(set(l.link_id for l in wrapped if l.was_comment), data=True, return_dict=True)
        # subreddits of the links (for comment-as-message)
        l_subreddits = Subreddit._byID(set(l.sr_id for l in links.values()), data=True, return_dict=True)

        parents = Comment._byID(
            set(l.parent_id for l in wrapped if l.parent_id and l.was_comment), data=True, return_dict=True
        )

        # load the inbox relations for the messages to determine new-ness
        # TODO: query cache?
        inbox = Inbox._fast_query(c.user, [item.lookups[0] for item in wrapped], ["inbox", "selfreply"])

        # we don't care about the username or the rel name
        inbox = dict((m._fullname, v) for (u, m, n), v in inbox.iteritems() if v)

        msgs = filter(lambda x: isinstance(x.lookups[0], Message), wrapped)

        modinbox = ModeratorInbox._fast_query(m_subreddits.values(), msgs, ["inbox"])

        # best to not have to eager_load the things
        def make_message_fullname(mid):
            return "t%s_%s" % (utils.to36(Message._type_id), utils.to36(mid))

        modinbox = dict((make_message_fullname(v._thing2_id), v) for (u, m, n), v in modinbox.iteritems() if v)

        for item in wrapped:
            item.to = tos.get(item.to_id)
            if item.sr_id:
                item.recipient = item.author_id != c.user._id
            else:
                item.recipient = item.to_id == c.user._id

            # new-ness is stored on the relation
            if item.author_id == c.user._id:
                item.new = False
            elif item._fullname in inbox:
                item.new = getattr(inbox[item._fullname], "new", False)
                # wipe new messages if preferences say so, and this isn't a feed
                # and it is in the user's personal inbox
                if item.new and c.user.pref_mark_messages_read and c.extension not in ("rss", "xml", "api", "json"):
                    queries.set_unread(inbox[item._fullname]._thing2, c.user, False)
            elif item._fullname in modinbox:
                item.new = getattr(modinbox[item._fullname], "new", False)
            else:
                item.new = False

            item.score_fmt = Score.none

            item.message_style = ""
            # comment as message:
            if item.was_comment:
                link = links[item.link_id]
                sr = l_subreddits[link.sr_id]
                item.to_collapse = False
                item.author_collapse = False
                item.link_title = link.title
                item.link_permalink = link.make_permalink(sr)
                if item.parent_id:
                    item.subject = _("comment reply")
                    item.message_style = "comment-reply"
                    parent = parents[item.parent_id]
                    item.parent = parent._fullname
                    item.parent_permalink = parent.make_permalink(link, sr)
                else:
                    item.subject = _("post reply")
                    item.message_style = "post-reply"
            elif item.sr_id is not None:
                item.subreddit = m_subreddits[item.sr_id]

            if c.user.pref_no_profanity:
                item.subject = profanity_filter(item.subject)

            item.is_collapsed = None
            if not item.new:
                if item.recipient:
                    item.is_collapsed = item.to_collapse
                if item.author_id == c.user._id:
                    item.is_collapsed = item.author_collapse
                if c.user.pref_collapse_read_messages:
                    item.is_collapsed = item.is_collapsed is not False

        # Run this last
        Printable.add_props(user, wrapped)
Exemplo n.º 14
0
    def add_props(cls, user, wrapped):
        from r2.lib.db import queries
        #TODO global-ish functions that shouldn't be here?
        #reset msgtime after this request
        msgtime = c.have_messages

        # make sure there is a sr_id set:
        for w in wrapped:
            if not hasattr(w, "sr_id"):
                w.sr_id = None

        # load the to fields if one exists
        to_ids = set(w.to_id for w in wrapped if w.to_id is not None)
        tos = Account._byID(to_ids, True) if to_ids else {}

        # load the subreddit field if one exists:
        sr_ids = set(w.sr_id for w in wrapped if w.sr_id is not None)
        m_subreddits = Subreddit._byID(sr_ids, data=True, return_dict=True)

        # load the links and their subreddits (if comment-as-message)
        links = Link._byID(set(l.link_id for l in wrapped if l.was_comment),
                           data=True,
                           return_dict=True)
        # subreddits of the links (for comment-as-message)
        l_subreddits = Subreddit._byID(set(l.sr_id for l in links.values()),
                                       data=True,
                                       return_dict=True)

        parents = Comment._byID(set(l.parent_id for l in wrapped
                                    if l.parent_id and l.was_comment),
                                data=True,
                                return_dict=True)

        # load the unread list to determine message newness
        unread = set(queries.get_unread_inbox(user))

        msg_srs = set(
            m_subreddits[x.sr_id] for x in wrapped
            if x.sr_id is not None and isinstance(x.lookups[0], Message))
        # load the unread mod list for the same reason
        mod_unread = set(
            queries.merge_results(
                *[queries.get_unread_subreddit_messages(sr)
                  for sr in msg_srs]))

        for item in wrapped:
            item.to = tos.get(item.to_id)
            if item.sr_id:
                item.recipient = (item.author_id != c.user._id)
            else:
                item.recipient = (item.to_id == c.user._id)

            # new-ness is stored on the relation
            if item.author_id == c.user._id:
                item.new = False
            elif item._fullname in unread:
                item.new = True
                # wipe new messages if preferences say so, and this isn't a feed
                # and it is in the user's personal inbox
                if (item.new and c.user.pref_mark_messages_read
                        and c.extension not in ("rss", "xml", "api", "json")):
                    queries.set_unread(item.lookups[0], c.user, False)
            else:
                item.new = (item._fullname in mod_unread)

            item.score_fmt = Score.none

            item.message_style = ""
            # comment as message:
            if item.was_comment:
                link = links[item.link_id]
                sr = l_subreddits[link.sr_id]
                item.to_collapse = False
                item.author_collapse = False
                item.link_title = link.title
                item.permalink = item.lookups[0].make_permalink(link, sr=sr)
                item.link_permalink = link.make_permalink(sr)
                if item.parent_id:
                    item.subject = _('comment reply')
                    item.message_style = "comment-reply"
                    parent = parents[item.parent_id]
                    item.parent = parent._fullname
                    item.parent_permalink = parent.make_permalink(link, sr)
                else:
                    item.subject = _('post reply')
                    item.message_style = "post-reply"
            elif item.sr_id is not None:
                item.subreddit = m_subreddits[item.sr_id]

            item.is_collapsed = None
            if not item.new:
                if item.recipient:
                    item.is_collapsed = item.to_collapse
                if item.author_id == c.user._id:
                    item.is_collapsed = item.author_collapse
                if c.user.pref_collapse_read_messages:
                    item.is_collapsed = (item.is_collapsed is not False)
            if item.author_id in c.user.enemies and not item.was_comment:
                item.is_collapsed = True
                if not c.user_is_admin:
                    item.subject = _('[message from blocked user]')
                    item.body = _('[unblock user to see this message]')

        # Run this last
        Printable.add_props(user, wrapped)
Exemplo n.º 15
0
    def add_props(cls, user, wrapped):
        from r2.lib.db import queries
        #TODO global-ish functions that shouldn't be here?
        #reset msgtime after this request
        msgtime = c.have_messages

        # make sure there is a sr_id set:
        for w in wrapped:
            if not hasattr(w, "sr_id"):
                w.sr_id = None

        # load the to fields if one exists
        to_ids = set(w.to_id for w in wrapped if w.to_id is not None)
        tos = Account._byID(to_ids, True) if to_ids else {}

        # load the subreddit field if one exists:
        sr_ids = set(w.sr_id for w in wrapped if w.sr_id is not None)
        m_subreddits = Subreddit._byID(sr_ids, data=True, return_dict=True)

        # load the links and their subreddits (if comment-as-message)
        links = Link._byID(set(l.link_id for l in wrapped if l.was_comment),
                           data=True,
                           return_dict=True)
        # subreddits of the links (for comment-as-message)
        l_subreddits = Subreddit._byID(set(l.sr_id for l in links.values()),
                                       data=True,
                                       return_dict=True)

        parents = Comment._byID(set(l.parent_id for l in wrapped
                                    if l.parent_id and l.was_comment),
                                data=True,
                                return_dict=True)

        # load the inbox relations for the messages to determine new-ness
        # TODO: query cache?
        inbox = Inbox._fast_query(c.user,
                                  [item.lookups[0] for item in wrapped],
                                  ['inbox', 'selfreply'])

        # we don't care about the username or the rel name
        inbox = dict(
            (m._fullname, v) for (u, m, n), v in inbox.iteritems() if v)

        msgs = filter(lambda x: isinstance(x.lookups[0], Message), wrapped)

        modinbox = ModeratorInbox._fast_query(m_subreddits.values(), msgs,
                                              ['inbox'])

        # best to not have to eager_load the things
        def make_message_fullname(mid):
            return "t%s_%s" % (utils.to36(Message._type_id), utils.to36(mid))

        modinbox = dict((make_message_fullname(v._thing2_id), v)
                        for (u, m, n), v in modinbox.iteritems() if v)

        for item in wrapped:
            item.to = tos.get(item.to_id)
            if item.sr_id:
                item.recipient = (item.author_id != c.user._id)
            else:
                item.recipient = (item.to_id == c.user._id)

            # new-ness is stored on the relation
            if item.author_id == c.user._id:
                item.new = False
            elif item._fullname in inbox:
                item.new = getattr(inbox[item._fullname], "new", False)
                # wipe new messages if preferences say so, and this isn't a feed
                # and it is in the user's personal inbox
                if (item.new and c.user.pref_mark_messages_read
                        and c.extension not in ("rss", "xml", "api", "json")):
                    queries.set_unread(inbox[item._fullname]._thing2, c.user,
                                       False)
            elif item._fullname in modinbox:
                item.new = getattr(modinbox[item._fullname], "new", False)
            else:
                item.new = False

            item.score_fmt = Score.none

            item.message_style = ""
            # comment as message:
            if item.was_comment:
                link = links[item.link_id]
                sr = l_subreddits[link.sr_id]
                item.to_collapse = False
                item.author_collapse = False
                item.link_title = link.title
                item.link_permalink = link.make_permalink(sr)
                if item.parent_id:
                    item.subject = _('comment reply')
                    item.message_style = "comment-reply"
                    parent = parents[item.parent_id]
                    item.parent = parent._fullname
                    item.parent_permalink = parent.make_permalink(link, sr)
                else:
                    item.subject = _('post reply')
                    item.message_style = "post-reply"
            elif item.sr_id is not None:
                item.subreddit = m_subreddits[item.sr_id]

            if c.user.pref_no_profanity:
                item.subject = profanity_filter(item.subject)

            item.is_collapsed = None
            if not item.new:
                if item.recipient:
                    item.is_collapsed = item.to_collapse
                if item.author_id == c.user._id:
                    item.is_collapsed = item.author_collapse
                if c.user.pref_collapse_read_messages:
                    item.is_collapsed = (item.is_collapsed is not False)

        # Run this last
        Printable.add_props(user, wrapped)