Skip to content
This repository was archived by the owner on May 14, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions FileReceiver.sln
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileReceiver.Tests.Bl", "te
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{165C050E-2183-4DB4-A63D-B362532F77F4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Integrations", "Integrations", "{C02CCF88-D61D-41B1-9E65-4DBC4580462D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileReceiver.Mega", "src\FileReceiver.Mega\FileReceiver.Mega.csproj", "{25D09645-AC3C-40E7-8729-979B0D38F57A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileReceiver.Tests.Fakers", "tests\FileReceiver.Tests.Fakers\FileReceiver.Tests.Fakers.csproj", "{E421D5E4-8760-4936-BFB3-3E313EB223D1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -40,6 +46,9 @@ Global
{92A3C8FD-79EE-4157-9035-C2110F8953DB} = {8D9067D7-7807-4616-9C5C-800B53EC5010}
{9AC28975-E12B-449D-B340-782EBAB3E858} = {8D9067D7-7807-4616-9C5C-800B53EC5010}
{97FA2C2F-34CE-46F3-A426-C5BF1E6A3C54} = {165C050E-2183-4DB4-A63D-B362532F77F4}
{C02CCF88-D61D-41B1-9E65-4DBC4580462D} = {9045B708-F21E-4EB8-ABB2-76EB6695F6A3}
{25D09645-AC3C-40E7-8729-979B0D38F57A} = {C02CCF88-D61D-41B1-9E65-4DBC4580462D}
{E421D5E4-8760-4936-BFB3-3E313EB223D1} = {165C050E-2183-4DB4-A63D-B362532F77F4}
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{70B0EF0C-D42D-4CF2-93E2-357FC9190A32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
Expand Down Expand Up @@ -74,5 +83,13 @@ Global
{97FA2C2F-34CE-46F3-A426-C5BF1E6A3C54}.Debug|Any CPU.Build.0 = Debug|Any CPU
{97FA2C2F-34CE-46F3-A426-C5BF1E6A3C54}.Release|Any CPU.ActiveCfg = Release|Any CPU
{97FA2C2F-34CE-46F3-A426-C5BF1E6A3C54}.Release|Any CPU.Build.0 = Release|Any CPU
{25D09645-AC3C-40E7-8729-979B0D38F57A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{25D09645-AC3C-40E7-8729-979B0D38F57A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{25D09645-AC3C-40E7-8729-979B0D38F57A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{25D09645-AC3C-40E7-8729-979B0D38F57A}.Release|Any CPU.Build.0 = Release|Any CPU
{E421D5E4-8760-4936-BFB3-3E313EB223D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E421D5E4-8760-4936-BFB3-3E313EB223D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E421D5E4-8760-4936-BFB3-3E313EB223D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E421D5E4-8760-4936-BFB3-3E313EB223D1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
61 changes: 61 additions & 0 deletions src/FileReceiver.Bl.Abstract/Services/IBotTransactionService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System.Threading.Tasks;

using FileReceiver.Common.Enums;
using FileReceiver.Common.Extensions;
using FileReceiver.Common.Models;

namespace FileReceiver.Bl.Abstract.Services
{
public interface IBotTransactionService
{
/// <summary>
/// Adds the given transaction to the database.
/// </summary>
/// <param name="transaction">Transaction's model which will be converted to entity.</param>
/// <returns><see cref="Task"/></returns>
Task<TransactionModel> Add(TransactionModel transaction);

/// <summary>
/// Creates a transaction with the specified type for user.
/// </summary>
/// <param name="userId">Transaction's owner</param>
/// <param name="transactionType"><see cref="TransactionType">Type</see> of the transaction which will be completed</param>
/// <returns><see cref="Task{TResult}"/></returns>
Task<TransactionModel> Create(long userId, TransactionType transactionType);

/// <summary>
/// Receives the last active transaction with a given type for user.
/// </summary>
/// <param name="userId">Transaction's owner</param>
/// <param name="transactionType"><see cref="TransactionType">Type</see> of the transaction which will be completed</param>
/// <exception cref="TransactionNotFoundException">Throws when transaction with this type is not exists for user or it's not active</exception>
/// <returns><see cref="Task{TransactionModel}"/></returns>
Task<TransactionModel> Get(long userId, TransactionType transactionType);

/// <summary>
/// Updates the last active transaction with a given type for user.
/// </summary>
/// <exception cref="TransactionNotFoundException">Throws when transaction with this type is not exists for user or it's not active</exception>
/// <returns><see cref="Task"/></returns>
Task Update(TransactionModel transaction);

/// <summary>
/// Updates the last active transaction's state with a given type for user.
/// </summary>
/// <param name="userId">Transaction's owner</param>
/// <param name="transactionType"><see cref="TransactionType">Type</see> of the transaction which will be completed</param>
/// <param name="transactionState"><see cref="TransactionState">State</see> of the transaction</param>
/// <exception cref="TransactionNotFoundException">Throws when transaction with this type is not exists for user or it's not active</exception>
/// <returns><see cref="Task"/></returns>
Task UpdateState(long userId, TransactionType transactionType, TransactionState transactionState);

/// <summary>
/// Completes the last active transaction by user's Id.
/// </summary>
/// <param name="userId">Transaction's owner</param>
/// <param name="transactionType"><see cref="TransactionType">Type</see> of the transaction which will be completed</param>
/// <returns><see cref="Task"/></returns>
Task Complete(long userId, TransactionType transactionType);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ public interface IFileReceivingService
{
Task UpdateFileReceivingState(long userId, FileReceivingState newState);
Task FinishReceivingTransaction(long userId);
Task<bool> SaveDocument(Document document);
Task<bool> SavePhoto(PhotoSize photoSize);
Task<bool> SaveDocument(long userId, Guid sessionId, Document document);
Task<FileReceivingState> GetFileReceivingStateForUser(long userId);
Task<bool> CheckIfSessionExists(Guid token);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace FileReceiver.Bl.Abstract.Services
{
public interface IFileReceivingSessionService
{
Task<Guid> GetId(long userId);
Task CreateFileReceivingSessionAsync(long userId);
Task SetFileSizeConstraintAsync(Guid sessionId, int bytes = 1_000_000);
Task SetFileNameConstraintAsync(Guid sessionId, string regexPatterns);
Expand All @@ -16,6 +17,5 @@ public interface IFileReceivingSessionService
Task<string> ExecuteSessionAsync(long userId);
Task StopSessionAsync(long userId);
Task<FileReceivingSessionState> GetSessionStateAsync(Guid sessionId);
Task<Guid?> GetFirstActiveFileReceivingSessionIdByUserIdAsync(long userId);
}
}
1 change: 1 addition & 0 deletions src/FileReceiver.Bl.Impl/FileReceiver.Bl.Impl.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<ProjectReference Include="..\dal\FileReceiver.Dal.Abstract\FileReceiver.Dal.Abstract.csproj" />
<ProjectReference Include="..\FileReceiver.Bl.Abstract\FileReceiver.Bl.Abstract.csproj" />
<ProjectReference Include="..\FileReceiver.Common\FileReceiver.Common.csproj" />
<ProjectReference Include="..\FileReceiver.Mega\FileReceiver.Mega.csproj" />
</ItemGroup>

</Project>
1 change: 1 addition & 0 deletions src/FileReceiver.Bl.Impl/FileReceiverBlInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ private static void AddServices(this IServiceCollection services)
services.AddTransient<IUserRegistrationService, UserRegistrationService>();
services.AddTransient<IFileReceivingSessionService, FileReceivingSessionService>();
services.AddTransient<IFileReceivingService, FileReceivingService>();
services.AddTransient<IBotTransactionService, BotTransactionService>();
}

private static void AddMapperConfiguration(this IServiceCollection services)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using FileReceiver.Common.Enums;
using FileReceiver.Common.Exceptions;
using FileReceiver.Common.Extensions;
using FileReceiver.Integrations.Mega.Abstract;

using Telegram.Bot;
using Telegram.Bot.Types;
Expand All @@ -19,67 +20,77 @@ public class FileReceivingSessionCreatingUpdateHandler : IUpdateHandler
private readonly IBotMessagesService _botMessagesService;
private readonly IFileReceivingSessionService _receivingSessionService;
private readonly ITelegramBotClient _botClient;
private readonly IMegaApiClient _megaClient;

public FileReceivingSessionCreatingUpdateHandler(
IBotMessagesService botMessagesService,
IFileReceivingSessionService receivingSessionService,
ITelegramBotClient botClient)
ITelegramBotClient botClient,
IMegaApiClient megaClient)
{
_botMessagesService = botMessagesService;
_receivingSessionService = receivingSessionService;
_botClient = botClient;
_megaClient = megaClient;
}

public async Task HandleUpdateAsync(Update update)
{
var userId = update.GetTgUserId();
var sessionId = await _receivingSessionService
.GetFirstActiveFileReceivingSessionIdByUserIdAsync(userId);
if (!sessionId.HasValue)

try
{
var sessionId = await _receivingSessionService.GetId(userId);
var sessionState = await _receivingSessionService.GetSessionStateAsync(sessionId);

var data = new FileReceivingSessionDataDto()
{
UserId = userId,
SessionId = sessionId,
Update = update,
};

// TODO: rewrite with pattern matching
switch (sessionState)
{
case FileReceivingSessionState.FileSizeConstraintSet:
await SetFileSizeConstraintAsync(data);
break;
case FileReceivingSessionState.FileNameConstraintSet:
await SetFileNameConstraintAsync(data);
break;
case FileReceivingSessionState.FileExtensionConstraintSet:
await SetFileExtensionsConstraintAsync(data);
break;
case FileReceivingSessionState.SessionMaxFilesConstraint:
await SetSessionMaxFilesConstraintAsync(data);
break;
case FileReceivingSessionState.SetFilesStorage:
await SetFileStorageAsync(data);
break;
case FileReceivingSessionState.ActiveSession:
await ExecuteFileReceivingSessionAsync(data.UserId);
break;
case FileReceivingSessionState.EndedSession:
await _botMessagesService.SendTextMessageAsync(data.UserId, "This session ended");
break;
default:
await _botMessagesService.SendErrorAsync(userId,
"Invalid action. Use command /cancel and then /start_receiving to recreate session");
break;
}
}
catch (FileReceivingSessionNotFound)
{
// TODO: log exception
await _botMessagesService.SendErrorAsync(userId, "All your sessions are configured and executed now. " +
"To check the list of active file receiving sessions " +
"use command /active_sessions");
return;
}

var sessionState = await _receivingSessionService.GetSessionStateAsync(sessionId.Value);

var data = new FileReceivingSessionDataDto()
{
UserId = userId,
SessionId = sessionId.Value,
Update = update,
};

// TODO: rewrite with pattern matching
switch (sessionState)
catch (Exception ex)
{
case FileReceivingSessionState.FileSizeConstraintSet:
await SetFileSizeConstraintAsync(data);
break;
case FileReceivingSessionState.FileNameConstraintSet:
await SetFileNameConstraintAsync(data);
break;
case FileReceivingSessionState.FileExtensionConstraintSet:
await SetFileExtensionsConstraintAsync(data);
break;
case FileReceivingSessionState.SessionMaxFilesConstraint:
await SetSessionMaxFilesConstraintAsync(data);
break;
case FileReceivingSessionState.SetFilesStorage:
await SetFileStorageAsync(data);
break;
case FileReceivingSessionState.ActiveSession:
await ExecuteFileReceivingSessionAsync(data.UserId);
break;
case FileReceivingSessionState.EndedSession:
await _botMessagesService.SendTextMessageAsync(data.UserId, "This session ended");
break;
default:
await _botMessagesService.SendErrorAsync(userId,
"Invalid action. Use command /cancel and then /start_receiving to recreate session");
break;
// TODO: log exception
await _botMessagesService.SendErrorAsync(userId, ex.Message);
}
}

Expand Down Expand Up @@ -218,11 +229,15 @@ private async Task ExecuteFileReceivingSessionAsync(long userId)
{
await _botMessagesService.SendTextMessageAsync(userId,
"Okay, this operation may take some time. I need to create all the required infrastructure");
await _botClient.SendChatActionAsync(userId, ChatAction.FindLocation);
await _botClient.SendChatActionAsync(userId, ChatAction.Typing);

var sessionId = await _receivingSessionService.ExecuteSessionAsync(userId);
await Task.Delay(7000);
// TODO: Remove delay
await _botMessagesService.SendTextMessageAsync(userId, $"Great. Your session id is: `{sessionId}`");

var clientResponse = await _megaClient.CreateFolder(Guid.Empty, sessionId);
await _botMessagesService.SendTextMessageAsync(userId,
$"Great. Your session id is: `{sessionId}` " +
"and your files are located at " +
$"{clientResponse.ActionDetails.NodeLink}");
}
catch (FileReceivingSessionActionErrorException ex)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Linq;
using System.Threading.Tasks;

using FileReceiver.Bl.Abstract.Handlers;
Expand All @@ -15,13 +14,15 @@ public class FileSendingUpdateHandler : IUpdateHandler
{
private readonly IFileReceivingService _fileReceivingService;
private readonly IBotMessagesService _botMessagesService;
private readonly IBotTransactionService _transactionService;

public FileSendingUpdateHandler(
IFileReceivingService fileReceivingService,
IBotMessagesService botMessagesService)
IBotMessagesService botMessagesService, IBotTransactionService transactionService)
{
_fileReceivingService = fileReceivingService;
_botMessagesService = botMessagesService;
_transactionService = transactionService;
}

public async Task HandleUpdateAsync(Update update)
Expand Down Expand Up @@ -60,12 +61,16 @@ private async Task HandleReceivedToken(FileSendingUpdateData data)
await _fileReceivingService.UpdateFileReceivingState(data.UserId, FileReceivingState.FileReceived);
}


private async Task HandleReceivedFile(FileSendingUpdateData data)
{
var transaction = await _transactionService.Get(data.UserId, TransactionType.FileSending);
if (data.Update.Message.Document is not null)
{
var isDocumentSaved = await _fileReceivingService.SaveDocument(data.Update.Message.Document);
var isDocumentSaved = await _fileReceivingService.SaveDocument(
data.UserId,
new Guid(transaction.TransactionData.GetDataPiece(
TransactionDataParameter.FileReceivingSessionId).ToString() ?? Guid.Empty.ToString()),
data.Update.Message.Document);

if (!isDocumentSaved)
{
Expand All @@ -77,15 +82,8 @@ await _botMessagesService.SendErrorAsync(data.UserId,

if (data.Update.Message.Photo is not null)
{
// Telegram always returns 4 photos. The last one is in original quality
var isPhotoSaved = await _fileReceivingService.SavePhoto(data.Update.Message.Photo.Last());

if (!isPhotoSaved)
{
await _botMessagesService.SendErrorAsync(data.UserId,
"An error occured while photo saving. Try again");
return;
}
await _botMessagesService.SendNotSupportedAsync(data.UserId, "Currently photos saving is not supported. " +
"You can save photo as a document");
}

await _botMessagesService.SendTextMessageAsync(data.UserId, "Your file saved");
Expand All @@ -103,13 +101,16 @@ private async Task<bool> ParseTokenAndCheckIfSessionExists(FileSendingUpdateData
return false;
}

if (!await _fileReceivingService.CheckIfSessionExists(token))
if (await _fileReceivingService.CheckIfSessionExists(token))
{
await _botMessagesService.SendErrorAsync(data.UserId, "Session with this token is not exists");
return false;
var transaction = await _transactionService.Get(data.UserId, TransactionType.FileSending);
transaction.TransactionData.AddDataPiece(TransactionDataParameter.FileReceivingSessionId, token);
await _transactionService.Update(transaction);
return true;
}

return true;
await _botMessagesService.SendErrorAsync(data.UserId, "Session with this token is not exists");
return false;
}

private class FileSendingUpdateData
Expand Down
Loading