Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gerard Backend Task #607

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@
node_modules
bower_components
npm-debug.log
*.vsidx
/jobs/Backend/Task/.vs/ExchangeRates/v17/TestStore/0
19 changes: 0 additions & 19 deletions jobs/Backend/Task/ExchangeRateProvider.cs

This file was deleted.

8 changes: 0 additions & 8 deletions jobs/Backend/Task/ExchangeRateUpdater.csproj

This file was deleted.

22 changes: 0 additions & 22 deletions jobs/Backend/Task/ExchangeRateUpdater.sln

This file was deleted.

28 changes: 28 additions & 0 deletions jobs/Backend/Task/ExchangeRates.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExchangesRatesApp", "src\ExchangesRatesApp.csproj", "{0C2EC045-59FC-4AE7-B39E-C3FD037096A6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExchangeRatesTests", "test\ExchangeRatesTests.csproj", "{CE380A25-4484-41B4-BEC0-FC3292A46DF7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0C2EC045-59FC-4AE7-B39E-C3FD037096A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0C2EC045-59FC-4AE7-B39E-C3FD037096A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0C2EC045-59FC-4AE7-B39E-C3FD037096A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0C2EC045-59FC-4AE7-B39E-C3FD037096A6}.Release|Any CPU.Build.0 = Release|Any CPU
{CE380A25-4484-41B4-BEC0-FC3292A46DF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CE380A25-4484-41B4-BEC0-FC3292A46DF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CE380A25-4484-41B4-BEC0-FC3292A46DF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CE380A25-4484-41B4-BEC0-FC3292A46DF7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
43 changes: 0 additions & 43 deletions jobs/Backend/Task/Program.cs

This file was deleted.

24 changes: 24 additions & 0 deletions jobs/Backend/Task/src/ExchangesRatesApp.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>

<ItemGroup>
<None Update="local.settings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
18 changes: 18 additions & 0 deletions jobs/Backend/Task/src/Models/CnbRateDailyResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace ExchangeRateUpdater.Models
{
public class CnbRateDailyResponse
{
public IEnumerable<CnbRate> Rates { get; set; }
}

public class CnbRate
{
public string ValidFor { get; set; }
public int Order { get; set; }
public string Country { get; set; }
public string Currency { get; set; }
public int Amount { get; set; }
public string CurrencyCode { get; set; }
public decimal Rate { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace ExchangeRateUpdater
namespace ExchangeRateUpdater.Models
{
public class Currency
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace ExchangeRateUpdater
namespace ExchangeRateUpdater.Models
{
public class ExchangeRate
{
Expand Down
10 changes: 10 additions & 0 deletions jobs/Backend/Task/src/Options/CnbApiOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace ExchangeRateUpdater.Options
{
public class CnbApiOptions
{
public const string OptionsName = "CnbApi";
public const string ClientName = "CnbClient";

public string BaseAddress { get; set; }
}
}
9 changes: 9 additions & 0 deletions jobs/Backend/Task/src/Options/CurrenciesOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace ExchangeRateUpdater.Options
{
public class CurrenciesOptions
{
public const string OptionsName = "CurrenciesOptions";

public IEnumerable<string> Currencies { get; set; }
}
}
64 changes: 64 additions & 0 deletions jobs/Backend/Task/src/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using ExchangeRateUpdater.Models;
using ExchangeRateUpdater.Options;
using ExchangeRateUpdater.Services;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Http;

namespace ExchangeRateUpdater
{
public static class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();

var rates = host.Services.GetService<IExchangeRateProvider>().GetExchangeRates(System.Threading.CancellationToken.None).GetAwaiter().GetResult();

foreach (var rate in rates)
{
Console.WriteLine(rate.ToString());
}
}

private static IHostBuilder CreateHostBuilder(string[] args)
{
var _configuration = new ConfigurationBuilder()
.AddJsonFile("local.settings.json",
optional: true,
reloadOnChange: true)
.Build();

var hostBuilder = Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, builder) =>
{
builder.SetBasePath(Directory.GetCurrentDirectory());
})
.ConfigureServices((context, services) =>
{
// Remove httpClient default Console.WriteLine behaviour
services.RemoveAll<IHttpMessageHandlerBuilderFilter>();

// Options
services.Configure<CurrenciesOptions>(_configuration.GetSection(CurrenciesOptions.OptionsName));

var cnbApiOptions = new CnbApiOptions();
_configuration.GetSection(CnbApiOptions.OptionsName).Bind(cnbApiOptions);

// Services
services.AddSingleton<IExchangeRateProvider, ExchangeRateProvider>();
services.AddSingleton<ICnbApiService, CnbApiService>();

// CnbHttpClient
services.AddHttpClient(CnbApiOptions.ClientName, x =>
{
x.BaseAddress = new Uri(cnbApiOptions.BaseAddress);
});
});

return hostBuilder;
}
}
}
46 changes: 46 additions & 0 deletions jobs/Backend/Task/src/Services/CnbApiService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using ExchangeRateUpdater.Models;
using ExchangeRateUpdater.Options;
using Newtonsoft.Json;
using Microsoft.Extensions.Options;

namespace ExchangeRateUpdater.Services
{
public class CnbApiService : ICnbApiService
{
private readonly string GET_RATES_ENDPOINT = "/cnbapi/exrates/daily";

private readonly HttpClient _client;

public CnbApiService(IHttpClientFactory clientFactory)
{
_client = clientFactory.CreateClient(CnbApiOptions.ClientName);
}

public async Task<CnbRateDailyResponse> GetExchangeRate(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();

var httpRequest = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(GET_RATES_ENDPOINT, UriKind.Relative)
};

var httpResponse = await _client.SendAsync(httpRequest, cancellationToken);

if (!httpResponse.IsSuccessStatusCode)
{
return new CnbRateDailyResponse
{
Rates = new List<CnbRate>()
};
}

var response = await httpResponse.Content.ReadAsStringAsync(cancellationToken);

var cnbRates = JsonConvert.DeserializeObject<CnbRateDailyResponse>(response);

return cnbRates;
}
}
}
58 changes: 58 additions & 0 deletions jobs/Backend/Task/src/Services/ExchangeRateProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using ExchangeRateUpdater.Models;
using ExchangeRateUpdater.Options;
using Microsoft.Extensions.Options;

namespace ExchangeRateUpdater.Services
{
public class ExchangeRateProvider : IExchangeRateProvider
{
/// <summary>
/// Should return exchange rates among the specified currencies that are defined by the source. But only those defined
/// by the source, do not return calculated exchange rates. E.g. if the source contains "CZK/USD" but not "USD/CZK",
/// do not return exchange rate "USD/CZK" with value calculated as 1 / "CZK/USD". If the source does not provide
/// some of the currencies, ignore them.
/// </summary>

private readonly ICnbApiService _cnbApiService;
private readonly CurrenciesOptions _currenciesOptions;

public ExchangeRateProvider(
ICnbApiService cnbApiService,
IOptionsMonitor<CurrenciesOptions> currenciesOptions
)
{
_cnbApiService = cnbApiService;
_currenciesOptions = currenciesOptions.CurrentValue;
}

public async Task<IEnumerable<ExchangeRate>> GetExchangeRates(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();

// GET CNB RATES
var cnbRates = await _cnbApiService.GetExchangeRate(cancellationToken);

var result = new List<ExchangeRate>();

foreach (var currencyCode in _currenciesOptions.Currencies)
{
var currencyTarget = new Currency(currencyCode);

var rate = cnbRates.Rates.FirstOrDefault(x => x.CurrencyCode.Equals(currencyTarget.Code));

if (rate == null)
{
continue;
}

var value = rate.Rate / rate.Amount;

var exchangeRate = new ExchangeRate(new Currency("CZK"), currencyTarget, value);

result.Add(exchangeRate);
}

return result;
}
}
}
9 changes: 9 additions & 0 deletions jobs/Backend/Task/src/Services/ICnbApiService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using ExchangeRateUpdater.Models;

namespace ExchangeRateUpdater.Services
{
public interface ICnbApiService
{
Task<CnbRateDailyResponse> GetExchangeRate(CancellationToken cancellationToken);
}
}
Loading