diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..82743c5 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,75 @@ +kind: pipeline +type: docker +name: EfCsLoL + +trigger: + event: + - push + +steps: + + - name: build + image: mcr.microsoft.com/dotnet/sdk:6.0 + volumes: + - name: docs + path: /docs + commands: + - cd Sources/ + - dotnet restore LeagueOfLegends.sln + - dotnet build LeagueOfLegends.sln -c Release --no-restore + - dotnet publish LeagueOfLegends.sln -c Release --no-restore -o CI_PROJECT_DIR/build/release + +# docker image build + - name: docker-build-and-push + image: plugins/docker + settings: + dockerfile: Sources/API_LoL/Dockerfile + context: Sources/ + registry: hub.codefirst.iut.uca.fr + repo: hub.codefirst.iut.uca.fr/corentin.richard/entityframework_consodeservices_tp + + username: + from_secret: SECRET_REGISTRY_USERNAME + password: + from_secret: SECRET_REGISTRY_PASSWORD + +# docker test + - name: tests + image: mcr.microsoft.com/dotnet/sdk:6.0 + commands: + - cd Sources/ + - dotnet restore LeagueOfLegends.sln + - dotnet test LeagueOfLegends.sln --no-restore + depends_on: [docker-build-and-push] + + - name: code-analysis + image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dronesonarplugin-dotnet6 + commands: + - cd Sources/ + - dotnet restore LeagueOfLegends.sln + - dotnet sonarscanner begin /k:entityframework_consodeservices_tp /d:sonar.host.url=$${PLUGIN_SONAR_HOST} /d:sonar.coverageReportPaths="coveragereport/SonarQube.xml" /d:sonar.coverage.exclusions="Tests/**" /d:sonar.login=$${PLUGIN_SONAR_TOKEN} + - dotnet build LeagueOfLegends.sln -c Release --no-restore + - dotnet test LeagueOfLegends.sln --logger trx --no-restore /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura --collect "XPlat Code Coverage" + - reportgenerator -reports:"**/coverage.cobertura.xml" -reporttypes:SonarQube -targetdir:"coveragereport" + - dotnet publish LeagueOfLegends.sln -c Release --no-restore -o CI_PROJECT_DIR/build/release + - dotnet sonarscanner end /d:sonar.login=$${PLUGIN_SONAR_TOKEN} + secrets: [ SECRET_SONAR_LOGIN ] + settings: + # accessible en ligne de commande par ${PLUGIN_SONAR_HOST} + sonar_host: https://codefirst.iut.uca.fr/sonar/ + # accessible en ligne de commande par ${PLUGIN_SONAR_TOKEN} + sonar_token: + from_secret: SECRET_SONAR_LOGIN + depends_on: [tests] + + # container deployment + - name: deploy-container + image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest + environment: + IMAGENAME: hub.codefirst.iut.uca.fr/corentin.richard/entityframework_consodeservices_tp:latest + CONTAINERNAME: entityframework_consodeservices_tp + COMMAND: create + OVERWRITE: true + ADMIN: corentinrichard,pierreferreira + depends_on: [ code-analysis, docker-build-and-push ] + diff --git a/README.md b/README.md index 3228583..b0ba7c5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,108 @@ + +# Projet d'Entity FrameWork et Consomation et Développement de services + +Notre projet à pour objectif la liaison entre une base de donnée et un client, par l'utilisation d' ``EntityFramework`` et d'une ``API`` C# créé par nous même. + +![C#](https://img.shields.io/badge/c%23-%23239120.svg?style=for-the-badge&logo=c-sharp&logoColor=white) +![JWT](https://img.shields.io/badge/JWT-black?style=for-the-badge&logo=JSON%20web%20tokens) +![Markdown](https://img.shields.io/badge/markdown-%23000000.svg?style=for-the-badge&logo=markdown&logoColor=white) + +> *A noter que seul la v1 est prise en compte, la v2 et v2.2 ne sont presentes uniquement pour prouver notre capacité à versionner* + +Ce projet est decoupé en deux parties : + +## :alien: Consomation et Développement de services :construction_worker: + + +#### :steam_locomotive: Comment lancer le projet ? + +> (Explication...) :construction: + + +#### :checkered_flag: État des livrables : + +:construction: +> * :heavy_check_mark: Mise en place de toutes les opérations CRUD +> * :heavy_check_mark: API RESTful (respect des règles de routage, utilisation des bons status code ...) +> * :heavy_exclamation_mark: Utilisation des fichiers configurations +> * :heavy_check_mark: Versionnage de l'api (avec versionnage de la doc) +> * :heavy_check_mark: Logs +> * :heavy_check_mark: Tests unitaires +> * :heavy_exclamation_mark: Réalisation du client MAUI et liaison avec l'api +> * :heavy_check_mark:Liaison avec la base de données +> * :heavy_check_mark:Filtrage + Pagination des données +> * :construction: Propreté du code (Vous pouvez vous servir de sonarqube) +> * :heavy_check_mark: Dockerisation et Hébergement des API (CodeFirst) + +> * :heavy_exclamation_mark: Sécurité +> * :heavy_check_mark: Utilisation SonarQube + +[![Build Status](https://codefirst.iut.uca.fr/api/badges/corentin.richard/EntityFramework_ConsoDeServices_TP/status.svg)](https://codefirst.iut.uca.fr/corentin.richard/EntityFramework_ConsoDeServices_TP) + + +#### Diagramme d'architechture : + +=> Disponible à `./Diagramme d'architecture.jpg` + +--- +## :package: Entity FrameWork :construction_worker: +:construction: + +#### :checkered_flag: État des livrables : + +Partie 1 : +* Exo1 : :construction: + une base de données + une table de champion + utilisation du client console/mobile + requetes CRUD (+ tri, filtrage) + +* Exo2 : :heavy_check_mark: + UT + Base de données stubbée + SQLiteInMemory + +* Exo3 : :heavy_check_mark: + Déploiement EF et tests via code#0 + +--- + +Partie 2 : +* Exo4 : :heavy_check_mark: + implémentation des runes et skins (1 table -> pas de relation) + +* Exo5 : :heavy_check_mark: + Relation entre champion et skin (OneToMany) + +* Exo6 : :heavy_check_mark: + Relation entre Champion, RunePage et Rune (ManyToMany) +> La relation entre Rune et RunePage à été simplifiée par manque de temps, il ne s'agit donc pas d'un dictionaire mais d'un OneToMany. + +* Exo7 : :heavy_check_mark: + mapping entre model et entité (intégration de qualité) + (en 1 table et avec relations) + +* Exo8 : :heavy_exclamation_mark: + Ajouter le paterne UnitOfWork (rollback en cas de probleme sur les transaction) + +--- +## Explication de ce qu'on a fait et ce qu'on a pas fait et pourquoi on a priorisé ca plutot que d'autre : + +:construction: + + + +## Coordonnées : + +``Corentin Richard`` : **[corentin.richard@etu.uca.fr](https://codefirst.iut.uca.fr/git/corentin.richard)** + +``Pierre Ferreira`` : **[pierre.ferreira@etu.uca.fr](https://codefirst.iut.uca.fr/git/pierre.ferreira)** + + +--- +# Sujet principal : + +--- # prepaLoL ## Diagramme de classes du modèle diff --git a/Sources/.editorconfig b/Sources/.editorconfig new file mode 100644 index 0000000..73bb42e --- /dev/null +++ b/Sources/.editorconfig @@ -0,0 +1,4 @@ +[*.cs] + +# CS8604: Possible null reference argument. +dotnet_diagnostic.CS8604.severity = none diff --git a/Sources/API_LoL/API_LoL.csproj b/Sources/API_LoL/API_LoL.csproj index 8902068..91c61d0 100644 --- a/Sources/API_LoL/API_LoL.csproj +++ b/Sources/API_LoL/API_LoL.csproj @@ -1,20 +1,24 @@ - + net6.0 enable enable 1c8da478-3029-41d1-b936-853a71a8b812 - Windows + Linux + + + + diff --git a/Sources/API_LoL/Controllers/ChampionsController.cs b/Sources/API_LoL/Controllers/ChampionsController.cs index 9461ad4..2c35997 100644 --- a/Sources/API_LoL/Controllers/ChampionsController.cs +++ b/Sources/API_LoL/Controllers/ChampionsController.cs @@ -3,61 +3,242 @@ using Model; using StubLib; using DTO; using DTO.Mapper; +using System.CodeDom.Compiler; +using System.Drawing; +using System; +using API_LoL.Mapper; +using System.Xml.Linq; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using System.Reflection.PortableExecutable; // For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 namespace API_LoL.Controllers { - [Route("api/[controller]")] + //[Route("api/[controller]")] + [ApiVersion("1.0")] + [Route("api/v{version:apiVersion}/[controller]")] [ApiController] public class ChampionsController : ControllerBase { - private StubData.ChampionsManager ChampionsManager { get; set; } = new StubData.ChampionsManager(new StubData()); - // GET: api/ + public ChampionsController(IDataManager Manager) { + this._logger = LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger(); + this.ChampionsManager = Manager.ChampionsMgr; + this.SkinsManager = Manager.SkinsMgr; + } + + + private IChampionsManager ChampionsManager; + private ISkinsManager SkinsManager; + //private StubData stubData; + private ILogger logger; + private readonly ILogger _logger; + + // GET api//5 + + [HttpGet("count")] + public async Task GetCount() + { + _logger.LogInformation(message: "count returned", "Get", "/Champion/Count", 200, DateTime.Now); + return Ok(ChampionsManager.GetNbItems()); + } + [HttpGet] - public async Task Get() + public async Task Get(string? name = null,String? skill = null, String? characteristic = null,int index = 0,int size =10) { - var list = await ChampionsManager.GetItems(0,await ChampionsManager.GetNbItems()); - if (list.Count() == 0) { - return Ok(list.Select(champion => champion?.toDTO())); - }else { - return NoContent(); + if (size - index > 10) + { + _logger.LogError(message : "Oversized","Get","/Champion",400,"name : "+name,"skill : "+skill,"characteristics : "+characteristic,"index : "+index,"size : "+size,DateTime.Now); + return BadRequest(); + } + if (!string.IsNullOrEmpty(name)) + { + var list = await ChampionsManager.GetItemsByName(name, index, size); + if (list.Count() != 0) + { + _logger.LogInformation(message: "Champion returned by name", "Get", "/Champion", 200, "name : " + name, "skill : " + skill, "characteristic : " + characteristic, "index : " + index, "size : " + size, DateTime.Now); + return Ok(list.Select(champion => champion?.ToDTO())); + } + else { + _logger.LogInformation(message: "No Champion found by name", "Get", "/Champion", 204, "name : " + name, "skill : " + skill, "characteristic : " + characteristic, "index : " + index, "size : " + size, DateTime.Now); + return NoContent(); } + } + else if(!string.IsNullOrEmpty(skill)) { + var list = await ChampionsManager.GetItemsBySkill(skill, index, size); + if (list.Count() != 0) + { + _logger.LogInformation(message: "Champion returned by skill", "Get", "/Champion", 200, "name : " + name, "skill : " + skill, "characteristic : " + characteristic, "index : " + index, "size : " + size, DateTime.Now); + return Ok(list.Select(champion => champion?.ToDTO())); + } + else { + _logger.LogInformation(message: "No Champion found by skill", "Get", "/Champion", 204, "name : " + name, "skill : " + skill, "characteristic : " + characteristic, "index : " + index, "size : " + size, DateTime.Now); + return NoContent(); } + } + else if(!string.IsNullOrEmpty (characteristic)) { + var list = await ChampionsManager.GetItems(index, size); + if (list.Count() != 0) + { + _logger.LogInformation(message: "Champion returned by characteristic", "Get", "/Champion", 200, "name : " + name, "skill : " + skill, "characteristic : " + characteristic, "index : " + index, "size : " + size, DateTime.Now); + return Ok(list.Select(champion => champion?.ToDTO())); + } + else { + _logger.LogInformation(message: "No Champion found by char", "Get", "/Champion", 204, "name : " + name, "skill : " + skill, "characteristic : " + characteristic, "index : " + index, "size : " + size, DateTime.Now); + return NoContent(); } + } + else { + var list = await ChampionsManager.GetItems(index, size); + if (list.Count() != 0) + { + _logger.LogInformation(message: "Champion returned default", "Get", "/Champion", 200, "name : " + name, "skill : " + skill, "characteristic : " + characteristic, "index : " + index, "size : " + size, DateTime.Now); + return Ok(list.Select(champion => champion?.ToDTO())); + } + else { + _logger.LogInformation(message: "No Champion found Default", "Get", "/Champion", 204, "name : " + name,"skill : " + skill,"characteristic : "+ characteristic,"index : "+index,"size : "+size, DateTime.Now); + return NoContent(); + } } } - // GET api//5 - [HttpGet("{id}")] - public string Get(String name) + [HttpGet("name")] + public async Task GetByName(String name) { - return "value"; + if (string.IsNullOrEmpty(name)) + { + _logger.LogError(message: "No paramater given", "Get", "/Champion/Name", 400, "name : " + name, DateTime.Now); + return BadRequest(); + } + var list = await ChampionsManager.GetItemsByName(name, 0, 1); + if (list.Count() == 1) + { + _logger.LogInformation(message: "Champion found", "Get", "/Champion/Name", 20, "name : " + name, DateTime.Now); + return Ok(list.Select(champion => champion?.ToDTO()).First()); + } + else { + _logger.LogInformation(message: "No Champion found", "Get", "/Champion/Name", 204, "name : " + name, DateTime.Now); + return NoContent(); + } + } + [HttpGet("name/skins")] + public async Task GetSkinsByName(String name) + { + if (string.IsNullOrEmpty(name)) + { + _logger.LogError(message: "No paramater given", "Get", "/Champion/Name/Skins", 400, "name : " + name, DateTime.Now); + return BadRequest(); + } + var list = await ChampionsManager.GetItemsByName(name, 0, 1); + if (list.Count() == 1) + { + var nb = await SkinsManager.GetNbItemsByChampion(list.First()); + if (nb != 0) + { + var skins = await SkinsManager.GetItemsByChampion(list.First(), 0, nb); + return Ok(skins.Select(skin => skin?.ToDTO())); + } + else { + _logger.LogInformation(message: "No Skin found found", "Get", "/Champion/Name/Skins", 204, "name : " + name, DateTime.Now); + return NoContent(); } + } + else { + _logger.LogInformation(message: "No Champion found", "Get", "/Champion/Name/Skins", 204, "name : " + name, DateTime.Now); + + return NoContent(); + } + + } + + //[HttpGet("name/skills")] + //public async Task GetSkillsByName(String name) + //{ + // if (string.IsNullOrEmpty(name)) return BadRequest(); + // var list = await ChampionsManager.GetItemsByName(name, 0, 1); + // if (list.Count() == 1) + // { + // var skins = await SkinsManager.GetItemsByChampion(list.First(), 0, await SkinsManager.GetNbItemsByChampion(list.First())); + // if (skins.Count() != 0) + // { + // return Ok(skins.Select(skin => skin?.ToDTO())); + // } + // else { return NoContent(); } + // } + // else { return NoContent(); } + //} + + + // POST api/ [HttpPost] public async Task Post(ChampionDTO champion) { if (champion == null) { + _logger.LogError(message: "Null paramater given", "Post", "/Champion", 422, "champion : " + champion.toString, DateTime.Now); return UnprocessableEntity(); } else { - //ChampionsManager.AddItem(champion) - return CreatedAtAction("Post",champion.Name); + var list = await ChampionsManager.GetItemsByName(champion.Name, 0, 1); + Champion champ = list.FirstOrDefault(); + if (champ != null) + { + if(champ.Name == champion.Name) + { + _logger.LogError(message: "Champion with this id already exists", "Post", "/Champion", 409, "champion : " + champion.toString, DateTime.Now); + return Conflict(champion); + } + } + await ChampionsManager.AddItem(champion.ToChampion()); + _logger.LogInformation(message: "Champion created", "Post", "Champion/Name", 201, "champion : " + champion.toString, DateTime.Now); + return CreatedAtAction("Post",champion); + } } // PUT api//5 - [HttpPut("{id}")] - public void Put(int id, [FromBody] string value) + [HttpPut("name")] + public async Task Put(string name, ChampionDTO championDTO) { + if (string.IsNullOrEmpty(name)) + { + _logger.LogError(message: "Null paramater given for Name", "Put", "/Champion/Name", 400,"name : "+name, "champion : " + championDTO.toString, DateTime.Now); + return BadRequest(); + } + if(championDTO == null) + { + _logger.LogError(message: "Null paramater given for Champion", "Put", "/Champion/Name", 422, "name : " + name, "champion : " + championDTO.toString, DateTime.Now); + return UnprocessableEntity(); + } + var list = await ChampionsManager.GetItemsByName(name, 0, 1); + if (list.Count() == 1) + { + _logger.LogInformation(message: "Champion updated", "Put", "Champion/Name", 200, "name : " + name, "champion : " + championDTO.toString, DateTime.Now); + return Ok(ChampionsManager.UpdateItem(list.First(), championDTO.ToChampion())); + } + else { + _logger.LogInformation(message: "No champion Found", "Put", "/Champion/Name", 204, "name : " + name, "champion : " + championDTO.toString, DateTime.Now); + return NoContent(); + } } // DELETE api//5 - [HttpDelete("{id}")] - public void Delete(int id) + [HttpDelete("name")] + public async Task Delete(string name) { + if (string.IsNullOrEmpty(name)) + { + _logger.LogError(message: "Null paramater given for Name", "Delete", "/Champion/Name", 400, "name : " + name, DateTime.Now); + return BadRequest(); + } + var list = await ChampionsManager.GetItemsByName(name, 0, 1); + if(list.Count() == 1){ + _logger.LogInformation(message: "Champion Deleted", "Delete", "/Champion/Name", 200, "name : " + name, DateTime.Now); + return Ok(await ChampionsManager.DeleteItem(list.First())); + }else { + _logger.LogInformation(message: "No champion Found", "Delete", "/Champion/Name", 204, "name : " + name, DateTime.Now); + return NoContent(); } } } } diff --git a/Sources/API_LoL/Controllers/ChampionsControllerVersioned.cs b/Sources/API_LoL/Controllers/ChampionsControllerVersioned.cs new file mode 100644 index 0000000..87598d9 --- /dev/null +++ b/Sources/API_LoL/Controllers/ChampionsControllerVersioned.cs @@ -0,0 +1,108 @@ +using Microsoft.AspNetCore.Mvc; +using Model; +using StubLib; +using DTO; +using DTO.Mapper; +using System.CodeDom.Compiler; + +namespace API_LoL.Controllers +{ + [ApiVersion("2.0")] + [ApiVersion("2.2")] + [Route("api/v{version:apiVersion}/versioned")] + [ApiController] + public class ChampionsControllerVersioned : ControllerBase + { + public ChampionsControllerVersioned(IDataManager Manager) + { + this.ChampionsManager = Manager.ChampionsMgr; + } + + private IChampionsManager ChampionsManager; + + // GET api//5 + + //[HttpGet] + //public async Task Get(String? name = null, String? skill = null, String? characteristic = null, int index = 0, int size = 10) + //{ + // if (size - index > 10) + // { + // return BadRequest(); + // } + // if (!string.IsNullOrEmpty(name)) + // { + // var list = await ChampionsManager.GetItemsByName(name, index, size); + // if (list.Count() != 0) + // { + // return Ok(list.Select(champion => champion?.ToDTO())); + // } + // else { return NoContent(); } + // } + // else if (!string.IsNullOrEmpty(skill)) + // { + // var list = await ChampionsManager.GetItemsBySkill(skill, index, size); + // if (list.Count() != 0) + // { + // return Ok(list.Select(champion => champion?.ToDTO())); + // } + // else { return NoContent(); } + // } + // else if (!string.IsNullOrEmpty(characteristic)) + // { + // var list = await ChampionsManager.GetItems(index, size); + // if (list.Count() != 0) + // { + // return Ok(list.Select(champion => champion?.ToDTO())); + // } + // else { return NoContent(); } + // } + // else + // { + // var list = await ChampionsManager.GetItems(index, size); + // if (list.Count() != 0) + // { + // return Ok(list.Select(champion => champion?.ToDTO())); + // } + // else { return NoContent(); } + // } + //} + + + //// POST api/ + //[HttpPost] + //public async Task Post(ChampionDTO champion) + //{ + // if (champion == null) + // { + // return UnprocessableEntity(); + // } + // else + // { + // await ChampionsManager.AddItem(champion.ToChampion()); + // return CreatedAtAction("Post", champion); + // } + //} + + //// PUT api//5 + //[HttpPut("{id}")] + //public void Put(int id, [FromBody] string value) + //{ + //} + + //// DELETE api//5 + //[HttpDelete("{id}")] + //public void Delete(int id) + //{ + //} + + + ///---------- Versioning ----------/// + [HttpGet, MapToApiVersion("2.0")] + public string GetThatOnlySayHello() => "Hello v2.0!"; + + + //! FIXME : not working, mais avec la version 2.0 ca marche ! + [HttpGet, MapToApiVersion("2.2")] + public string GetThatOnlySayHelloV2() => "Hello but i'm from v2.2!"; + } +} diff --git a/Sources/API_LoL/Dockerfile b/Sources/API_LoL/Dockerfile index 5634a24..7ff2075 100644 --- a/Sources/API_LoL/Dockerfile +++ b/Sources/API_LoL/Dockerfile @@ -1,8 +1,5 @@ #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. -#Depending on the operating system of the host machines(s) that will build or run the containers, the image specified in the FROM statement may need to be changed. -#For more information, please see https://aka.ms/containercompat - FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 80 @@ -11,6 +8,10 @@ EXPOSE 443 FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /src COPY ["API_LoL/API_LoL.csproj", "API_LoL/"] +COPY ["DTO/DTO.csproj", "DTO/"] +COPY ["Model/Model.csproj", "Model/"] +COPY ["Shared/Shared.csproj", "Shared/"] +COPY ["StubLib/StubLib.csproj", "StubLib/"] RUN dotnet restore "API_LoL/API_LoL.csproj" COPY . . WORKDIR "/src/API_LoL" diff --git a/Sources/API_LoL/Dockerfile.original b/Sources/API_LoL/Dockerfile.original new file mode 100644 index 0000000..5634a24 --- /dev/null +++ b/Sources/API_LoL/Dockerfile.original @@ -0,0 +1,25 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +#Depending on the operating system of the host machines(s) that will build or run the containers, the image specified in the FROM statement may need to be changed. +#For more information, please see https://aka.ms/containercompat + +FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +WORKDIR /app +EXPOSE 80 +EXPOSE 443 + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +WORKDIR /src +COPY ["API_LoL/API_LoL.csproj", "API_LoL/"] +RUN dotnet restore "API_LoL/API_LoL.csproj" +COPY . . +WORKDIR "/src/API_LoL" +RUN dotnet build "API_LoL.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "API_LoL.csproj" -c Release -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "API_LoL.dll"] \ No newline at end of file diff --git a/Sources/API_LoL/Mapper/ChampionClassMapper.cs b/Sources/API_LoL/Mapper/ChampionClassMapper.cs new file mode 100644 index 0000000..638f500 --- /dev/null +++ b/Sources/API_LoL/Mapper/ChampionClassMapper.cs @@ -0,0 +1,34 @@ +using DTO; +using Model; + +namespace API_LoL.Mapper +{ + public static class ChampionClassMapper + { + public static string ToDTO(this ChampionClass championClass) + { + return championClass.ToString(); + } + + public static ChampionClass ToChampionClass(this String championClass) + { + switch (championClass) + { + case "Assassin": + return ChampionClass.Assassin; + case "Fighter": + return ChampionClass.Fighter; + case "Mage": + return ChampionClass.Mage; + case "Marksman": + return ChampionClass.Marksman; + case "Support": + return ChampionClass.Support; + case "Tank": + return ChampionClass.Tank; + default: + return ChampionClass.Unknown; + } + } + } +} diff --git a/Sources/API_LoL/Mapper/ChampionMapper.cs b/Sources/API_LoL/Mapper/ChampionMapper.cs index f091999..632149e 100644 --- a/Sources/API_LoL/Mapper/ChampionMapper.cs +++ b/Sources/API_LoL/Mapper/ChampionMapper.cs @@ -1,4 +1,5 @@ -using Model; +using API_LoL.Mapper; +using Model; using System; using System.Collections.Generic; using System.Linq; @@ -9,13 +10,15 @@ namespace DTO.Mapper { public static class ChampionMapper { - public static ChampionDTO toDTO(this Champion champion) + public static ChampionDTO ToDTO(this Champion champion) { - return new ChampionDTO() - { - Name = champion.Name, - Bio = champion.Bio, - }; + return new ChampionDTO(champion.Name, champion.Bio, champion.Icon, champion.Class.ToDTO(), champion.Image.Base64); + } + + public static Champion ToChampion(this ChampionDTO champion) + { + return new Champion(champion.Name, champClass: champion.Class.ToChampionClass(),icon: champion.Icon,bio: champion.Bio,image :champion.Image); + } } } diff --git a/Sources/API_LoL/Mapper/SkinMapper.cs b/Sources/API_LoL/Mapper/SkinMapper.cs new file mode 100644 index 0000000..5b18c55 --- /dev/null +++ b/Sources/API_LoL/Mapper/SkinMapper.cs @@ -0,0 +1,18 @@ +using DTO; +using Model; + +namespace API_LoL.Mapper +{ + public static class SkinMapper + { + public static SkinDTO ToDTO(this Skin skin) + { + return new SkinDTO(skin.Name, skin.Description, skin.Icon,skin.Image.Base64,skin.Price); + } + + public static Skin ToSkin(this SkinDTO skin) + { + return new Skin(skin.Name, null,price: skin.Price, icon:skin.Icon,image: skin.Image,description: skin.Description) ; + } + } +} diff --git a/Sources/API_LoL/Program.cs b/Sources/API_LoL/Program.cs index 48863a6..78d467f 100644 --- a/Sources/API_LoL/Program.cs +++ b/Sources/API_LoL/Program.cs @@ -1,19 +1,79 @@ +using API_LoL; +using EntityFramework; +using EntityFramework.Manager; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.AspNetCore.Mvc.Versioning; +using Microsoft.Extensions.Logging; +using Model; +using StubLib; + var builder = WebApplication.CreateBuilder(args); -// Add services to the container. -builder.Services.AddControllers(); +//Versioning + +///NOT WORKING WHEN CHANGING VERSIONS : +/// voir sur https://blog.christian-schou.dk/how-to-use-api-versioning-in-net-core-web-api/ rubrique "Configure SwaggerOptions" +/// (mais requiere l'injection de d�pendance). +/// Sinon, code plus simple disponible par le prof + + + +// Add ApiExplorer to discover versions +builder.Services.AddVersionedApiExplorer(setup => +{ + setup.GroupNameFormat = "'v'VVV"; + setup.SubstituteApiVersionInUrl = true; +}); + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); +builder.Services.ConfigureOptions(); + + +builder.Services.AddApiVersioning(o => o.ApiVersionReader = new UrlSegmentApiVersionReader()); + +// Add services to the container. +builder.Services.AddControllers(); + + + +//builder.Services.AddScoped(); + + +builder.Services.AddHttpClient(); + +//builder.Services.AddScoped(); +builder.Services.AddScoped(); + +builder.Services.AddDbContext(); + var app = builder.Build(); +using(var scope = app.Services.CreateScope()) +{ + var context = scope.ServiceProvider.GetService(); + context.Database.EnsureCreated(); +} + +var apiVersionDescriptionProvider = app.Services.GetRequiredService(); + + // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); - app.UseSwaggerUI(); + app.UseSwaggerUI(options => + { + + foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions) + { + options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", + description.GroupName.ToUpperInvariant()); + } + }); } app.UseHttpsRedirection(); diff --git a/Sources/API_LoL/SwaggerOptions.cs b/Sources/API_LoL/SwaggerOptions.cs new file mode 100644 index 0000000..46ad759 --- /dev/null +++ b/Sources/API_LoL/SwaggerOptions.cs @@ -0,0 +1,61 @@ +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace API_LoL +{ + public class ConfigureSwaggerOptions : IConfigureNamedOptions + { + private readonly IApiVersionDescriptionProvider _provider; + + public ConfigureSwaggerOptions(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", + 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/Sources/API_LoL/champion.db b/Sources/API_LoL/champion.db new file mode 100644 index 0000000..cfdeed2 Binary files /dev/null and b/Sources/API_LoL/champion.db differ diff --git a/Sources/API_LoL/champion.db-shm b/Sources/API_LoL/champion.db-shm new file mode 100644 index 0000000..39d4916 Binary files /dev/null and b/Sources/API_LoL/champion.db-shm differ diff --git a/Sources/API_LoL/champion.db-wal b/Sources/API_LoL/champion.db-wal new file mode 100644 index 0000000..932d20c Binary files /dev/null and b/Sources/API_LoL/champion.db-wal differ diff --git a/Sources/ApiTests/Program.cs b/Sources/ApiTests/Program.cs deleted file mode 100644 index a5af879..0000000 --- a/Sources/ApiTests/Program.cs +++ /dev/null @@ -1 +0,0 @@ -// See https://aka.ms/new-console-template for more information diff --git a/Sources/Api_UT/Api_UT.csproj b/Sources/Api_UT/Api_UT.csproj new file mode 100644 index 0000000..efdc9e5 --- /dev/null +++ b/Sources/Api_UT/Api_UT.csproj @@ -0,0 +1,34 @@ + + + + net6.0 + enable + enable + + false + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + diff --git a/Sources/Api_UT/ChampionControllerTest.cs b/Sources/Api_UT/ChampionControllerTest.cs new file mode 100644 index 0000000..0a93acf --- /dev/null +++ b/Sources/Api_UT/ChampionControllerTest.cs @@ -0,0 +1,88 @@ +using API_LoL.Controllers; +using DTO; +using FluentAssertions; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.Extensions.Logging; +using Model; +using StubLib; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Api_UT +{ + [TestClass] + public class ChampionControllerTest + { + + ChampionsController api = new ChampionsController(new StubData()); + + [TestMethod] + public async Task Get_Default_OkList() + { + + List list = new List {new ChampionDTO("Akali","","","Assassin",""), new ChampionDTO("Aatrox", "", "", "Fighter",""), new ChampionDTO("Ahri", "", "", "Mage",""), new ChampionDTO("Akshan", "", "", "Marksman",""), new ChampionDTO("Bard", "", "","Support",""), new ChampionDTO("Alistar", "", "","Tank","") }; + IActionResult a = await api.Get(); + a.Should().NotBeNull(); + var aObject = a as OkObjectResult; + aObject.Should().NotBeNull(); + var championresult = aObject.Value as IEnumerable; + list.Should().BeEquivalentTo(championresult); + } + + [TestMethod] + public async Task Get_MoreThanLimit_BadRequest() + { + IActionResult a = await api.Get(index :0,size :11); + + a.Should().NotBeNull(); + a.Should().BeOfType(); + } + + [TestMethod] + public async Task Get_2First_OkListOf2() + { + List list = new List { new ChampionDTO("Akali", "", "", "Assassin",""), new ChampionDTO("Aatrox", "", "", "Fighter","") }; + + IActionResult a = await api.Get(index: 0,size: 2); + + a.Should().NotBeNull(); + a.Should().BeOfType(); + var aObject = a as OkObjectResult; + aObject.Should().NotBeNull(); + var championresult = aObject.Value as IEnumerable; + list.Should().BeEquivalentTo(championresult); + } + + [TestMethod] + public async Task Get_FilterAName_OkListOf5() + { + List list = new List { new ChampionDTO("Akali", "", "", "Assassin", ""), new ChampionDTO("Akshan", "", "", "Marksman", "") }; + + IActionResult a = await api.Get(name: "Ak"); + + a.Should().NotBeNull(); + a.Should().BeOfType(); + var aObject = a as OkObjectResult; + aObject.Should().NotBeNull(); + var championresult = aObject.Value as IEnumerable; + list.Should().BeEquivalentTo(championresult); + } + + + + [TestMethod] + public async Task Post_ValidChampion_Created() + { + ChampionsController api = new ChampionsController(new StubData()); + IActionResult a = await api.Post(new ChampionDTO("nom","bio","icon", "Assassin","")); + var action = (CreatedAtActionResult)a; + var champAction = action.Value as IEnumerable; + Assert.IsNotNull(a); + ChampionDTO champ = new ChampionDTO("nom", "bio", "icon","Assassin", ""); + Assert.IsTrue(champ.equals(other: (ChampionDTO)((CreatedAtActionResult)a).Value)); + } + + } +} \ No newline at end of file diff --git a/Sources/Api_UT/Usings.cs b/Sources/Api_UT/Usings.cs new file mode 100644 index 0000000..ab67c7e --- /dev/null +++ b/Sources/Api_UT/Usings.cs @@ -0,0 +1 @@ +global using Microsoft.VisualStudio.TestTools.UnitTesting; \ No newline at end of file diff --git a/Sources/ApiTests/ApiTests.csproj b/Sources/ConsoleApplication/ConsoleApplication.csproj similarity index 60% rename from Sources/ApiTests/ApiTests.csproj rename to Sources/ConsoleApplication/ConsoleApplication.csproj index 74abf5c..3e93ad0 100644 --- a/Sources/ApiTests/ApiTests.csproj +++ b/Sources/ConsoleApplication/ConsoleApplication.csproj @@ -7,4 +7,9 @@ enable + + + + + diff --git a/Sources/ConsoleApplication/Program.cs b/Sources/ConsoleApplication/Program.cs new file mode 100644 index 0000000..d3916f1 --- /dev/null +++ b/Sources/ConsoleApplication/Program.cs @@ -0,0 +1,44 @@ + +using ConsoleApplication; +using EntityFramework; +using HttpClient; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using Model; + +var builder = WebApplication.CreateBuilder(); + +builder.Services.AddDbContext(); + +var app = builder.Build(); + +using (var scope = app.Services.CreateScope()) +{ + var context = scope.ServiceProvider.GetService(); + context.Database.EnsureCreated(); +} + +IDataManager dataManager = new HttpClientManager(); + +string choice = "0"; + +while (choice != "9") +{ + Utils.showMainMenu(); + choice = Console.ReadLine(); + + switch (choice) + { + case "1": + { + Utils.championMenu(dataManager.ChampionsMgr); + break; + } + case "2": + { + //Utils. + break; + } + + } +} \ No newline at end of file diff --git a/Sources/ConsoleApplication/Utils.cs b/Sources/ConsoleApplication/Utils.cs new file mode 100644 index 0000000..fb70443 --- /dev/null +++ b/Sources/ConsoleApplication/Utils.cs @@ -0,0 +1,55 @@ +using Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ConsoleApplication +{ + public static class Utils + { + public static void showMainMenu() + { + Console.WriteLine("-------- Menu -------"); + Console.WriteLine(" 1 - Champions "); + Console.WriteLine(" 2 - Skills "); + Console.WriteLine("\n 9 - Quitter"); + } + + public static void showChampionMenu() + { + Console.WriteLine("-------- Champion -------"); + Console.WriteLine(" 1 - Count "); + Console.WriteLine(" 2 - Default "); + Console.WriteLine("\n 9 - Quitter"); + } + + public static async void championMenu(IChampionsManager championsManager ) { + string choix = "0"; + + while (choix != "9") + { + Utils.showChampionMenu(); + choix = Console.ReadLine(); + + switch (choix) + { + case "1": + //Console.WriteLine("# result : "+ await championsManager.GetNbItems()); + break; + case "2": + var list = await championsManager.GetItems(0, 10); + foreach(var cham in list) + { + Console.WriteLine("# result : " +cham.ToString()); + + } + break; + } + } + } + + + } +} diff --git a/Sources/ConsoleTestAPI/ConsoleTestAPI.csproj b/Sources/ConsoleTestAPI/ConsoleTestAPI.csproj new file mode 100644 index 0000000..a2be5fa --- /dev/null +++ b/Sources/ConsoleTestAPI/ConsoleTestAPI.csproj @@ -0,0 +1,20 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + + + + + diff --git a/Sources/ConsoleTestAPI/Program.cs b/Sources/ConsoleTestAPI/Program.cs new file mode 100644 index 0000000..0f9440f --- /dev/null +++ b/Sources/ConsoleTestAPI/Program.cs @@ -0,0 +1,194 @@ +// See https://aka.ms/new-console-template for more information +using System.Net.Security; +using Model; +using System.Net.Http; +using System.Reflection.Metadata; +using Newtonsoft.Json; +using DTO; +using System.Text.Json; +using Microsoft.AspNetCore.Mvc; +using System.Net.Http.Json; + +class APIResponse +{ + public string status { get; set; } + public List champions { get; set; } +} + + +static class Program +{ + + static HttpClient client = new HttpClient(); + static async Task Main(string[] args) { + HttpClient client = new HttpClient(); + await DisplayMainMenu(); + } + + public static async Task DisplayMainMenu() + { + Dictionary choices = new Dictionary() + { + [1] = "1- Manage Champions", + [2] = "2- Manage Skins", + [3] = "3- Manage Runes", + [4] = "4- Manage Rune Pages", + [99] = "99- Quit" + }; + + while (true) + { + int input = DisplayAMenu(choices); + + switch (input) + { + case 1: + await DisplayChampionsMenu(); + break; + case 2: + break; + case 3: + break; + case 4: + break; + case 99: + Console.WriteLine("Bye bye!"); + return; + default: + break; + } + } + } + + private static int DisplayAMenu(Dictionary choices) + { + int input = -1; + while (true) + { + Console.WriteLine("What is your choice?"); + Console.WriteLine("--------------------"); + foreach (var choice in choices.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value)) + { + Console.WriteLine(choice); + } + if (!int.TryParse(Console.ReadLine(), out input) || input == -1) + { + Console.WriteLine("I do not understand what your choice is. Please try again."); + continue; + } + break; + } + Console.WriteLine($"You have chosen: {choices[input]}"); + Console.WriteLine(); + return input; + } + + public static async Task DisplayChampionsMenu() + { + Dictionary choices = new Dictionary() + { + [0] = "0- Get number of champions", + [1] = "1- Get champions", + [2] = "2- Find champions by name", + [3] = "3- Find champions by characteristic", + [4] = "4- Find champions by class", + [5] = "5- Find champions by skill", + [6] = "6- Add new champion", + [7] = "7- Delete a champion", + [8] = "8- Update a champion", + }; + + int input = DisplayAMenu(choices); + + switch (input) + { + case 0: + + case 1: + { + var response = await client.GetFromJsonAsync( + "https://localhost:7144/api/Champions"); + + + + Console.WriteLine(response.ToString()); + string? json = response.ToString(); + List f = System.Text.Json.JsonSerializer.Deserialize>(json: json); + foreach(var c in f) + { + Console.WriteLine(c.ToString()); + } + + } + break; + case 2: + { + + } + break; + case 3: + { + + } + break; + case 4: + { + + } + break; + case 5: + { + + } + break; + case 6: + { + + } + break; + case 7: + { + + } + break; + case 8: + { + + } + break; + default: + break; + } + + } + + public static void DisplayCreationChampionMenu(Champion champion) + { + Dictionary choices = new Dictionary() + { + [1] = "1- Add a skill", + [2] = "2- Add a skin", + [3] = "3- Add a characteristic", + [99] = "99- Finish" + }; + + while (true) + { + int input = DisplayAMenu(choices); + + switch (input) + { + case 1: + + case 2: + + case 3: + + case 99: + return; + default: + break; + } + } + } +} \ No newline at end of file diff --git a/Sources/DTO/ChampionClassDTO.cs b/Sources/DTO/ChampionClassDTO.cs new file mode 100644 index 0000000..c85525f --- /dev/null +++ b/Sources/DTO/ChampionClassDTO.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DTO +{ + public class ChampionClassDTO + { + public string Name; + public ChampionClassDTO(string name) { + this.Name = name; + } + } +} diff --git a/Sources/DTO/ChampionDTO.cs b/Sources/DTO/ChampionDTO.cs index 35c9515..23478dd 100644 --- a/Sources/DTO/ChampionDTO.cs +++ b/Sources/DTO/ChampionDTO.cs @@ -1,11 +1,33 @@ -namespace DTO +using Model; +using System.Collections.Immutable; + +namespace DTO { public class ChampionDTO { + public ChampionDTO(string name, string bio, string icon, string Class, string image) + { + Name = name; + Bio = bio; + Icon = icon; + this.Class = Class; + Image = image; + } public string Name { get; set; } public string Bio { get; set; } + public string Icon { get; set; } + + public string Image { get; set; } + public string Class { get; set; } - + public bool equals(ChampionDTO other) + { + return other.Name==this.Name && other.Bio==this.Bio && other.Icon==this.Icon; + } + public string toString() + { + return Name + Bio + Icon; + } } } \ No newline at end of file diff --git a/Sources/DTO/DTO.csproj b/Sources/DTO/DTO.csproj index 132c02c..dd77eab 100644 --- a/Sources/DTO/DTO.csproj +++ b/Sources/DTO/DTO.csproj @@ -6,4 +6,9 @@ enable + + + + + diff --git a/Sources/DTO/Program.cs b/Sources/DTO/Program.cs new file mode 100644 index 0000000..8133fe8 --- /dev/null +++ b/Sources/DTO/Program.cs @@ -0,0 +1,30 @@ +//using Model; +//using StubLib; + +//var builder = WebApplication.CreateBuilder(args); + +//// Add services to the container. + +//builder.Services.AddControllers(); +//// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +//builder.Services.AddEndpointsApiExplorer(); +//builder.Services.AddSwaggerGen(); + +//builder.Services.AddScoped(); + +//var app = builder.Build(); + +//// Configure the HTTP request pipeline. +//if (app.Environment.IsDevelopment()) +//{ +// app.UseSwagger(); +// app.UseSwaggerUI(); +//} + +//app.UseHttpsRedirection(); + +//app.UseAuthorization(); + +//app.MapControllers(); + +//app.Run(); diff --git a/Sources/DTO/SkinDTO.cs b/Sources/DTO/SkinDTO.cs new file mode 100644 index 0000000..eb255f6 --- /dev/null +++ b/Sources/DTO/SkinDTO.cs @@ -0,0 +1,29 @@ +using Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DTO +{ + public class SkinDTO + { + public string Name { get; set; } + public string Description { get; set; } + public string Icon { get; set; } + + public string Image { get; set; } + + public float Price { get; set; } + + public SkinDTO(string name,string description,string icon,string image,float price) { + this.Name = name; + this.Description = description; + this.Icon = icon; + this.Image = image; + this.Price = price; + + } + } +} diff --git a/Sources/EF_UT/EFDataManagerChampionTest.cs b/Sources/EF_UT/EFDataManagerChampionTest.cs new file mode 100644 index 0000000..486a8be --- /dev/null +++ b/Sources/EF_UT/EFDataManagerChampionTest.cs @@ -0,0 +1,53 @@ +using EntityFramework; +using EntityFramework.Manager; +using FluentAssertions; +using FluentAssertions.Primitives; +using Microsoft.AspNetCore.Builder; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EF_UT +{ + [TestClass] + public class EFDataManagerChampionTest + { + [TestMethod] + public void Add_ValidChampion_Added() + { + IDataManager dataManager = new EFDataManager(); + IChampionsManager championsManager = dataManager.ChampionsMgr; + + var champ = championsManager.AddItem(new Champion("test")); + } + + [TestMethod] + public async Task GetItemsByName_DefaultChamp_One() + { + var builder = WebApplication.CreateBuilder(); + + builder.Services.AddDbContext(); + + var app = builder.Build(); + + using (var scope = app.Services.CreateScope()) + { + var context = scope.ServiceProvider.GetService(); + context.Database.EnsureCreated(); + } + + IDataManager dataManager = new EFDataManager(); + IChampionsManager championsManager = dataManager.ChampionsMgr; + + var ak = (await championsManager.GetItemsByName("A", 0, 1)).First(); + + Assert.IsNotNull(ak); + Assert.AreEqual("Aatrox", ak.Name); + } + } +} diff --git a/Sources/EF_UT/EF_UT.csproj b/Sources/EF_UT/EF_UT.csproj new file mode 100644 index 0000000..eadf5a3 --- /dev/null +++ b/Sources/EF_UT/EF_UT.csproj @@ -0,0 +1,27 @@ + + + + net6.0 + enable + enable + + false + + + + + + + + + + + + + + + + + + + diff --git a/Sources/EF_UT/EntityTest.cs b/Sources/EF_UT/EntityTest.cs new file mode 100644 index 0000000..5fd0afb --- /dev/null +++ b/Sources/EF_UT/EntityTest.cs @@ -0,0 +1,90 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using EntityFramework; +using System.Threading.Tasks; + + +namespace EF_UT +{ + [TestClass] + public class EntityTest + { + [TestMethod] + public void TestAdd() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(databaseName: "Add_Test_database").Options; + + + //prepares the database with one instance of the context + using (var context = new LoLDbContext(options)) + { + + ChampionEntity chewie = new ChampionEntity { Name = "Chewbacca", Bio = "", Icon = "" }; + ChampionEntity yoda = new ChampionEntity{ Name = "Yoda", Bio = "", Icon = "" }; + ChampionEntity ewok = new ChampionEntity{ Name = "Ewok", Bio = "", Icon = "" }; + + //SkinEntity defaulSkin = new SkinEntity("Skin Default", chewie); + //chewie.AddSkin(defaulSkin); + Console.WriteLine("Creates and inserts new Champion for tests"); + context.Add(chewie); + context.Add(yoda); + context.Add(ewok); + context.SaveChanges(); + } + + //prepares the database with one instance of the context + using (var context = new LoLDbContext(options)) + { + Assert.AreEqual(3, context.Champions.Count()); + Assert.AreEqual("Chewbacca", context.Champions.First().Name); + } + } + + + [TestMethod] + public void TestUpdate() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(databaseName: "Modify_Test_database") + .Options; + + //prepares the database with one instance of the context + using (var context = new LoLDbContext(options)) + { + ChampionEntity chewie = new ChampionEntity{ Name = "Chewbacca", Bio = "ewa", Icon = "" }; + ChampionEntity yoda = new ChampionEntity{ Name = "Yoda", Bio = "wewo", Icon = "" }; + ChampionEntity ewok = new ChampionEntity{ Name = "Ewok", Bio = "", Icon = "" }; + + context.Add(chewie); + context.Add(yoda); + context.Add(ewok); + context.SaveChanges(); + } + + //prepares the database with one instance of the context + using (var context = new LoLDbContext(options)) + { + string BioToFind = "ew"; + Assert.AreEqual(2, context.Champions.Where(n => n.Bio.ToLower().Contains(BioToFind)).Count()); + BioToFind = "ewo"; + Assert.AreEqual(1, context.Champions.Where(n => n.Bio.ToLower().Contains(BioToFind)).Count()); + var ewok = context.Champions.Where(n => n.Bio.ToLower().Contains(BioToFind)).First(); + ewok.Bio = "Wicket"; + context.SaveChanges(); + } + + //prepares the database with one instance of the context + //using (var context = new LoLDbContext(options)) + //{ + // string NameToFind = "ew"; + // Assert.AreEqual(1, context.Champions.Where(n => n.Bio.ToLower().Contains(NameToFind)).Count()); + // NameToFind = "wick"; + // Assert.AreEqual(1, context.Champions.Where(n => n.Bio.ToLower().Contains(NameToFind)).Count()); + //} + } + } +} diff --git a/Sources/EF_UT/Usings.cs b/Sources/EF_UT/Usings.cs new file mode 100644 index 0000000..ab67c7e --- /dev/null +++ b/Sources/EF_UT/Usings.cs @@ -0,0 +1 @@ +global using Microsoft.VisualStudio.TestTools.UnitTesting; \ No newline at end of file diff --git a/Sources/EntityFramework/ChampionEntity.cs b/Sources/EntityFramework/ChampionEntity.cs new file mode 100644 index 0000000..c090b08 --- /dev/null +++ b/Sources/EntityFramework/ChampionEntity.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Collections.ObjectModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EntityFramework +{ + [Table("Champion")] + public class ChampionEntity + { + //[Key] + //[DatabaseGenerated(DatabaseGeneratedOption.Identity)] + //public int Id { get; set; } + + [Key] + [MaxLength(50)] + public string Name { get; set; } + + + [MaxLength(500)] + [Column("Bio", TypeName = "string")] + public string Bio { get; set; } + + [Required] + public string Icon { get; set; } + + //public ImmutableHashSet Skills => skills.ToImmutableHashSet(); + //private HashSet skills = new HashSet(); + + public ICollection Skills { get; set; } = new Collection(); + + //public ReadOnlyCollection Skins { get; private set; } + //private List skins = new(); + + public ICollection skins { get; set; } = new Collection(); + + //public LargeImageEntity? Image { get; set; } ====> voir pour faire "plus propre" => créé une table pour l'entity Largeimage + public string? Image { get; set; } + + // Pour le many to many Champion *<---->* RunePage + public ICollection RunePageEntities{ get; set; } + + + + /// + /// pas besoin de constructeur ! (sans lui, il est possible d'utiliser la syntaxe utilisé dans le stubbedbDBCOntext) + /// + /// + //public ChampionEntity(string name,string bio,string icon) { + // this.Name = name; + // this.Bio = bio; + // this.Icon = icon; + // Skills= new List(); + // //Skins = new ReadOnlyCollection(skins); + //} + + public override string ToString() + { + return Name; + } + + + + public void AddSkill(SkillEntity skill) + => Skills.Add(skill); + + public void RemoveSkill(SkillEntity skill) + => Skills.Remove(skill); + + public bool AddSkin(SkinEntity skin) + { + if (skins.Contains(skin)) + return false; + skins.Add(skin); + return true; + } + + + } +} diff --git a/Sources/EntityFramework/EntityFramework.csproj b/Sources/EntityFramework/EntityFramework.csproj new file mode 100644 index 0000000..358fe36 --- /dev/null +++ b/Sources/EntityFramework/EntityFramework.csproj @@ -0,0 +1,33 @@ + + + + Exe + net6.0 + enable + enable + $(MSBuildProjectDirectory) + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/Sources/EntityFramework/EnumCategory.cs b/Sources/EntityFramework/EnumCategory.cs new file mode 100644 index 0000000..8276ed2 --- /dev/null +++ b/Sources/EntityFramework/EnumCategory.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EntityFramework +{ + public enum EnumCategory + { + Major, + Minor1, + Minor2, + Minor3, + OtherMinor1, + OtherMinor2 + } +} diff --git a/Sources/EntityFramework/EnumChampionClass.cs b/Sources/EntityFramework/EnumChampionClass.cs new file mode 100644 index 0000000..b8a039f --- /dev/null +++ b/Sources/EntityFramework/EnumChampionClass.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EntityFramework +{ + public enum ChampionClass + { + Unknown, + Assassin, + Fighter, + Mage, + Marksman, + Support, + Tank + } +} diff --git a/Sources/EntityFramework/EnumRuneFamily.cs b/Sources/EntityFramework/EnumRuneFamily.cs new file mode 100644 index 0000000..cbeacc0 --- /dev/null +++ b/Sources/EntityFramework/EnumRuneFamily.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EntityFramework +{ + public enum EnumRuneFamily + { + Unknown, + Precision, + Domination + } +} diff --git a/Sources/EntityFramework/EnumSkillType.cs b/Sources/EntityFramework/EnumSkillType.cs new file mode 100644 index 0000000..f8f56f8 --- /dev/null +++ b/Sources/EntityFramework/EnumSkillType.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EntityFramework +{ + public enum SkillType + { + Unknown, + Basic, + Passive, + Ultimate + } +} diff --git a/Sources/EntityFramework/LargeImageEntity.cs b/Sources/EntityFramework/LargeImageEntity.cs new file mode 100644 index 0000000..b925a83 --- /dev/null +++ b/Sources/EntityFramework/LargeImageEntity.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EntityFramework +{ + + public class LargeImageEntity + { + public int Id { get; set; } + public string Base64 { get; set; } + + //public LargeImageEntity(string base64) + //{ + // Base64 = base64; + //} + } +} diff --git a/Sources/EntityFramework/LoLDBContextWithStub.cs b/Sources/EntityFramework/LoLDBContextWithStub.cs new file mode 100644 index 0000000..7379162 --- /dev/null +++ b/Sources/EntityFramework/LoLDBContextWithStub.cs @@ -0,0 +1,25 @@ +using EntityFramework.Mapper; +using Microsoft.EntityFrameworkCore; +using StubLib; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EntityFramework +{ + public class LoLDBContextWithStub : LoLDbContext + { + protected override async void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + var stub = new StubData.ChampionsManager(new StubData()); + var list = await stub.GetItems(0, await stub.GetNbItems()); + modelBuilder.Entity().HasData( + list.Select(champion => champion.ToEntity()) + ); + } + } +} diff --git a/Sources/EntityFramework/LoLDbContext.cs b/Sources/EntityFramework/LoLDbContext.cs new file mode 100644 index 0000000..042b646 --- /dev/null +++ b/Sources/EntityFramework/LoLDbContext.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; + +namespace EntityFramework +{ + public class LoLDbContext : DbContext + { + public DbSet Champions { get; set; } + + public DbSet Skins { get; set; } + + public DbSet Image { get; set; } + + + public DbSet Rune { get; set; } + + public DbSet RunePage { get; set; } + + public LoLDbContext() + { } + + public LoLDbContext(DbContextOptions options) + : base(options) + { } + + + protected override void OnConfiguring(DbContextOptionsBuilder options) + { + if (!options.IsConfigured) + { + options.UseSqlite("Data Source=champion.db"); + } + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().HasKey(entity => entity.Name); + modelBuilder.Entity().ToTable("Champions"); + + //modelBuilder.Entity().Property(entity => entity.Id) + // .ValueGeneratedOnAdd(); + + modelBuilder.Entity().Property(entity => entity.Name) + .IsRequired() + .HasMaxLength(50); + + modelBuilder.Entity().Property(entity => entity.Bio) + .HasMaxLength(500) + .HasColumnName("Bio") + .HasColumnType("string"); + + modelBuilder.Entity().Property(entity => entity.Icon) + .IsRequired(); + + + + /// One to many + /// ChampionEntity 1 ---> * SkinEntity + //création de la table Skin + modelBuilder.Entity().HasKey(skin => skin.Name); //définition de la clé primaire + modelBuilder.Entity().Property(skin => skin.Name) + .ValueGeneratedOnAdd(); //définition du mode de génération de la clé : génération à l'insertion + + // Add the shadow property to the model + modelBuilder.Entity() + .Property("ChampionEntityForeignKey"); + + // Use the shadow property as a foreign key + modelBuilder.Entity() + .HasOne(skin => skin.Champion) + .WithMany(champion => champion.skins) + .HasForeignKey("ChampionEntityForeignKey"); + + + + + + // Many to Many ChampionEntity - RunePageEntity + modelBuilder.Entity().HasKey(entity => entity.Name); + modelBuilder.Entity().HasKey(entity => entity.Name); + modelBuilder.Entity().ToTable("RunePage"); + + + // Use the shadow property as a foreign key + modelBuilder.Entity() + .HasMany(r => r.Champion) + .WithMany(c => c.RunePageEntities); + //.HasForeignKey("AlbumForeignKey"); + + modelBuilder.Entity() + .HasMany(c => c.RunePageEntities) + .WithMany(r => r.Champion); + //.HasForeignKey("AlbumForeignKey"); + } + } +} diff --git a/Sources/EntityFramework/Manager/EFDataManager.Champions.cs b/Sources/EntityFramework/Manager/EFDataManager.Champions.cs new file mode 100644 index 0000000..689959b --- /dev/null +++ b/Sources/EntityFramework/Manager/EFDataManager.Champions.cs @@ -0,0 +1,186 @@ +using EntityFramework.Mapper; +using Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + +namespace EntityFramework.Manager +{ + public partial class EFDataManager + { + public class ChampionsManager : IChampionsManager + { + private readonly EFDataManager parent; + + public ChampionsManager(EFDataManager parent) + { + this.parent = parent; + } + + public async Task AddItem(Champion? item) + { + using(var context = new LoLDBContextWithStub()) + { + if (item != null) + { + + context.Add(item.ToEntity()); + context.SaveChanges(); + return item; + } + else + { + throw new Exception(); + } + } + } + + public async Task DeleteItem(Champion? item) + { + using (var context = new LoLDBContextWithStub()) + { + var champ = context.Champions.Select(c => c == item.ToEntity()); + + if(champ.Count()<1) + { + return false; + } + context.Champions.Remove(item.ToEntity()); + context.SaveChanges(); + return true; + + } + } + + public async Task> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false) + { + using(var context = new LoLDBContextWithStub() ) + { + var champ = context.Champions.ToArray(); + if (descending == false) + { + return champ.ToList().Skip(index * count).Take(count).Select(c => c.ToChampion()).OrderBy(c => c.Name); + } + else + { + return champ.ToList().Skip(index * count).Take(count).Select(c => c.ToChampion()).OrderByDescending(c => c.Name); + } + } + } + + public Task> GetItemsByCharacteristic(string charName, int index, int count, string? orderingPropertyName = null, bool descending = false) + { + throw new NotImplementedException(); + } + + public Task> GetItemsByClass(Model.ChampionClass championClass, int index, int count, string? orderingPropertyName = null, bool descending = false) + { + throw new NotImplementedException(); + } + + public async Task> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false) + { + using (var context = new LoLDBContextWithStub()) + { + var champ = context.Champions.Where(c => c.Name.Contains(substring)).AsEnumerable(); + if (descending == false) + { + return champ.Select(c => c.ToChampion()).ToList().Skip(index * count).Take(count).OrderBy(c=> c.Name); + + } + else + { + return champ.Select(c => c.ToChampion()).ToList().Skip(index*count).Take(count).OrderByDescending(c => c.Name); + + } + + + + } + } + + public Task> GetItemsByRunePage(RunePage? runePage, int index, int count, string? orderingPropertyName = null, bool descending = false) + { + throw new NotImplementedException(); + } + + public Task> GetItemsBySkill(Skill? skill, int index, int count, string? orderingPropertyName = null, bool descending = false) + { + throw new NotImplementedException(); + } + + public async Task> GetItemsBySkill(string skill, int index, int count, string? orderingPropertyName = null, bool descending = false) + { + using(var context = new LoLDBContextWithStub()) + { + var champ = context.Champions.Where(c => c.Skills.Any(c => c.Name.Contains(skill))); + if (descending.Equals(false)) + { + return champ.Select(c=> c.ToChampion()).ToList().Skip(index * count).Take(count).OrderBy(c => c.Name); + + } + else + { + return champ.Select(c => c.ToChampion()).ToList().Skip(index * count).Take(count).OrderByDescending(c => c.Name); + } + } + } + + public async Task GetNbItems() + { + using(var context = new LoLDBContextWithStub()) + { + return context.Champions.Count(); + } + } + + public Task GetNbItemsByCharacteristic(string charName) + { + throw new NotImplementedException(); + } + + public Task GetNbItemsByClass(Model.ChampionClass championClass) + { + throw new NotImplementedException(); + } + + public Task GetNbItemsByName(string substring) + { + throw new NotImplementedException(); + } + + public Task GetNbItemsByRunePage(RunePage? runePage) + { + throw new NotImplementedException(); + } + + public Task GetNbItemsBySkill(Skill? skill) + { + throw new NotImplementedException(); + } + + public Task GetNbItemsBySkill(string skill) + { + throw new NotImplementedException(); + } + + public async Task UpdateItem(Champion? oldItem, Champion? newItem) + { + using(var context = new LoLDBContextWithStub()) + { + if (oldItem != null && newItem != null) + { + var champ = context.Champions.Where(c => c == oldItem.ToEntity()).First(); + champ = newItem.ToEntity(); + context.SaveChanges(); + return newItem; + } + else { throw new Exception(); } + } + } + } + } +} diff --git a/Sources/EntityFramework/Manager/EFDataManager.Skins.cs b/Sources/EntityFramework/Manager/EFDataManager.Skins.cs new file mode 100644 index 0000000..bed5678 --- /dev/null +++ b/Sources/EntityFramework/Manager/EFDataManager.Skins.cs @@ -0,0 +1,85 @@ +using EntityFramework.Mapper; +using Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EntityFramework.Manager +{ + public partial class EFDataManager + { + public class SkinsManager : ISkinsManager + { + private readonly EFDataManager parent; + + public SkinsManager(EFDataManager parent) + { + this.parent = parent; + } + + public Task AddItem(Skin? item) + { + throw new NotImplementedException(); + } + + public Task DeleteItem(Skin? item) + { + throw new NotImplementedException(); + } + + public Task> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false) + { + throw new NotImplementedException(); + } + + public async Task> GetItemsByChampion(Champion? champion, int index, int count, string? orderingPropertyName = null, bool descending = false) + { + using (var context = new LoLDBContextWithStub()) + { + var skins = context.Skins.Where(c => c.Champion.Equals(champion)).ToList(); + + if (descending == false) + { + return skins.Select(c => c.ToSkin()).ToList().Skip(index * count).Take(count).OrderBy(c => c.Name); + + } + else + { + return skins.Select(c => c.ToSkin()).ToList().Skip(index * count).Take(count).OrderByDescending(c => c.Name); + + } + } + } + + public Task> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false) + { + throw new NotImplementedException(); + } + + public Task GetNbItems() + { + throw new NotImplementedException(); + } + + public async Task GetNbItemsByChampion(Champion? champion) + { + using(var context = new LoLDBContextWithStub()) + { + return context.Skins.Where(c => c.Champion.Equals(champion.ToEntity())).Count(); + } + } + + public Task GetNbItemsByName(string substring) + { + throw new NotImplementedException(); + } + + public Task UpdateItem(Skin? oldItem, Skin? newItem) + { + throw new NotImplementedException(); + } + } + } +} diff --git a/Sources/EntityFramework/Manager/EFDataManager.cs b/Sources/EntityFramework/Manager/EFDataManager.cs new file mode 100644 index 0000000..5c5d677 --- /dev/null +++ b/Sources/EntityFramework/Manager/EFDataManager.cs @@ -0,0 +1,25 @@ +using Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EntityFramework.Manager +{ + public partial class EFDataManager : IDataManager + { + public EFDataManager() { + ChampionsMgr = new ChampionsManager(this); + SkinsMgr = new SkinsManager(this); + } + public IChampionsManager ChampionsMgr { get; } + + public ISkinsManager SkinsMgr { get; } + + public IRunesManager RunesMgr { get; } + + public IRunePagesManager RunePagesMgr { get; } + + } +} diff --git a/Sources/EntityFramework/Mapper/ChampionMapper.cs b/Sources/EntityFramework/Mapper/ChampionMapper.cs new file mode 100644 index 0000000..da146b2 --- /dev/null +++ b/Sources/EntityFramework/Mapper/ChampionMapper.cs @@ -0,0 +1,22 @@ +using Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EntityFramework.Mapper +{ + public static class ChampionMapper + { + public static ChampionEntity ToEntity(this Champion champion) { + return new ChampionEntity { Name = champion.Name, Bio = champion.Bio, Icon = champion.Icon }; + } + + public static Champion ToChampion(this ChampionEntity champion) + { + return new Champion(champion.Name,bio: champion.Bio,icon: champion.Icon); + } + + } +} diff --git a/Sources/EntityFramework/Mapper/SkinMapper.cs b/Sources/EntityFramework/Mapper/SkinMapper.cs new file mode 100644 index 0000000..3ce09ff --- /dev/null +++ b/Sources/EntityFramework/Mapper/SkinMapper.cs @@ -0,0 +1,24 @@ +using Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EntityFramework.Mapper +{ + public static class SkinMapper + { + public static SkinEntity ToEntity(this Skin skin) + { + return new SkinEntity { Champion = skin.Champion.ToEntity(), Description = skin.Description, Icon = skin.Icon, Image = skin.Image.Base64, Name = skin.Name, Price = skin.Price }; + } + + public static Skin ToSkin(this SkinEntity entity) + { + return new Skin(entity.Name,entity.Champion.ToChampion(),price: entity.Price,icon: entity.Icon, image: entity.Image,description: entity.Description); + } + + + } +} diff --git a/Sources/EntityFramework/Program.cs b/Sources/EntityFramework/Program.cs new file mode 100644 index 0000000..56915f8 --- /dev/null +++ b/Sources/EntityFramework/Program.cs @@ -0,0 +1,132 @@ +// See https://aka.ms/new-console-template for more information +using EntityFramework; +using EntityFramework.Manager; +using Microsoft.EntityFrameworkCore; +using Model; +using System.Buffers.Text; + +using ( var context = new LoLDbContext()) +{ + //context.Add(new ChampionEntity{ Name = "test", Bio = "test", Icon = "test" } ); + context.SaveChanges(); + + ChampionEntity champ = context.Find("Akali"); + + if( champ != null) + { + Console + .WriteLine(champ.ToString()); + + } + else + { + Console.WriteLine("Not Found"); + } + + //Test BDD Skills + ChampionEntity champSkill = new ChampionEntity { Name="nomSkill", Bio="bioSkill", Icon="iconSkill" }; + + //SkillEntity s1 = new SkillEntity { Name = "Skill1", Description = "desc", Type = SkillType.Unknown }; + SkillEntity s2 = new SkillEntity { Name="Skill2", Description="desc2", Type= EntityFramework.SkillType.Ultimate }; + SkillEntity s3 = new SkillEntity { Name = "Skill3", Description = "desc3", Type = EntityFramework.SkillType.Passive }; + + champSkill.AddSkill(new SkillEntity { Name = "Skill1", Description = "desc", Type = EntityFramework.SkillType.Unknown }); + champSkill.AddSkill(s2); + champSkill.AddSkill(s3); + + context.Add(champSkill); + + context.SaveChanges(); + +IDataManager dataManager = new EFDataManager(); +IChampionsManager championsManager = dataManager.ChampionsMgr; +IEnumerable champions = await championsManager.GetItemsByName("A", 0, 1); +Console.WriteLine(champions.First().Name); + + +//using ( var context = new LoLDbContext()) +//{ +// //context.Add(new ChampionEntity{ Name = "test", Bio = "test", Icon = "test" } ); +// context.SaveChanges(); + +// ChampionEntity champ = context.Find("Akali"); + +// if( champ != null) +// { +// Console +// .WriteLine(champ.ToString()); + +// } +// else +// { +// Console.WriteLine("Not Found"); +// } + +// //Test BDD Skills +// ChampionEntity champSkill = new ChampionEntity { Name="nomSkill", Bio="bioSkill", Icon="iconSkill" }; + +// //SkillEntity s1 = new SkillEntity { Name = "Skill1", Description = "desc", Type = SkillType.Unknown }; +// SkillEntity s2 = new SkillEntity { Name="Skill2", Description="desc2", Type=SkillType.Ultimate }; +// SkillEntity s3 = new SkillEntity { Name = "Skill3", Description = "desc3", Type = SkillType.Passive }; + +// champSkill.AddSkill(new SkillEntity { Name = "Skill1", Description = "desc", Type = SkillType.Unknown }); +// champSkill.AddSkill(s2); +// champSkill.AddSkill(s3); + +// context.Add(champSkill); + +// context.SaveChanges(); + + +// //OneToMany +// Console.WriteLine("Champions : "); +// foreach (var champi in context.Champions.Include(a => a.skins)) +// { +// Console.WriteLine($"\t{champi.Name} : {champi.Bio}"); +// foreach (var s in champi.skins) +// { +// Console.WriteLine($"\t\t{s.Name}"); +// } +// } + +// Console.WriteLine(); + +// Console.WriteLine("Skin :"); +// foreach (var s in context.Skins) +// { +// Console.WriteLine($"\t{s.Name}: {s.Description} (Champion : {s.Champion.Name})"); +// } + + + var r1 = new RuneEntity { Name = "Rune1", Description = "aaa", Family = EnumRuneFamily.Domination, Image = new LargeImage("base") }; + var r2 = new RuneEntity { Name = "Rune2", Description = "aaa", Family = EnumRuneFamily.Domination, Image = new LargeImage("base") }; + var corichard = new ChampionEntity { Name = "Corichard", Bio = "biobio", Icon = "Icon.png" }; + var pintrand = new ChampionEntity { Name = "Pintrand", Bio = "biobio", Icon = "Icon.png" }; + var rp1 = new RunePageEntity { Name = "RP1", Rune = new RuneEntity { Name = "aa", Description = "aaa", Family = EnumRuneFamily.Domination, Image = new LargeImage("base") }, Champion = new List { corichard } }; + var rp2 = new RunePageEntity { Name = "RP2", Rune = new RuneEntity{ Name = "aaa", Description = "aaa", Family = EnumRuneFamily.Domination, Image = new LargeImage("base") }, Champion = new List { pintrand } }; + + context.Rune.AddRange(new[] { r1, r2 }); + context.Champions.AddRange(new[] { corichard, pintrand }); + context.RunePage.AddRange(new[] { rp1, rp2 }); + context.SaveChanges(); +} +// Console.WriteLine("\nAjout d'un Champion et 6 Skins...\n"); + +// ChampionEntity captainMarvel = new ChampionEntity { Name = "Captain Marvel", Bio="Mais que fait un avenger ici ??", Icon="Icon.png"}; +// SkinEntity[] skins = { new SkinEntity {Name = "La Fiesta", Champion = captainMarvel}, +// new SkinEntity { Name = "Five Hundred Miles High", Champion = captainMarvel }, +// new SkinEntity { Name = "Captain Marvel", Champion = captainMarvel }, +// new SkinEntity { Name = "Time's Lie", Champion = captainMarvel }, +// new SkinEntity { Name = "Lush Life", Champion = captainMarvel }, +// new SkinEntity { Name = "Day Waves", Champion = captainMarvel } +// }; +// foreach (var s in skins) +// { +// captainMarvel.skins.Add(s); +// } + +// context.Add(captainMarvel); +// context.SaveChanges(); + + +//} diff --git a/Sources/EntityFramework/RuneEntity.cs b/Sources/EntityFramework/RuneEntity.cs new file mode 100644 index 0000000..c9de7da --- /dev/null +++ b/Sources/EntityFramework/RuneEntity.cs @@ -0,0 +1,24 @@ +using Model; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EntityFramework +{ + //[Table("Rune")] + public class RuneEntity + { + [Key] + public string Name; + + public string Description; + + public EnumRuneFamily Family; + + public LargeImage Image; + } +} diff --git a/Sources/EntityFramework/RunePageEntity.cs b/Sources/EntityFramework/RunePageEntity.cs new file mode 100644 index 0000000..842806b --- /dev/null +++ b/Sources/EntityFramework/RunePageEntity.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static Model.RunePage; + +namespace EntityFramework +{ + public class RunePageEntity + { + [Key] + public string Name { get; set; } + + public RuneEntity? Rune { get; set; } + + //? voir si cela pause probleme + public Dictionary Dico = new Dictionary(); + + // Pour le many to many Champion *<---->* RunePage + public ICollection Champion{ get; set; } + + + + public void CheckRunes(EnumCategory newRuneCategory){} + public void CheckFamilies(EnumCategory cat1, EnumCategory cat2){} + public void UpdateMajorFamily(EnumCategory minor, bool expectedValue){} + } +} diff --git a/Sources/EntityFramework/SkillEntity.cs b/Sources/EntityFramework/SkillEntity.cs new file mode 100644 index 0000000..505a427 --- /dev/null +++ b/Sources/EntityFramework/SkillEntity.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EntityFramework +{ + + public class SkillEntity + { + public SkillType Type { get; set; } + + [Key] + public string Name { get; set; } + //public string Name + //{ + // get => name; + // private init + // { + // if (string.IsNullOrWhiteSpace(value)) + // { + // throw new ArgumentException("a Skill needs a name"); + // } + // name = value; + // } + //} + //private readonly string name = null!; + + public string Description { get; set; } + //public string Description + //{ + // get => description; + // set + // { + // if (string.IsNullOrWhiteSpace(value)) + // { + // description = ""; + // return; + // } + // description = value; + // } + //} + //private string description = ""; + + //public SkillEntity(string Name, string Description, SkillType Type) { + // this.name = Name; + // this.Description = Description; + // this.Type = Type; + //} + } +} diff --git a/Sources/EntityFramework/SkinEntity.cs b/Sources/EntityFramework/SkinEntity.cs new file mode 100644 index 0000000..e9650b3 --- /dev/null +++ b/Sources/EntityFramework/SkinEntity.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EntityFramework +{ + public class SkinEntity //ONE TO MANY + { + + public string? Name { get; set; } + + public string? Description { get; set; } + + //public string Name + //{ + // get => name; + // private init + // { + // if (string.IsNullOrWhiteSpace(value)) + // { + // throw new ArgumentException("A skin must have a name"); + // } + // name = value; + // } + //} + //private readonly string name = null!; + + //public string Description + //{ + // get => description; + // set + // { + // if (string.IsNullOrWhiteSpace(value)) + // { + // description = ""; + // return; + // } + // description = value; + // } + //} + //private string description = ""; + + public string Icon { get; set; } = ""; + + + //public LargeImageEntity Image { get; set; } + public string? Image { get; set; } + + + public float Price { get; set; } + public ChampionEntity Champion { get; set; } + + + //public ChampionEntity Champion + //{ + // get => champion; + // private init + // { + // if (value == null) + // throw new ArgumentNullException("A skill can't have a null champion"); + // champion = value; + // } + //} + //private readonly ChampionEntity champion = null!; + + //public SkinEntity(string name, ChampionEntity champion, float price = 0.0f, string icon = "", string image = "", string description = "") + //{ + // Name = name; + // Champion = champion; + // //Champion.AddSkin(this); + // Price = price; + // Icon = icon; + // Image = new LargeImageEntity(image); + // Description = description; + //} + } +} diff --git a/Sources/EntityFramework/StubbedContext.cs b/Sources/EntityFramework/StubbedContext.cs new file mode 100644 index 0000000..3731035 --- /dev/null +++ b/Sources/EntityFramework/StubbedContext.cs @@ -0,0 +1,51 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EntityFramework +{ + public class StubbedContext : LoLDbContext + { + //protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + //{ + // optionsBuilder.EnableSensitiveDataLogging(); + //} + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + ChampionEntity corichard = new ChampionEntity { Name = "Corichard", Bio = "biobiobiobio", Icon = "/a/a/a/a" }; + ChampionEntity pintrand = new ChampionEntity { Name = "Pintrand", Bio = "mimimimimim", Icon = "/small.png" }; + + RuneEntity r1 = new RuneEntity { Name = "FirstRune", Description = "desc", Family = EnumRuneFamily.Domination }; + RuneEntity r2 = new RuneEntity { Name = "SecondRune", Description = "desc", Family = EnumRuneFamily.Unknown }; + + //ChampionEntity corichard = new ChampionEntity() { Name = "Corichard", Bio = "biobiobiobio", Icon = "/a/a/a/a", Image = new LargeImageEntity { Base64 = "base" } }; + //ChampionEntity pintrand = new ChampionEntity { Name = "Pintrand", Bio = "mimimimimim", Icon = "/small.png", Image = new LargeImageEntity { Base64 = "base" } }; + + modelBuilder.Entity().HasData(corichard, pintrand); + + modelBuilder.Entity().HasData(new { Name = "aaaa", ChampionEntityForeignKey = "Corichard", Description = "So What", Icon="/Icon.png", Price=10.0f }, + new { Name = "skin", ChampionEntityForeignKey = "Corichard", Description = "So What", Icon = "/Icon.png", Price = 10.0f }, + new { Name = "bo", ChampionEntityForeignKey = "Corichard", Description = "So What", Icon = "/Icon.png", Price = 10.0f }, + new { Name = "Joulie", ChampionEntityForeignKey = "Corichard", Description = "So What", Icon = "/Icon.png", Price = 10.0f }, + new { Name = "Radiance", ChampionEntityForeignKey = "Corichard", Description = "So What", Icon = "/Icon.png", Price = 10.0f }, + new { Name = "void", ChampionEntityForeignKey = "Corichard", Description = "So What", Icon = "/Icon.png", Price = 10.0f }, + new { Name = "Radiance", ChampionEntityForeignKey = "Pintrand", Description = "So What", Icon = "/Icon.png", Price = 10.0f }, + new { Name = "void", ChampionEntityForeignKey = "Pintrand", Description = "So What", Icon = "/Icon.png", Price = 10.0f }, + new { Name = "DarkTheme", ChampionEntityForeignKey = "Pintrand", Description = "So What", Icon = "/Icon.png", Price = 10.0f }, + new { Name = "gold", ChampionEntityForeignKey = "Pintrand", Description = "So What", Icon = "/Icon.png", Price = 10.0f }, + new { Name = "ruby", ChampionEntityForeignKey = "Pintrand", Description = "So What", Icon = "/Icon.png", Price = 10.0f } + ); + + modelBuilder.Entity().HasData(new { Name = "RP1", Rune = r1, Champion = corichard}, + new { Name = "RP2", Rune = r2, Champion = pintrand} + ); + } + + } +} diff --git a/Sources/HttpClient/HttpClient.csproj b/Sources/HttpClient/HttpClient.csproj new file mode 100644 index 0000000..9e4e01f --- /dev/null +++ b/Sources/HttpClient/HttpClient.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + + + diff --git a/Sources/HttpClient/HttpClientManager.Champion.cs b/Sources/HttpClient/HttpClientManager.Champion.cs new file mode 100644 index 0000000..9ffc79b --- /dev/null +++ b/Sources/HttpClient/HttpClientManager.Champion.cs @@ -0,0 +1,128 @@ +using Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http.Json; +using System.Reflection; +using System.Reflection.Metadata; +using System.Runtime.ConstrainedExecution; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace HttpClient +{ + public partial class HttpClientManager + { + public class ChampionManager : IChampionsManager + { + + + private readonly HttpClientManager parent; + + private System.Net.Http.HttpClient httpc; + + public string BaseAddress; + + + public ChampionManager(HttpClientManager parent, System.Net.Http.HttpClient httpc) { + + this.httpc = httpc; + this.parent = parent; + } + + public async Task AddItem(Champion? item) //return le champion ajouté, null sinon ? + { + if(item==null) throw new ArgumentNullException("item is null"); + var response = await httpc.PostAsJsonAsync("/Champion?Name = " + item.Name, item); + + return response.IsSuccessStatusCode ? item : null; + } + + public async Task DeleteItem(Champion? item) + { + HttpResponseMessage response = await httpc.DeleteAsync("/Champion?Name=" + item.Name); + return response.IsSuccessStatusCode; + } + + public Task> GetItems(int index, int count, string? orderingPropertyName = null, bool descending = false) + { + return httpc.GetFromJsonAsync>("/Champion?index="+index+"&size="+count); + } + + + + + + public Task> GetItemsByCharacteristic(string charName, int index, int count, string? orderingPropertyName = null, bool descending = false) + { + throw new NotImplementedException(); + } + + public Task> GetItemsByClass(ChampionClass championClass, int index, int count, string? orderingPropertyName = null, bool descending = false) + { + throw new NotImplementedException(); + } + + public Task> GetItemsByName(string substring, int index, int count, string? orderingPropertyName = null, bool descending = false) + { + return httpc.GetFromJsonAsync>("/Champion?name="+substring+"&index=" + index + "&size=" + count); + } + + public Task> GetItemsByRunePage(RunePage? runePage, int index, int count, string? orderingPropertyName = null, bool descending = false) + { + throw new NotImplementedException(); + } + + public Task> GetItemsBySkill(Skill? skill, int index, int count, string? orderingPropertyName = null, bool descending = false) + { + throw new NotImplementedException(); + } + + public Task> GetItemsBySkill(string skill, int index, int count, string? orderingPropertyName = null, bool descending = false) + { + throw new NotImplementedException(); + } + + public Task GetNbItems() + { + throw new NotImplementedException(); + } + + public Task GetNbItemsByCharacteristic(string charName) + { + throw new NotImplementedException(); + } + + public Task GetNbItemsByClass(ChampionClass championClass) + { + throw new NotImplementedException(); + } + + public Task GetNbItemsByName(string substring) + { + throw new NotImplementedException(); + } + + public Task GetNbItemsByRunePage(RunePage? runePage) + { + throw new NotImplementedException(); + } + + public Task GetNbItemsBySkill(Skill? skill) + { + throw new NotImplementedException(); + } + + public Task GetNbItemsBySkill(string skill) + { + throw new NotImplementedException(); + } + + public Task UpdateItem(Champion? oldItem, Champion? newItem) + { + throw new NotImplementedException(); + } + } + } +} diff --git a/Sources/HttpClient/HttpClientManager.cs b/Sources/HttpClient/HttpClientManager.cs new file mode 100644 index 0000000..49ddb70 --- /dev/null +++ b/Sources/HttpClient/HttpClientManager.cs @@ -0,0 +1,29 @@ +using Model; + +namespace HttpClient +{ + public partial class HttpClientManager : IDataManager + { + + + public System.Net.Http.HttpClient httpC { get; set; } = new System.Net.Http.HttpClient(); + + public string BaseAddress; + + + public HttpClientManager() { + ChampionsMgr = new ChampionManager(this, httpC); + httpC.BaseAddress = new Uri("https://localhost:7144/api/"); + + } + + public ISkinsManager SkinsMgr => throw new NotImplementedException(); + + public IRunesManager RunesMgr => throw new NotImplementedException(); + + public IRunePagesManager RunePagesMgr => throw new NotImplementedException(); + + public IChampionsManager ChampionsMgr { get; set; } + + } +} diff --git a/Sources/LeagueOfLegends.sln b/Sources/LeagueOfLegends.sln index 5339e1f..007e972 100644 --- a/Sources/LeagueOfLegends.sln +++ b/Sources/LeagueOfLegends.sln @@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "Model\Model.csproj EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C76D0C23-1FFA-4963-93CD-E12BD643F030}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleTests", "Tests\ConsoleTests\ConsoleTests.csproj", "{1889FA6E-B7C6-416E-8628-9449FB9070B9}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "Shared\Shared.csproj", "{3B720C0C-53FE-4642-A2DB-87FD8634CD74}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Stub", "Stub", "{2C607793-B163-4731-A4D1-AFE8A7C4C170}" @@ -17,9 +15,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StubLib", "StubLib\StubLib. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "API_LoL", "API_LoL\API_LoL.csproj", "{BE86E19B-3461-4EF6-8871-94E6CCB75928}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApiTests", "ApiTests\ApiTests.csproj", "{AE65F7E0-FA95-4D64-938D-78DB6C905F7B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DTO", "DTO\DTO.csproj", "{E39C3FBC-DE5E-4DAF-945A-98CE4ADE54D9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EntityFramework", "EntityFramework\EntityFramework.csproj", "{23483395-5091-4956-822F-17234E8C9E5C}" + ProjectSection(ProjectDependencies) = postProject + {2960F9BA-49DE-494D-92E3-CE5A794BA1A9} = {2960F9BA-49DE-494D-92E3-CE5A794BA1A9} + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Api_UT", "Api_UT\Api_UT.csproj", "{20A1A7DC-1E93-4506-BD32-8597A5DADD7B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EF_UT", "EF_UT\EF_UT.csproj", "{74F469C3-A94A-4507-9DC7-7DBADCD18173}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DTO", "DTO\DTO.csproj", "{E39C3FBC-DE5E-4DAF-945A-98CE4ADE54D9}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpClient", "HttpClient\HttpClient.csproj", "{DE2E40D5-1B4D-491C-B7E7-4E91B32DB93F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -31,10 +38,6 @@ Global {2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Debug|Any CPU.Build.0 = Debug|Any CPU {2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Release|Any CPU.ActiveCfg = Release|Any CPU {2960F9BA-49DE-494D-92E3-CE5A794BA1A9}.Release|Any CPU.Build.0 = Release|Any CPU - {1889FA6E-B7C6-416E-8628-9449FB9070B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1889FA6E-B7C6-416E-8628-9449FB9070B9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1889FA6E-B7C6-416E-8628-9449FB9070B9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1889FA6E-B7C6-416E-8628-9449FB9070B9}.Release|Any CPU.Build.0 = Release|Any CPU {3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Debug|Any CPU.Build.0 = Debug|Any CPU {3B720C0C-53FE-4642-A2DB-87FD8634CD74}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -47,22 +50,34 @@ Global {BE86E19B-3461-4EF6-8871-94E6CCB75928}.Debug|Any CPU.Build.0 = Debug|Any CPU {BE86E19B-3461-4EF6-8871-94E6CCB75928}.Release|Any CPU.ActiveCfg = Release|Any CPU {BE86E19B-3461-4EF6-8871-94E6CCB75928}.Release|Any CPU.Build.0 = Release|Any CPU - {AE65F7E0-FA95-4D64-938D-78DB6C905F7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AE65F7E0-FA95-4D64-938D-78DB6C905F7B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AE65F7E0-FA95-4D64-938D-78DB6C905F7B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AE65F7E0-FA95-4D64-938D-78DB6C905F7B}.Release|Any CPU.Build.0 = Release|Any CPU {E39C3FBC-DE5E-4DAF-945A-98CE4ADE54D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E39C3FBC-DE5E-4DAF-945A-98CE4ADE54D9}.Debug|Any CPU.Build.0 = Debug|Any CPU {E39C3FBC-DE5E-4DAF-945A-98CE4ADE54D9}.Release|Any CPU.ActiveCfg = Release|Any CPU {E39C3FBC-DE5E-4DAF-945A-98CE4ADE54D9}.Release|Any CPU.Build.0 = Release|Any CPU + {23483395-5091-4956-822F-17234E8C9E5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {23483395-5091-4956-822F-17234E8C9E5C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23483395-5091-4956-822F-17234E8C9E5C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23483395-5091-4956-822F-17234E8C9E5C}.Release|Any CPU.Build.0 = Release|Any CPU + {20A1A7DC-1E93-4506-BD32-8597A5DADD7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {20A1A7DC-1E93-4506-BD32-8597A5DADD7B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {20A1A7DC-1E93-4506-BD32-8597A5DADD7B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {20A1A7DC-1E93-4506-BD32-8597A5DADD7B}.Release|Any CPU.Build.0 = Release|Any CPU + {74F469C3-A94A-4507-9DC7-7DBADCD18173}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {74F469C3-A94A-4507-9DC7-7DBADCD18173}.Debug|Any CPU.Build.0 = Debug|Any CPU + {74F469C3-A94A-4507-9DC7-7DBADCD18173}.Release|Any CPU.ActiveCfg = Release|Any CPU + {74F469C3-A94A-4507-9DC7-7DBADCD18173}.Release|Any CPU.Build.0 = Release|Any CPU + {DE2E40D5-1B4D-491C-B7E7-4E91B32DB93F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DE2E40D5-1B4D-491C-B7E7-4E91B32DB93F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DE2E40D5-1B4D-491C-B7E7-4E91B32DB93F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DE2E40D5-1B4D-491C-B7E7-4E91B32DB93F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {1889FA6E-B7C6-416E-8628-9449FB9070B9} = {C76D0C23-1FFA-4963-93CD-E12BD643F030} {B01D7EF2-2D64-409A-A29A-61FB7BB7A9DB} = {2C607793-B163-4731-A4D1-AFE8A7C4C170} - {AE65F7E0-FA95-4D64-938D-78DB6C905F7B} = {C76D0C23-1FFA-4963-93CD-E12BD643F030} + {20A1A7DC-1E93-4506-BD32-8597A5DADD7B} = {C76D0C23-1FFA-4963-93CD-E12BD643F030} + {74F469C3-A94A-4507-9DC7-7DBADCD18173} = {C76D0C23-1FFA-4963-93CD-E12BD643F030} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {92F3083D-793F-4552-8A9A-0AD6534159C9} diff --git a/Sources/Model/Properties/launchSettings.json b/Sources/Model/Properties/launchSettings.json new file mode 100644 index 0000000..ed8cba2 --- /dev/null +++ b/Sources/Model/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "Model": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:49972;http://localhost:49973" + } + } +} \ No newline at end of file diff --git a/Sources/StubLib/StubData.Champions.cs b/Sources/StubLib/StubData.Champions.cs index ad19275..90a33d9 100644 --- a/Sources/StubLib/StubData.Champions.cs +++ b/Sources/StubLib/StubData.Champions.cs @@ -8,7 +8,7 @@ namespace StubLib private List champions = new() { new Champion("Akali", ChampionClass.Assassin), - new Champion("Aatrox", ChampionClass.Fighter), + new Champion("Aatrox", ChampionClass.Fighter), new Champion("Ahri", ChampionClass.Mage), new Champion("Akshan", ChampionClass.Marksman), new Champion("Bard", ChampionClass.Support), diff --git a/Sources/Tests/ConsoleTests/ConsoleTests.csproj b/Sources/Tests/ConsoleTests/ConsoleTests.csproj index 1602b94..d401cce 100644 --- a/Sources/Tests/ConsoleTests/ConsoleTests.csproj +++ b/Sources/Tests/ConsoleTests/ConsoleTests.csproj @@ -1,4 +1,4 @@ - + Exe @@ -8,6 +8,7 @@ + diff --git a/Sources/Tests/ConsoleTests/Properties/launchSettings.json b/Sources/Tests/ConsoleTests/Properties/launchSettings.json new file mode 100644 index 0000000..c8ab57c --- /dev/null +++ b/Sources/Tests/ConsoleTests/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "ConsoleTests": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:49970;http://localhost:49971" + } + } +} \ No newline at end of file diff --git a/Sources/Tests/Tests.csproj b/Sources/Tests/Tests.csproj new file mode 100644 index 0000000..01bb70b --- /dev/null +++ b/Sources/Tests/Tests.csproj @@ -0,0 +1,18 @@ + + + + net7.0 + enable + enable + + false + + + + + + + + + + diff --git a/Sources/Tests/UnitTest1.cs b/Sources/Tests/UnitTest1.cs new file mode 100644 index 0000000..872f935 --- /dev/null +++ b/Sources/Tests/UnitTest1.cs @@ -0,0 +1,10 @@ +namespace Tests; + +[TestClass] +public class UnitTest1 +{ + [TestMethod] + public void TestMethod1() + { + } +} \ No newline at end of file diff --git a/Sources/Tests/Usings.cs b/Sources/Tests/Usings.cs new file mode 100644 index 0000000..ab67c7e --- /dev/null +++ b/Sources/Tests/Usings.cs @@ -0,0 +1 @@ +global using Microsoft.VisualStudio.TestTools.UnitTesting; \ No newline at end of file