Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
ac1213c
Initial commit
comandir26 Sep 16, 2025
0f7b2c8
Add classes
comandir26 Sep 28, 2025
7fb6b3c
Fix classes, add comments
comandir26 Sep 30, 2025
a053bfd
Add test data
comandir26 Oct 1, 2025
a8a15a6
Add tests
comandir26 Oct 2, 2025
cad8d29
Fix tests and add comments
comandir26 Oct 2, 2025
fff2303
Add dotnet_tests.yml for automatic testing
comandir26 Oct 2, 2025
f136366
Fix dotnet_tests
comandir26 Oct 2, 2025
73ae2ec
Fix dotnet_tests again
comandir26 Oct 2, 2025
795031b
Move github directory
comandir26 Oct 2, 2025
2d3e343
Move github directory and change dotnet_tests file again x2
comandir26 Oct 2, 2025
1a4f80a
Small fixes
comandir26 Oct 2, 2025
2593bc0
Corrected all comments
comandir26 Oct 6, 2025
cc14fcb
Updated readme and comments
comandir26 Oct 6, 2025
ad639de
Marked methods as static where needed
comandir26 Oct 6, 2025
b994255
Add IRepository interface class for inmemory repo classes, also add B…
comandir26 Oct 28, 2025
c16fb27
Implement inmemory repo classess
comandir26 Nov 9, 2025
cdc9362
Add DTO classes, add interfaces for service classes and their impleme…
comandir26 Nov 9, 2025
77d5033
Add Bikes.Api.Host project and comments
comandir26 Nov 10, 2025
bfc2c0a
Update tests and fix comments
comandir26 Nov 10, 2025
8835b0d
Update readme
comandir26 Nov 11, 2025
213953a
add primary constructors, collection expressoins
comandir26 Dec 7, 2025
c89309d
Fix api
comandir26 Dec 10, 2025
8a078e8
Fix dto's and small fixes
comandir26 Dec 10, 2025
2c0d95b
Fix tests
comandir26 Dec 10, 2025
1fc2bec
Validation of DTOs and fix creating objects
comandir26 Dec 11, 2025
ecb7245
some validation checks
comandir26 Dec 11, 2025
52c0e27
Fix create methods
comandir26 Dec 11, 2025
442349f
Add new projects. Add DbContext and repositories.
comandir26 Dec 14, 2025
e9d1a44
Success build Infrastructure.MongoDb, update program.cs and extensions
comandir26 Dec 14, 2025
7ba2bc1
everything is working, but need to use Entity Framework Core(
comandir26 Dec 15, 2025
3ee4acf
Using EfCore
comandir26 Dec 16, 2025
8f92086
Update readme
comandir26 Dec 16, 2025
adf69fa
Small fixes
comandir26 Dec 17, 2025
c8f1079
Add Bikes.Generator project and add kafka in AppHost
comandir26 Dec 21, 2025
694af2a
Success build Bikes.Generator
comandir26 Dec 21, 2025
948b081
The generator and kafka are working correctly, the data is successful…
comandir26 Dec 24, 2025
a86c1bf
update readme and small fixes
comandir26 Dec 24, 2025
1d0c94c
Update readme2
comandir26 Dec 24, 2025
22ca967
Fixes and fixes
comandir26 Dec 26, 2025
d5d8213
Merge branch 'main' of https://github.com/comandir26/enterprise-devel…
comandir26 Dec 26, 2025
5f3a85e
smallest fix
comandir26 Dec 26, 2025
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
29 changes: 29 additions & 0 deletions .github/workflows/dotnet_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: .NET Tests

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]

jobs:
test:
runs-on: windows-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.x'

- name: Restore dependencies
run: dotnet restore Bikes/Bikes.sln

- name: Build
run: dotnet build --no-restore --configuration Release Bikes/Bikes.sln

- name: Run tests
run: dotnet test Bikes/Bikes.Tests/Bikes.Tests.csproj --no-build --configuration Release
22 changes: 22 additions & 0 deletions Bikes/Bikes.Api.Host/Bikes.Api.Host.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
<PackageReference Include="Confluent.Kafka" Version="2.5.3" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Bikes.Application\Bikes.Application.csproj" />
<ProjectReference Include="..\Bikes.Contracts\Bikes.Contracts.csproj" />
<ProjectReference Include="..\Bikes.Infrastructure.MongoDb\Bikes.Infrastructure.MongoDb.csproj" />
<ProjectReference Include="..\Bikes.ServiceDefaults\Bikes.ServiceDefaults.csproj" />
</ItemGroup>

</Project>
171 changes: 171 additions & 0 deletions Bikes/Bikes.Api.Host/Controllers/AnalyticsController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
using Bikes.Application.Interfaces;
using Bikes.Contracts.Dto;
using Bikes.Domain.Models;
using Microsoft.AspNetCore.Mvc;

namespace Bikes.Api.Host.Controllers;

