diff --git a/src/ApiMappeur/AthleteMappeur.cs b/src/ApiMappeur/AthleteMappeur.cs index 6737e3b..55ffc17 100644 --- a/src/ApiMappeur/AthleteMappeur.cs +++ b/src/ApiMappeur/AthleteMappeur.cs @@ -1,10 +1,13 @@ -using Dto; +using System.Buffers; +using Dto; using Model; namespace ApiMappeur; -// anotine public static class UserMappeur { + private static readonly ArrayPool UserDtoPool = ArrayPool.Create(); + private static readonly Dictionary userToDtoMap = new Dictionary(); + private static readonly Dictionary dtoToUserMap = new Dictionary(); public static UserDto ToDto(this User user) { return new UserDto @@ -27,8 +30,71 @@ public static class UserMappeur public static User ToModel(this UserDto userDto) { - if (userDto.IsCoach) + return new User { + Username = userDto.Username, + ProfilePicture = userDto.ProfilePicture, + LastName = userDto.LastName, + FirstName = userDto.FirstName, + Email = userDto.Email, + MotDePasse = userDto.Password, + Sexe = userDto.Sexe, + Lenght = userDto.Lenght, + Weight = userDto.Weight, + DateOfBirth = userDto.DateOfBirth, + Role = userDto.IsCoach ? new Coach() : new Athlete() + + }; + } +} +/* +using Dto; +using Model; +using System.Buffers; + +namespace ApiMappeur +{ + // anotine + public static class UserMappeur + { + private static readonly ArrayPool UserDtoPool = ArrayPool.Create(); + + public static UserDto ToDto(this User user) + { + UserDto userDto = UserDtoPool.Rent(); + userDto.Id = user.Id; + userDto.Username = user.Username; + userDto.ProfilePicture = user.ProfilePicture; + userDto.LastName = user.LastName; + userDto.FirstName = user.FirstName; + userDto.Email = user.Email; + userDto.Password = user.MotDePasse; + userDto.Sexe = user.Sexe; + userDto.Lenght = user.Lenght; + userDto.Weight = user.Weight; + userDto.DateOfBirth = user.DateOfBirth; + userDto.IsCoach = user.Role is Coach; + return userDto; + } + + public static User ToModel(this UserDto userDto) + { + if (userDto.IsCoach) + { + return new User( + userDto.Username, + userDto.ProfilePicture, + userDto.LastName, + userDto.FirstName, + userDto.Email, + userDto.Password, + userDto.Sexe, + userDto.Lenght, + userDto.Weight, + userDto.DateOfBirth, + new Coach() + ); + } return new User( userDto.Username, userDto.ProfilePicture, @@ -40,20 +106,13 @@ public static class UserMappeur userDto.Lenght, userDto.Weight, userDto.DateOfBirth, - new Coach() - ); + new Athlete()); + } + + public static void ReturnToPool(this UserDto userDto) + { + UserDtoPool.Return(userDto); } - return new User( - userDto.Username, - userDto.ProfilePicture, - userDto.LastName, - userDto.FirstName, - userDto.Email, - userDto.Password, - userDto.Sexe, - userDto.Lenght, - userDto.Weight, - userDto.DateOfBirth, - new Athlete()); } -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/src/DbContextLib/DbContextLib.csproj b/src/DbContextLib/DbContextLib.csproj index 928ae7a..a2d1b08 100644 --- a/src/DbContextLib/DbContextLib.csproj +++ b/src/DbContextLib/DbContextLib.csproj @@ -6,13 +6,14 @@ enable - - - + + + + - - + + diff --git a/src/DbContextLib/Identity/AuthDbContext.cs b/src/DbContextLib/Identity/AuthDbContext.cs new file mode 100644 index 0000000..89924a7 --- /dev/null +++ b/src/DbContextLib/Identity/AuthDbContext.cs @@ -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 +{ + + public AuthDbContext(DbContextOptions options) : base(options) { } + public AuthDbContext() { } + /* + /// + /// Configures the database options if they are not already configured. + /// + /// The options builder instance. + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + if (!optionsBuilder.IsConfigured) + { + optionsBuilder.UseSqlite($"Data Source=uca.HeartTrack.db"); + } + }*/ +} \ No newline at end of file diff --git a/src/Dto/ActivityFitFileDto.cs b/src/Dto/ActivityFitFileDto.cs new file mode 100644 index 0000000..eb8fec0 --- /dev/null +++ b/src/Dto/ActivityFitFileDto.cs @@ -0,0 +1,9 @@ +namespace Dto; + +public class ActivityFitFileDto +{ + public string ActivityName { get; set; } + public string ActivityType { get; set; } + public int EffortFeel { get; set; } + //public IFormFile +} \ No newline at end of file diff --git a/src/Entities/AthleteEntity.cs b/src/Entities/AthleteEntity.cs index cc883d6..e37379a 100644 --- a/src/Entities/AthleteEntity.cs +++ b/src/Entities/AthleteEntity.cs @@ -8,6 +8,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.AspNetCore.Identity; namespace Entities { @@ -15,8 +16,10 @@ namespace Entities /// Represents an athlete entity in the database. /// [Table("Athlete")] - public class AthleteEntity + public class AthleteEntity : IdentityUser { + public AthleteEntity() : base() { } + /// /// Gets or sets the unique identifier of the athlete. /// @@ -28,36 +31,36 @@ namespace Entities /// Gets or sets the username of the athlete. /// [MaxLength(100)] - [Required(ErrorMessage = "Athlete Username is required")] - public required string Username { get; set; } + [Required(ErrorMessage = "Athlete Username is ")] + public string Username { get; set; } /// /// Gets or sets the last name of the athlete. /// [MaxLength(100)] - [Required(ErrorMessage = "Athlete Last Name is required")] - public required string LastName { get; set; } + [Required(ErrorMessage = "Athlete Last Name is ")] + public string LastName { get; set; } /// /// Gets or sets the first name of the athlete. /// [MaxLength(150)] - [Required(ErrorMessage = "Athlete First Name is required")] - public required string FirstName { get; set; } + [Required(ErrorMessage = "Athlete First Name is ")] + public string FirstName { get; set; } /// /// Gets or sets the email of the athlete. /// [MaxLength(100)] - [Required(ErrorMessage = "Athlete Email is required")] - public required string Email { get; set; } + [Required(ErrorMessage = "Athlete Email is ")] + public string Email { get; set; } /// /// Gets or sets the gender of the athlete. /// [MaxLength(1)] - [Required(ErrorMessage = "Athlete Sexe is required")] - public required string Sexe { get; set; } + [Required(ErrorMessage = "Athlete Sexe is ")] + public string Sexe { get; set; } /// /// Gets or sets the height of the athlete. @@ -72,13 +75,13 @@ namespace Entities /// /// Gets or sets the password of the athlete. /// - [Required(ErrorMessage = "Athlete Password is required")] - public required string Password { get; set; } + [Required(ErrorMessage = "Athlete Password is ")] + public string Password { get; set; } /// /// Gets or sets the date of birth of the athlete. /// - [Required(ErrorMessage = "Athlete Date of Birth is required")] + [Required(ErrorMessage = "Athlete Date of Birth is ")] [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)] public DateOnly DateOfBirth { get; set; } @@ -87,7 +90,7 @@ namespace Entities /// public bool IsCoach { get; set; } - public required byte[] ProfilPicture { get; set; } + public byte[] ProfilPicture { get; set; } diff --git a/src/Entities/Entities.csproj b/src/Entities/Entities.csproj index bb23fb7..e37f82e 100644 --- a/src/Entities/Entities.csproj +++ b/src/Entities/Entities.csproj @@ -6,4 +6,10 @@ enable + + + ..\..\..\..\..\.nuget\packages\microsoft.extensions.identity.stores\8.0.2\lib\net8.0\Microsoft.Extensions.Identity.Stores.dll + + + diff --git a/src/HeartTrackAPI/AppBootstrap.cs b/src/HeartTrackAPI/AppBootstrap.cs new file mode 100644 index 0000000..1e1b452 --- /dev/null +++ b/src/HeartTrackAPI/AppBootstrap.cs @@ -0,0 +1,137 @@ +using DbContextLib.Identity; +using Entities; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.UI.Services; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.AspNetCore.Mvc.Versioning; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; +using Model.Manager; +using Model.Service; + +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(); + //services.AddTransient, ConfigureSwaggerOption>(); + // include Xml comment + // addsecurityRequiment + // securityDef + services.AddSwaggerGen(); + AddHeartTrackContextServices(services); + AddModelService(services); + AddIdentityServices(services); + AddApiVersioning(services); + AddSwagger(services); + + services.AddHealthChecks(); + + } + + private void AddHeartTrackContextServices(IServiceCollection services) + { + var connectionString = Configuration.GetConnectionString("HeartTrackAuthConnection"); + if (string.IsNullOrWhiteSpace(connectionString)) + { + throw new InvalidOperationException("The connection string for the database is not set."); + } + else + { + services.AddDbContext(options => options.UseInMemoryDatabase("AuthDb")); +// builder.Services.AddDbContext(options => options.UseSqlite(connectionString)); + services.AddSingleton(); + } + + } + private void AddModelService(IServiceCollection services) + { + services.AddSingleton(); + services.AddTransient(); + } + + private void AddIdentityServices(IServiceCollection services) + { +// services.AddTransient, EmailSender>(); + services.AddAuthorization(); + + services.AddIdentityApiEndpoints() + .AddEntityFrameworkStores(); + //services.AddIdentity() + // .AddEntityFrameworkStores().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.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.MapControllers(); + app.UseAuthorization(); + app.MapIdentityApi(); + + app.MapHealthChecks("/health"); + + // Configure the HTTP request pipeline. + if (true) + { + var apiVersionDescriptionProvider = app.Services.GetRequiredService(); + 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()); + } + }); + + } + + + } +} diff --git a/src/HeartTrackAPI/Controllers/ActivityController.cs b/src/HeartTrackAPI/Controllers/ActivityController.cs index 0319803..6ad3e22 100644 --- a/src/HeartTrackAPI/Controllers/ActivityController.cs +++ b/src/HeartTrackAPI/Controllers/ActivityController.cs @@ -5,6 +5,7 @@ using HeartTrackAPI.Responce; using Microsoft.AspNetCore.Mvc; using Shared; using Model; +using Model.Manager; using Model.Repository; namespace HeartTrackAPI.Controllers; @@ -14,6 +15,7 @@ public class ActivityController : Controller { private readonly IActivityRepository _activityService; private readonly ILogger _logger; + private readonly IActivityManager _activityManager; public ActivityController(IActivityRepository activityService, ILogger logger) { @@ -46,6 +48,21 @@ public class ActivityController : Controller return StatusCode(500); } } + /* + public async Task PostFitFile([FromForm] IFormFile file) + { + if (file == null) + { + return BadRequest("No file was provided"); + } + var activity = await _activityManager.AddActivityFromFitFile(file); + if (activity == null) + { + return BadRequest("The file provided is not a valid fit file"); + } + return CreatedAtAction(nameof(GetActivities), activity.ToDto()); + }*/ + /* [HttpGet("{id}")] public async Task> GetActivity(int id) diff --git a/src/HeartTrackAPI/Controllers/UsersController.cs b/src/HeartTrackAPI/Controllers/UsersController.cs index ea98a15..b3369c7 100644 --- a/src/HeartTrackAPI/Controllers/UsersController.cs +++ b/src/HeartTrackAPI/Controllers/UsersController.cs @@ -1,7 +1,9 @@ using ApiMappeur; using Dto; +using Entities; using HeartTrackAPI.Request; using HeartTrackAPI.Responce; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Model; using Model.Manager; @@ -11,11 +13,13 @@ using Shared; namespace HeartTrackAPI.Controllers; [ApiController] -[Route("api/users")] +[ApiVersion("1.0")] +[Route("api/v{version:apiVersion}/users")] public class UsersController : Controller { private readonly ILogger _logger; private readonly IUserRepository _userService; + // private readonly public UsersController(ILogger logger, IDataManager dataManager) { _logger = logger; @@ -156,5 +160,52 @@ public class UsersController : Controller } } - + + [HttpPost("{id}/friend/{friendId}")] + [ProducesResponseType(200)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public async Task AddFriend(int id, int friendId) + { + try + { + _logger.LogInformation("Executing {Action} with parameters: {Parameters} for {Id}", nameof(AddFriend), friendId,id); + var athlete = await _userService.GetItemById(id); + if (athlete == null) + { + _logger.LogError("Athlete with id {id} not found", id); + return NotFound($"Athlete with id {id} not found"); + } + var friend = await _userService.GetItemById(friendId); + if (friend == null) + { + _logger.LogError("Athlete with id {id} not found", friendId); + return NotFound($"Athlete with id {friendId} not found"); + } + var isAdded = await _userService.AddFriend(athlete, friend); + if(!isAdded) + { + _logger.LogError("Error while adding friend with id {friendId} to athlete with id {id}", friendId, id); + return StatusCode(500); + } + return Ok(); + } + catch (Exception e) + { + _logger.LogError(e, "Error while getting the number of users"); + return StatusCode(500); + } + } + + [HttpPost("logout")] + [ProducesResponseType(200)] + [ProducesResponseType(401)] + [ProducesResponseType(500)] + public async Task Logout(SignInManager signInManager, [FromBody] object? empty) + { + if (empty == null) return Unauthorized(); + await signInManager.SignOutAsync(); + return Ok(); + } + } \ No newline at end of file diff --git a/src/HeartTrackAPI/HeartTrackAPI.csproj b/src/HeartTrackAPI/HeartTrackAPI.csproj index c572e11..e0f7022 100644 --- a/src/HeartTrackAPI/HeartTrackAPI.csproj +++ b/src/HeartTrackAPI/HeartTrackAPI.csproj @@ -8,12 +8,17 @@ + + + + + diff --git a/src/HeartTrackAPI/Program.cs b/src/HeartTrackAPI/Program.cs index b43dfbe..c79cc12 100644 --- a/src/HeartTrackAPI/Program.cs +++ b/src/HeartTrackAPI/Program.cs @@ -1,25 +1,23 @@ -using Model; +using DbContextLib; +using DbContextLib.Identity; +using Entities; +using HeartTrackAPI; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc.Versioning; +using Microsoft.EntityFrameworkCore; +using Microsoft.OpenApi.Models; using Model.Manager; -using Model.Repository; using StubAPI; - 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(); -var app = builder.Build(); - -// Configure the HTTP request pipeline. +builder.Logging.AddConsole(); - app.UseSwagger(); - app.UseSwaggerUI(); +var init = new AppBootstrap(builder.Configuration); +init.ConfigureServices(builder.Services); -app.UseHttpsRedirection(); +var app = builder.Build(); -app.MapControllers(); +init.Configure(app, app.Environment); +// app?.Services?.GetService()?.Database.EnsureCreated(); app.Run(); \ No newline at end of file diff --git a/src/HeartTrackAPI/Utils/SwaggerOptions.cs b/src/HeartTrackAPI/Utils/SwaggerOptions.cs new file mode 100644 index 0000000..7754a52 --- /dev/null +++ b/src/HeartTrackAPI/Utils/SwaggerOptions.cs @@ -0,0 +1,64 @@ +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +namespace HeartTrackAPI.Utils; + +public class SwaggerOptions: IConfigureNamedOptions + + { + private readonly IApiVersionDescriptionProvider _provider; + + public SwaggerOptions( + IApiVersionDescriptionProvider provider) + { + _provider = provider; + } + + /// + /// Configure each API discovered for Swagger Documentation + /// + /// + 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)); + } + } + + /// + /// Configure Swagger Options. Inherited from the Interface + /// + /// + /// + public void Configure(string name, SwaggerGenOptions options) + { + Configure(options); + } + + /// + /// Create information about the version of the API + /// + /// + /// Information about the API + private OpenApiInfo CreateVersionInfo( + ApiVersionDescription desc) + { + var info = new OpenApiInfo() + { + Title = ".NET Core (.NET 6) Web API For Lol", + Version = desc.ApiVersion.ToString() + }; + + if (desc.IsDeprecated) + { + info.Description += " This API version has been deprecated. Please use one of the new APIs available from the explorer."; + } + + return info; + } + } diff --git a/src/HeartTrackAPI/appsettings.json b/src/HeartTrackAPI/appsettings.json index 4d56694..952a46c 100644 --- a/src/HeartTrackAPI/appsettings.json +++ b/src/HeartTrackAPI/appsettings.json @@ -5,5 +5,8 @@ "Microsoft.AspNetCore": "Warning" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "ConnectionStrings": { + "HeartTrackAuthConnection": "Data Source=uca.HeartTrack.db" + } } diff --git a/src/Model/Manager/ActivityManager.cs b/src/Model/Manager/ActivityManager.cs new file mode 100644 index 0000000..6cd1ef1 --- /dev/null +++ b/src/Model/Manager/ActivityManager.cs @@ -0,0 +1,9 @@ +namespace Model.Manager; + +public class ActivityManager : IActivityManager +{ + public void AddActivityFromFitFile(byte filePath) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/Model/Manager/Contract/IActivityManager.cs b/src/Model/Manager/Contract/IActivityManager.cs new file mode 100644 index 0000000..5722a41 --- /dev/null +++ b/src/Model/Manager/Contract/IActivityManager.cs @@ -0,0 +1,7 @@ +using Microsoft.AspNetCore.Http; +namespace Model.Manager; + +public interface IActivityManager +{ + public void AddActivityFromFitFile(byte filePath); +} \ No newline at end of file diff --git a/src/Model/Manager/UserManager.cs b/src/Model/Manager/UserManager.cs new file mode 100644 index 0000000..d1b697a --- /dev/null +++ b/src/Model/Manager/UserManager.cs @@ -0,0 +1,6 @@ +namespace Model.Manager; + +public class UserManager +{ + +} \ No newline at end of file diff --git a/src/Model/Model.csproj b/src/Model/Model.csproj index 18de4eb..915e21e 100644 --- a/src/Model/Model.csproj +++ b/src/Model/Model.csproj @@ -7,7 +7,18 @@ + + + + + + + + ..\..\..\..\..\.dotnet\shared\Microsoft.AspNetCore.App\8.0.1\Microsoft.AspNetCore.Identity.dll + + + diff --git a/src/Model/Repository/IUserRepository.cs b/src/Model/Repository/IUserRepository.cs index d6d528c..4c38ba4 100644 --- a/src/Model/Repository/IUserRepository.cs +++ b/src/Model/Repository/IUserRepository.cs @@ -5,4 +5,6 @@ namespace Model.Repository; public interface IUserRepository : IGenericRepository { public Task> GetUsers(int index, int count, AthleteOrderCriteria? criteria , bool descending = false); + + public Task AddFriend(User user, User friend); } \ No newline at end of file diff --git a/src/Model/Service/EmailSender.cs b/src/Model/Service/EmailSender.cs new file mode 100644 index 0000000..fc9d5e6 --- /dev/null +++ b/src/Model/Service/EmailSender.cs @@ -0,0 +1,31 @@ + +using Entities; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.UI.Services; + +namespace Model.Service; + +public class EmailSender : IEmailSender +{ + private IEmailSender _emailSenderImplementation; + + public async Task SendEmailAsync(string email, string subject, string htmlMessage) + { + throw new NotImplementedException(); + } + + public async Task SendConfirmationLinkAsync(AthleteEntity user, string email, string confirmationLink) + { + throw new NotImplementedException(); + } + + public async Task SendPasswordResetLinkAsync(AthleteEntity user, string email, string resetLink) + { + throw new NotImplementedException(); + } + + public async Task SendPasswordResetCodeAsync(AthleteEntity user, string email, string resetCode) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/Model/User.cs b/src/Model/User.cs index 6efffa8..0991ca5 100644 --- a/src/Model/User.cs +++ b/src/Model/User.cs @@ -8,7 +8,7 @@ public class User public string LastName { get; set; } public string FirstName { get; set; } public string Email { get; set; } - public string MotDePasse { get; set; } + public string? MotDePasse { get; set; } public string Sexe { get; set; } public float Lenght { get; set; } public float Weight { get; set; } @@ -17,6 +17,8 @@ public class User protected List Notifications { get; set; } = new List(); + public List Users { get; set; } = new List(); + public User( string username, string profilePicture, string nom, string prenom, string email, string motDePasse, string sexe, float taille, float poids, DateTime dateNaissance, Role role) { Username = username; diff --git a/src/Model2Entities/DbDataManager.cs b/src/Model2Entities/DbDataManager.cs index ec2a3fe..b89d82b 100644 --- a/src/Model2Entities/DbDataManager.cs +++ b/src/Model2Entities/DbDataManager.cs @@ -8,7 +8,6 @@ public partial class DbDataManager: IDataManager { public IActivityRepository ActivityRepo { get; } public IUserRepository UserRepo { get; } - protected HeartTrackContext DbContext { get; } diff --git a/src/Model2Entities/UserRepository.cs b/src/Model2Entities/UserRepository.cs index e9716f1..020dcb6 100644 --- a/src/Model2Entities/UserRepository.cs +++ b/src/Model2Entities/UserRepository.cs @@ -49,5 +49,10 @@ public partial class DbDataManager { throw new NotImplementedException(); } + + public async Task AddFriend(User user, User friend) + { + throw new NotImplementedException(); + } } } \ No newline at end of file diff --git a/src/StubAPI/AthleteService.cs b/src/StubAPI/AthleteService.cs index b1b1a28..d666873 100644 --- a/src/StubAPI/AthleteService.cs +++ b/src/StubAPI/AthleteService.cs @@ -34,6 +34,23 @@ public class UserService : IUserRepository public async Task> GetUsers(int index, int count, AthleteOrderCriteria? orderingProperty = null, bool descending = false) => athletes.GetItemsWithFilterAndOrdering(c=>true,index, count,orderingProperty != AthleteOrderCriteria.None ? orderingProperty: null , descending); + public async Task AddFriend(User user, User friend) + { + if (user == null || friend == null) + { + return false; + } + + if (user.Users.Contains(friend)) + { + return false; + } + + user.Users.Add(friend); + + return true; + } + public async Task> GetItems(int index, int count, string? orderingProperty = null, bool descending = false) {