fix merge conflicts
continuous-integration/drone/push Build is passing Details

pull/27/head
Alexandre AGOSTINHO 2 years ago
commit e7ced7634d

@ -0,0 +1,71 @@
kind: pipeline
type: docker
name: default
trigger:
event:
- push
steps:
- name: build
image: mcr.microsoft.com/dotnet/sdk:7.0
volumes:
- name: docs
path: /docs
commands:
- cd MCTG/
- dotnet restore ./ConsoleApp/ConsoleApp.csproj
- dotnet restore ./Model/Model.csproj
- dotnet restore ./Tests/Model_UnitTests/Model_UnitTests.csproj
- dotnet build SAE-2.01.sln -c CI --no-restore
- dotnet publish SAE-2.01.sln -c CI --no-restore -o CI_PROJECT_DIR/build/release
- name: tests
image: mcr.microsoft.com/dotnet/sdk:7.0
commands:
- cd MCTG/
- dotnet restore ./ConsoleApp/ConsoleApp.csproj
- dotnet restore ./Model/Model.csproj
- dotnet restore ./Tests/Model_UnitTests/Model_UnitTests.csproj
- dotnet test SAE-2.01.sln -c CI --no-restore
depends_on: [ build ]
- name: code-analysis
image: hub.codefirst.iut.uca.fr/marc.chevaldonne/codefirst-dronesonarplugin-dotnet7
commands:
- cd MCTG/
- dotnet restore ./ConsoleApp/ConsoleApp.csproj
- dotnet restore ./Model/Model.csproj
- dotnet restore ./Tests/Model_UnitTests/Model_UnitTests.csproj
- dotnet sonarscanner begin /k:SAE-2.01 /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 SAE-2.01.sln -c CI --no-restore
- dotnet test SAE-2.01.sln -c CI --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 SAE-2.01.sln -c CI --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 ]
- name: generate-and-deploy-docs
image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-docdeployer
failure: ignore
volumes:
- name: docs
path: /docs
commands:
- cd Doc/doxygen
- doxygen Doxyfile
when:
branch:
- master
depends_on: [ build ]
volumes:
- name: docs
temp: {}

4
.gitignore vendored

@ -4,6 +4,10 @@
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-spacific editor config
.editorconfig
.vscode
# User-specific files
*.rsuser
*.suo

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

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Menu
{
internal interface IMenuDisplay
{
/// <summary>
/// Update the menu display in the Console.
/// </summary>
void UpdateDisplay();
/// <summary>
/// Select the next line in the menu
/// </summary>
/// <returns>The current number of the new selected line</returns>
int SelectNextLine();
/// <summary>
/// Select the previous line in the menu
/// </summary>
/// <returns>The current number of the new selected line</returns>
int SelectPrevioustLine();
}
}

@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using Model;
namespace ConsoleApp.Menu
{
/// <summary>
/// An utility to find a recipe.
/// </summary>
public class SearcherRecipe : SelectMenu<Recipe>
{
#region Attribute
private RecipeCollection _recipeOnSearch;
#endregion
#region Properties
/// <summary>
/// A collection of recipe where the title contain the search string
/// </summary>
public RecipeCollection SearchResult { get; private set; }
/// <summary>
/// The search string
/// </summary>
public string ResearchStr { get; set; }
#endregion
/// <summary>
/// Constructor of the SearcherRecipe utility.
/// </summary>
/// <param name="recipeOnSearch">The collection of recipe where to search</param>
public SearcherRecipe(RecipeCollection recipeOnSearch)
{
_recipeOnSearch = recipeOnSearch;
SearchResult = _recipeOnSearch;
ResearchStr = "";
}
#region Methodes
/// <summary>
/// Launch a search by name request in the collection of Recipe with with a string.
/// </summary>
/// <param name="researchStr">The string for search</param>
/// <returns>True if the result of the search gave at least 1 element. False otherwise.</returns>
public bool ComputeSearch(string researchStr = "")
{
ResearchStr = researchStr;
SearchResult = _recipeOnSearch.ResearchByName(ResearchStr.ToLower());
_maxLines = SearchResult.Count - 1;
return SearchResult.Count > 0;
}
public override void UpdateDisplay()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("---------------------------------------------------------");
sb.AppendLine($" Research: {ResearchStr}");
sb.AppendLine("---------------------------------------------------------");
for (int i = 0; i < SearchResult.Count; i++)
{
if (i == CurrentLine)
{
CurrentSelected = SearchResult[i];
sb.Append($">");
}
sb.AppendLine($" [ {SearchResult[i].Id} ]:\t{SearchResult[i].Title} ");
}
Console.Clear();
Console.WriteLine(sb);
}
/// <summary>
/// Launch and pilot the search menu.
/// </summary>
/// <param name="recipeOnSearch">The collection of recipe where to search</param>
/// <returns>The recipe selected</returns>
public static Recipe? ResearchOn(RecipeCollection recipeOnSearch)
{
SearcherRecipe sr = new SearcherRecipe(recipeOnSearch);
StringBuilder sb = new StringBuilder();
sr.ComputeSearch();
sr.UpdateDisplay();
ConsoleKeyInfo cki;
do
{
cki = Console.ReadKey(true);
switch (cki.Key)
{
case ConsoleKey.UpArrow:
sr.SelectPrevioustLine();
break;
case ConsoleKey.DownArrow:
sr.SelectNextLine();
break;
case ConsoleKey.Backspace:
if (sb.Length > 0)
{
sb.Remove(sb.Length - 1, 1);
sr.ComputeSearch(sb.ToString());
}
break;
default:
sb.Append(cki.KeyChar);
sr.ComputeSearch(sb.ToString());
break;
}
sr.UpdateDisplay();
} while (cki.Key != ConsoleKey.Enter);
return sr.CurrentSelected;
}
#endregion
}
}