/// <summary>
/// A class that implements a controller for processing HTTP requests for the AnalyticsService class
/// </summary>
/// <param name="service"></param>
/// <param name="logger"></param>
[ApiController]
[Route("api/[controller]")]
[Produces("application/json")]
public class AnalyticsController(
IAnalyticsService service,
ILogger<AnalyticsController> logger) : ControllerBase
{
/// <summary>
/// A method that returns information about all sports bikes
/// </summary>
[HttpGet("sport-bikes")]
[ProducesResponseType(typeof(List<BikeGetDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
public ActionResult<List<BikeGetDto>> GetSportBikes()
{
try
{
logger.LogInformation("Getting sport bikes");
var bikes = service.GetSportBikes();
logger.LogInformation("Retrieved {Count} sport bikes", bikes.Count);
return Ok(bikes);
}
catch (Exception ex)
{
logger.LogError(ex, "Error getting sport bikes");
return Problem(
title: "Internal Server Error",
detail: "An error occurred while retrieving sport bikes.",
statusCode: StatusCodes.Status500InternalServerError);
}
}

/// <summary>
/// A method that returns the top 5 bike models by rental duration
/// </summary>
[HttpGet("top-models/duration")]
[ProducesResponseType(typeof(List<BikeModelGetDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
public ActionResult<List<BikeModelGetDto>> GetTopModelsByDuration()
{
try
{
logger.LogInformation("Getting top models by rent duration");
var models = service.GetTopFiveModelsByRentDuration();
logger.LogInformation("Retrieved top {Count} models by duration", models.Count);
return Ok(models);
}
catch (Exception ex)
{
logger.LogError(ex, "Error getting top models by duration");
return Problem(
title: "Internal Server Error",
detail: "An error occurred while retrieving top models by duration.",
statusCode: StatusCodes.Status500InternalServerError);
}
}

/// <summary>
/// A method that returns the top 5 bike models in terms of rental income
/// </summary>
[HttpGet("top-models/profit")]
[ProducesResponseType(typeof(List<BikeModelGetDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
public ActionResult<List<BikeModelGetDto>> GetTopModelsByProfit()
{
try
{
logger.LogInformation("Getting top models by profit");
var models = service.GetTopFiveModelsByProfit();
logger.LogInformation("Retrieved top {Count} models by profit", models.Count);
return Ok(models);
}
catch (Exception ex)
{
logger.LogError(ex, "Error getting top models by profit");
return Problem(
title: "Internal Server Error",
detail: "An error occurred while retrieving top models by profit.",
statusCode: StatusCodes.Status500InternalServerError);
}
}

/// <summary>
/// A method that returns information about the minimum, maximum, and average bike rental time.
/// </summary>
[HttpGet("stats/duration")]
[ProducesResponseType(typeof(RentalDurationStatsDto), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
public ActionResult<RentalDurationStatsDto> GetRentalDurationStats()
{
try
{
logger.LogInformation("Getting rental duration statistics");
var stats = service.GetRentalDurationStats();
logger.LogInformation("Retrieved rental duration stats: Min={Min}, Max={Max}, Avg={Avg}",
stats.Min, stats.Max, stats.Average);

return Ok(stats);
}
catch (Exception ex)
{
logger.LogError(ex, "Error getting rental duration statistics");
return Problem(
title: "Internal Server Error",
detail: "An error occurred while retrieving rental duration statistics.",
statusCode: StatusCodes.Status500InternalServerError);
}
}

/// <summary>
/// A method that returns the total rental time of each type of bike
/// </summary>
[HttpGet("stats/rental-time-by-type")]
[ProducesResponseType(typeof(Dictionary<BikeType, int>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
public ActionResult<Dictionary<BikeType, int>> GetTotalRentalTimeByType()
{
try
{
logger.LogInformation("Getting total rental time by bike type");
var stats = service.GetTotalRentalTimeByType();
logger.LogInformation("Retrieved rental time by type for {Count} bike types", stats.Count);
return Ok(stats);
}
catch (Exception ex)
{
logger.LogError(ex, "Error getting total rental time by type");
return Problem(
title: "Internal Server Error",
detail: "An error occurred while retrieving total rental time by type.",
statusCode: StatusCodes.Status500InternalServerError);
}
}

/// <summary>
/// A method that returns information about the customers who have rented bicycles the most times.
/// </summary>
[HttpGet("top-renters")]
[ProducesResponseType(typeof(List<RenterGetDto>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
public ActionResult<List<RenterGetDto>> GetTopRenters()
{
try
{
logger.LogInformation("Getting top renters");
var renters = service.GetTopThreeRenters();
logger.LogInformation("Retrieved top {Count} renters", renters.Count);
return Ok(renters);
}
catch (Exception ex)
{
logger.LogError(ex, "Error getting top renters");
return Problem(
title: "Internal Server Error",
detail: "An error occurred while retrieving top renters.",
statusCode: StatusCodes.Status500InternalServerError);
}
}
}
Loading