diff --git a/src/dotnet/csharp/WeatherApi.Tests/Controllers/WeatherForecastsControllerTests.cs b/src/dotnet/csharp/WeatherApi.Tests/Controllers/WeatherForecastsControllerTests.cs index d6c6de0..649ff0b 100644 --- a/src/dotnet/csharp/WeatherApi.Tests/Controllers/WeatherForecastsControllerTests.cs +++ b/src/dotnet/csharp/WeatherApi.Tests/Controllers/WeatherForecastsControllerTests.cs @@ -37,5 +37,69 @@ public async Task GetWeatherForecastNotFound() //Assert Assert.IsType(result.Result); } + + /// + /// Test when get weather by id is found + /// + [Fact()] + public async Task GetWeatherForecastFound() + { + //Setup + var service = new Mock(); + + var controller = new WeatherForecastsController(new NullLogger(), service.Object); + + WeatherForecast weather = new WeatherForecast { Id = 1, Date = DateTime.Now, TemperatureC = 20, Summary = "Test" }; + + service.Setup(x => x.GetWeatherForecastAsync(It.IsAny())).ReturnsAsync(weather); + + //Act + var result = await controller.GetWeatherForecast(1); + + //Assert + Assert.IsType(result.Value); + } + + /// + /// Test when adding a weather forecast is successful + /// + [Fact()] + public async Task AddWeatherForecastSuccess() + { + // Setup + var service = new Mock(); + var controller = new WeatherForecastsController(new NullLogger(), service.Object); + WeatherForecast newWeather = new WeatherForecast { Id = 2, Date = DateTime.Now, TemperatureC = 25, Summary = "Sunny" }; + + service.Setup(x => x.AddWeatherForecastAsync(It.IsAny())).ReturnsAsync(newWeather); + + // Act + var result = await controller.AddWeatherForecast(newWeather); + + // Assert + var actionResult = Assert.IsType(result); + var returnValue = Assert.IsType(actionResult.Value); + Assert.Equal(newWeather.Id, returnValue.Id); + } + + /// + /// Test when adding a weather forecast fails due to invalid input + /// + [Fact()] + public async Task AddWeatherForecastFailure() + { + // Setup + var service = new Mock(); + var controller = new WeatherForecastsController(new NullLogger(), service.Object); + WeatherForecast invalidWeather = null; // Simulating invalid input + + service.Setup(x => x.AddWeatherForecastAsync(It.IsAny())).ReturnsAsync(invalidWeather); + + // Act + var result = await controller.AddWeatherForecast(invalidWeather); + + // Assert + Assert.IsType(result); + } } } \ No newline at end of file diff --git a/src/dotnet/csharp/WeatherApi/Controllers/WeatherForecastsController.cs b/src/dotnet/csharp/WeatherApi/Controllers/WeatherForecastsController.cs index 3a75bc6..8d6d220 100644 --- a/src/dotnet/csharp/WeatherApi/Controllers/WeatherForecastsController.cs +++ b/src/dotnet/csharp/WeatherApi/Controllers/WeatherForecastsController.cs @@ -51,5 +51,33 @@ public async Task> GetWeatherForecast(int id) return weatherForecast; } + + /// + /// adds a new weather forecast. + /// + /// The weather forecast to add. + /// The added weather forecast. + /// Returns the newly created weather forecast. + [HttpPost] + [ProducesResponseType(StatusCodes.Status201Created)] + public async Task> AddWeatherForecast(WeatherForecast weatherForecast) + { + try + { + if (weatherForecast == null) + { + return BadRequest(); + } + + var addedWeatherForecast = await _weatherService.AddWeatherForecastAsync(weatherForecast); + + return CreatedAtAction(nameof(GetWeatherForecast), new { id = addedWeatherForecast.Id }, addedWeatherForecast); + } + catch (Exception ex) + { + _logger.LogError(ex, "An error occurred while adding a weather forecast."); + return StatusCode(StatusCodes.Status500InternalServerError, "An error occurred while adding a weather forecast."); + } + } } } diff --git a/src/dotnet/csharp/WeatherApi/Services/IWeatherService.cs b/src/dotnet/csharp/WeatherApi/Services/IWeatherService.cs index 62109c0..044872f 100644 --- a/src/dotnet/csharp/WeatherApi/Services/IWeatherService.cs +++ b/src/dotnet/csharp/WeatherApi/Services/IWeatherService.cs @@ -2,9 +2,29 @@ namespace WeatherApi.Services { + /// + /// Represents a service for retrieving weather forecasts. + /// public interface IWeatherService { + /// + /// Retrieves a collection of weather forecasts asynchronously. + /// + /// A task that represents the asynchronous operation. The task result contains the collection of weather forecasts. Task> GetWeatherForecastsAsync(); + + /// + /// Retrieves a weather forecast asynchronously based on the specified ID. + /// + /// The ID of the weather forecast to retrieve. + /// A task that represents the asynchronous operation. The task result contains the weather forecast. Task GetWeatherForecastAsync(int id); + + /// + /// Adds a new weather forecast asynchronously. + /// + /// The weather forecast to add. + /// A task that represents the asynchronous operation. The task result contains the added weather forecast. + Task AddWeatherForecastAsync(WeatherForecast weatherForecast); } } diff --git a/src/dotnet/csharp/WeatherApi/Services/UnsafeService.cs b/src/dotnet/csharp/WeatherApi/Services/UnsafeService.cs index c329d40..e1c09b2 100644 --- a/src/dotnet/csharp/WeatherApi/Services/UnsafeService.cs +++ b/src/dotnet/csharp/WeatherApi/Services/UnsafeService.cs @@ -1,15 +1,34 @@ using Microsoft.Data.SqlClient; using System.Data; +using System.IO; using System.Text; - namespace WeatherApi.Services { + /// + /// Represents a service that performs unsafe operations. + /// public class UnSafeService { + // Assuming "safeDirectory" is the directory you allow access to + private readonly string safeDirectory = "path/to/safe/directory"; + + /// + /// Reads a file from the safe directory. + /// + /// The user input representing the file name. + /// The content of the file as a string. + /// Thrown when access to the path is denied. public string ReadFile(string userInput) { - using (FileStream fs = File.Open(userInput, FileMode.Open)) + // Validate the userInput to prevent path traversal + var fullPath = Path.GetFullPath(Path.Combine(safeDirectory, userInput)); + if (!fullPath.StartsWith(safeDirectory)) + { + throw new UnauthorizedAccessException("Access to the path is denied."); + } + + using (FileStream fs = File.Open(fullPath, FileMode.Open)) { byte[] b = new byte[1024]; UTF8Encoding temp = new UTF8Encoding(true); @@ -23,18 +42,29 @@ public string ReadFile(string userInput) return null; } + /// + /// Gets the product ID for the specified product name. + /// + /// The name of the product. + /// The product ID as an integer. public int GetProduct(string productName) { using (SqlConnection connection = new SqlConnection("fakeconnectionstring")) { + // Use parameterized query to prevent SQL injection SqlCommand sqlCommand = new SqlCommand() { - CommandText = "SELECT ProductId FROM Products WHERE ProductName = '" + productName + "'", + CommandText = "SELECT ProductId FROM Products WHERE ProductName = @ProductName", CommandType = CommandType.Text, + Connection = connection }; + sqlCommand.Parameters.AddWithValue("@ProductName", productName); + + connection.Open(); + var result = sqlCommand.ExecuteScalar(); + connection.Close(); - SqlDataReader reader = sqlCommand.ExecuteReader(); - return reader.GetInt32(0); + return result != null ? Convert.ToInt32(result) : 0; } } } diff --git a/src/dotnet/csharp/WeatherApi/Services/WeatherService.cs b/src/dotnet/csharp/WeatherApi/Services/WeatherService.cs index 34bd539..b27bb15 100644 --- a/src/dotnet/csharp/WeatherApi/Services/WeatherService.cs +++ b/src/dotnet/csharp/WeatherApi/Services/WeatherService.cs @@ -15,6 +15,11 @@ public WeatherService(ILogger logger, WebApiContext context) _logger = logger; } + /// + /// Retrieves the weather forecast for a given ID asynchronously. + /// + /// The ID of the weather forecast to retrieve. + /// The weather forecast with the specified ID. public async Task GetWeatherForecastAsync(int id) { var weatherForecasts = await _context.GetMockDataAsync.ToListAsync(); @@ -23,11 +28,35 @@ public async Task GetWeatherForecastAsync(int id) return weatherForecast; } + /// + /// Retrieves the weather forecasts asynchronously. + /// + /// A task that represents the asynchronous operation. The task result contains the collection of weather forecasts. public async Task> GetWeatherForecastsAsync() { return await _context.GetMockDataAsync.ToListAsync(); } + /// + /// Adds a new weather forecast asynchronously. + /// + /// The weather forecast to add. + /// A task that represents the asynchronous operation. The task result contains the added weather forecast. + public async Task AddWeatherForecastAsync(WeatherForecast weatherForecast) + { + try + { + return await _context.AddWeatherForecastAsync(weatherForecast); + + } + catch (Exception ex) + { + _logger.LogError(ex, "An error occurred while adding the weather forecast."); + throw; // rethrow the exception to be handled by the caller + } + } + + } }