@ -0,0 +1,52 @@
using ConsoleApp;
using Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp.Menu
{
/// <summary>
/// An abstract class that define the components of a selection-type menu.
/// </summary>
/// <typeparam name="T">The return type of the currently selected item</typeparam>
public abstract class SelectMenu<T> : IMenuDisplay
{
protected int _currentLine = 0;
protected int _maxLines = 0;
/// <summary>
/// The currently selected item.
/// </summary>
public T? CurrentSelected { get; protected set; }
/// <summary>
/// The current line selected in the menu.
/// </summary>
public int CurrentLine
{
get => _currentLine;
protected set
{
_currentLine = value;
if (_currentLine > _maxLines)
{
_currentLine = _maxLines;
}
if (_currentLine < 0)
{
_currentLine = 0;
}
return;
}
}
public int SelectNextLine() { return ++CurrentLine; }
public int SelectPrevioustLine() { return --CurrentLine; }
public abstract void UpdateDisplay();
}
}

@ -0,0 +1,29 @@
// See https://aka.ms/new-console-template for more information
using ConsoleApp;
using ConsoleApp.Menu;
using Model;
using System.Text;
Console.WriteLine("Hello, World!\n\n");
// TESTS:
Stub stub = new Stub();
List<Recipe> recipes = stub.LoadRecipes();
List<RecipeCollection> recipeCollections = stub.LoadRecipeCollection();
RecipeCollection? allRecipe = recipeCollections.Find(x => x.Description.Equals("All"));
if (allRecipe == null)
throw new ArgumentException("Load AllRecipe in stub: can't find 'All'.");
Manager manager = new Manager(allRecipe);
Recipe? ret = SearcherRecipe.ResearchOn(allRecipe);
Console.WriteLine(ret);
// press any key to quit
Console.ReadKey();

