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
19 changes: 19 additions & 0 deletions src/FileReceiver.Bl.Abstract/Services/IFileReceivingService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Threading.Tasks;

using FileReceiver.Common.Enums;

using Telegram.Bot.Types;

namespace FileReceiver.Bl.Abstract.Services
{
public interface IFileReceivingService
{
Task UpdateFileReceivingState(long userId, FileReceivingState newState);
Task FinishReceivingTransaction(long userId);
Task<bool> SaveDocument(Document document);
Task<bool> SavePhoto(PhotoSize photoSize);
Task<FileReceivingState> GetFileReceivingStateForUser(long userId);
Task<bool> CheckIfSessionExists(Guid token);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public ICommandHandler CreateCommandHandler(string command)
"/profile" => _serviceProvider.GetService<ProfileCommandHandler>(),
"/profile_edit" => _serviceProvider.GetService<ProfileEditCommandHandler>(),
"/start_receiving" => _serviceProvider.GetService<StartReceivingCommandHandler>(),
"/send_file" => _serviceProvider.GetService<SendFileCommandHandler>(),
{ } when command.StartsWith("/") => _serviceProvider.GetService<DefaultCommandHandler>(),
_ => null
};
Expand Down
1 change: 1 addition & 0 deletions src/FileReceiver.Bl.Impl/Factories/UpdateHandlerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public IUpdateHandler CreateUpdateHandler(TransactionType transactionType)
TransactionType.Registration => _serviceProvider.GetService<RegistrationUpdateHandler>(),
TransactionType.EditProfile => _serviceProvider.GetService<EditProfileUpdateHandler>(),
TransactionType.FileReceivingSessionCreating => _serviceProvider.GetService<FileReceivingSessionCreatingUpdateHandler>(),
TransactionType.FileSending => _serviceProvider.GetService<FileSendingUpdateHandler>(),
_ => _serviceProvider.GetService<DefaultUpdateHandler>(),
};
}
Expand Down
3 changes: 3 additions & 0 deletions src/FileReceiver.Bl.Impl/FileReceiverBlInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ private static void AddServices(this IServiceCollection services)
services.AddTransient<IBotMessagesService, BotMessagesService>();
services.AddTransient<IUserRegistrationService, UserRegistrationService>();
services.AddTransient<IFileReceivingSessionService, FileReceivingSessionService>();
services.AddTransient<IFileReceivingService, FileReceivingService>();
}

private static void AddMapperConfiguration(this IServiceCollection services)
Expand All @@ -56,6 +57,7 @@ private static void AddCommandHandlers(this IServiceCollection services)
services.AddTransient<ProfileCommandHandler, ProfileCommandHandler>();
services.AddTransient<ProfileEditCommandHandler, ProfileEditCommandHandler>();
services.AddTransient<StartReceivingCommandHandler, StartReceivingCommandHandler>();
services.AddTransient<SendFileCommandHandler, SendFileCommandHandler>();
}

private static void AddUpdateHandlers(this IServiceCollection services)
Expand All @@ -64,6 +66,7 @@ private static void AddUpdateHandlers(this IServiceCollection services)
services.AddTransient<DefaultUpdateHandler, DefaultUpdateHandler>();
services.AddTransient<EditProfileUpdateHandler, EditProfileUpdateHandler>();
services.AddTransient<FileReceivingSessionCreatingUpdateHandler, FileReceivingSessionCreatingUpdateHandler>();
services.AddTransient<FileSendingUpdateHandler, FileSendingUpdateHandler>();
}

private static void AddCallbackQueryHandlers(this IServiceCollection services)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System.Threading.Tasks;

using AutoMapper;

using FileReceiver.Bl.Abstract.Handlers;
using FileReceiver.Bl.Abstract.Services;
using FileReceiver.Common.Enums;
using FileReceiver.Common.Extensions;
using FileReceiver.Common.Models;
using FileReceiver.Dal.Abstract.Repositories;
using FileReceiver.Dal.Entities;

using Telegram.Bot.Types;

