public async Task <List <ChannelDto> > CreateOrUpdateUserChannelsAsync(List <ChannelDto> channels)
        {
            using (MessengerDbContext context = contextFactory.Create())
            {
                var channelsCondition = PredicateBuilder.New <Channel>();
                channelsCondition = channels.Aggregate(channelsCondition,
                                                       (current, value) => current.Or(opt => opt.ChannelId == value.ChannelId).Expand());
                List <Channel> existingChannels = await context.Channels
                                                  .Include(opt => opt.ChannelUsers)
                                                  .Where(channelsCondition)
                                                  .ToListAsync()
                                                  .ConfigureAwait(false);

                for (int i = 0; i < existingChannels.Count; i++)
                {
                    ChannelDto editedChannel = channels.FirstOrDefault(opt => opt.ChannelId == existingChannels[i].ChannelId);
                    existingChannels[i] = ChannelConverter.GetChannel(existingChannels[i], editedChannel);
                    if (!editedChannel.ChannelUsers.IsNullOrEmpty())
                    {
                        existingChannels[i].ChannelUsers = ChannelConverter.GetChannelUsers(editedChannel.ChannelUsers).ToList();
                    }
                }
                context.UpdateRange(existingChannels);
                List <ChannelDto> nonExistingChannels = channels.Where(channelDto => !existingChannels.Any(channel => channelDto.ChannelId == channel.ChannelId))?.ToList();
                List <Channel>    newChannels         = ChannelConverter.GetChannels(nonExistingChannels);
                await context.AddRangeAsync(newChannels).ConfigureAwait(false);

                await context.SaveChangesAsync().ConfigureAwait(false);

                return(ChannelConverter.GetChannelsDto(newChannels.Concat(existingChannels)));
            }
        }
Beispiel #2
0
        private async Task MarkMessagesAsReadAsync()
        {
            var chats = await _context.Chats.Include(opt => opt.ChatUsers).ToListAsync();

            foreach (var chat in chats)
            {
                var firstMessage = await _context.Messages.OrderBy(opt => opt.SendingTime).FirstOrDefaultAsync(opt => opt.ChatId == chat.Id);

                var lastMessage = await _context.Messages.OrderByDescending(opt => opt.SendingTime).FirstOrDefaultAsync(opt => opt.ChatId == chat.Id);

                foreach (var chatUser in chat.ChatUsers)
                {
                    chatUser.LastReadedChatMessageId   = firstMessage.Id;
                    chatUser.LastReadedGlobalMessageId = firstMessage.GlobalId;
                }
                chat.LastMessageGlobalId = lastMessage.GlobalId;
                chat.LastMessageId       = lastMessage.Id;
            }
            _context.UpdateRange(chats);
            var channels = await _context.Channels.Include(opt => opt.ChannelUsers).ToListAsync();

            foreach (var channel in channels)
            {
                var firstMessage = await _context.Messages.OrderBy(opt => opt.SendingTime).FirstOrDefaultAsync(opt => opt.ChannelId == channel.ChannelId);

                var lastMessage = await _context.Messages.OrderByDescending(opt => opt.SendingTime).FirstOrDefaultAsync(opt => opt.ChannelId == channel.ChannelId);

                foreach (var channelUser in channel.ChannelUsers)
                {
                    channelUser.LastReadedGlobalMessageId = firstMessage.GlobalId;
                }
            }
            await _context.SaveChangesAsync();
        }
Beispiel #3
0
        public async Task <List <long> > DeleteFilesAsync(IEnumerable <string> filesId, long userId)
        {
            using (MessengerDbContext context = contextFactory.Create())
            {
                var filesCondition = PredicateBuilder.New <FileInfo>();
                filesCondition = filesId.Aggregate(filesCondition,
                                                   (current, value) => current.Or(file => file.Id == value).Expand());
                List <FileInfo> filesInfo = await context.FilesInfo
                                            .Where(filesCondition)
                                            .Where(file => file.UploaderId == userId && file.Deleted == false)
                                            .ToListAsync()
                                            .ConfigureAwait(false);

                if (filesInfo.Count < filesId.Count())
                {
                    throw new ObjectDoesNotExistsException();
                }

                filesInfo.ForEach(fileInfo => fileInfo.Deleted = true);
                context.UpdateRange(filesInfo);
                await context.SaveChangesAsync().ConfigureAwait(false);

                return(filesInfo.Select(file => file.NumericId).ToList());
            }
        }
