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))); } }
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(); }
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()); } }
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())); } }
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); } }
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); } }
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); } }