namespace FileReceiver.Bl.Impl.Handlers.Commands
{
public class SendFileCommandHandler : ICommandHandler
{
private readonly IBotMessagesService _botMessagesService;
private readonly IUserRepository _userRepository;
private readonly ITransactionRepository _transactionRepository;
private readonly IMapper _mapper;

public SendFileCommandHandler(
IBotMessagesService botMessagesService,
IUserRepository userRepository,
ITransactionRepository transactionRepository,
IMapper mapper)
{
_botMessagesService = botMessagesService;
_userRepository = userRepository;
_transactionRepository = transactionRepository;
_mapper = mapper;
}

public async Task HandleCommandAsync(Update update)
{
var userId = update.GetTgUserId();

if (!await _userRepository.CheckIfUserExistsAsync(userId))
{
await _botMessagesService.SendErrorAsync(userId,
"You should register before you can use this command, to do this you can use command /register");
return;
}

var transactionData = new TransactionDataModel();
transactionData.AddDataPiece(TransactionDataParameter.FileReceivingState,
FileReceivingState.TokenReceived);

var transaction = new TransactionModel()
{
UserId = userId,
TransactionType = TransactionType.FileSending,
TransactionState = TransactionState.Active,
TransactionData = transactionData,
};

await _transactionRepository.AddAsync(_mapper.Map<TransactionEntity>(transaction));
await _botMessagesService.SendTextMessageAsync(userId, "Okay, send me the session token");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
using System;
using System.Linq;
using System.Threading.Tasks;

using FileReceiver.Bl.Abstract.Handlers;
using FileReceiver.Bl.Abstract.Services;
using FileReceiver.Common.Enums;
using FileReceiver.Common.Extensions;

using Telegram.Bot.Types;

namespace FileReceiver.Bl.Impl.Handlers.TelegramUpdate
{
public class FileSendingUpdateHandler : IUpdateHandler
{
private readonly IFileReceivingService _fileReceivingService;
private readonly IBotMessagesService _botMessagesService;

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

public async Task HandleUpdateAsync(Update update)
{
var userId = update.GetTgUserId();

var data = new FileSendingUpdateData()
{
UserId = userId,
Update = update,
};

var fileReceivingState = await _fileReceivingService.GetFileReceivingStateForUser(userId);

switch (fileReceivingState)
{
case FileReceivingState.TokenReceived:
await HandleReceivedToken(data);
break;
case FileReceivingState.FileReceived:
await HandleReceivedFile(data);
break;
default:
throw new ArgumentOutOfRangeException();
}
}

private async Task HandleReceivedToken(FileSendingUpdateData data)
{
if (!await ParseTokenAndCheckIfSessionExists(data))
{
return;
}

await _botMessagesService.SendTextMessageAsync(data.UserId, "Okay and now send me the file please");
await _fileReceivingService.UpdateFileReceivingState(data.UserId, FileReceivingState.FileReceived);
}


private async Task HandleReceivedFile(FileSendingUpdateData data)
{
if (data.Update.Message.Document is not null)
{
var isDocumentSaved = await _fileReceivingService.SaveDocument(data.Update.Message.Document);

if (!isDocumentSaved)
{
await _botMessagesService.SendErrorAsync(data.UserId,
"An error occured while saving file. Try again");
return;
}
}

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.SendTextMessageAsync(data.UserId, "Your file saved");
await _fileReceivingService.UpdateFileReceivingState(data.UserId, FileReceivingState.Complete);
await _fileReceivingService.FinishReceivingTransaction(data.UserId);
}

private async Task<bool> ParseTokenAndCheckIfSessionExists(FileSendingUpdateData data)
{
bool isTokenParsed = Guid.TryParse(data.Update.Message.Text, out Guid token);

if (!isTokenParsed)
{
await _botMessagesService.SendErrorAsync(data.UserId, "Invalid token. Try another one");
return false;
}

if (!await _fileReceivingService.CheckIfSessionExists(token))
{
await _botMessagesService.SendErrorAsync(data.UserId, "Session with this token is not exists");
return false;
}

return true;
}

private class FileSendingUpdateData
{
public long UserId { get; set; }
public Update Update { get; set; }
}
}
}
115 changes: 115 additions & 0 deletions src/FileReceiver.Bl.Impl/Services/FileReceivingService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
using System;
using System.Threading.Tasks;

using AutoMapper;

using FileReceiver.Bl.Abstract.Services;
using FileReceiver.Common.Enums;
using FileReceiver.Common.Exceptions;
using FileReceiver.Common.Models;
using FileReceiver.Dal.Abstract.Repositories;
using FileReceiver.Dal.Entities.Enums;

using Telegram.Bot.Types;

namespace FileReceiver.Bl.Impl.Services
{
public class FileReceivingService : IFileReceivingService
{
private readonly IBotMessagesService _botMessagesService;
private readonly ITransactionRepository _transactionRepository;
private readonly IFileReceivingSessionRepository _fileReceivingSessionRepository;
private readonly IMapper _mapper;

public FileReceivingService(
IBotMessagesService botMessagesService,
ITransactionRepository transactionRepository,
IFileReceivingSessionRepository fileReceivingSessionRepository,
IMapper mapper)
{
_botMessagesService = botMessagesService;
_transactionRepository = transactionRepository;
_fileReceivingSessionRepository = fileReceivingSessionRepository;
_mapper = mapper;
}

public async Task UpdateFileReceivingState(long userId, FileReceivingState newState)
{
var transactionEntity = await _transactionRepository.GetLastActiveTransactionByUserId(userId);

if (transactionEntity.TransactionType is not TransactionTypeDb.FileSending)
{
throw new InvalidTransactionTypeException();
}

var transactionData = new TransactionDataModel(transactionEntity.TransactionData);
transactionData.UpdateParameter(TransactionDataParameter.FileReceivingState, newState);
transactionEntity.TransactionData = transactionData.ParametersAsJson;

await _transactionRepository.UpdateAsync(transactionEntity);
}

public async Task FinishReceivingTransaction(long userId)
{
var transactionEntity = await _transactionRepository.GetLastActiveTransactionByUserId(userId);
if (transactionEntity.TransactionType is not TransactionTypeDb.FileSending)
{
return;
}

transactionEntity.TransactionState = TransactionStateDb.Committed;
await _transactionRepository.UpdateAsync(transactionEntity);
}

public async Task<bool> SaveDocument(Document document)
{
// TODO: Add saving the document to the datasource
await Task.Delay(5000);
return true;
}

public async Task<bool> SavePhoto(PhotoSize photoSize)
{
// TODO: Add saving the photo to the datasource
await Task.Delay(5000);
return true;
}

public async Task<FileReceivingState> GetFileReceivingStateForUser(long userId)
{
try
{
var transaction = await GetTransactionAndNotifyIfItsTypeInvalid(userId);

return transaction.TransactionData.GetDataPiece<FileReceivingState>(
TransactionDataParameter.FileReceivingState);
}
catch (InvalidTransactionTypeException)
{
await _botMessagesService.SendErrorAsync(userId, "An error occured while processing you input. " +
"Try to use command /cancel and then start " +
"a file sending process again");
return await Task.FromResult(FileReceivingState.None);
}
}

public async Task<bool> CheckIfSessionExists(Guid token)
{
var session = await _fileReceivingSessionRepository.GetByIdAsync(token);
return session is not null;
}

// TODO: maybe create a separate service for actioning with transactions?
private async Task<TransactionModel> GetTransactionAndNotifyIfItsTypeInvalid(long userId)
{
var transaction = _mapper.Map<TransactionModel>(
await _transactionRepository.GetLastActiveTransactionByUserId(userId));
if (transaction.TransactionType is not TransactionType.FileSending)
{
throw new InvalidTransactionTypeException();
}

return transaction;
}
}
}
3 changes: 3 additions & 0 deletions src/FileReceiver.Bl.Impl/Services/UpdateHandlerService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ public async Task HandleUpdateAsync(Update update)
case { Message: { Text: { } } }:
await HandleMessageAsync(update);
break;
case { Message: { Document: { } } or { Photo: { } } }:
await HandleMessageAsync(update);
break;
case { CallbackQuery: { Message: { Text: { } } } cb }:
await HandleCallbackQuery(cb);
break;
Expand Down
11 changes: 11 additions & 0 deletions src/FileReceiver.Common/Enums/FileReceivingState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace FileReceiver.Common.Enums
{
public enum FileReceivingState
{
None,
CommandReceived,
TokenReceived,
FileReceived,
Complete,
}
}
1 change: 1 addition & 0 deletions src/FileReceiver.Common/Enums/TransactionDataParameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ public enum TransactionDataParameter
RegistrationState = 1,
ProfileEditingAction = 2,
FileReceivingSessionId = 3,
FileReceivingState = 4,
}
}
1 change: 1 addition & 0 deletions src/FileReceiver.Common/Enums/TransactionType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ public enum TransactionType
Registration = 1,
EditProfile = 2,
FileReceivingSessionCreating = 3,
FileSending = 4,
}
}
Loading