Beispiel #4
0
        public async Task <MessageDto> EditMessageAsync(MessageDto message, long editorId)
        {
            using (MessengerDbContext context = contextFactory.Create())
            {
                var messageQuery = context.Messages
                                   .Include(opt => opt.Attachments)
                                   .Where(opt =>
                                          !opt.Deleted &&
                                          opt.SenderId == message.SenderId &&
                                          opt.ReceiverId == message.ReceiverId &&
                                          opt.GlobalId == message.GlobalId);
                switch (message.ConversationType)
                {
                case ConversationType.Dialog:
                {
                    messageQuery = messageQuery.Where(opt => opt.SenderId == editorId);
                }
                break;

                case ConversationType.Chat:
                {
                    messageQuery = messageQuery.Where(opt => opt.ChatId == message.ConversationId && opt.SenderId == editorId);
                }
                break;

                case ConversationType.Channel:
                {
                    messageQuery = messageQuery.Where(opt => opt.ChannelId == message.ConversationId)
                                   .Where(opt => opt.Channel.ChannelUsers
                                          .Any(channelUser => channelUser.UserId == editorId && channelUser.ChannelUserRole > ChannelUserRole.Subscriber));
                }
                break;
                }
                var editableMessages = await messageQuery.ToListAsync().ConfigureAwait(false);

                if (!editableMessages.Any())
                {
                    throw new ObjectDoesNotExistsException();
                }

                var editedMessages = new List <EditedMessage>();
                editedMessages = editableMessages.Select(opt => new EditedMessage(opt, editorId)).ToList();
                long updatedTime = DateTime.UtcNow.ToUnixTime();
                foreach (var edited in editableMessages)
                {
                    edited.Text      = message.Text;
                    edited.UpdatedAt = updatedTime;
                    if (message.Attachments != null)
                    {
                        edited.Attachments = AttachmentConverter.GetAttachments(message.Attachments, edited.Id);
                    }
                }
                context.UpdateRange(editableMessages);
                await context.AddRangeAsync(editedMessages).ConfigureAwait(false);

                await context.SaveChangesAsync().ConfigureAwait(false);

                return(MessageConverter.GetMessageDto(editableMessages.FirstOrDefault()));
            }
        }
Beispiel #5
0
        public async Task <List <MessageDto> > SetDialogMessagesReadAsync(IEnumerable <Guid> messagesId, long userId, long dialogId)
        {
            try
            {
                using (MessengerDbContext context = contextFactory.Create())
                {
                    var messagesCondition = PredicateBuilder.New <Message>();
                    messagesCondition = messagesId.Aggregate(messagesCondition,
                                                             (current, value) => current.Or(message => message.GlobalId == value).Expand());
                    IQueryable <long> dialogQuery = from dialog in context.Dialogs
                                                    join dialog2 in context.Dialogs on dialog.FirstUID equals dialog2.SecondUID
                                                    where (dialog.SecondUID == dialog2.FirstUID && dialog.Id == dialogId && dialog.FirstUID == userId)
                                                    select dialog2.Id;
                    long secondDialogId = await dialogQuery.FirstOrDefaultAsync().ConfigureAwait(false);

                    List <Message> messages = await context.Messages
                                              .Where(message => message.DialogId == dialogId || message.DialogId == secondDialogId)
                                              .Where(messagesCondition)
                                              .ToListAsync()
                                              .ConfigureAwait(false);

                    messages.ForEach(message => message.Read = true);
                    context.UpdateRange(messages);
                    await context.SaveChangesAsync().ConfigureAwait(false);

                    return(MessageConverter.GetMessagesDto(messages));
                }
            }
            catch (Exception ex)
            {
                throw new ReadMessageException("Unable to mark a message as read", ex);
            }
        }
