Merge branch 'master' into RuneBranch
continuous-integration/drone/push Build is failing Details

pull/36/head
Pierre Ferreira 2 years ago
commit 116d150949

@ -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

@ -0,0 +1,4 @@
[*.cs]
# CS8604: Possible null reference argument.
dotnet_diagnostic.CS8604.severity = none

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
@ -11,6 +11,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>

@ -8,6 +8,8 @@ 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
@ -21,18 +23,24 @@ namespace API_LoL.Controllers
{
public ChampionsController(IDataManager Manager) {
this._logger = LoggerFactory.Create(builder => builder.AddConsole()).CreateLogger<ChampionsController>();
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/<ChampionController>/5
[HttpGet("count")]
public async Task<IActionResult> GetCount()
{
_logger.LogInformation(message: "count returned", "Get", "/Champion/Count", 200, DateTime.Now);
return Ok(ChampionsManager.GetNbItems());
}
@ -41,6 +49,7 @@ namespace API_LoL.Controllers
{
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))
@ -48,53 +57,78 @@ namespace API_LoL.Controllers
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 { return NoContent(); }
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 { return NoContent(); }
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 { return NoContent(); }
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 { return NoContent(); }
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();
}
}
}
[HttpGet("name")]
public async Task<IActionResult> GetByName(String name)
{
if (string.IsNullOrEmpty(name)) return BadRequest();
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 { return NoContent(); }
else {
_logger.LogInformation(message: "No Champion found", "Get", "/Champion/Name", 204, "name : " + name, DateTime.Now);
return NoContent();
}
}
[HttpGet("name/skins")]
public async Task<IActionResult> GetSkinsByName(String name)
{
if (string.IsNullOrEmpty(name)) return BadRequest();
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)
{
@ -104,9 +138,16 @@ namespace API_LoL.Controllers
var skins = await SkinsManager.GetItemsByChampion(list.First(), 0, nb);
return Ok(skins.Select(skin => skin?.ToDTO()));
}
else { return NoContent(); }
else {
_logger.LogInformation(message: "No Skin found found", "Get", "/Champion/Name/Skins", 204, "name : " + name, DateTime.Now);
return NoContent(); }
}
else { return NoContent(); }
else {
_logger.LogInformation(message: "No Champion found", "Get", "/Champion/Name/Skins", 204, "name : " + name, DateTime.Now);
return NoContent();
}
}
//[HttpGet("name/skills")]
@ -134,16 +175,23 @@ namespace API_LoL.Controllers
{
if (champion == null)
{
_logger.LogError(message: "Null paramater given", "Post", "/Champion", 422, "champion : " + champion.toString, DateTime.Now);
return UnprocessableEntity();
}
else
{
var champ = await ChampionsManager.GetItemsByName(champion.Name, 0, 1);
if(champ.Count() != 0 && champ.FirstOrDefault().Name == champion.Name)
var list = await ChampionsManager.GetItemsByName(champion.Name, 0, 1);
Champion champ = list.FirstOrDefault();
if (champ != null)
{
return Conflict(champion);
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);
}
@ -153,16 +201,26 @@ namespace API_LoL.Controllers
[HttpPut("name")]
public async Task<IActionResult> Put(string name, ChampionDTO championDTO)
{
if(string.IsNullOrEmpty(name))
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 { return NoContent(); }
else {
_logger.LogInformation(message: "No champion Found", "Put", "/Champion/Name", 204, "name : " + name, "champion : " + championDTO.toString, DateTime.Now);
return NoContent();
}
}
// DELETE api/<ChampionController>/5
@ -170,11 +228,17 @@ namespace API_LoL.Controllers
public async Task<IActionResult> Delete(string name)
{
if (string.IsNullOrEmpty(name))
return BadRequest();
{
_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 { return NoContent(); }
}else {
_logger.LogInformation(message: "No champion Found", "Delete", "/Champion/Name", 204, "name : " + name, DateTime.Now);
return NoContent(); }
}
}
}

@ -3,6 +3,7 @@ using EntityFramework;
using EntityFramework.Manager;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.Extensions.Logging;
using Model;
using StubLib;

Binary file not shown.

Binary file not shown.

@ -3,6 +3,7 @@ using DTO;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.Extensions.Logging;
using Model;
using StubLib;
using System.Collections;

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\HttpClient\HttpClient.csproj" />
<ProjectReference Include="..\Model\Model.csproj" />
</ItemGroup>
</Project>

@ -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<LoLDBContextWithStub>();
var app = builder.Build();
using (var scope = app.Services.CreateScope())
{
var context = scope.ServiceProvider.GetService<LoLDBContextWithStub>();
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;
}
}
}

@ -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;
}
}
}
}
}

@ -47,7 +47,7 @@ namespace EF_UT
var ak = (await championsManager.GetItemsByName("A", 0, 1)).First();
Assert.IsNotNull(ak);
//Assert.AreEqual("Akali", ak.Name);
Assert.AreEqual("Aatrox", ak.Name);
}
}
}

Loading…
Cancel
Save