public async Task Regression_OldMessagesExposeNewParent()
    {
        //Force the cache to invalidate every time
        config.DataCacheExpire = System.TimeSpan.Zero;

        //Write comments to public room
        const int COMMENTCOUNT  = 5;
        var       comments      = Enumerable.Range(0, COMMENTCOUNT).Select(x => GetNewCommentView(AllAccessContentId));
        var       writeComments = new List <MessageView>();

        foreach (var c in comments)
        {
            writeComments.Add(await writer.WriteAsync(c, NormalUserId));
        }

        //move comments to private room
        await shortcuts.RethreadMessagesAsync(writeComments.Select(x => x.id).ToList(), SuperAccessContentId, SuperUserId);

        //Now read by normal user. The resultset should not have the private room or messages
        var user = await searcher.GetById <UserView>(RequestType.user, NormalUserId);

        var events = await queue.ListenAsync(user, 0, safetySource.Token);

        Assert.True(events.lastId >= COMMENTCOUNT); //We should've done multiple things

        var allIds = writeComments.Select(x => x.id).ToList();

        allIds.Add(SuperAccessContentId);

        Assert.DoesNotContain(events.objects.SelectMany(x => x.Value.SelectMany(y => y.Value)), x =>
        {
            return(x.ContainsKey("id") && allIds.Contains((long)x["id"]));
        });
    }
    public async Task RethreadMissing(long content1, long content2, long write1, long write2, long rethreadUser, long rethreadPlace, bool allowed)
    {
        const int commentsCount = 5;

        var writtenMessages = new List <MessageView>();

        //Add a bunch of comments to the two contents (might be the same)
        for (var i = 0; i < commentsCount; i++)
        {
            var ncomment = GetNewCommentView(content1);
            writtenMessages.Add(await writer.WriteAsync(ncomment, write1));
            var scomment = GetNewCommentView(content2);
            writtenMessages.Add(await writer.WriteAsync(scomment, write2));
        }

        Assert.Equal(commentsCount * 2, writtenMessages.Count);

        var work = new Func <Task <List <MessageView> > >(() => service.RethreadMessagesAsync(writtenMessages.Select(x => x.id).ToList(), rethreadPlace, rethreadUser));

        //Now, try to rethread
        if (allowed)
        {
            var result = await work();

            Assert.All(result, x =>
            {
                AssertDateClose(x.editDate ?? throw new InvalidOperationException("NO EDIT DATE SET"));
                Assert.Equal(rethreadPlace, x.contentId);
                Assert.Contains(writtenMessages, y => y.id == x.id);
                Assert.Equal(rethreadUser, x.editUserId);
            });
        }
        else
        {
            //This could be permissions or it could be request or anything... this is kind of dangerous but whatever
            await Assert.ThrowsAnyAsync <Exception>(work);

            //Go search these messages
            var currentMessages = await search.SearchSingleTypeUnrestricted <MessageView>(new SearchRequest()
            {
                type   = "message",
                fields = "*",
                query  = "id in @ids"
            }, new Dictionary <string, object>()
            {
                { "ids", writtenMessages.Select(x => x.id) }
            });

            Assert.All(currentMessages, x =>
            {
                Assert.Null(x.editDate);
                Assert.NotEqual(rethreadPlace, x.contentId);
                Assert.NotEqual(rethreadUser, x.editUserId);
            });
        }
    }
    public Task <ActionResult <List <MessageView> > > RethreadAsync([FromBody] RethreadData rethread)
    {
        return(MatchExceptions(async() =>
        {
            RateLimit(RateWrite);
            var uid = GetUserIdStrict();

            if (rethread.contentId == 0)
            {
                throw new RequestException("Must set contentId!");
            }
            if (rethread.messageIds.Count == 0)
            {
                throw new RequestException("Must set at least one messageId!");
            }

            return await shortcuts.RethreadMessagesAsync(rethread.messageIds, rethread.contentId, uid, rethread.message);
        }));
    }