Beispiel #6
0
        public async Task SetDeviceTokenIdNullAsync(string deviceTokenId)
        {
            using (MessengerDbContext context = contextFactory.Create())
            {
                var existingTokens =
                    await context.Tokens.Where(opt => opt.DeviceTokenId == deviceTokenId).ToListAsync().ConfigureAwait(false);

                existingTokens.ForEach(opt => opt.DeviceTokenId = null);
                context.UpdateRange(existingTokens);
                await context.SaveChangesAsync().ConfigureAwait(false);
            }
        }
        public async Task SetUsersConfirmedAsync(List <long> usersIds)
        {
            using (MessengerDbContext context = contextFactory.Create())
            {
                var usersCondition = PredicateBuilder.New <User>();
                usersCondition = usersIds.Aggregate(usersCondition,
                                                    (current, value) => current.Or(opt => opt.Id == value && !opt.Confirmed.Value).Expand());
                var users = await context.Users.Where(usersCondition).ToListAsync().ConfigureAwait(false);

                if (users.Count < usersIds.Count)
                {
                    throw new ObjectDoesNotExistsException();
                }

                users.ForEach(opt => opt.Confirmed = true);
                context.UpdateRange(users);
                await context.SaveChangesAsync().ConfigureAwait(false);
            }
        }