@ -0,0 +1,99 @@
using Model;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp
{
internal struct Stub
{
public List<Recipe> LoadRecipes()
{
List<Recipe> stub = new List<Recipe>();
stub.AddRange(new[]
{
new Recipe(),
new Recipe(
title: "Cookies"),
new Recipe(
title: "Cookies", id: 23),
new Recipe(
title: "Cookies au chocolat", id: null),
new Recipe(
title: "", id: null),
new Recipe(
title: "", id: 24),
new Recipe(
title: "Cookies", id: 24,
preparationSteps: new[]{
new PreparationStep(1)
}),
new Recipe(
title: "Cookies", id: 26,
preparationSteps: new[]{
new PreparationStep(1),
new PreparationStep(2, "Faire cuire.")
}),
new Recipe(
title: "Gateau à la crème",
preparationSteps: new[]{
new PreparationStep(1, "Ajouter les oeufs."),
new PreparationStep(2, "Ajouter la farine."),
new PreparationStep(3, "Mélanger le tout."),
new PreparationStep(4, "Faire cuire 1h10 au four traditionnel.")
}),
new Recipe(
title: "Gateau au chocolat",
preparationSteps: new[]{
new PreparationStep(1, "Ajouter les oeufs."),
new PreparationStep(2, "Ajouter la farine."),
new PreparationStep(2, "Ajouter 100g de chocolat fondu."),
new PreparationStep(3, "Mélanger le tout."),
new PreparationStep(4, "Faire cuire 45h au four traditionnel.")
}),
new Recipe(
title: "Gateau aux cerises",
preparationSteps: new[]{
new PreparationStep(1, "Ajouter les oeufs."),
new PreparationStep(2, "Ajouter la farine."),
new PreparationStep(2, "Ajouter des morceaux de fraises découpées en petits carré"),
new PreparationStep(3, "Mélanger le tout."),
new PreparationStep(4, "Faire cuire 30min au four traditionnel.")
}),
});
return stub;
}
public List<RecipeCollection> LoadRecipeCollection()
{
List<RecipeCollection> stub = new List<RecipeCollection>();
stub.AddRange(new[]
{
new RecipeCollection("All", LoadRecipes().ToArray()),
new RecipeCollection("Starters", LoadRecipes().FindAll(x => x.Id.Equals(23)).ToArray()),
new RecipeCollection("Dishies", LoadRecipes().FindAll(x => x.Id.Equals(24)).ToArray()),
new RecipeCollection("Desserts", LoadRecipes().FindAll(x => x.Id.Equals(26)).ToArray()),
});
return stub;
}
public List<User> ConstrucList()
{
List<User> Users = new List<User>();
User Roger = new User("Roger", "Rabbit", "carotte@mail.fr");
User Dylan = new User("d", "r", "dr@mail.fr");
User Val = new User("V", "entin", "Valentin@mail.fr");
Users.Add(Roger);
Users.Add(Dylan);
Users.Add(Val);
return Users;
}
}
}

@ -1,60 +0,0 @@
using System.Text;
namespace Model
{
public class Recipe
{
public uint Id { get; set; }
public string Title { get; set; }
public List<string> Ingredients { get; set; }
public string Preparation { get; set; }
/// <summary>
/// Constructor of a Recipe.
/// </summary>
/// <param name="id">Identificator</param>
/// <param name="title">The name of the recipe</param>
/// <param name="ingredients">A list of ingredient needed by the preparation</param>
/// <param name="preparation">The text that explain the preparation of the recipe</param>
public Recipe(uint id, string title, List<string> ingredients, string preparation)
{
Id = id;
Title = title;
Ingredients = ingredients;
Preparation = preparation;
}
/// <summary>
/// Concatenate the list of ingredients in a single string
/// </summary>
/// <returns>The list of ingredients in string format</returns>
private string ConcatIngredients()
{
StringBuilder sb = new StringBuilder();
foreach (string str in Ingredients) sb.Append("\t- " + str + "\n");
return sb.ToString();
}
/// <summary>
/// Build a string with all elements (title, ingredients, preparation, ...)
/// </summary>
/// <returns>A string that represent the recipe</returns>
public override string ToString()
{
return $"{Title} -- id:{Id}\n\n"
+ "List of ingredient:\n"
+ ConcatIngredients() + "\n\n"
+ "Preparation:\n"
+ $"{Preparation}\n";
}
/// <summary>
/// Display the recipe in the console
/// </summary>
public void Display()
{
Console.WriteLine(this.ToString());
}
}
}

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Model
{
/// <summary>
/// Manager of the model. Here is stoked all the recipes, the users, etc...
/// </summary>
public class Manager
{
/// <summary>
/// A collection of all the recipe loaded in the app.
/// </summary>
public RecipeCollection AllRecipes { get; protected set; }
/// <summary>
/// The constructor of the manager.
/// </summary>
public Manager()
{
AllRecipes = new RecipeCollection(description: "All Recipes");
}
/// <summary>
/// The constructor of the manager.
/// </summary>
/// <param name="allRecipes">A list of loaded recipes</param>
public Manager(RecipeCollection allRecipes)
{
AllRecipes = new RecipeCollection(
description: "All Recipes",
recipes: allRecipes.ToArray());
}
}
}

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Configurations>Debug;Release;CI</Configurations>
</PropertyGroup>
</Project>

