commit
de458a8f35
@ -1,3 +1,16 @@
|
||||
# EF_WebAPI
|
||||
|
||||
This repository make a meeting of EF and WebAPI parts.
|
||||
This repository make a meeting of EF and WebAPI parts.
|
||||
|
||||
FROM /src dir
|
||||
|
||||
do
|
||||
|
||||
```bash
|
||||
dotnet ef migrations add --project StubbedContextLib/StubbedContextLib.csproj --startup-project HeartTrackAPI/HeartTrackAPI.csproj --context StubbedContextLib.TrainingStubbedContext --configuration Debug Initial --output-dir Migrations
|
||||
```
|
||||
then
|
||||
|
||||
```bash
|
||||
dotnet ef database update --project StubbedContextLib/StubbedContextLib.csproj --startup-project HeartTrackAPI/HeartTrackAPI.csproj --context StubbedContextLib.TrainingStubbedContext --configuration Debug
|
||||
```
|
||||
|
@ -0,0 +1,53 @@
|
||||
using Dto;
|
||||
using Model;
|
||||
using Shared;
|
||||
|
||||
namespace APIMappers;
|
||||
|
||||
public static class ActivityMapper
|
||||
{
|
||||
private static GenericMapper<Activity, ActivityDto> _mapper = new GenericMapper<Activity, ActivityDto>();
|
||||
|
||||
public static ActivityDto ToDto(this Activity activity)
|
||||
{
|
||||
return activity.ToU(_mapper, activityDto => new ActivityDto
|
||||
{
|
||||
Id = activity.Id,
|
||||
Type = activity.Type,
|
||||
Date = activity.Date,
|
||||
StartTime = activity.StartTime,
|
||||
EndTime = activity.EndTime,
|
||||
EffortFelt = activity.Effort,
|
||||
Variability = activity.Variability,
|
||||
Variance = activity.Variance,
|
||||
StandardDeviation = activity.StandardDeviation,
|
||||
Average = activity.Average,
|
||||
Maximum = activity.Maximum,
|
||||
Minimum = activity.Minimum,
|
||||
AverageTemperature = activity.AverageTemperature,
|
||||
HasAutoPause = activity.HasAutoPause
|
||||
});
|
||||
}
|
||||
|
||||
public static Activity ToModel(this ActivityDto activityDto)
|
||||
{
|
||||
return activityDto.ToT(_mapper, activity => new Activity
|
||||
{
|
||||
Id = activityDto.Id,
|
||||
Type = activityDto.Type,
|
||||
Date = activityDto.Date,
|
||||
StartTime = activityDto.StartTime,
|
||||
EndTime = activityDto.EndTime,
|
||||
Effort = activityDto.EffortFelt,
|
||||
Variability = activityDto.Variability,
|
||||
Variance = activityDto.Variance,
|
||||
StandardDeviation = activityDto.StandardDeviation,
|
||||
Average = activityDto.Average,
|
||||
Maximum = activityDto.Maximum,
|
||||
Minimum = activityDto.Minimum,
|
||||
AverageTemperature = activityDto.AverageTemperature,
|
||||
HasAutoPause = activityDto.HasAutoPause
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
using Entities;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace DbContextLib.Identity;
|
||||
|
||||
public class AuthDbContext: IdentityDbContext<IdentityUser>
|
||||
{
|
||||
|
||||
public AuthDbContext(DbContextOptions<AuthDbContext> options) : base(options) { }
|
||||
public AuthDbContext() { }
|
||||
/*
|
||||
/// <summary>
|
||||
/// Configures the database options if they are not already configured.
|
||||
/// </summary>
|
||||
/// <param name="optionsBuilder">The options builder instance.</param>
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
if (!optionsBuilder.IsConfigured)
|
||||
{
|
||||
optionsBuilder.UseSqlite($"Data Source=uca.HeartTrack.db");
|
||||
}
|
||||
}*/
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
namespace Dto;
|
||||
|
||||
public class ActivityFitFileDto
|
||||
{
|
||||
public ActivityFitFileDto(string activityName, string activityType, int effortFeel)
|
||||
{
|
||||
ActivityName = activityName;
|
||||
ActivityType = activityType;
|
||||
EffortFeel = effortFeel;
|
||||
}
|
||||
|
||||
public string ActivityName { get; set; }
|
||||
public string ActivityType { get; set; }
|
||||
public int EffortFeel { get; set; }
|
||||
//public IFormFile
|
||||
}
|
@ -0,0 +1,224 @@
|
||||
using System.Reflection;
|
||||
using DbContextLib;
|
||||
using DbContextLib.Identity;
|
||||
using Entities;
|
||||
using HeartTrackAPI.Utils;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||
using Microsoft.AspNetCore.Mvc.Versioning;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Model.Manager;
|
||||
using Model2Entities;
|
||||
using StubAPI;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
|
||||
namespace HeartTrackAPI;
|
||||
|
||||
public class AppBootstrap(IConfiguration configuration)
|
||||
{
|
||||
private IConfiguration Configuration { get; } = configuration;
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddControllers();
|
||||
services.AddEndpointsApiExplorer();
|
||||
AddSwagger(services);
|
||||
// include Xml comment
|
||||
// addsecurityRequiment
|
||||
// securityDef
|
||||
AddHeartTrackContextServices(services);
|
||||
AddModelService(services);
|
||||
AddIdentityServices(services);
|
||||
AddApiVersioning(services);
|
||||
|
||||
services.AddHealthChecks();
|
||||
|
||||
}
|
||||
|
||||
private void AddHeartTrackContextServices(IServiceCollection services)
|
||||
{
|
||||
string connectionString;
|
||||
|
||||
switch (Environment.GetEnvironmentVariable("TYPE"))
|
||||
{
|
||||
case "BDD":
|
||||
var HOST = System.Environment.GetEnvironmentVariable("HOST");
|
||||
var PORT = System.Environment.GetEnvironmentVariable("PORTDB");
|
||||
var DATABASE = System.Environment.GetEnvironmentVariable("DATABASE");
|
||||
var USERNAME = System.Environment.GetEnvironmentVariable("USERNAME");
|
||||
var PASSWORD = System.Environment.GetEnvironmentVariable("PASSWORD");
|
||||
|
||||
connectionString = $"Server={HOST};port={PORT};database={DATABASE};user={USERNAME};password={PASSWORD}";
|
||||
Console.WriteLine(connectionString);
|
||||
Console.WriteLine("======================");
|
||||
Console.WriteLine($"server={HOST};port={PORT};database={DATABASE};user={USERNAME};password={PASSWORD}");
|
||||
Console.WriteLine(connectionString);
|
||||
services.AddDbContext<HeartTrackContext>(options =>
|
||||
options.UseMySql($"{connectionString}", new MySqlServerVersion(new Version(10, 11, 1)))
|
||||
, ServiceLifetime.Singleton);
|
||||
break;
|
||||
default:
|
||||
connectionString = Configuration.GetConnectionString("HeartTrackAuthConnection");
|
||||
if (!string.IsNullOrWhiteSpace(connectionString))
|
||||
{
|
||||
services.AddDbContext<AuthDbContext>(options => options.UseInMemoryDatabase("AuthDb"));
|
||||
Console.WriteLine(connectionString);
|
||||
Console.WriteLine("======================");
|
||||
//options => options.UseSqlite(connectionString)
|
||||
//services.AddDbContext<HeartTrackContext>();
|
||||
services.AddDbContext<HeartTrackContext>(options =>
|
||||
options.UseSqlite(connectionString), ServiceLifetime.Singleton);
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddDbContext<AuthDbContext>(options => options.UseInMemoryDatabase("AuthDb"));
|
||||
services.AddDbContext<HeartTrackContext>(options => options.UseInMemoryDatabase("HeartTrackDb"));
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
services.AddSingleton<DbContextOptions<HeartTrackContext>>(provider =>
|
||||
{
|
||||
var connection = new SqliteConnection("DataSource=:memory:");
|
||||
connection.Open();
|
||||
|
||||
var options = new DbContextOptionsBuilder<HeartTrackContext>()
|
||||
.UseSqlite(connection)
|
||||
.Options;
|
||||
|
||||
return options;
|
||||
});*/
|
||||
}
|
||||
|
||||
private void AddModelService(IServiceCollection services)
|
||||
{
|
||||
//services.AddSingleton<IDataManager>(provider => new DbDataManager(provider.GetService<HeartTrackContext>()));
|
||||
//services.AddSingleton<IDataManager, StubData>();
|
||||
services.AddSingleton<IDataManager>(provider => new DbDataManager(provider.GetRequiredService<HeartTrackContext>()));
|
||||
|
||||
//services.AddTransient<IActivityManager, ActivityManager>();
|
||||
}
|
||||
|
||||
private void AddIdentityServices(IServiceCollection services)
|
||||
{
|
||||
// services.AddTransient<IEmailSender<AthleteEntity>, EmailSender>();
|
||||
services.AddAuthorization();
|
||||
|
||||
services.AddIdentityApiEndpoints<IdentityUser>()
|
||||
.AddEntityFrameworkStores<AuthDbContext>();
|
||||
//services.AddIdentity<AthleteEntity, IdentityRole>()
|
||||
// .AddEntityFrameworkStores<AuthDbContext>().AddDefaultTokenProviders();
|
||||
}
|
||||
|
||||
private void AddApiVersioning(IServiceCollection services)
|
||||
{
|
||||
|
||||
services.AddApiVersioning(opt =>
|
||||
{
|
||||
opt.ReportApiVersions = true;
|
||||
opt.AssumeDefaultVersionWhenUnspecified = true;
|
||||
opt.DefaultApiVersion = new Microsoft.AspNetCore.Mvc.ApiVersion(1, 0);
|
||||
// options.ApiVersionReader = new HeaderApiVersionReader("api-version");
|
||||
|
||||
opt.ApiVersionReader = ApiVersionReader.Combine(new UrlSegmentApiVersionReader(),
|
||||
new HeaderApiVersionReader("x-api-version"),
|
||||
new MediaTypeApiVersionReader("x-api-version"));
|
||||
});
|
||||
|
||||
}
|
||||
private void AddSwagger(IServiceCollection services)
|
||||
{
|
||||
services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.OperationFilter<SwaggerDefaultValues>();
|
||||
|
||||
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||
options.IncludeXmlComments(xmlPath);
|
||||
|
||||
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
Description =
|
||||
"JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
|
||||
Name = "Authorization",
|
||||
In = ParameterLocation.Header,
|
||||
Type = SecuritySchemeType.ApiKey
|
||||
});
|
||||
var scheme = new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
new OpenApiSecurityScheme
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Bearer"
|
||||
},
|
||||
Scheme = "oauth2",
|
||||
Name = "Bearer",
|
||||
In = ParameterLocation.Header,
|
||||
},
|
||||
new List<string>()
|
||||
}
|
||||
};
|
||||
options.AddSecurityRequirement(scheme);
|
||||
});
|
||||
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, SwaggerOptions>();
|
||||
services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.OperationFilter<SwaggerDefaultValues>();
|
||||
});
|
||||
/* services.AddSwaggerGen(options =>
|
||||
{
|
||||
options.SwaggerDoc("v1", new OpenApiInfo { Title = "HeartTrackAPI", Version = "v1" });
|
||||
options.SwaggerDoc("v2", new OpenApiInfo { Title = "HeartTrackAPI", Version = "v2" });
|
||||
});*/
|
||||
|
||||
services.AddVersionedApiExplorer(setup =>
|
||||
{
|
||||
setup.GroupNameFormat = "'v'VVV";
|
||||
setup.SubstituteApiVersionInUrl = true;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void Configure(WebApplication app, IWebHostEnvironment env)
|
||||
{
|
||||
app.UseHttpsRedirection();
|
||||
app.MapIdentityApi<IdentityUser>();
|
||||
|
||||
app.MapControllers();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapHealthChecks("/health");
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (true)
|
||||
{
|
||||
var apiVersionDescriptionProvider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
app.MapSwagger();
|
||||
app.UseSwaggerUI(options =>
|
||||
{
|
||||
foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions)
|
||||
|
||||
//foreach (var description in apiVersionDescriptionProvider)
|
||||
{
|
||||
options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json",
|
||||
description.GroupName.ToUpperInvariant());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace HeartTrackAPI;
|
||||
|
||||
public class FileUploadSummary
|
||||
{
|
||||
public int TotalFilesUploaded { get; set; }
|
||||
public string TotalSizeUploaded { get; set; }
|
||||
public IList<string> FilePaths { get; set; } = new List<string>();
|
||||
public IList<string> NotUploadedFiles { get; set; } = new List<string>();
|
||||
}
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
|
||||
public class MultipartFormDataAttribute : ActionFilterAttribute
|
||||
{
|
||||
public override void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
var request = context.HttpContext.Request;
|
||||
|
||||
if (request.HasFormContentType
|
||||
&& request.ContentType.StartsWith("multipart/form-data", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
context.Result = new StatusCodeResult(StatusCodes.Status415UnsupportedMediaType);
|
||||
}
|
||||
}
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
|
||||
{
|
||||
public void OnResourceExecuting(ResourceExecutingContext context)
|
||||
{
|
||||
var factories = context.ValueProviderFactories;
|
||||
factories.RemoveType<FormValueProviderFactory>();
|
||||
factories.RemoveType<FormFileValueProviderFactory>();
|
||||
factories.RemoveType<JQueryFormValueProviderFactory>();
|
||||
}
|
||||
|
||||
public void OnResourceExecuted(ResourceExecutedContext context)
|
||||
{
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
@HeartTrackAPI_HostAddress = http://localhost:5030
|
||||
|
||||
GET {{HeartTrackAPI_HostAddress}}/weatherforecast/
|
||||
Accept: application/json
|
||||
|
||||
###
|
@ -1,25 +1,22 @@
|
||||
using Model;
|
||||
using Model.Manager;
|
||||
using Model.Repository;
|
||||
using StubAPI;
|
||||
using DbContextLib;
|
||||
using HeartTrackAPI;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddSingleton<IDataManager, StubData>();
|
||||
var app = builder.Build();
|
||||
builder.Logging.AddConsole();
|
||||
builder.WebHost.ConfigureKestrel(serverOptions =>
|
||||
{
|
||||
serverOptions.Limits.MaxRequestBodySize = long.MaxValue;
|
||||
});
|
||||
|
||||
var init = new AppBootstrap(builder.Configuration);
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
init.ConfigureServices(builder.Services);
|
||||
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
var app = builder.Build();
|
||||
|
||||
init.Configure(app, app.Environment);
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.Services.GetService<HeartTrackContext>()!.Database.EnsureCreated();
|
||||
|
||||
app.MapControllers();
|
||||
app.Run();
|
@ -1,10 +1,16 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace HeartTrackAPI.Request;
|
||||
|
||||
public class PageRequest
|
||||
{
|
||||
|
||||
public string? OrderingPropertyName { get; set; } = null;// need to be map on the dto OrderCriteria
|
||||
public string? OrderingPropertyName { get; set; } = null;
|
||||
public bool? Descending { get; set; } = false;
|
||||
|
||||
// [Range(0, int.MaxValue, ErrorMessage = "Count must be greater than 0")]
|
||||
public int Index { get; set; } = 0;
|
||||
public int Count { get; set; } = 5;
|
||||
|
||||
// [Range(0, int.MaxValue, ErrorMessage = "Count must be greater than 0")]
|
||||
public int Count { get; set; } = 1;
|
||||
}
|
||||
|
@ -0,0 +1,53 @@
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
namespace HeartTrackAPI.Utils;
|
||||
|
||||
public class SwaggerDefaultValues : IOperationFilter
|
||||
{
|
||||
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||
{
|
||||
var apiDescription = context.ApiDescription;
|
||||
operation.Deprecated |= apiDescription.IsDeprecated();
|
||||
|
||||
foreach (var responseType in context.ApiDescription.SupportedResponseTypes)
|
||||
{
|
||||
var responseKey = responseType.IsDefaultResponse ? "default" : responseType.StatusCode.ToString();
|
||||
var response = operation.Responses[responseKey];
|
||||
|
||||
foreach (var contentType in response.Content.Keys)
|
||||
{
|
||||
if (responseType.ApiResponseFormats.All(x => x.MediaType != contentType))
|
||||
{
|
||||
response.Content.Remove(contentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (operation.Parameters == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var parameter in operation.Parameters)
|
||||
{
|
||||
var description = apiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name);
|
||||
|
||||
parameter.Description ??= description.ModelMetadata?.Description;
|
||||
|
||||
if (parameter.Schema.Default == null &&
|
||||
description.DefaultValue != null &&
|
||||
description.DefaultValue is not DBNull &&
|
||||
description.ModelMetadata is ModelMetadata modelMetadata)
|
||||
{
|
||||
var json = JsonSerializer.Serialize(description.DefaultValue, modelMetadata.ModelType);
|
||||
parameter.Schema.Default = OpenApiAnyFactory.CreateFromJson(json);
|
||||
}
|
||||
|
||||
parameter.Required |= description.IsRequired;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
namespace HeartTrackAPI.Utils;
|
||||
|
||||
public class SwaggerOptions: IConfigureNamedOptions<SwaggerGenOptions>
|
||||
|
||||
{
|
||||
private readonly IApiVersionDescriptionProvider _provider;
|
||||
|
||||
public SwaggerOptions(
|
||||
IApiVersionDescriptionProvider provider)
|
||||
{
|
||||
_provider = provider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure each API discovered for Swagger Documentation
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
public void Configure(SwaggerGenOptions options)
|
||||
{
|
||||
// add swagger document for every API version discovered
|
||||
foreach (var description in _provider.ApiVersionDescriptions)
|
||||
{
|
||||
options.SwaggerDoc(
|
||||
description.GroupName,
|
||||
CreateVersionInfo(description));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure Swagger Options. Inherited from the Interface
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="options"></param>
|
||||
public void Configure(string? name, SwaggerGenOptions options)
|
||||
{
|
||||
Configure(options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create information about the version of the API
|
||||
/// </summary>
|
||||
/// <param name="description"></param>
|
||||
/// <returns>Information about the API</returns>
|
||||
private OpenApiInfo CreateVersionInfo(
|
||||
ApiVersionDescription desc)
|
||||
{
|
||||
var info = new OpenApiInfo()
|
||||
{
|
||||
Title = "Web API For HeartTrack .NET 8",
|
||||
Version = desc.ApiVersion.ToString(),
|
||||
Description = "The HeartTrack project API, aims to provide an Open Source solution for heart rate data analysis.",
|
||||
Contact = new OpenApiContact { Name = "HeartTrackDev", Email = "toto@toto.fr" },
|
||||
License = new OpenApiLicense { Name = "MIT", Url = new Uri("https://opensource.org/licenses/MIT") }
|
||||
|
||||
};
|
||||
|
||||
if (desc.IsDeprecated)
|
||||
{
|
||||
info.Description += " This API version has been deprecated. Please use one of the new APIs available from the explorer.";
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
namespace Model.Manager;
|
||||
|
||||
public class ActivityManager : IActivityManager
|
||||
{
|
||||
public void AddActivityFromFitFile(byte filePath)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
namespace Model.Manager;
|
||||
|
||||
public interface IActivityManager
|
||||
{
|
||||
public void AddActivityFromFitFile(byte filePath);
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
namespace Model.Manager;
|
||||
|
||||
public class UserManager
|
||||
{
|
||||
|
||||
}
|
@ -1 +0,0 @@
|
||||
global using Xunit;
|
@ -1,10 +0,0 @@
|
||||
namespace TestsXUnit;
|
||||
|
||||
public class UnitTest1
|
||||
{
|
||||
[Fact]
|
||||
public void Test1()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,225 @@
|
||||
using ApiMappeur;
|
||||
using Dto;
|
||||
using HeartTrackAPI.Controllers;
|
||||
using HeartTrackAPI.Request;
|
||||
using HeartTrackAPI.Responce;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Model;
|
||||
using Model.Manager;
|
||||
using Model.Repository;
|
||||
using Moq;
|
||||
using Shared;
|
||||
using StubAPI;
|
||||
|
||||
namespace UnitTestApi.Controllers;
|
||||
|
||||
[TestClass]
|
||||
[TestSubject(typeof(UsersController))]
|
||||
public class UsersControllerTest
|
||||
{
|
||||
private Mock<IDataManager> _dataManagerMock;
|
||||
private IDataManager _dataManager;
|
||||
private UsersController _usersController;
|
||||
|
||||
private readonly List<User> _users =
|
||||
[
|
||||
new User
|
||||
{
|
||||
Id = 1, Username = "DoeDoe",
|
||||
ProfilePicture =
|
||||
"https://images.unsplash.com/photo-1682687982134-2ac563b2228b?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||
FirstName = "John", LastName = "Doe",
|
||||
Sexe = "M", Lenght = 180, Weight = 70, DateOfBirth = new DateTime(1990, 1, 1),
|
||||
Email = "john.doe@example.com", Role = new Athlete()
|
||||
},
|
||||
|
||||
new User
|
||||
{
|
||||
Id = 2, Username = "SmithSmith",
|
||||
ProfilePicture =
|
||||
"https://images.unsplash.com/photo-1709507779917-242b560288be?q=80&w=2080&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||
FirstName = "Jane", LastName = "Smith",
|
||||
Sexe = "F", Lenght = 170, Weight = 60, DateOfBirth = new DateTime(1992, 2, 2),
|
||||
Email = "athlete2@example.com", Role = new Coach()
|
||||
},
|
||||
|
||||
new User
|
||||
{
|
||||
Id = 3, Username = "Athlete3",
|
||||
ProfilePicture =
|
||||
"https://plus.unsplash.com/premium_photo-1705091981693-6006f8a20479?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
||||
FirstName = "First3", LastName = "Last3",
|
||||
Sexe = "M", Lenght = 190, Weight = 80, DateOfBirth = new DateTime(1994, 3, 3), Email = "ath@ex.fr",
|
||||
Role = new Athlete()
|
||||
}
|
||||
];
|
||||
|
||||
[TestInitialize]
|
||||
public void SetUp()
|
||||
{
|
||||
_dataManagerMock = new Mock<IDataManager>();
|
||||
|
||||
_dataManagerMock.Setup(dm => dm.UserRepo.GetNbItems()).ReturnsAsync(_users.Count);
|
||||
_dataManagerMock.Setup(dm =>
|
||||
dm.UserRepo.GetUsers(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<AthleteOrderCriteria>(),
|
||||
It.IsAny<bool>())).ReturnsAsync(
|
||||
(int index, int count, AthleteOrderCriteria criteria, bool descending) =>
|
||||
_users.GetItemsWithFilterAndOrdering(c => true, index, count,
|
||||
criteria != AthleteOrderCriteria.None ? criteria : null, descending)
|
||||
);
|
||||
|
||||
|
||||
|
||||
_usersController = new UsersController(new NullLogger<UsersController>(), _dataManagerMock.Object);
|
||||
}
|
||||
/*
|
||||
[TestInitialize]
|
||||
public void SetUp()
|
||||
{
|
||||
_dataManager = new StubData();
|
||||
_usersController = new UsersController(new NullLogger<UsersController>(), _dataManager);
|
||||
}*/
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public async Task Get_ReturnsPageResponse_WhenRequestIsValid()
|
||||
{
|
||||
// Arrange
|
||||
var request = new PageRequest
|
||||
{
|
||||
Index = 0,
|
||||
Count = 3,
|
||||
OrderingPropertyName = "Id",
|
||||
Descending = false
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _usersController.Get(request);
|
||||
Assert.IsInstanceOfType(result.Result, typeof(OkObjectResult));
|
||||
var okResult = result.Result as OkObjectResult;
|
||||
// Assert
|
||||
Assert.IsNotNull(okResult);
|
||||
Assert.IsInstanceOfType(okResult.Value, typeof(PageResponse<UserDto>));
|
||||
var pageResponse = okResult.Value as PageResponse<UserDto>;
|
||||
Assert.IsNotNull(pageResponse);
|
||||
Assert.AreEqual(3, pageResponse.Items.Count());
|
||||
Assert.AreEqual(3, pageResponse.Total);
|
||||
Assert.AreEqual(0, pageResponse.Index);
|
||||
Assert.AreEqual(3, pageResponse.Count);
|
||||
Assert.AreEqual(3, pageResponse.Count);
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow(0, 2, "Id", false, 2)]
|
||||
[DataRow(1, 1, "Id", false, 1)]
|
||||
[DataRow(0, 3, "Id", true, 3)]
|
||||
public async Task Get_ReturnsCorrectPaginationAndOrdering(int index, int count, string orderingProperty,
|
||||
bool descending, int expectedItemCount)
|
||||
{
|
||||
// Arrange
|
||||
var request = new PageRequest
|
||||
{
|
||||
Index = index,
|
||||
Count = count,
|
||||
OrderingPropertyName = orderingProperty,
|
||||
Descending = descending
|
||||
};
|
||||
// Act
|
||||
var result = await _usersController.Get(request);
|
||||
Assert.IsInstanceOfType(result.Result, typeof(OkObjectResult));
|
||||
var okResult = result.Result as OkObjectResult;
|
||||
// Assert
|
||||
Assert.IsNotNull(okResult);
|
||||
Assert.IsInstanceOfType(okResult.Value, typeof(PageResponse<UserDto>));
|
||||
var pageResponse = okResult.Value as PageResponse<UserDto>;
|
||||
Assert.IsNotNull(pageResponse);
|
||||
Assert.AreEqual(expectedItemCount, pageResponse.Items.Count());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Get_ReturnsInternalServerError_OnException()
|
||||
{
|
||||
_dataManagerMock.Setup(dm =>
|
||||
dm.UserRepo.GetUsers(It.IsAny<int>(), It.IsAny<int>(), It.IsAny<AthleteOrderCriteria>(),
|
||||
It.IsAny<bool>()))
|
||||
.ThrowsAsync(new Exception("Simulated database failure."));
|
||||
|
||||
var request = new PageRequest { Index = 0, Count = 3 };
|
||||
|
||||
var result = await _usersController.Get(request);
|
||||
|
||||
Assert.IsInstanceOfType(result.Result, typeof(ObjectResult));
|
||||
var objectResult = result.Result as ObjectResult;
|
||||
Assert.AreEqual(500, objectResult.StatusCode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public async Task GetById_ReturnsUserDto_WhenRequestIsValid()
|
||||
{
|
||||
// Arrange
|
||||
var id = 1;
|
||||
_dataManagerMock.Setup(dm => dm.UserRepo.GetItemById(id)).ReturnsAsync(_users.First(x => x.Id == id));
|
||||
|
||||
// Act
|
||||
var result = await _usersController.GetById(id) ;
|
||||
Assert.IsInstanceOfType(result.Result, typeof(OkObjectResult));
|
||||
var okResult = result.Result as OkObjectResult;
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(okResult);
|
||||
var resultObject = result.Result as OkObjectResult;
|
||||
Assert.IsNotNull(resultObject);
|
||||
Assert.IsInstanceOfType(resultObject.Value, typeof(UserDto));
|
||||
var user = resultObject.Value as UserDto;
|
||||
Assert.IsNotNull(user);
|
||||
var tmp = _users.First(x => x.Id == id).ToDto();
|
||||
Assert.AreEqual(tmp.Id, user.Id);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task GetById_ReturnsUserDto_WhenRequestUserDoesNotExist()
|
||||
{
|
||||
// Arrange
|
||||
var id = 0;
|
||||
_dataManagerMock.Setup(dm => dm.UserRepo.GetItemById(id)).ReturnsAsync((User)null!);
|
||||
|
||||
// Act
|
||||
var result = await _usersController.GetById(id) ;
|
||||
|
||||
// Assert
|
||||
Assert.IsInstanceOfType(result.Result, typeof(NotFoundObjectResult));
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public async Task GetById_Returns404_WhenIdIsInvalid()
|
||||
{
|
||||
// Arrange
|
||||
var id = -2;
|
||||
|
||||
// Act
|
||||
var result = await _usersController.GetById(id);
|
||||
|
||||
// Assert
|
||||
Assert.IsInstanceOfType(result.Result, typeof(NotFoundObjectResult));
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public async Task Count_ReturnsInt_WhenRequestIsValid()
|
||||
{
|
||||
// Act
|
||||
var result = await _usersController.Count();
|
||||
Assert.IsNotNull(result);
|
||||
result = result.Result as OkObjectResult;
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsInstanceOfType(result.Value, typeof(int));
|
||||
}
|
||||
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
using Dto;
|
||||
using HeartTrackAPI.Controllers;
|
||||
using HeartTrackAPI.Request;
|
||||
using HeartTrackAPI.Responce;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Model.Manager;
|
||||
using Model.Repository;
|
||||
using StubAPI;
|
||||
|
||||
namespace UnitTestApi;
|
||||
|
||||
[TestClass]
|
||||
public class UserControllerTest
|
||||
{
|
||||
private readonly IDataManager StubDataManager;
|
||||
private readonly UsersController _usersController;
|
||||
|
||||
public UserControllerTest()
|
||||
{
|
||||
StubDataManager = new StubData();
|
||||
_usersController = new UsersController(new NullLogger<UsersController>(), StubDataManager);
|
||||
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Get_ReturnsPageResponse_WhenRequestIsValid()
|
||||
{
|
||||
// Arrange
|
||||
var request = new PageRequest
|
||||
{
|
||||
Index = 0,
|
||||
Count = 10,
|
||||
OrderingPropertyName = "Id",
|
||||
Descending = false
|
||||
};
|
||||
|
||||
// Act
|
||||
//var result = _usersController.Get(request).Result as OkObjectResult;
|
||||
|
||||
// Assert
|
||||
// Assert.IsNotNull(result);
|
||||
//Assert.IsInstanceOfType(result.Value, typeof(PageResponse<UserDto>));
|
||||
}
|
||||
/*
|
||||
[TestMethod]
|
||||
public void GetById_ReturnsUserDto_WhenRequestIsValid()
|
||||
{
|
||||
// Arrange
|
||||
var id = 1;
|
||||
|
||||
// Act
|
||||
var result = _usersController.GetById(id).Result as OkObjectResult;
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsInstanceOfType(result.Value, typeof(UserDto));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetById_Returns404_WhenIdIsInvalid()
|
||||
{
|
||||
// Arrange
|
||||
var id = 0;
|
||||
|
||||
// Act
|
||||
var result = _usersController.GetById(id).Result as NotFoundResult;
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(result);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetById_Returns500_WheExceptionIsThrown()
|
||||
{
|
||||
// Arrange
|
||||
var id = 0;
|
||||
|
||||
// Act
|
||||
var result = _usersController.GetById(id).Result as StatusCodeResult;
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(500, result.StatusCode);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Count_ReturnsInt_WhenRequestIsValid()
|
||||
{
|
||||
// Act
|
||||
var result = _usersController.Count().Result as OkObjectResult;
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsInstanceOfType(result.Value, typeof(int));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Count_Returns500_WheExceptionIsThrown()
|
||||
{
|
||||
// Act
|
||||
var result = _usersController.Count().Result as StatusCodeResult;
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(500, result.StatusCode);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Update_ReturnsUserDto_WhenRequestIsValid()
|
||||
{
|
||||
// Arrange
|
||||
var id = 1;
|
||||
var user = new UserDto
|
||||
{
|
||||
Id = 1,
|
||||
FirstName = "John",
|
||||
LastName = "Doe",
|
||||
Email = "toto@eoeo.fr",
|
||||
};
|
||||
|
||||
}*/
|
||||
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
namespace UnitTestsEntities;
|
||||
using Xunit;
|
||||
using System.Linq;
|
||||
using Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
public class ActivityEntityTests
|
||||
{
|
||||
[Fact]
|
||||
public void Add_Activity_Success()
|
||||
{
|
||||
|
||||
|
||||
var activity = new ActivityEntity
|
||||
{
|
||||
Type = "Running",
|
||||
Date = new DateOnly(2024, 3, 15),
|
||||
StartTime = new TimeOnly(9, 0),
|
||||
EndTime = new TimeOnly(10, 0),
|
||||
EffortFelt = 7,
|
||||
Variability = 0.5f,
|
||||
Variance = 0.2f,
|
||||
StandardDeviation = 0.3f,
|
||||
Average = 0.4f,
|
||||
Maximum = 200,
|
||||
Minimum = 100,
|
||||
AverageTemperature = 25.5f,
|
||||
HasAutoPause = true,
|
||||
DataSourceId = 1,
|
||||
AthleteId = 1
|
||||
};
|
||||
|
||||
/*
|
||||
using (var context = new StubbedContext(options))
|
||||
{
|
||||
context.Database.EnsureCreated();
|
||||
context.Activities.Add(activity);
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
using (var context = new StubbedContext(options))
|
||||
{
|
||||
var savedActivity = context.Activities.First(a => a.Type == "Running");
|
||||
Assert.NotNull(savedActivity);
|
||||
Assert.Equal("Running", savedActivity.Type );
|
||||
|
||||
}*/
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Update_Activity_Success()
|
||||
{
|
||||
var activity = new ActivityEntity
|
||||
{
|
||||
Type = "Running",
|
||||
Date = new DateOnly(2024, 3, 15),
|
||||
StartTime = new TimeOnly(9, 0),
|
||||
EndTime = new TimeOnly(10, 0),
|
||||
EffortFelt = 7,
|
||||
Variability = 0.5f,
|
||||
Variance = 0.2f,
|
||||
StandardDeviation = 0.3f,
|
||||
Average = 0.4f,
|
||||
Maximum = 200,
|
||||
Minimum = 100,
|
||||
AverageTemperature = 25.5f,
|
||||
HasAutoPause = true,
|
||||
DataSourceId = 1,
|
||||
AthleteId = 1
|
||||
};
|
||||
|
||||
/*
|
||||
using (var context = new StubbedContext(options))
|
||||
{
|
||||
context.Database.EnsureCreated();
|
||||
context.Activities.Add(activity);
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
using (var context = new StubbedContext(options))
|
||||
{
|
||||
var savedActivity = context.Activities.First(a => a.Type == "Running");
|
||||
savedActivity.Type = "Walking";
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
using (var context = new StubbedContext(options))
|
||||
{
|
||||
var updatedActivity = context.Activities.First(a => a.Type == "Walking");
|
||||
Assert.NotNull(updatedActivity);
|
||||
Assert.Equal("Walking", updatedActivity.Type );
|
||||
Assert.Equal(7, updatedActivity.EffortFelt );
|
||||
}*/
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Delete_Activity_Success()
|
||||
{
|
||||
var activity = new ActivityEntity
|
||||
{
|
||||
Type = "Running",
|
||||
Date = new DateOnly(2024, 3, 15),
|
||||
StartTime = new TimeOnly(9, 0),
|
||||
EndTime = new TimeOnly(10, 0),
|
||||
EffortFelt = 7,
|
||||
Variability = 0.5f,
|
||||
Variance = 0.2f,
|
||||
StandardDeviation = 0.3f,
|
||||
Average = 0.4f,
|
||||
Maximum = 200,
|
||||
Minimum = 100,
|
||||
AverageTemperature = 25.5f,
|
||||
HasAutoPause = true,
|
||||
DataSourceId = 1,
|
||||
AthleteId = 1
|
||||
};
|
||||
|
||||
/*
|
||||
using (var context = new StubbedContext(options))
|
||||
{
|
||||
context.Database.EnsureCreated();
|
||||
context.Activities.Add(activity);
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
using (var context = new StubbedContext(options))
|
||||
{
|
||||
var savedActivity = context.Activities.First(a => a.Type == "Running");
|
||||
context.Activities.Remove(savedActivity);
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
using (var context = new StubbedContext(options))
|
||||
{
|
||||
var deletedActivity = context.Activities.FirstOrDefault(a => a.Type == "Running");
|
||||
Assert.Null(deletedActivity);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
namespace UnitTestsEntities;
|
||||
|
||||
public class UnitTest1
|
||||
{
|
||||
[Fact]
|
||||
public void Test1()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
namespace UnitTestsEntities2
|
||||
{
|
||||
public class UnitTest1
|
||||
{
|
||||
[Fact]
|
||||
public void Test1()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||
<PackageReference Include="xunit" Version="2.5.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
Loading…
Reference in new issue