Beispiel #8
0
        public async Task <ChatVm> AddUsersToChatAsync(IEnumerable <long> usersId, long chatId, long userId)
        {
            using (MessengerDbContext context = contextFactory.Create())
            {
                using (var transaction = await context.Database.BeginTransactionAsync().ConfigureAwait(false))
                {
                    Chat chat = await context.Chats.FirstOrDefaultAsync(opt => opt.Id == chatId).ConfigureAwait(false);

                    if (chat == null)
                    {
                        throw new ConversationNotFoundException(chatId);
                    }
                    User requestingUser = await context.Users.FindAsync(userId).ConfigureAwait(false);

                    if (requestingUser == null || requestingUser.Deleted)
                    {
                        throw new AddUserChatException();
                    }
                    ChatUser chatUser = await context.ChatUsers
                                        .FirstOrDefaultAsync(opt => opt.ChatId == chatId && opt.UserId == userId).ConfigureAwait(false);

                    List <ChatUserVm> addedUsers = new List <ChatUserVm>();
                    if (chat.Deleted)
                    {
                        throw new ConversationIsNotValidException();
                    }
                    if (chatUser != null && chatUser.Banned)
                    {
                        throw new ChatUserBlockedException();
                    }
                    if (usersId.Count() == 1 && usersId.FirstOrDefault() == userId)
                    {
                        if (chat.Type == (int)ChatType.Private)
                        {
                            throw new AddUserChatException();
                        }
                        if (chatUser == null)
                        {
                            chatUser = ChatUserConverter.GetNewChatUser(chatId, userId, null);
                            await context.AddAsync(chatUser).ConfigureAwait(false);
                        }
                        else if (chatUser.Deleted)
                        {
                            chatUser.Deleted = false;
                            chatUser.User    = requestingUser;
                            context.Update(chatUser);
                        }
                        if (!chat.NodesId.Contains(NodeSettings.Configs.Node.Id))
                        {
                            createMessagesService.DownloadMessageHistoryAsync(chat.NodesId.FirstOrDefault(), chat.Id, ConversationType.Chat, null, false);
                        }
                        chat.NodesId = chat.NodesId.Append(requestingUser.NodeId.Value).Distinct().ToArray();
                        addedUsers.Add(ChatUserConverter.GetChatUserVm(chatUser));
                    }
                    else
                    {
                        if ((chatUser?.Deleted).GetValueOrDefault(true))
                        {
                            throw new AddUserChatException();
                        }

                        if (await loadUsersService.IsUserBlacklisted(userId, usersId).ConfigureAwait(false))
                        {
                            throw new UserBlockedException();
                        }

                        ExpressionStarter <User> usersCondition = PredicateBuilder.New <User>();
                        usersCondition = usersId.Aggregate(usersCondition,
                                                           (current, value) => current.Or(opt => opt.Id == value).Expand());
                        List <User> existingUsers = await context.Users
                                                    .AsNoTracking()
                                                    .Where(usersCondition)
                                                    .ToListAsync()
                                                    .ConfigureAwait(false);

                        ExpressionStarter <ChatUser> chatUsersCondition = PredicateBuilder.New <ChatUser>();
                        chatUsersCondition = existingUsers.Select(opt => opt.Id).Aggregate(chatUsersCondition,
                                                                                           (current, value) => current.Or(opt => opt.UserId == value && opt.ChatId == chatId).Expand());
                        List <ChatUser> validChatUsers = await context.ChatUsers
                                                         .Where(chatUsersCondition)
                                                         .Include(opt => opt.User)
                                                         .ToListAsync()
                                                         .ConfigureAwait(false);

                        foreach (ChatUser user in validChatUsers)
                        {
                            if (!user.Banned && user.Deleted)
                            {
                                user.Deleted = false;
                                addedUsers.Add(ChatUserConverter.GetChatUserVm(user));
                            }
                        }
                        context.UpdateRange(validChatUsers);
                        List <long>     newChatUsersId = existingUsers.Select(opt => opt.Id).Except(validChatUsers.Select(opt => opt.UserId)).ToList();
                        List <ChatUser> newChatUsers   = newChatUsersId.Select(id => ChatUserConverter.GetNewChatUser(chatId, id, userId)).ToList();
                        chat.NodesId = chat.NodesId?.Concat(existingUsers.Select(opt => opt.NodeId.GetValueOrDefault())).Distinct().ToArray()
                                       ?? existingUsers.Select(opt => opt.NodeId.GetValueOrDefault()).Distinct().ToArray();
                        await context.ChatUsers
                        .AddRangeAsync(newChatUsers)
                        .ConfigureAwait(false);

                        /* foreach (ChatUser user in newChatUsers)
                         * {
                         *   user.User = existingUsers.FirstOrDefault(opt => opt.Id == user.UserId);
                         * }*/
                        addedUsers.AddRange(ChatUserConverter.GetChatUsersVm(newChatUsers));
                    }
                    context.Update(chat);
                    transaction.Commit();
                    await context.SaveChangesAsync()
                    .ConfigureAwait(false);

                    ChatVm resultChat = ChatConverter.GetChatVm(chat);
                    resultChat.Users = addedUsers;
                    return(resultChat);
                }
            }
        }
        public async Task <List <ChannelUserVm> > AddUsersToChannelAsync(List <long> usersId, long channelId, long requestorId)
        {
            using (MessengerDbContext context = contextFactory.Create())
            {
                var usersCondition = PredicateBuilder.New <ChannelUser>();
                usersCondition = usersId.Aggregate(usersCondition,
                                                   (current, value) => current.Or(opt => opt.UserId == value).Expand());
                var requestorUser = await context.ChannelUsers
                                    .FirstOrDefaultAsync(opt =>
                                                         opt.ChannelUserRole >= ChannelUserRole.Administrator &&
                                                         opt.ChannelId == channelId &&
                                                         opt.UserId == requestorId &&
                                                         opt.Channel.Deleted == false)
                                    .ConfigureAwait(false);

                if (requestorUser == null && (usersId.Count() > 1 || (usersId.Count() == 1 && usersId.ElementAt(0) != requestorId)))
                {
                    throw new AddUserToChannelException();
                }

                List <ChannelUser> existingUsers = await context.ChannelUsers
                                                   .Where(usersCondition)
                                                   .Where(opt => opt.ChannelId == channelId)
                                                   .ToListAsync()
                                                   .ConfigureAwait(false);

                List <long> nonExistingUsersId;
                if (existingUsers?.Any() ?? false)
                {
                    nonExistingUsersId = usersId.Where(id => !existingUsers.Any(opt => opt.UserId == id)).ToList();
                }
                else
                {
                    nonExistingUsersId = usersId;
                }

                List <ChannelUser> newChannelUsers = nonExistingUsersId.Select(id => new ChannelUser
                {
                    ChannelId       = channelId,
                    ChannelUserRole = ChannelUserRole.Subscriber,
                    SubscribedTime  = DateTime.UtcNow.ToUnixTime(),
                    UserId          = id
                }).ToList();
                var users = await loadUsersService.GetUsersByIdAsync(nonExistingUsersId).ConfigureAwait(false);

                Channel channel = await context.Channels.FirstOrDefaultAsync(opt => opt.ChannelId == channelId).ConfigureAwait(false);

                channel.NodesId = channel.NodesId.Concat(users.Select(opt => opt.NodeId.GetValueOrDefault())).Distinct().ToArray();
                context.Update(channel);
                var updatedUsers = new List <ChannelUser>();
                if (existingUsers != null)
                {
                    existingUsers.ForEach(channelUser =>
                    {
                        if (!channelUser.Banned && channelUser.Deleted)
                        {
                            channelUser.Deleted = false;
                            updatedUsers.Add(channelUser);
                        }
                    });
                    context.UpdateRange(existingUsers);
                }
                await context.AddRangeAsync(newChannelUsers).ConfigureAwait(false);

                await context.SaveChangesAsync().ConfigureAwait(false);

                return(ChannelConverter.GetChannelUsers(newChannelUsers.Concat(updatedUsers)));
            }
        }
        private async Task <List <MessageDto> > DeleteChatMessagesInfoAsync(long chatId, IEnumerable <Guid> messagesIds, long userId)
        {
            try
            {
                using (MessengerDbContext context = contextFactory.Create())
                {
                    var messagesCondition = PredicateBuilder.New <Message>();
                    messagesCondition = messagesIds.Aggregate(messagesCondition,
                                                              (current, value) => current.Or(opt => opt.GlobalId == value && opt.ChatId == chatId && opt.Deleted == false));
                    var query = from conversation in context.Chats
                                join chatUser in context.ChatUsers on conversation.Id equals chatUser.ChatId
                                where chatUser.Banned == false &&
                                chatUser.Deleted == false &&
                                conversation.Deleted == false &&
                                chatUser.UserId == userId &&
                                conversation.Id == chatId
                                select new
                    {
                        Chat = conversation,
                        User = chatUser
                    };
                    var result = await query.FirstOrDefaultAsync().ConfigureAwait(false);

                    if (result == null || result.User == null)
                    {
                        return(new List <MessageDto>());
                    }

                    List <Message> messages = await context.Messages
                                              .Include(opt => opt.Attachments)
                                              .Where(messagesCondition)
                                              .ToListAsync()
                                              .ConfigureAwait(false);

                    if (!messages.Any())
                    {
                        return(new List <MessageDto>());
                    }
                    var deletedMessagesIds = messages.Select(message => message.GlobalId).ToList();
                    var usersCondition     = PredicateBuilder.New <ChatUser>();
                    usersCondition = deletedMessagesIds.Aggregate(usersCondition,
                                                                  (current, value) => current.Or(opt => opt.LastReadedGlobalMessageId == value).Expand());
                    var chatUsers = await context.ChatUsers.Where(usersCondition).ToListAsync().ConfigureAwait(false);

                    var groupedChatUsers = chatUsers.GroupBy(opt => opt.LastReadedGlobalMessageId);
                    foreach (var group in groupedChatUsers)
                    {
                        var message = await context.Messages
                                      .OrderByDescending(opt => opt.SendingTime)
                                      .ThenBy(opt => opt.GlobalId)
                                      .Where(opt => !deletedMessagesIds.Contains(opt.GlobalId) && opt.ChatId == chatId && !opt.Deleted)
                                      .FirstOrDefaultAsync()
                                      .ConfigureAwait(false);

                        foreach (var chatUser in group)
                        {
                            chatUser.LastReadedGlobalMessageId = message?.GlobalId;
                        }
                        context.ChatUsers.UpdateRange(group);
                    }
                    List <MessageDto> deletedMessages = MessageConverter.GetMessagesDto(messages);
                    foreach (var message in messages)
                    {
                        if (message.SenderId != result.User.UserId && result.User.UserRole == UserRole.User)
                        {
                            continue;
                        }

                        message.Deleted   = true;
                        message.UpdatedAt = DateTime.UtcNow.ToUnixTime();
                        if (NodeSettings.Configs.Node.PermanentlyDeleting)
                        {
                            message.Attachments = null;
                            message.Replyto     = null;
                            message.SendingTime = 0;
                            message.Text        = null;
                            message.SenderId    = null;
                        }
                    }
                    context.UpdateRange(messages);
                    await context.SaveChangesAsync().ConfigureAwait(false);

                    Message lastMessage = await _loadMessagesService.GetLastValidChatMessageAsync(chatId).ConfigureAwait(false);

                    result.Chat.LastMessageId       = lastMessage?.Id ?? null;
                    result.Chat.LastMessageGlobalId = lastMessage?.GlobalId;
                    context.Update(result.Chat);
                    await context.SaveChangesAsync().ConfigureAwait(false);

                    return(deletedMessages);
                }
            }
            catch (Exception ex)
            {
                throw new DeleteMessagesException("An error occurred while deleting messages.", ex);
            }
        }
        private async Task <List <MessageDto> > DeleteChannelMessagesInfoAsync(long channelId, IEnumerable <Guid> messagesIds, long userId)
        {
            try
            {
                using (MessengerDbContext context = contextFactory.Create())
                {
                    var messagesCondition = PredicateBuilder.New <Message>();
                    messagesCondition = messagesIds.Aggregate(messagesCondition,
                                                              (current, value) => current.Or(opt => opt.GlobalId == value).Expand());
                    var channelUser = await context.ChannelUsers
                                      .Include(opt => opt.Channel)
                                      .FirstOrDefaultAsync(opt =>
                                                           opt.ChannelId == channelId &&
                                                           opt.UserId == userId &&
                                                           opt.ChannelUserRole >= ChannelUserRole.Administrator)
                                      .ConfigureAwait(false);

                    if (channelUser == null)
                    {
                        throw new PermissionDeniedException();
                    }

                    var messages = await context.Messages
                                   .Include(opt => opt.Attachments)
                                   .Where(messagesCondition)
                                   .Where(opt => opt.ChannelId == channelId)
                                   .ToListAsync()
                                   .ConfigureAwait(false);

                    if (!messages.Any())
                    {
                        return(new List <MessageDto>());
                    }
                    var deletedMessagesIds = messages.Select(message => message.GlobalId).ToList();
                    var usersCondition     = PredicateBuilder.New <ChannelUser>();
                    usersCondition = deletedMessagesIds.Aggregate(usersCondition,
                                                                  (current, value) => current.Or(opt => opt.LastReadedGlobalMessageId == value).Expand());
                    var channelUsers = await context.ChannelUsers.Where(usersCondition).ToListAsync().ConfigureAwait(false);

                    var groupedChannelUsers = channelUsers.GroupBy(opt => opt.LastReadedGlobalMessageId);
                    foreach (var group in groupedChannelUsers)
                    {
                        var message = await context.Messages
                                      .OrderByDescending(opt => opt.SendingTime)
                                      .ThenBy(opt => opt.GlobalId)
                                      .Where(opt => !deletedMessagesIds.Contains(opt.GlobalId) && opt.ChannelId == channelId && !opt.Deleted)
                                      .FirstOrDefaultAsync()
                                      .ConfigureAwait(false);

                        foreach (var user in group)
                        {
                            user.LastReadedGlobalMessageId = message?.GlobalId;
                        }
                        context.ChannelUsers.UpdateRange(group);
                    }
                    var deletedMessages = MessageConverter.GetMessagesDto(messages);
                    messages.ForEach(message =>
                    {
                        message.Deleted   = true;
                        message.UpdatedAt = DateTime.UtcNow.ToUnixTime();
                        if (NodeSettings.Configs.Node.PermanentlyDeleting)
                        {
                            message.Attachments = null;
                            message.Replyto     = null;
                            message.SendingTime = 0;
                            message.Text        = null;
                            message.SenderId    = null;
                        }
                    });
                    context.UpdateRange(messages);
                    await context.SaveChangesAsync().ConfigureAwait(false);

                    Message lastValidMessage = await _loadMessagesService.GetLastValidChannelMessageAsync(channelId).ConfigureAwait(false);

                    channelUser.Channel.LastMessageId       = lastValidMessage?.Id ?? null;
                    channelUser.Channel.LastMessageGlobalId = lastValidMessage?.GlobalId;
                    context.Update(channelUser);
                    await context.SaveChangesAsync().ConfigureAwait(false);

                    return(deletedMessages);
                }
            }
            catch (Exception ex)
            {
                throw new DeleteMessagesException("An error ocurred while deleting the messages.", ex);
            }
        }
        private async Task <List <MessageDto> > DeleteDialogMessagesInfoAsync(long dialogId, IEnumerable <Guid> messagesIds, long userId)
        {
            try
            {
                using (MessengerDbContext context = contextFactory.Create())
                {
                    long mirrorDialogId = await _loadDialogsService.GetMirrorDialogIdAsync(dialogId).ConfigureAwait(false);

                    var messagesCondition = PredicateBuilder.New <Message>();
                    messagesCondition = messagesIds.Aggregate(messagesCondition,
                                                              (current, value) => current.Or(opt => opt.GlobalId == value &&
                                                                                             (opt.DialogId == dialogId || opt.DialogId == mirrorDialogId) &&
                                                                                             (opt.SenderId == userId || opt.ReceiverId == userId)).Expand());
                    List <MessageDto> deletedMessages;
                    List <Message>    messages = await context.Messages
                                                 .Include(opt => opt.Attachments)
                                                 .Where(messagesCondition)
                                                 .ToListAsync()
                                                 .ConfigureAwait(false);

                    if (!messages.Any())
                    {
                        return(new List <MessageDto>());
                    }
                    deletedMessages = MessageConverter.GetMessagesDto(messages);
                    Dialog firstDialog = await context.Dialogs.FirstOrDefaultAsync(opt => opt.Id == dialogId).ConfigureAwait(false);

                    Dialog mirrorDialog = await context.Dialogs.FirstOrDefaultAsync(opt => opt.Id == mirrorDialogId).ConfigureAwait(false);

                    foreach (var message in messages)
                    {
                        message.Deleted   = true;
                        message.UpdatedAt = DateTime.UtcNow.ToUnixTime();
                        if (NodeSettings.Configs.Node.PermanentlyDeleting)
                        {
                            message.Attachments = null;
                            message.Replyto     = null;
                            message.SendingTime = 0;
                            message.Text        = null;
                            message.SenderId    = null;
                            message.ReceiverId  = null;
                        }
                    }
                    context.UpdateRange(messages);
                    await context.SaveChangesAsync().ConfigureAwait(false);

                    Message lastMessageFirstDialog = await _loadMessagesService.GetLastValidDialogMessageAsync(dialogId).ConfigureAwait(false);

                    Message lastMessageSecondDialog = await _loadMessagesService.GetLastValidDialogMessageAsync(mirrorDialogId).ConfigureAwait(false);

                    firstDialog.LastMessageId        = lastMessageFirstDialog?.Id ?? null;
                    mirrorDialog.LastMessageId       = lastMessageSecondDialog?.Id ?? null;
                    firstDialog.LastMessageGlobalId  = lastMessageFirstDialog?.GlobalId;
                    mirrorDialog.LastMessageGlobalId = lastMessageSecondDialog?.GlobalId;
                    context.Dialogs.UpdateRange(firstDialog, mirrorDialog);
                    await context.SaveChangesAsync().ConfigureAwait(false);

                    return(deletedMessages);
                }
            }
            catch (Exception ex)
            {
                throw new DeleteMessagesException("An error occurred while deleting messages.", ex);
            }
        }