@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Model
{
/// <summary>
/// Define a step of the preparation of a recipe.
/// </summary>
public class PreparationStep : IEquatable<PreparationStep>
{
#region Attributes
private string _description = "";
#endregion
#region Properties
/// <summary>
/// The order of this step in the preparation of the meal.
/// </summary>
public int Order { get; init; }
/// <summary>
/// The description of the task the user need to do for this step of the preparation. <br/>
/// Set to "No description." when the value passed is null, empty or contain white spaces.
/// </summary>
public string Description
{
get => _description;
private set
{
if (string.IsNullOrWhiteSpace(value))
_description = "No description.";
else
_description = value;
}
}
#endregion
#region Constructors
/// <summary>
/// Construct a new step of preparation.
/// </summary>
/// <param name="order">The number of the order in preparation</param>
/// <param name="description">The description of the task</param>
public PreparationStep(int order, string description = "")
{
Order = order;
Description = description;
}
#endregion
#region Methods
public virtual bool Equals(PreparationStep? other)
{
if (other == null) return false;
if (other == this) return true;
return Order.Equals(other.Order) && Description.Equals(other.Description);
}
public override bool Equals(object? obj)
{
var item = obj as PreparationStep;
if (item == null) return false;
return Equals(obj);
}
public override int GetHashCode()
{
return Order.GetHashCode() + Description.GetHashCode();
}
public override string ToString()
{
return $"{Order}- {Description}";
}
#endregion
}
}

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
namespace Model
{
/// <summary>
/// Define a Recipe for the preparation of a meal.
/// </summary>
public class Recipe : IEquatable<Recipe>
{
#region Attributes
private string _title = "";
#endregion
#region Properties
/// <summary>
/// The ID of the recipe - allows you to compare and/or get this item in an easier way.
/// </summary>
public int Id { get; init; }
/// <summary>
/// The Title of the recipe. <br/>
/// Set to "No title." when the value passed is null, empty or contain white spaces.
/// </summary>
public string Title
{
get => _title;
set
{
if (string.IsNullOrWhiteSpace(value))
_title = "No title.";
else
_title = value;
}
}
/// <summary>
/// The steps of the preparation. See: <see cref="PreparationStep"/>.
/// </summary>
public List<PreparationStep> PreparationSteps { get; set; }
#endregion
#region Constructors
/// <summary>
/// Construct a new recipe.
/// </summary>
/// <param name="title">The title of the recipe</param>
/// <param name="id">The id of the recipe. If not given, get a new id.</param>
/// <param name="preparationSteps">The steps of the preparation of the meal</param>
public Recipe(string title = "", int? id = null,
params PreparationStep[] preparationSteps)
{
Title = title;
PreparationSteps = new List<PreparationStep>(preparationSteps);
if (id == null)
{
var randomGenerator = RandomNumberGenerator.Create();
byte[] data = new byte[16];
randomGenerator.GetBytes(data);
Id = Math.Abs(BitConverter.ToInt16(data));
}
else Id = (int)id;
}
#endregion
#region Methods
public virtual bool Equals(Recipe? other)
{
if (other == null) return false;
if (other == this) return true;
return Title.Equals(other.Title) && PreparationSteps.Equals(other.PreparationSteps);
}
public override bool Equals(object? obj)
{
var item = obj as Recipe;
if (item == null) return false;
return Equals(obj);
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
public override string ToString()
{
StringBuilder sb = new StringBuilder($"[Recipe n°{Id}] - {Title}\n");
foreach (PreparationStep ps in PreparationSteps)
{
sb.AppendFormat("\t* {0}\n", ps.ToString());
}
return sb.ToString();
}
#endregion
}
}

@ -0,0 +1,165 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
namespace Model
{
/// <summary>
/// Define a collection of <see cref="Recipe"/>.
/// <br/>This class implement <see cref="IList"/> and <see cref="IEquatable{T}"/>.
/// </summary>
public class RecipeCollection : IList<Recipe>, IEquatable<RecipeCollection>
{
#region Attributes
private readonly List<Recipe> _recipes;
private string _description = "";
#endregion
#region Properties
/// <summary>
/// A short description of what this collection contain. <br/>
/// Set to "No description." when the value passed is null, empty or contain white spaces.
/// </summary>
public string Description
{
get => _description;
set
{
if (string.IsNullOrWhiteSpace(value))
_description = "No description.";
else
_description = value;
}
}
#region IList Prperties
public int Count => _recipes.Count;
public bool IsReadOnly => false;
public Recipe this[int index] { get => _recipes[index]; set => _recipes[index] = value; }
#endregion
#endregion
#region Constructors
/// <summary>
/// Construct a new collection of _recipes.
/// </summary>
/// <param name="description">A short description of what this list will contain</param>
/// <param name="recipes">Recipes to add in this new collection</param>
public RecipeCollection(string description, params Recipe[] recipes)
{
_recipes = new List<Recipe>(recipes);
Description = description;
}
#endregion
#region Methods
/// <summary>
/// Find a recipe in this list by giving the id.
/// </summary>
/// <param name="id">The id of the list we are looking for</param>
/// <returns>The recipe of the id given</returns>
/// <exception cref="ArgumentException"/>
public Recipe? GetRecipeById(int id)
{
Recipe? recipe = _recipes.Find(r => r.Id == id);
if (recipe == null) throw new ArgumentException("No _recipes match the given id.");
return recipe;
}
/// <summary>
/// Utility to find a recipe by his name.
/// </summary>
/// <param name="str">The string for the search</param>
/// <returns>A collection of Recipe where their Title contain the string.</returns>
public RecipeCollection ResearchByName(string str)
{
return new RecipeCollection(
description: $"Results of the research: {str}",
recipes: _recipes.FindAll(x => x.Title.ToLower().Contains(str.ToLower())).ToArray());
}
#region IList Methods
public int IndexOf(Recipe item)
{
return _recipes.IndexOf(item);
}
public void Insert(int index, Recipe item)
{
_recipes.Insert(index, item);
}
public void RemoveAt(int index)
{
_recipes.RemoveAt(index);
}
public void Add(Recipe item)
{
_recipes.Add(item);
}
public void Clear()
{
_recipes.Clear();
}
public bool Contains(Recipe item)
{
return _recipes.Contains(item);
}
public void CopyTo(Recipe[] array, int arrayIndex)
{
_recipes.CopyTo(array, arrayIndex);
}
public bool Remove(Recipe item)
{
return _recipes.Remove(item);
}
public IEnumerator<Recipe> GetEnumerator()
{
return _recipes.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _recipes.GetEnumerator();
}
#endregion
public virtual bool Equals(RecipeCollection? other)
{
if (other == null) return false;
if (other == this) return true;
return _description.Equals(other.Description) && _recipes.Equals(other._recipes);
}
public override bool Equals(object? obj)
{
var item = obj as RecipeCollection;
if (item == null) return false;
return Equals(obj);
}
public override int GetHashCode()
{
return _recipes.GetHashCode();
}
public override string ToString()
{
StringBuilder sb = new StringBuilder($"[RecipeCollection] - {Description}:\n");
foreach (Recipe r in _recipes)
{
sb.AppendFormat("\t - {0}\n", r.ToString());
}
return sb.ToString();
}
#endregion
}
}

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Model
{
public interface IPasswordManager
{
public void changePassword(User user, string newPassword);
public string HashPassword(User user);
public bool VerifyPassword(string hashedPassword);
}
}

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Model
{
public class PasswordManager : IPasswordManager
{
public void changePassword(User user, string newPassword)
{
throw new NotImplementedException();
}
public string HashPassword(User user)
{
throw new NotImplementedException();
}
public bool VerifyPassword(string hashedPassword)
{
throw new NotImplementedException();
}
}
}

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Model
{
/// <summary>
/// This is the list of priorities that user can define in his profil. Priorities
/// are also present in recipes to match the first user's priority with the recipe's priority.
/// </summary>
public enum Priority
{ Economic, Fast, Easy, Light, Gourmet };
}

@ -0,0 +1,150 @@
using System;
using System.Collections.Generic;
using System.Collections;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
namespace Model
{
/// <summary>
/// A user is an entity with a name, a surname, mail, profilePict and a list of priority.
/// This user can login with a Id and password
/// </summary>
public class User : IEquatable<User>
{
#region Private Attributes
private string name="";
private string surname="";
private string mail = "";
private string picture = "";
private string password = "";
//private string defaultUserSavePath = "";
private List<Priority> priorities;
#endregion
#region Properties
/// <summary>
/// Property to get Name of users and a setter
/// </summary>
/// <exception cref="ArgumentException" >Setter have Exception which is trigger when Name is null</exception>
public string Name
{
get { return name; }
private set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("Impossible d'avoir un champ Nom vide!");
}
name = value;
}
}
/// <summary>
/// Property to get Surname of users and a setter
/// </summary>
/// <exception cref="ArgumentException" >Setter have Exception which is trigger when Surname is null</exception>
public string Surname
{
get { return surname; }
private set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("Impossible d'avoir un champ Prénom vide!");
}
surname = value;
}
}
/// <summary>
/// Property to get mail of users and a setter
/// </summary>
/// <exception cref="ArgumentException" >User's mail will serve to log the user. So there's no setter, just an init. User will enter one time his email at his
/// account creation.</exception>
public string Mail
{
get { return mail; }
private init
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("Impossible d'avoir un champ Email vide!");
}
mail = value;
}
}
///<summary>
/// Property to initiate password, change it, and
/// </summary>
public string Password
{
get { return password; }
set { password = value; }
}
/// <summary>
/// For now, we define the ProfilPict as a string which is "PhotoParDefaut"
/// when the value is null.
/// </summary>
public string ProfilPict
{
get => picture;
set => picture = value;
}
/// <summary>
/// This is the list of priorities specific tu the user. This list is initiate
/// by default. User could change it at will.
/// </summary>
public List<Priority> Priorities
{
get => priorities;
set=> priorities = value;
}
public bool Equals(User other)
{
return Name.Equals(other.Name) && Surname.Equals(other.Surname) && Mail.Equals(other.Mail);
}
#endregion
#region Constructors
/// <summary>
/// Construtors of user.
/// </summary>
/// <param name="name">The name of the user</param>
/// <param name="surname">The surname of the user</param>
/// <param name="mail">The user needs an email to login. </param>
public User(string name, string surname, string mail)
{
Name = name;
Surname = surname;
Mail = mail;
priorities = new List<Priority> {
Priority.Gourmet,
Priority.Economic,
Priority.Fast,
Priority.Light,
Priority.Easy};
ProfilPict = picture;
}
#endregion
}
}

@ -3,24 +3,55 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.33516.290
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp", "ConsoleApp\ConsoleApp.csproj", "{666C2211-8EBB-4FC8-9484-CB93BC854153}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model", "Model\Model.csproj", "{42FF86BD-92F9-4A32-A938-68515905378F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Views", "Views\Views.csproj", "{508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Model_UnitTests", "Tests\Model_UnitTests\Model_UnitTests.csproj", "{45AB746A-194B-4E43-81EB-83B06F35AA33}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{08B80CE8-A01D-4D86-8989-AF225D5DA48C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
CI|Any CPU = CI|Any CPU
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{666C2211-8EBB-4FC8-9484-CB93BC854153}.CI|Any CPU.ActiveCfg = Release|Any CPU
{666C2211-8EBB-4FC8-9484-CB93BC854153}.CI|Any CPU.Build.0 = Release|Any CPU
{666C2211-8EBB-4FC8-9484-CB93BC854153}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{666C2211-8EBB-4FC8-9484-CB93BC854153}.Debug|Any CPU.Build.0 = Debug|Any CPU
{666C2211-8EBB-4FC8-9484-CB93BC854153}.Release|Any CPU.ActiveCfg = Release|Any CPU
{666C2211-8EBB-4FC8-9484-CB93BC854153}.Release|Any CPU.Build.0 = Release|Any CPU
{42FF86BD-92F9-4A32-A938-68515905378F}.CI|Any CPU.ActiveCfg = Release|Any CPU
{42FF86BD-92F9-4A32-A938-68515905378F}.CI|Any CPU.Build.0 = Release|Any CPU
{42FF86BD-92F9-4A32-A938-68515905378F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{42FF86BD-92F9-4A32-A938-68515905378F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{42FF86BD-92F9-4A32-A938-68515905378F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{42FF86BD-92F9-4A32-A938-68515905378F}.Release|Any CPU.Build.0 = Release|Any CPU
{508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.CI|Any CPU.ActiveCfg = CI|Any CPU
{508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Debug|Any CPU.Build.0 = Debug|Any CPU
{508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Release|Any CPU.ActiveCfg = Release|Any CPU
{508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Release|Any CPU.Build.0 = Release|Any CPU
{508B5600-AFD0-4AE4-A3CF-5FA8BE3ECE75}.Release|Any CPU.Deploy.0 = Release|Any CPU
{45AB746A-194B-4E43-81EB-83B06F35AA33}.CI|Any CPU.ActiveCfg = Release|Any CPU
{45AB746A-194B-4E43-81EB-83B06F35AA33}.CI|Any CPU.Build.0 = Release|Any CPU
{45AB746A-194B-4E43-81EB-83B06F35AA33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{45AB746A-194B-4E43-81EB-83B06F35AA33}.Debug|Any CPU.Build.0 = Debug|Any CPU
{45AB746A-194B-4E43-81EB-83B06F35AA33}.Release|Any CPU.ActiveCfg = Release|Any CPU
{45AB746A-194B-4E43-81EB-83B06F35AA33}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{45AB746A-194B-4E43-81EB-83B06F35AA33} = {08B80CE8-A01D-4D86-8989-AF225D5DA48C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {ADEA5603-1EF6-4D43-9493-7D6D9DE7FA3F}
EndGlobalSection

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<Configurations>Debug;Release;CI</Configurations>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Model\Model.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Model;
namespace Model_UnitTests
{
public class RecipeCollection_UT
{
[Fact]
public void TestResearchByName()
{
RecipeCollection recipes = new RecipeCollection(
description: "test recipe",
recipes: new[]
{
new Recipe(title: "Gateau à la crème", id: 1),
new Recipe(title: "Gateau au chocolat", id: 2),
new Recipe(title: "Gateau aux cerises", id: 3)
});
Assert.Equal(2, recipes.ResearchByName("chocolat").FirstOrDefault().Id);
}
}
}

@ -0,0 +1,26 @@
using Model;
namespace Model_UnitTests
{
public class Recipe_UT
{
[Fact]
public void TestVoidConstructor()
{
Recipe r = new Recipe(id: 999); // id is given to avoid tests errors with the static atrribute 'idCreator'.
Assert.NotNull(r.Title);
}
[Theory]
[InlineData("Cookies", 23, "Cookies", 23)]
[InlineData("Cookies", 1, "Cookies", 1)]
[InlineData("No title.", 1, "", 1)]
public void TestConstructor(string expectedTitle, int expectedId, string title, int? id)
{
Recipe r = new Recipe(title, id);
Assert.NotNull(r.Title);
Assert.Equal(expectedId, r.Id);
Assert.Equal(expectedTitle, r.Title);
}
}
}

@ -0,0 +1,19 @@
using Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Model_UnitTests
{
public class test_unit_user
{
[Fact]
public void TestConstructUser()
{
User user = new User("Bob","Dylan", "bd@gmail.com");
//Assert.
}
}
}

@ -64,7 +64,8 @@
<Label Text="Priorités du compte : " TextColor="{AppThemeBinding Light={StaticResource Black}, Dark={StaticResource Gray100}}"
FontSize="20" Padding="15"/>
<Grid BackgroundColor="#D1E8E2"
MinimumHeightRequest="300">
MinimumHeightRequest="300"
Padding="20">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
@ -81,13 +82,13 @@
</Grid.ColumnDefinitions>
<Label Text="Recettes économiques" Grid.Row="0" Padding="5,0,0,0"/>
<BoxView Color="Black" HeightRequest="1" Margin="10,10,10,10" Grid.Row="1" />
<Label Text="Phrase 2" Grid.Row="2"/>
<Label Text="Recettes rapides" Grid.Row="2"/>
<BoxView Color="Black" HeightRequest="1" Margin="10,10,10,10" Grid.Row="3" />
<Label Text="Phrase 3" Grid.Row="4"/>
<Label Text="Recettes simples" Grid.Row="4"/>
<BoxView Color="Black" HeightRequest="1" Margin="10,10,10,10" Grid.Row="5" />
<Label Text="Phrase 4" Grid.Row="6"/>
<Label Text="Recettes légères" Grid.Row="6"/>
<BoxView Color="Black" HeightRequest="1" Margin="10,10,10,10" Grid.Row="7" />
<Label Text="Phrase 5" Grid.Row="8"/>
<Label Text="Recettes gourmandes" Grid.Row="8"/>
</Grid>

@ -30,6 +30,7 @@
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
<Configurations>Debug;Release;CI</Configurations>
</PropertyGroup>
<ItemGroup>

@ -0,0 +1,206 @@
*Rappel :*
* ne rendez que des documents pdf, contenant lintégralité des schémas, diagrammes, descriptions aussi bien pour la SAÉ que pour les 2 ressources,
* ne rendez quune seule solution faites de plusieurs projets et ressources pour vos programmes
* une évaluation blanche n'est qu'indicative : elle ne comptera pas dans la moyenne. Le soin apporté aux corrections n'est pas le même que pour l'évaluation finale et les notes blanches ne sont qu'un aperçu de votre travail à un instant t.
* Critères dévaluation pour chaque note :
(Notes : le barème nest pas définitif et très susceptible dévoluer ; il nest donné quà titre indicatif ; chaque diagramme doit être accompagné de notes et dune description écrite)
---
## SAÉ2.01 : Développement d'une application : *5,26666666666667/20*
*Le sujet est choisi par le binôme mais doit être validé par l'enseignant.*
### Documents sur la préparation de l'application et l'IHM : *15,8/20*
#### Documentation à rendre en semaine 13:
* description du contexte [3 sur 3 points]
*OK*
* persona [1,8 sur 2 points]
*Normalement, on ne choisit pas un persona avec un nom qui pourrait évoquer quelqu'un d'existant.*
* user stories [3 sur 3 points]
*OK*
* sketchs [4 sur 4 points]
*OK*
* storyboards [3 sur 3 points]
*OK*
* diagramme de cas dutilisation [1 sur 5 points]
*Un acteur est sensé être relié à un cas par un trait uniquement
Pas d'accueil n'est pas un UC
Les fautes !
Certaines flèches sont à l'envers.
Il est à reprendre, sans oublier d'ajouter les description !!*
### Persistance et ajouts personnels à l'application : *0/40*
#### Documentation à rendre à la fin de la semaine 23 :
* diagramme de paquetage mettant en avant la partie persistance [ sur 2 points]
**
* diagramme de classes mettant en avant la partie persistance [ sur 4 points]
**
* diagramme de classes sur votre (vos) partie(s) ajoutée(s) [ sur 4 points]
**
#### Programmation à rendre à la fin du projet :
* persistance (XML, JSON, BDD, WebService…) [ sur 3 points]
**
* autre ajout personnel [ sur 3 points]
**
**fonctionnement de lapplication**
* compilation [ sur 3 points]
**
* exécution [ sur 5 points]
**
* déploiement [ sur 2 points]
**
* aboutissement du projet [ sur 4 points]
**
#### Vidéo à rendre à la fin du projet :
* vidéo de 1 à 3 minute(s) du projet [ sur 10 points]
**
## R2.02 : Développement d'applications avec IHM: *1,33333333333333/20*
### Documents : *4/20*
#### Documentation à rendre en semaine 23:
* diagramme de paquetage [ sur 2 points]
**
* diagramme de classes [4 sur 8 points]
*Quelle drôle de tête !!
Les filles de Sauveur et Loader ne sont dépendantes de personne. Ce n'est pas du tout logique.
L'interface Idisplyable est très bizarre. Je ne comprend pas ce qu'elle fait là.
Cette BaseItem me perturbe beaucoup. Quelle est son intention ?
Allez, ce n'est pas si mal !*
* diagramme de séquence (sur quelques cas particuliers) [ sur 2 points]
**
* description écrite de larchitecture (dont patrons de conception, dépendances…) [ sur 8 points]
**
### Programmation : *0/40*
#### XAML [0 sur 7 points] :
* répartition dans lespace (layout des vues et usercontrols) [ sur 2 points]
**
* utilisation des controls (vues et usercontrols) [ sur 1 point]
**
* ressources, styles [ sur 2 points]
**
* DataTemplate (locaux et globaux) [ sur 2 points]
**
#### C# [ sur 20 points] :
* bases (classes, structures, instances, …) [ sur 3 points]
*Pour l'instant, je n'ai qu'une classe. J'imagine que je ne suis pas sur la bonne branche. Redemandez une éval blanche pour la partie code.*
* abstraction (héritage, interfaces, polymorphisme) [ sur 4 points]
**
* collections simples (tableaux, listes…) [ sur 3 points]
**
* collections avancées (dictionnaires, sets) [ sur 3 points]
**
* encapsulation [ sur 5 points]
**
* LINQ [ sur 1 point]
**
* évènements (cf. module IHM) [ sur 1 point]
**
#### boucle Model <-> View (dont Binding) [0 sur 13 points] :
* gestion dévènements sur la vue [ sur 2 points]
**
* gestion dévènements depuis le métier (notifications) [ sur 2 points]
**
* DataBinding (sur le Master) [ sur 2 points]
**
* DataBinding (sur le Detail) [ sur 2 points]
**
* DataBinding sur les UserControl + Dependency Property [ sur 2 points]
**
* gestion du Master-Detail** [ sur 3 points]
**
## R2.03 : Qualité de développement : *0/20*
#### Tests [0 sur 10 points] :
* tests fonctionnels [ sur 5 points]
**
* tests unitaires [ sur 5 points]
**
* gestion automatique des tests (cf. plus bas)
**
* bonus : tests unitaires d'interfaces
**
#### Documentation [0 sur 0 points] :
* qualité de la documentation du code [ sur 2 points]
**
* génération de la documentation doxygen [ sur 2 points]
**
* génération automatique de la documentation (cf. plus bas)
**
#### Gestion de projet [0 sur 10 points] :
* utilisation simple de git (git clone, commit, add, push, pull) [ sur 3 points]
**
* utilisation avancée (git merge, branch, conflits) sur 2 points]
**
* utilisation de tickets et Merge Requests à travers la plateforme git (gitlab ou Code#0) [ sur 3 points]
**
* mise en place de l'intégration continue (CI) pour la gestion automatique des tests et la génération de la documentation [ sur 2 points]
**
---
## Note finale R2.02 : *1,33333333333333/20*
## Note finale R2.03 : *0/20*
## Note finale S2.01 : *5,26666666666667/20*
Loading…
Cancel
Save