From 39de7eb0aeabbcc233722044bd53fd1f132c8cae Mon Sep 17 00:00:00 2001 From: anperederi Date: Thu, 7 Mar 2024 09:47:33 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A7=20Work=20in=20progress=20on=20enti?= =?UTF-8?q?ties?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/DbContextLib/LibraryContext.cs | 72 +++++-- src/Entities/AthleteEntity.cs | 13 +- src/Entities/FriendshipEntity.cs | 14 ++ src/Entities/NotificationEntity.cs | 5 +- src/Entities/Picture.cs | 11 + src/Entities/TrainingEntity.cs | 5 +- .../FriendshipStubbedContext.cs | 49 +++++ .../HeartRateStubbedContext.cs | 2 +- ...> 20240307081406_MyMigrations.Designer.cs} | 201 +++++++++++++++--- ...ions.cs => 20240307081406_MyMigrations.cs} | 165 +++++++++++--- .../TrainingStubbedContextModelSnapshot.cs | 199 ++++++++++++++--- .../NotificationStubbedContext.cs | 10 +- .../TrainingStubbedContext.cs | 10 +- src/Tests/ConsoleTestRelationships/Program.cs | 200 ++++++++++++----- .../uca.HeartTrack.db | Bin 81920 -> 118784 bytes 15 files changed, 773 insertions(+), 183 deletions(-) create mode 100644 src/Entities/FriendshipEntity.cs create mode 100644 src/Entities/Picture.cs create mode 100644 src/StubbedContextLib/FriendshipStubbedContext.cs rename src/StubbedContextLib/Migrations/{20240226170604_MyMigrations.Designer.cs => 20240307081406_MyMigrations.Designer.cs} (82%) rename src/StubbedContextLib/Migrations/{20240226170604_MyMigrations.cs => 20240307081406_MyMigrations.cs} (71%) diff --git a/src/DbContextLib/LibraryContext.cs b/src/DbContextLib/LibraryContext.cs index 1cf6224..c326091 100644 --- a/src/DbContextLib/LibraryContext.cs +++ b/src/DbContextLib/LibraryContext.cs @@ -8,6 +8,7 @@ using Entities; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Migrations.Operations; namespace DbContextLib { @@ -112,6 +113,11 @@ namespace DbContextLib modelBuilder.Entity() .Property(at => at.IdAthlete) .ValueGeneratedOnAdd(); + // add image column type + // modelBuilder.Entity() + // .Property(at => at.ProfilPicture) + // .HasColumnType("image"); + //primary key of StatisticEntity modelBuilder.Entity() @@ -121,7 +127,7 @@ namespace DbContextLib .Property(s => s.IdStatistic) .ValueGeneratedOnAdd(); - //primary key of + //primary key of TrainingEntity modelBuilder.Entity() .HasKey(t => t.IdTraining); //generation mode (at insertion) @@ -129,7 +135,7 @@ namespace DbContextLib .Property(t => t.IdTraining) .ValueGeneratedOnAdd(); - //primary key of + //primary key of NotificationEntity modelBuilder.Entity() .HasKey(n => n.IdNotif); //generation mode (at insertion) @@ -137,28 +143,57 @@ namespace DbContextLib .Property(n => n.IdNotif) .ValueGeneratedOnAdd(); + modelBuilder.Entity() + .HasKey(f => new { f.FollowingId, f.FollowerId }); + + modelBuilder.Entity() + .HasOne(fing => fing.Following) + .WithMany(fings => fings.Followings) + .HasForeignKey(fing => fing.FollowingId); + + modelBuilder.Entity() + .HasOne(fer => fer.Follower) + .WithMany(fers => fers.Followers) + .HasForeignKey(fing => fing.FollowerId); + + // ! + // ? Plusieurs questions sur les required ou non, différence difficile à comprendre + modelBuilder.Entity() - .HasMany(at => at.Trainings) - .WithOne(n => n.Athlete) - .HasForeignKey(n => n.AthleteId) - .IsRequired(); + .HasMany(at => at.TrainingsCoach) + .WithOne(tc => tc.Coach) + .HasForeignKey(tc => tc.CoachId); modelBuilder.Entity() - .HasMany(at => at.Trainings) - .WithOne(t => t.Athlete) - .HasForeignKey(t => t.AthleteId) - .IsRequired(); + .HasMany(at => at.TrainingsAthlete) + .WithMany(ta => ta.Athletes); + + modelBuilder.Entity() + .HasMany(at => at.NotificationsReceived) + .WithMany(nr => nr.Receivers); + + modelBuilder.Entity() + .HasMany(at => at.NotificationsSent) + .WithOne(ns => ns.Sender) + .HasForeignKey(ns => ns.SenderId); + // required car on veut toujours savoir le receveur et l'envoyeur de la notification meme admin ou systeme modelBuilder.Entity() .HasMany(at => at.Statistics) .WithOne(s => s.Athlete) .HasForeignKey(s => s.AthleteId) - .IsRequired(); + .IsRequired(false); modelBuilder.Entity() .HasMany(at => at.Activities) .WithOne(a => a.Athlete) .HasForeignKey(a => a.AthleteId) + .IsRequired(false); + + modelBuilder.Entity() + .HasMany(a => a.HeartRates) + .WithOne(h => h.Activity) + .HasForeignKey(h => h.ActivityId) .IsRequired(); modelBuilder.Entity() @@ -166,18 +201,21 @@ namespace DbContextLib .WithOne(a => a.DataSource) .HasForeignKey(a => a.DataSourceId) .IsRequired(); - - modelBuilder.Entity() - .HasMany(a => a.HeartRates) - .WithOne(h => h.Activity) - .HasForeignKey(h => h.ActivityId) - .IsRequired(); modelBuilder.Entity() .HasMany(ds => ds.Activities) .WithOne(at => at.DataSource) .HasForeignKey(at => at.DataSourceId) .IsRequired(false); + + // modelBuilder.Entity() + // .HasMany(fer => fer.Followers) + // .WithMany(fing => fing.Followings) + // .UsingEntity( + // l => l.HasOne().WithMany().HasForeignKey(fer => fer.FollowerId), + // r => r.HasOne().WithMany().HasForeignKey(fing => fing.FollowingId), + // j => j.Property(f => f.StartDate).HasDefaultValueSql("CURRENT_TIMESTAMP") + // ); } } } \ No newline at end of file diff --git a/src/Entities/AthleteEntity.cs b/src/Entities/AthleteEntity.cs index ee6c0b0..cc883d6 100644 --- a/src/Entities/AthleteEntity.cs +++ b/src/Entities/AthleteEntity.cs @@ -87,18 +87,25 @@ namespace Entities /// public bool IsCoach { get; set; } + public required byte[] ProfilPicture { get; set; } + + + public ICollection Activities { get; set; } = new List(); public ICollection Statistics { get; set; } = new List(); - public ICollection Trainings { get; set; } = new List(); + public ICollection TrainingsAthlete { get; set; } = new List(); + public ICollection TrainingsCoach { get; set; } = new List(); - public ICollection Notifications { get; set; } = new List(); + public ICollection NotificationsReceived { get; set; } = new List(); + public ICollection NotificationsSent { get; set; } = new List(); public int? DataSourceId { get; set; } public DataSourceEntity? DataSource { get; set; } - public ICollection + public ICollection Followers { get; set; } = []; + public ICollection Followings { get; set; } = []; } } \ No newline at end of file diff --git a/src/Entities/FriendshipEntity.cs b/src/Entities/FriendshipEntity.cs new file mode 100644 index 0000000..fb7446f --- /dev/null +++ b/src/Entities/FriendshipEntity.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations.Schema; + +namespace Entities; + +public class FriendshipEntity +{ + [ForeignKey("FollowingId")] + public int FollowingId { get; set; } + public AthleteEntity Following { get; set; } + [ForeignKey("FollowerId")] + public int FollowerId { get; set; } + public AthleteEntity Follower { get; set; } + public DateTime StartDate { get; set; } +} \ No newline at end of file diff --git a/src/Entities/NotificationEntity.cs b/src/Entities/NotificationEntity.cs index d7973b7..06650c2 100644 --- a/src/Entities/NotificationEntity.cs +++ b/src/Entities/NotificationEntity.cs @@ -49,8 +49,9 @@ namespace Entities [MaxLength(100)] public string Urgence { get; set; } = null!; - public int AthleteId { get; set; } + public int SenderId { get; set; } - public AthleteEntity Athlete { get; set; } = null!; + public AthleteEntity Sender { get; set; } = null!; + public ICollection Receivers { get; set; } = new List(); } } \ No newline at end of file diff --git a/src/Entities/Picture.cs b/src/Entities/Picture.cs new file mode 100644 index 0000000..53ab376 --- /dev/null +++ b/src/Entities/Picture.cs @@ -0,0 +1,11 @@ +using System.ComponentModel.DataAnnotations; + +public class Picture +{ + + [Key] + public Guid Id { get; set; } + [Required] + public byte[] Bytes { get; set; } + +} \ No newline at end of file diff --git a/src/Entities/TrainingEntity.cs b/src/Entities/TrainingEntity.cs index 7f467ef..f0e01b2 100644 --- a/src/Entities/TrainingEntity.cs +++ b/src/Entities/TrainingEntity.cs @@ -53,8 +53,9 @@ namespace Entities [MaxLength(300)] public string? FeedBack { get; set; } - public int AthleteId { get; set; } + public int CoachId { get; set; } - public AthleteEntity Athlete { get; set; } = null!; + public AthleteEntity Coach { get; set; } = null!; + public ICollection Athletes { get; set; } = new List(); } } \ No newline at end of file diff --git a/src/StubbedContextLib/FriendshipStubbedContext.cs b/src/StubbedContextLib/FriendshipStubbedContext.cs new file mode 100644 index 0000000..43eff80 --- /dev/null +++ b/src/StubbedContextLib/FriendshipStubbedContext.cs @@ -0,0 +1,49 @@ +//----------------------------------------------------------------------- +// FILENAME: FriendshipStubbedContext.cs +// PROJECT: StubbedContextLib +// SOLUTION: HeartTrack +// DATE CREATED: 22/02/2024 +// AUTHOR: Antoine PEREDERII +//----------------------------------------------------------------------- + +using DbContextLib; +using Entities; +using Microsoft.EntityFrameworkCore; + +namespace StubbedContextLib +{ + /// + /// Represents the stubbed context for friendship entities. + /// + public class FriendshipStubbedContext : DataSourceStubbedContext + { + /// + /// Initializes a new instance of the class. + /// + public FriendshipStubbedContext() : base() { } + + /// + /// Initializes a new instance of the class with the specified options. + /// + /// The options for the context. + public FriendshipStubbedContext(DbContextOptions options) : base(options) { } + + /// + /// Configures the model for the heart rate stubbed context. + /// + /// The model builder instance. + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.Entity().HasData( + new FriendshipEntity { FollowerId = 1, FollowingId = 2 }, + new FriendshipEntity { FollowerId = 1, FollowingId = 3 }, + new FriendshipEntity { FollowerId = 1, FollowingId = 4 }, + new FriendshipEntity { FollowerId = 1, FollowingId = 5 }, + new FriendshipEntity { FollowerId = 2, FollowingId = 1 }, + new FriendshipEntity { FollowerId = 2, FollowingId = 3 } + ); + } + } +} \ No newline at end of file diff --git a/src/StubbedContextLib/HeartRateStubbedContext.cs b/src/StubbedContextLib/HeartRateStubbedContext.cs index 6fbaa9e..8441665 100644 --- a/src/StubbedContextLib/HeartRateStubbedContext.cs +++ b/src/StubbedContextLib/HeartRateStubbedContext.cs @@ -15,7 +15,7 @@ namespace StubbedContextLib /// /// Represents the stubbed context for heart rate entities. /// - public class HeartRateStubbedContext : DataSourceStubbedContext + public class HeartRateStubbedContext : FriendshipStubbedContext { /// /// Initializes a new instance of the class. diff --git a/src/StubbedContextLib/Migrations/20240226170604_MyMigrations.Designer.cs b/src/StubbedContextLib/Migrations/20240307081406_MyMigrations.Designer.cs similarity index 82% rename from src/StubbedContextLib/Migrations/20240226170604_MyMigrations.Designer.cs rename to src/StubbedContextLib/Migrations/20240307081406_MyMigrations.Designer.cs index 25efb7d..82a4cb8 100644 --- a/src/StubbedContextLib/Migrations/20240226170604_MyMigrations.Designer.cs +++ b/src/StubbedContextLib/Migrations/20240307081406_MyMigrations.Designer.cs @@ -11,7 +11,7 @@ using StubbedContextLib; namespace StubbedContextLib.Migrations { [DbContext(typeof(TrainingStubbedContext))] - [Migration("20240226170604_MyMigrations")] + [Migration("20240307081406_MyMigrations")] partial class MyMigrations { /// @@ -20,6 +20,36 @@ namespace StubbedContextLib.Migrations #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "8.0.2"); + modelBuilder.Entity("AthleteEntityNotificationEntity", b => + { + b.Property("NotificationsReceivedIdNotif") + .HasColumnType("INTEGER"); + + b.Property("ReceiversIdAthlete") + .HasColumnType("INTEGER"); + + b.HasKey("NotificationsReceivedIdNotif", "ReceiversIdAthlete"); + + b.HasIndex("ReceiversIdAthlete"); + + b.ToTable("AthleteEntityNotificationEntity"); + }); + + modelBuilder.Entity("AthleteEntityTrainingEntity", b => + { + b.Property("AthletesIdAthlete") + .HasColumnType("INTEGER"); + + b.Property("TrainingsAthleteIdTraining") + .HasColumnType("INTEGER"); + + b.HasKey("AthletesIdAthlete", "TrainingsAthleteIdTraining"); + + b.HasIndex("TrainingsAthleteIdTraining"); + + b.ToTable("AthleteEntityTrainingEntity"); + }); + modelBuilder.Entity("Entities.ActivityEntity", b => { b.Property("IdActivity") @@ -409,6 +439,62 @@ namespace StubbedContextLib.Migrations }); }); + modelBuilder.Entity("Entities.FriendshipEntity", b => + { + b.Property("FollowingId") + .HasColumnType("INTEGER"); + + b.Property("FollowerId") + .HasColumnType("INTEGER"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.HasKey("FollowingId", "FollowerId"); + + b.HasIndex("FollowerId"); + + b.ToTable("FriendshipEntity"); + + b.HasData( + new + { + FollowingId = 2, + FollowerId = 1, + StartDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }, + new + { + FollowingId = 3, + FollowerId = 1, + StartDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }, + new + { + FollowingId = 4, + FollowerId = 1, + StartDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }, + new + { + FollowingId = 5, + FollowerId = 1, + StartDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }, + new + { + FollowingId = 1, + FollowerId = 2, + StartDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }, + new + { + FollowingId = 3, + FollowerId = 2, + StartDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }); + }); + modelBuilder.Entity("Entities.HeartRateEntity", b => { b.Property("IdHeartRate") @@ -506,9 +592,6 @@ namespace StubbedContextLib.Migrations .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("AthleteId") - .HasColumnType("INTEGER"); - b.Property("Date") .HasColumnType("TEXT"); @@ -517,6 +600,9 @@ namespace StubbedContextLib.Migrations .HasMaxLength(100) .HasColumnType("TEXT"); + b.Property("SenderId") + .HasColumnType("INTEGER"); + b.Property("Statut") .HasColumnType("INTEGER"); @@ -527,7 +613,7 @@ namespace StubbedContextLib.Migrations b.HasKey("IdNotif"); - b.HasIndex("AthleteId"); + b.HasIndex("SenderId"); b.ToTable("Notification"); @@ -535,45 +621,45 @@ namespace StubbedContextLib.Migrations new { IdNotif = 1, - AthleteId = 1, Date = new DateTime(2023, 12, 25, 13, 0, 40, 0, DateTimeKind.Unspecified), Message = "You have a new activity to check", + SenderId = 1, Statut = true, Urgence = "A" }, new { IdNotif = 2, - AthleteId = 2, Date = new DateTime(2023, 12, 26, 13, 10, 40, 0, DateTimeKind.Unspecified), Message = "You have a new athlete to check", + SenderId = 2, Statut = false, Urgence = "3" }, new { IdNotif = 3, - AthleteId = 3, Date = new DateTime(2023, 12, 26, 16, 10, 4, 0, DateTimeKind.Unspecified), Message = "You have a new heart rate to check", + SenderId = 3, Statut = true, Urgence = "2" }, new { IdNotif = 4, - AthleteId = 4, Date = new DateTime(2024, 1, 12, 9, 30, 50, 0, DateTimeKind.Unspecified), Message = "You have a new data source to check", + SenderId = 4, Statut = false, Urgence = "1" }, new { IdNotif = 5, - AthleteId = 5, Date = new DateTime(2024, 2, 22, 12, 10, 0, 0, DateTimeKind.Unspecified), Message = "You have a new notification to check", + SenderId = 5, Statut = true, Urgence = "3" }); @@ -668,7 +754,7 @@ namespace StubbedContextLib.Migrations .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("AthleteId") + b.Property("CoachId") .HasColumnType("INTEGER"); b.Property("Date") @@ -690,7 +776,7 @@ namespace StubbedContextLib.Migrations b.HasKey("IdTraining"); - b.HasIndex("AthleteId"); + b.HasIndex("CoachId"); b.ToTable("Training"); @@ -698,7 +784,7 @@ namespace StubbedContextLib.Migrations new { IdTraining = 1, - AthleteId = 1, + CoachId = 1, Date = new DateOnly(2024, 1, 19), Description = "Running", FeedBack = "Good", @@ -708,7 +794,7 @@ namespace StubbedContextLib.Migrations new { IdTraining = 2, - AthleteId = 5, + CoachId = 5, Date = new DateOnly(2024, 2, 20), Description = "Cycling", Latitude = 48.8566f, @@ -717,7 +803,7 @@ namespace StubbedContextLib.Migrations new { IdTraining = 3, - AthleteId = 4, + CoachId = 4, Date = new DateOnly(2024, 2, 21), FeedBack = "Good", Latitude = 48.8566f, @@ -726,7 +812,7 @@ namespace StubbedContextLib.Migrations new { IdTraining = 4, - AthleteId = 3, + CoachId = 3, Date = new DateOnly(2024, 2, 22), Description = "Running", FeedBack = "Good", @@ -736,7 +822,7 @@ namespace StubbedContextLib.Migrations new { IdTraining = 5, - AthleteId = 1, + CoachId = 1, Date = new DateOnly(2024, 2, 23), Description = "Cycling", Latitude = 48.8566f, @@ -744,13 +830,41 @@ namespace StubbedContextLib.Migrations }); }); + modelBuilder.Entity("AthleteEntityNotificationEntity", b => + { + b.HasOne("Entities.NotificationEntity", null) + .WithMany() + .HasForeignKey("NotificationsReceivedIdNotif") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Entities.AthleteEntity", null) + .WithMany() + .HasForeignKey("ReceiversIdAthlete") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AthleteEntityTrainingEntity", b => + { + b.HasOne("Entities.AthleteEntity", null) + .WithMany() + .HasForeignKey("AthletesIdAthlete") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Entities.TrainingEntity", null) + .WithMany() + .HasForeignKey("TrainingsAthleteIdTraining") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Entities.ActivityEntity", b => { b.HasOne("Entities.AthleteEntity", "Athlete") .WithMany("Activities") - .HasForeignKey("AthleteId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); + .HasForeignKey("AthleteId"); b.HasOne("Entities.DataSourceEntity", "DataSource") .WithMany("Activities") @@ -770,6 +884,25 @@ namespace StubbedContextLib.Migrations b.Navigation("DataSource"); }); + modelBuilder.Entity("Entities.FriendshipEntity", b => + { + b.HasOne("Entities.AthleteEntity", "Follower") + .WithMany("Followers") + .HasForeignKey("FollowerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Entities.AthleteEntity", "Following") + .WithMany("Followings") + .HasForeignKey("FollowingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Follower"); + + b.Navigation("Following"); + }); + modelBuilder.Entity("Entities.HeartRateEntity", b => { b.HasOne("Entities.ActivityEntity", "Activity") @@ -783,35 +916,33 @@ namespace StubbedContextLib.Migrations modelBuilder.Entity("Entities.NotificationEntity", b => { - b.HasOne("Entities.AthleteEntity", "Athlete") - .WithMany("Notifications") - .HasForeignKey("AthleteId") + b.HasOne("Entities.AthleteEntity", "Sender") + .WithMany("NotificationsSent") + .HasForeignKey("SenderId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Athlete"); + b.Navigation("Sender"); }); modelBuilder.Entity("Entities.StatisticEntity", b => { b.HasOne("Entities.AthleteEntity", "Athlete") .WithMany("Statistics") - .HasForeignKey("AthleteId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); + .HasForeignKey("AthleteId"); b.Navigation("Athlete"); }); modelBuilder.Entity("Entities.TrainingEntity", b => { - b.HasOne("Entities.AthleteEntity", "Athlete") - .WithMany("Trainings") - .HasForeignKey("AthleteId") + b.HasOne("Entities.AthleteEntity", "Coach") + .WithMany("TrainingsCoach") + .HasForeignKey("CoachId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Athlete"); + b.Navigation("Coach"); }); modelBuilder.Entity("Entities.ActivityEntity", b => @@ -823,11 +954,15 @@ namespace StubbedContextLib.Migrations { b.Navigation("Activities"); - b.Navigation("Notifications"); + b.Navigation("Followers"); + + b.Navigation("Followings"); + + b.Navigation("NotificationsSent"); b.Navigation("Statistics"); - b.Navigation("Trainings"); + b.Navigation("TrainingsCoach"); }); modelBuilder.Entity("Entities.DataSourceEntity", b => diff --git a/src/StubbedContextLib/Migrations/20240226170604_MyMigrations.cs b/src/StubbedContextLib/Migrations/20240307081406_MyMigrations.cs similarity index 71% rename from src/StubbedContextLib/Migrations/20240226170604_MyMigrations.cs rename to src/StubbedContextLib/Migrations/20240307081406_MyMigrations.cs index 2473ddc..c4ebbca 100644 --- a/src/StubbedContextLib/Migrations/20240226170604_MyMigrations.cs +++ b/src/StubbedContextLib/Migrations/20240307081406_MyMigrations.cs @@ -85,8 +85,7 @@ namespace StubbedContextLib.Migrations name: "FK_Activity_Athlete_AthleteId", column: x => x.AthleteId, principalTable: "Athlete", - principalColumn: "IdAthlete", - onDelete: ReferentialAction.Cascade); + principalColumn: "IdAthlete"); table.ForeignKey( name: "FK_Activity_DataSource_DataSourceId", column: x => x.DataSourceId, @@ -94,6 +93,31 @@ namespace StubbedContextLib.Migrations principalColumn: "IdSource"); }); + migrationBuilder.CreateTable( + name: "FriendshipEntity", + columns: table => new + { + FollowingId = table.Column(type: "INTEGER", nullable: false), + FollowerId = table.Column(type: "INTEGER", nullable: false), + StartDate = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_FriendshipEntity", x => new { x.FollowingId, x.FollowerId }); + table.ForeignKey( + name: "FK_FriendshipEntity_Athlete_FollowerId", + column: x => x.FollowerId, + principalTable: "Athlete", + principalColumn: "IdAthlete", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_FriendshipEntity_Athlete_FollowingId", + column: x => x.FollowingId, + principalTable: "Athlete", + principalColumn: "IdAthlete", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.CreateTable( name: "Notification", columns: table => new @@ -104,14 +128,14 @@ namespace StubbedContextLib.Migrations Date = table.Column(type: "TEXT", nullable: false), Statut = table.Column(type: "INTEGER", nullable: false), Urgence = table.Column(type: "TEXT", maxLength: 100, nullable: false), - AthleteId = table.Column(type: "INTEGER", nullable: false) + SenderId = table.Column(type: "INTEGER", nullable: false) }, constraints: table => { table.PrimaryKey("PK_Notification", x => x.IdNotif); table.ForeignKey( - name: "FK_Notification_Athlete_AthleteId", - column: x => x.AthleteId, + name: "FK_Notification_Athlete_SenderId", + column: x => x.SenderId, principalTable: "Athlete", principalColumn: "IdAthlete", onDelete: ReferentialAction.Cascade); @@ -137,8 +161,7 @@ namespace StubbedContextLib.Migrations name: "FK_Statistic_Athlete_AthleteId", column: x => x.AthleteId, principalTable: "Athlete", - principalColumn: "IdAthlete", - onDelete: ReferentialAction.Cascade); + principalColumn: "IdAthlete"); }); migrationBuilder.CreateTable( @@ -152,14 +175,14 @@ namespace StubbedContextLib.Migrations Latitude = table.Column(type: "REAL", nullable: false), Longitude = table.Column(type: "REAL", nullable: false), FeedBack = table.Column(type: "TEXT", maxLength: 300, nullable: true), - AthleteId = table.Column(type: "INTEGER", nullable: false) + CoachId = table.Column(type: "INTEGER", nullable: false) }, constraints: table => { table.PrimaryKey("PK_Training", x => x.IdTraining); table.ForeignKey( - name: "FK_Training_Athlete_AthleteId", - column: x => x.AthleteId, + name: "FK_Training_Athlete_CoachId", + column: x => x.CoachId, principalTable: "Athlete", principalColumn: "IdAthlete", onDelete: ReferentialAction.Cascade); @@ -190,6 +213,54 @@ namespace StubbedContextLib.Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateTable( + name: "AthleteEntityNotificationEntity", + columns: table => new + { + NotificationsReceivedIdNotif = table.Column(type: "INTEGER", nullable: false), + ReceiversIdAthlete = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AthleteEntityNotificationEntity", x => new { x.NotificationsReceivedIdNotif, x.ReceiversIdAthlete }); + table.ForeignKey( + name: "FK_AthleteEntityNotificationEntity_Athlete_ReceiversIdAthlete", + column: x => x.ReceiversIdAthlete, + principalTable: "Athlete", + principalColumn: "IdAthlete", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AthleteEntityNotificationEntity_Notification_NotificationsReceivedIdNotif", + column: x => x.NotificationsReceivedIdNotif, + principalTable: "Notification", + principalColumn: "IdNotif", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AthleteEntityTrainingEntity", + columns: table => new + { + AthletesIdAthlete = table.Column(type: "INTEGER", nullable: false), + TrainingsAthleteIdTraining = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AthleteEntityTrainingEntity", x => new { x.AthletesIdAthlete, x.TrainingsAthleteIdTraining }); + table.ForeignKey( + name: "FK_AthleteEntityTrainingEntity_Athlete_AthletesIdAthlete", + column: x => x.AthletesIdAthlete, + principalTable: "Athlete", + principalColumn: "IdAthlete", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AthleteEntityTrainingEntity_Training_TrainingsAthleteIdTraining", + column: x => x.TrainingsAthleteIdTraining, + principalTable: "Training", + principalColumn: "IdTraining", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.InsertData( table: "Athlete", columns: new[] { "IdAthlete", "DataSourceId", "DateOfBirth", "Email", "FirstName", "IsCoach", "LastName", "Length", "Password", "Sexe", "Username", "Weight" }, @@ -233,14 +304,23 @@ namespace StubbedContextLib.Migrations { 5, 3, new DateOnly(1991, 1, 1), "bruce.lee@example.com", "Bruce", false, "Lee", 2.0, "hello321", "M", "Lee", 90f } }); + migrationBuilder.InsertData( + table: "FriendshipEntity", + columns: new[] { "FollowerId", "FollowingId", "StartDate" }, + values: new object[,] + { + { 1, 3, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) }, + { 1, 4, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) } + }); + migrationBuilder.InsertData( table: "Notification", - columns: new[] { "IdNotif", "AthleteId", "Date", "Message", "Statut", "Urgence" }, + columns: new[] { "IdNotif", "Date", "Message", "SenderId", "Statut", "Urgence" }, values: new object[,] { - { 1, 1, new DateTime(2023, 12, 25, 13, 0, 40, 0, DateTimeKind.Unspecified), "You have a new activity to check", true, "A" }, - { 3, 3, new DateTime(2023, 12, 26, 16, 10, 4, 0, DateTimeKind.Unspecified), "You have a new heart rate to check", true, "2" }, - { 4, 4, new DateTime(2024, 1, 12, 9, 30, 50, 0, DateTimeKind.Unspecified), "You have a new data source to check", false, "1" } + { 1, new DateTime(2023, 12, 25, 13, 0, 40, 0, DateTimeKind.Unspecified), "You have a new activity to check", 1, true, "A" }, + { 3, new DateTime(2023, 12, 26, 16, 10, 4, 0, DateTimeKind.Unspecified), "You have a new heart rate to check", 3, true, "2" }, + { 4, new DateTime(2024, 1, 12, 9, 30, 50, 0, DateTimeKind.Unspecified), "You have a new data source to check", 4, false, "1" } }); migrationBuilder.InsertData( @@ -256,7 +336,7 @@ namespace StubbedContextLib.Migrations migrationBuilder.InsertData( table: "Training", - columns: new[] { "IdTraining", "AthleteId", "Date", "Description", "FeedBack", "Latitude", "Longitude" }, + columns: new[] { "IdTraining", "CoachId", "Date", "Description", "FeedBack", "Latitude", "Longitude" }, values: new object[,] { { 1, 1, new DateOnly(2024, 1, 19), "Running", "Good", 48.8566f, 2.3522f }, @@ -274,6 +354,17 @@ namespace StubbedContextLib.Migrations { 4, 5, 0.5f, 20f, 3, new DateOnly(2024, 1, 2), 5, new TimeOnly(16, 1, 55), false, 0, 0, 0.5f, new TimeOnly(15, 0, 0), "Walking", 0.5f, 0.5f } }); + migrationBuilder.InsertData( + table: "FriendshipEntity", + columns: new[] { "FollowerId", "FollowingId", "StartDate" }, + values: new object[,] + { + { 2, 1, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) }, + { 1, 2, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) }, + { 2, 3, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) }, + { 1, 5, new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) } + }); + migrationBuilder.InsertData( table: "HeartRate", columns: new[] { "IdHeartRate", "ActivityId", "Altitude", "Bpm", "Latitude", "Longitude", "Temperature", "Time" }, @@ -285,11 +376,11 @@ namespace StubbedContextLib.Migrations migrationBuilder.InsertData( table: "Notification", - columns: new[] { "IdNotif", "AthleteId", "Date", "Message", "Statut", "Urgence" }, + columns: new[] { "IdNotif", "Date", "Message", "SenderId", "Statut", "Urgence" }, values: new object[,] { - { 2, 2, new DateTime(2023, 12, 26, 13, 10, 40, 0, DateTimeKind.Unspecified), "You have a new athlete to check", false, "3" }, - { 5, 5, new DateTime(2024, 2, 22, 12, 10, 0, 0, DateTimeKind.Unspecified), "You have a new notification to check", true, "3" } + { 2, new DateTime(2023, 12, 26, 13, 10, 40, 0, DateTimeKind.Unspecified), "You have a new athlete to check", 2, false, "3" }, + { 5, new DateTime(2024, 2, 22, 12, 10, 0, 0, DateTimeKind.Unspecified), "You have a new notification to check", 5, true, "3" } }); migrationBuilder.InsertData( @@ -299,7 +390,7 @@ namespace StubbedContextLib.Migrations migrationBuilder.InsertData( table: "Training", - columns: new[] { "IdTraining", "AthleteId", "Date", "Description", "FeedBack", "Latitude", "Longitude" }, + columns: new[] { "IdTraining", "CoachId", "Date", "Description", "FeedBack", "Latitude", "Longitude" }, values: new object[] { 2, 5, new DateOnly(2024, 2, 20), "Cycling", null, 48.8566f, 2.3522f }); migrationBuilder.InsertData( @@ -327,15 +418,30 @@ namespace StubbedContextLib.Migrations table: "Athlete", column: "DataSourceId"); + migrationBuilder.CreateIndex( + name: "IX_AthleteEntityNotificationEntity_ReceiversIdAthlete", + table: "AthleteEntityNotificationEntity", + column: "ReceiversIdAthlete"); + + migrationBuilder.CreateIndex( + name: "IX_AthleteEntityTrainingEntity_TrainingsAthleteIdTraining", + table: "AthleteEntityTrainingEntity", + column: "TrainingsAthleteIdTraining"); + + migrationBuilder.CreateIndex( + name: "IX_FriendshipEntity_FollowerId", + table: "FriendshipEntity", + column: "FollowerId"); + migrationBuilder.CreateIndex( name: "IX_HeartRate_ActivityId", table: "HeartRate", column: "ActivityId"); migrationBuilder.CreateIndex( - name: "IX_Notification_AthleteId", + name: "IX_Notification_SenderId", table: "Notification", - column: "AthleteId"); + column: "SenderId"); migrationBuilder.CreateIndex( name: "IX_Statistic_AthleteId", @@ -343,23 +449,32 @@ namespace StubbedContextLib.Migrations column: "AthleteId"); migrationBuilder.CreateIndex( - name: "IX_Training_AthleteId", + name: "IX_Training_CoachId", table: "Training", - column: "AthleteId"); + column: "CoachId"); } /// protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( - name: "HeartRate"); + name: "AthleteEntityNotificationEntity"); migrationBuilder.DropTable( - name: "Notification"); + name: "AthleteEntityTrainingEntity"); + + migrationBuilder.DropTable( + name: "FriendshipEntity"); + + migrationBuilder.DropTable( + name: "HeartRate"); migrationBuilder.DropTable( name: "Statistic"); + migrationBuilder.DropTable( + name: "Notification"); + migrationBuilder.DropTable( name: "Training"); diff --git a/src/StubbedContextLib/Migrations/TrainingStubbedContextModelSnapshot.cs b/src/StubbedContextLib/Migrations/TrainingStubbedContextModelSnapshot.cs index d1047be..93bd1a3 100644 --- a/src/StubbedContextLib/Migrations/TrainingStubbedContextModelSnapshot.cs +++ b/src/StubbedContextLib/Migrations/TrainingStubbedContextModelSnapshot.cs @@ -17,6 +17,36 @@ namespace StubbedContextLib.Migrations #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "8.0.2"); + modelBuilder.Entity("AthleteEntityNotificationEntity", b => + { + b.Property("NotificationsReceivedIdNotif") + .HasColumnType("INTEGER"); + + b.Property("ReceiversIdAthlete") + .HasColumnType("INTEGER"); + + b.HasKey("NotificationsReceivedIdNotif", "ReceiversIdAthlete"); + + b.HasIndex("ReceiversIdAthlete"); + + b.ToTable("AthleteEntityNotificationEntity"); + }); + + modelBuilder.Entity("AthleteEntityTrainingEntity", b => + { + b.Property("AthletesIdAthlete") + .HasColumnType("INTEGER"); + + b.Property("TrainingsAthleteIdTraining") + .HasColumnType("INTEGER"); + + b.HasKey("AthletesIdAthlete", "TrainingsAthleteIdTraining"); + + b.HasIndex("TrainingsAthleteIdTraining"); + + b.ToTable("AthleteEntityTrainingEntity"); + }); + modelBuilder.Entity("Entities.ActivityEntity", b => { b.Property("IdActivity") @@ -406,6 +436,62 @@ namespace StubbedContextLib.Migrations }); }); + modelBuilder.Entity("Entities.FriendshipEntity", b => + { + b.Property("FollowingId") + .HasColumnType("INTEGER"); + + b.Property("FollowerId") + .HasColumnType("INTEGER"); + + b.Property("StartDate") + .HasColumnType("TEXT"); + + b.HasKey("FollowingId", "FollowerId"); + + b.HasIndex("FollowerId"); + + b.ToTable("FriendshipEntity"); + + b.HasData( + new + { + FollowingId = 2, + FollowerId = 1, + StartDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }, + new + { + FollowingId = 3, + FollowerId = 1, + StartDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }, + new + { + FollowingId = 4, + FollowerId = 1, + StartDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }, + new + { + FollowingId = 5, + FollowerId = 1, + StartDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }, + new + { + FollowingId = 1, + FollowerId = 2, + StartDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }, + new + { + FollowingId = 3, + FollowerId = 2, + StartDate = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) + }); + }); + modelBuilder.Entity("Entities.HeartRateEntity", b => { b.Property("IdHeartRate") @@ -503,9 +589,6 @@ namespace StubbedContextLib.Migrations .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("AthleteId") - .HasColumnType("INTEGER"); - b.Property("Date") .HasColumnType("TEXT"); @@ -514,6 +597,9 @@ namespace StubbedContextLib.Migrations .HasMaxLength(100) .HasColumnType("TEXT"); + b.Property("SenderId") + .HasColumnType("INTEGER"); + b.Property("Statut") .HasColumnType("INTEGER"); @@ -524,7 +610,7 @@ namespace StubbedContextLib.Migrations b.HasKey("IdNotif"); - b.HasIndex("AthleteId"); + b.HasIndex("SenderId"); b.ToTable("Notification"); @@ -532,45 +618,45 @@ namespace StubbedContextLib.Migrations new { IdNotif = 1, - AthleteId = 1, Date = new DateTime(2023, 12, 25, 13, 0, 40, 0, DateTimeKind.Unspecified), Message = "You have a new activity to check", + SenderId = 1, Statut = true, Urgence = "A" }, new { IdNotif = 2, - AthleteId = 2, Date = new DateTime(2023, 12, 26, 13, 10, 40, 0, DateTimeKind.Unspecified), Message = "You have a new athlete to check", + SenderId = 2, Statut = false, Urgence = "3" }, new { IdNotif = 3, - AthleteId = 3, Date = new DateTime(2023, 12, 26, 16, 10, 4, 0, DateTimeKind.Unspecified), Message = "You have a new heart rate to check", + SenderId = 3, Statut = true, Urgence = "2" }, new { IdNotif = 4, - AthleteId = 4, Date = new DateTime(2024, 1, 12, 9, 30, 50, 0, DateTimeKind.Unspecified), Message = "You have a new data source to check", + SenderId = 4, Statut = false, Urgence = "1" }, new { IdNotif = 5, - AthleteId = 5, Date = new DateTime(2024, 2, 22, 12, 10, 0, 0, DateTimeKind.Unspecified), Message = "You have a new notification to check", + SenderId = 5, Statut = true, Urgence = "3" }); @@ -665,7 +751,7 @@ namespace StubbedContextLib.Migrations .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("AthleteId") + b.Property("CoachId") .HasColumnType("INTEGER"); b.Property("Date") @@ -687,7 +773,7 @@ namespace StubbedContextLib.Migrations b.HasKey("IdTraining"); - b.HasIndex("AthleteId"); + b.HasIndex("CoachId"); b.ToTable("Training"); @@ -695,7 +781,7 @@ namespace StubbedContextLib.Migrations new { IdTraining = 1, - AthleteId = 1, + CoachId = 1, Date = new DateOnly(2024, 1, 19), Description = "Running", FeedBack = "Good", @@ -705,7 +791,7 @@ namespace StubbedContextLib.Migrations new { IdTraining = 2, - AthleteId = 5, + CoachId = 5, Date = new DateOnly(2024, 2, 20), Description = "Cycling", Latitude = 48.8566f, @@ -714,7 +800,7 @@ namespace StubbedContextLib.Migrations new { IdTraining = 3, - AthleteId = 4, + CoachId = 4, Date = new DateOnly(2024, 2, 21), FeedBack = "Good", Latitude = 48.8566f, @@ -723,7 +809,7 @@ namespace StubbedContextLib.Migrations new { IdTraining = 4, - AthleteId = 3, + CoachId = 3, Date = new DateOnly(2024, 2, 22), Description = "Running", FeedBack = "Good", @@ -733,7 +819,7 @@ namespace StubbedContextLib.Migrations new { IdTraining = 5, - AthleteId = 1, + CoachId = 1, Date = new DateOnly(2024, 2, 23), Description = "Cycling", Latitude = 48.8566f, @@ -741,13 +827,41 @@ namespace StubbedContextLib.Migrations }); }); + modelBuilder.Entity("AthleteEntityNotificationEntity", b => + { + b.HasOne("Entities.NotificationEntity", null) + .WithMany() + .HasForeignKey("NotificationsReceivedIdNotif") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Entities.AthleteEntity", null) + .WithMany() + .HasForeignKey("ReceiversIdAthlete") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("AthleteEntityTrainingEntity", b => + { + b.HasOne("Entities.AthleteEntity", null) + .WithMany() + .HasForeignKey("AthletesIdAthlete") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Entities.TrainingEntity", null) + .WithMany() + .HasForeignKey("TrainingsAthleteIdTraining") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("Entities.ActivityEntity", b => { b.HasOne("Entities.AthleteEntity", "Athlete") .WithMany("Activities") - .HasForeignKey("AthleteId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); + .HasForeignKey("AthleteId"); b.HasOne("Entities.DataSourceEntity", "DataSource") .WithMany("Activities") @@ -767,6 +881,25 @@ namespace StubbedContextLib.Migrations b.Navigation("DataSource"); }); + modelBuilder.Entity("Entities.FriendshipEntity", b => + { + b.HasOne("Entities.AthleteEntity", "Follower") + .WithMany("Followers") + .HasForeignKey("FollowerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Entities.AthleteEntity", "Following") + .WithMany("Followings") + .HasForeignKey("FollowingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Follower"); + + b.Navigation("Following"); + }); + modelBuilder.Entity("Entities.HeartRateEntity", b => { b.HasOne("Entities.ActivityEntity", "Activity") @@ -780,35 +913,33 @@ namespace StubbedContextLib.Migrations modelBuilder.Entity("Entities.NotificationEntity", b => { - b.HasOne("Entities.AthleteEntity", "Athlete") - .WithMany("Notifications") - .HasForeignKey("AthleteId") + b.HasOne("Entities.AthleteEntity", "Sender") + .WithMany("NotificationsSent") + .HasForeignKey("SenderId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Athlete"); + b.Navigation("Sender"); }); modelBuilder.Entity("Entities.StatisticEntity", b => { b.HasOne("Entities.AthleteEntity", "Athlete") .WithMany("Statistics") - .HasForeignKey("AthleteId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); + .HasForeignKey("AthleteId"); b.Navigation("Athlete"); }); modelBuilder.Entity("Entities.TrainingEntity", b => { - b.HasOne("Entities.AthleteEntity", "Athlete") - .WithMany("Trainings") - .HasForeignKey("AthleteId") + b.HasOne("Entities.AthleteEntity", "Coach") + .WithMany("TrainingsCoach") + .HasForeignKey("CoachId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Athlete"); + b.Navigation("Coach"); }); modelBuilder.Entity("Entities.ActivityEntity", b => @@ -820,11 +951,15 @@ namespace StubbedContextLib.Migrations { b.Navigation("Activities"); - b.Navigation("Notifications"); + b.Navigation("Followers"); + + b.Navigation("Followings"); + + b.Navigation("NotificationsSent"); b.Navigation("Statistics"); - b.Navigation("Trainings"); + b.Navigation("TrainingsCoach"); }); modelBuilder.Entity("Entities.DataSourceEntity", b => diff --git a/src/StubbedContextLib/NotificationStubbedContext.cs b/src/StubbedContextLib/NotificationStubbedContext.cs index 6a15a4f..91ff31d 100644 --- a/src/StubbedContextLib/NotificationStubbedContext.cs +++ b/src/StubbedContextLib/NotificationStubbedContext.cs @@ -37,11 +37,11 @@ namespace StubbedContextLib base.OnModelCreating(modelBuilder); modelBuilder.Entity().HasData( - new NotificationEntity { IdNotif = 1, Message = "You have a new activity to check", Date = new DateTime(2023, 12, 25, 13, 00, 40), Statut = true, Urgence = "A", AthleteId = 1 }, - new NotificationEntity { IdNotif = 2, Message = "You have a new athlete to check", Date = new DateTime(2023, 12, 26, 13, 10, 40), Statut = false, Urgence = "3", AthleteId = 2 }, - new NotificationEntity { IdNotif = 3, Message = "You have a new heart rate to check", Date = new DateTime(2023, 12, 26, 16, 10, 04), Statut = true, Urgence = "2", AthleteId = 3 }, - new NotificationEntity { IdNotif = 4, Message = "You have a new data source to check", Date = new DateTime(2024, 01, 12, 09, 30, 50), Statut = false, Urgence = "1", AthleteId = 4 }, - new NotificationEntity { IdNotif = 5, Message = "You have a new notification to check", Date = new DateTime(2024, 02, 22, 12, 10, 00), Statut = true, Urgence = "3", AthleteId = 5 } + new NotificationEntity { IdNotif = 1, Message = "You have a new activity to check", Date = new DateTime(2023, 12, 25, 13, 00, 40), Statut = true, Urgence = "A", SenderId = 1 }, + new NotificationEntity { IdNotif = 2, Message = "You have a new athlete to check", Date = new DateTime(2023, 12, 26, 13, 10, 40), Statut = false, Urgence = "3", SenderId = 2 }, + new NotificationEntity { IdNotif = 3, Message = "You have a new heart rate to check", Date = new DateTime(2023, 12, 26, 16, 10, 04), Statut = true, Urgence = "2", SenderId = 3 }, + new NotificationEntity { IdNotif = 4, Message = "You have a new data source to check", Date = new DateTime(2024, 01, 12, 09, 30, 50), Statut = false, Urgence = "1", SenderId = 4 }, + new NotificationEntity { IdNotif = 5, Message = "You have a new notification to check", Date = new DateTime(2024, 02, 22, 12, 10, 00), Statut = true, Urgence = "3", SenderId = 5 } ); } } diff --git a/src/StubbedContextLib/TrainingStubbedContext.cs b/src/StubbedContextLib/TrainingStubbedContext.cs index 389ed6e..76a5820 100644 --- a/src/StubbedContextLib/TrainingStubbedContext.cs +++ b/src/StubbedContextLib/TrainingStubbedContext.cs @@ -37,11 +37,11 @@ namespace StubbedContextLib base.OnModelCreating(modelBuilder); modelBuilder.Entity().HasData( - new TrainingEntity { IdTraining = 1, Date = new DateOnly(2024, 01, 19), Description = "Running", Latitude = 48.8566f, Longitude = 2.3522f, FeedBack = "Good", AthleteId = 1 }, - new TrainingEntity { IdTraining = 2, Date = new DateOnly(2024, 02, 20), Description = "Cycling", Latitude = 48.8566f, Longitude = 2.3522f, AthleteId = 5 }, - new TrainingEntity { IdTraining = 3, Date = new DateOnly(2024, 02, 21), Latitude = 48.8566f, Longitude = 2.3522f, FeedBack = "Good", AthleteId = 4 }, - new TrainingEntity { IdTraining = 4, Date = new DateOnly(2024, 02, 22), Description = "Running", Latitude = 48.8566f, Longitude = 2.3522f, FeedBack = "Good", AthleteId = 3 }, - new TrainingEntity { IdTraining = 5, Date = new DateOnly(2024, 02, 23), Description = "Cycling", Latitude = 48.8566f, Longitude = 2.3522f, AthleteId = 1 } + new TrainingEntity { IdTraining = 1, Date = new DateOnly(2024, 01, 19), Description = "Running", Latitude = 48.8566f, Longitude = 2.3522f, FeedBack = "Good", CoachId = 1 }, + new TrainingEntity { IdTraining = 2, Date = new DateOnly(2024, 02, 20), Description = "Cycling", Latitude = 48.8566f, Longitude = 2.3522f, CoachId = 5 }, + new TrainingEntity { IdTraining = 3, Date = new DateOnly(2024, 02, 21), Latitude = 48.8566f, Longitude = 2.3522f, FeedBack = "Good", CoachId = 4 }, + new TrainingEntity { IdTraining = 4, Date = new DateOnly(2024, 02, 22), Description = "Running", Latitude = 48.8566f, Longitude = 2.3522f, FeedBack = "Good", CoachId = 3 }, + new TrainingEntity { IdTraining = 5, Date = new DateOnly(2024, 02, 23), Description = "Cycling", Latitude = 48.8566f, Longitude = 2.3522f, CoachId = 1 } ); } } diff --git a/src/Tests/ConsoleTestRelationships/Program.cs b/src/Tests/ConsoleTestRelationships/Program.cs index b43a033..17f9509 100644 --- a/src/Tests/ConsoleTestRelationships/Program.cs +++ b/src/Tests/ConsoleTestRelationships/Program.cs @@ -16,6 +16,8 @@ class Program DataSourceTests(db); AthleteTests(db); + + FriendshipTests(db); } } catch (Exception ex) @@ -34,12 +36,12 @@ class Program { Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); - Console.WriteLine("\tFréquences cardiaques :"); - Console.WriteLine("\t---------------------------------"); + Console.WriteLine("\t\tFréquences cardiaques :"); + Console.WriteLine("\t\t---------------------------------"); foreach (var heartRate in activity.HeartRates) { - Console.WriteLine($"\t\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); + Console.WriteLine($"\t\t\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); } } @@ -52,12 +54,12 @@ class Program { Console.WriteLine($"\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); - Console.WriteLine("\tFréquences cardiaques :"); - Console.WriteLine("\t---------------------------------"); + Console.WriteLine("\t\tFréquences cardiaques :"); + Console.WriteLine("\t\t---------------------------------"); foreach (var heartRate in activity.HeartRates) { - Console.WriteLine($"\t\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); + Console.WriteLine($"\t\t\t{heartRate.IdHeartRate} - {heartRate.Altitude}, {heartRate.Time}, {heartRate.Temperature}, {heartRate.Bpm}, {heartRate.Longitude}, {heartRate.Latitude}"); } } } @@ -69,24 +71,24 @@ class Program Console.WriteLine("Sources de données :"); Console.WriteLine("---------------------------------"); - foreach (var dataSource in db.DataSourcesSet.Include(ds => ds.Activities)) + foreach (var dataSource in db.DataSourcesSet.Include(ds => ds.Activities).Include(ds => ds.Athletes)) { Console.WriteLine($"\t{dataSource.IdSource} - {dataSource.Model}"); - Console.WriteLine("\tActivités :"); - Console.WriteLine("\t---------------------------------"); + Console.WriteLine("\t\tActivités :"); + Console.WriteLine("\t\t---------------------------------"); foreach (var activity in dataSource.Activities) { - Console.WriteLine($"\t\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + Console.WriteLine($"\t\t\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); } - Console.WriteLine("\tAthletes :"); - Console.WriteLine("\t---------------------------------"); + Console.WriteLine("\t\tAthletes :"); + Console.WriteLine("\t\t---------------------------------"); foreach (var athlete in dataSource.Athletes) { - Console.WriteLine($"\t\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); + Console.WriteLine($"\t\t\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); } } @@ -95,24 +97,24 @@ class Program Console.WriteLine("Accès à la source de données d'id '2' :"); Console.WriteLine("---------------------------------"); - foreach (var dataSource in db.DataSourcesSet.Where(ds => ds.IdSource == 2).Include(ds => ds.Activities)) + foreach (var dataSource in db.DataSourcesSet.Where(ds => ds.IdSource == 2).Include(ds => ds.Activities).Include(ds => ds.Athletes)) { Console.WriteLine($"\t{dataSource.IdSource} - {dataSource.Model}"); - Console.WriteLine("\tActivités :"); - Console.WriteLine("\t---------------------------------"); + Console.WriteLine("\t\tActivités :"); + Console.WriteLine("\t\t---------------------------------"); foreach (var activity in dataSource.Activities) { - Console.WriteLine($"\t\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + Console.WriteLine($"\t\t\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); } - Console.WriteLine("\tAthletes :"); - Console.WriteLine("\t---------------------------------"); + Console.WriteLine("\t\tAthletes :"); + Console.WriteLine("\t\t---------------------------------"); foreach (var athlete in dataSource.Athletes) { - Console.WriteLine($"\t\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); + Console.WriteLine($"\t\t\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); } } @@ -126,48 +128,62 @@ class Program Console.WriteLine("Athlètes :"); Console.WriteLine("---------------------------------"); - // ! Pas oublier de faire tous les includes necessaire ! - // ? Mais comment ? - foreach (var athlete in db.AthletesSet.Include(a => a.Statistics)) + foreach (var athlete in db.AthletesSet.Include(a => a.Statistics).Include(a => a.Activities).Include(a => a.TrainingsAthlete).Include(a => a.NotificationsSent).Include(a => a.DataSource).Include(a => a.TrainingsCoach).Include(a => a.NotificationsReceived)) { Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); - Console.WriteLine("\tStatistiques :"); - Console.WriteLine("\t---------------------------------"); + Console.WriteLine("\t\tStatistiques :"); + Console.WriteLine("\t\t---------------------------------"); foreach (var statistic in athlete.Statistics) { - Console.WriteLine($"\t\t{statistic.IdStatistic} - {statistic.Date}, {statistic.AverageCaloriesBurned}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}"); + Console.WriteLine($"\t\t\t{statistic.IdStatistic} - {statistic.Date}, {statistic.AverageCaloriesBurned}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}"); } - Console.WriteLine("\tActivités :"); - Console.WriteLine("\t---------------------------------"); + Console.WriteLine("\t\tActivités :"); + Console.WriteLine("\t\t---------------------------------"); foreach (var activity in athlete.Activities) { - Console.WriteLine($"\t\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + Console.WriteLine($"\t\t\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("\t\tEntraînements :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var training in athlete.TrainingsAthlete) + { + Console.WriteLine($"\t\t\t{training.IdTraining} - {training.Date}, {training.Latitude}, {training.Longitude}, {training.Description}, {training.FeedBack}"); + } + + Console.WriteLine("\t\tEntrainements données :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var training in athlete.TrainingsCoach) + { + Console.WriteLine($"\t\t\t{training.IdTraining} - {training.Date}, {training.Latitude}, {training.Longitude}, {training.Description}, {training.FeedBack}"); } - Console.WriteLine("\tEntraînements :"); - Console.WriteLine("\t---------------------------------"); + Console.WriteLine("\t\tNotifications reçus :"); + Console.WriteLine("\t\t---------------------------------"); - foreach (var training in athlete.Trainings) + foreach (var notification in athlete.NotificationsReceived) { - Console.WriteLine($"\t\t{training.IdTraining} - {training.Date}, {training.Latitude}, {training.Longitude}, {training.Description}, {training.FeedBack}"); + Console.WriteLine($"\t\t\t{notification.IdNotif} - {notification.Date}, {notification.Statut}, {notification.Message}"); } - Console.WriteLine("\tNotifications :"); - Console.WriteLine("\t---------------------------------"); + Console.WriteLine("\t\tNotifications données :"); + Console.WriteLine("\t\t---------------------------------"); - foreach (var notification in athlete.Notifications) + foreach (var notification in athlete.NotificationsSent) { - Console.WriteLine($"\t\t{notification.IdNotif} - {notification.Date}, {notification.Statut}, {notification.Message}"); + Console.WriteLine($"\t\t\t{notification.IdNotif} - {notification.Date}, {notification.Statut}, {notification.Message}"); } - Console.WriteLine("\tSources de données :"); - Console.WriteLine("\t---------------------------------"); + Console.WriteLine("\t\tSources de données :"); + Console.WriteLine("\t\t---------------------------------"); - Console.WriteLine("\t\t" + (athlete.DataSource?.Model ?? "Aucune source de données")); + Console.WriteLine("\t\t\t" + (athlete.DataSource?.Model ?? "Aucune source de données")); } Console.WriteLine("---------------------------------\n"); @@ -175,49 +191,117 @@ class Program Console.WriteLine("Accès à l'athlète d'id '2' :"); Console.WriteLine("---------------------------------"); - foreach (var athlete in db.AthletesSet.Where(a => a.IdAthlete == 2).Include(a => a.Statistics)) + foreach (var athlete in db.AthletesSet.Where(a => a.IdAthlete == 2).Include(a => a.Statistics).Include(a => a.Activities).Include(a => a.TrainingsAthlete).Include(a => a.NotificationsSent).Include(a => a.DataSource).Include(a => a.TrainingsCoach).Include(a => a.NotificationsReceived)) { Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); - Console.WriteLine("\tStatistiques :"); - Console.WriteLine("\t---------------------------------"); + Console.WriteLine("\t\tStatistiques :"); + Console.WriteLine("\t\t---------------------------------"); foreach (var statistic in athlete.Statistics) { - Console.WriteLine($"\t\t{statistic.IdStatistic} - {statistic.Date}, {statistic.AverageCaloriesBurned}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}"); + Console.WriteLine($"\t\t\t{statistic.IdStatistic} - {statistic.Date}, {statistic.AverageCaloriesBurned}, {statistic.AverageHeartRate}, {statistic.MaximumHeartRate}"); } - Console.WriteLine("\tActivités :"); - Console.WriteLine("\t---------------------------------"); + Console.WriteLine("\t\tActivités :"); + Console.WriteLine("\t\t---------------------------------"); foreach (var activity in athlete.Activities) { - Console.WriteLine($"\t\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + Console.WriteLine($"\t\t\t{activity.IdActivity} - {activity.Type}, {activity.Date}, {activity.StartTime}, {activity.EndTime}, {activity.EffortFelt}, {activity.Variability}, {activity.Variance}, {activity.StandardDeviation}, {activity.Average}, {activity.Maximum}, {activity.Minimum}, {activity.AverageTemperature}, {activity.HasAutoPause}"); + } + + Console.WriteLine("\t\tEntraînements :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var training in athlete.TrainingsAthlete) + { + Console.WriteLine($"\t\t\t{training.IdTraining} - {training.Date}, {training.Latitude}, {training.Longitude}, {training.Description}, {training.FeedBack}"); + } + + Console.WriteLine("\t\tEntrainements données :"); + Console.WriteLine("\t\t---------------------------------"); + + foreach (var training in athlete.TrainingsCoach) + { + Console.WriteLine($"\t\t\t{training.IdTraining} - {training.Date}, {training.Latitude}, {training.Longitude}, {training.Description}, {training.FeedBack}"); } - Console.WriteLine("\tEntraînements :"); - Console.WriteLine("\t---------------------------------"); + Console.WriteLine("\t\tNotifications reçus :"); + Console.WriteLine("\t\t---------------------------------"); - foreach (var training in athlete.Trainings) + foreach (var notification in athlete.NotificationsReceived) { - Console.WriteLine($"\t\t{training.IdTraining} - {training.Date}, {training.Latitude}, {training.Longitude}, {training.Description}, {training.FeedBack}"); + Console.WriteLine($"\t\t\t{notification.IdNotif} - {notification.Date}, {notification.Statut}, {notification.Message}"); } - Console.WriteLine("\tNotifications :"); - Console.WriteLine("\t---------------------------------"); + Console.WriteLine("\t\tNotifications données :"); + Console.WriteLine("\t\t---------------------------------"); - foreach (var notification in athlete.Notifications) + foreach (var notification in athlete.NotificationsSent) { - Console.WriteLine($"\t\t{notification.IdNotif} - {notification.Date}, {notification.Statut}, {notification.Message}"); + Console.WriteLine($"\t\t\t{notification.IdNotif} - {notification.Date}, {notification.Statut}, {notification.Message}"); } - Console.WriteLine("\tSources de données :"); - Console.WriteLine("\t---------------------------------"); + Console.WriteLine("\t\tSources de données :"); + Console.WriteLine("\t\t---------------------------------"); - Console.WriteLine("\t\t" + (athlete.DataSource?.Model ?? "Aucune source de données")); + Console.WriteLine("\t\t\t" + (athlete.DataSource?.Model ?? "Aucune source de données")); } Console.WriteLine("---------------------------------\n"); } + static void FriendshipTests(LibraryContext db) + { + Console.WriteLine("Accès à toutes les amitiés :"); + + Console.WriteLine("Amitiés :"); + Console.WriteLine("---------------------------------"); + + foreach (var athlete in db.AthletesSet.Include(f => f.Followers).Include(f => f.Followings)) + { + Console.WriteLine($"\t{athlete.IdAthlete} - {athlete.FirstName}, {athlete.LastName}, {athlete.DateOfBirth}, {athlete.Sexe}, {athlete.Weight}, {athlete.IsCoach}"); + + Console.WriteLine($""); + Console.WriteLine($""); + + Console.WriteLine($"\t\t{athlete.Followers.Aggregate("", (seed, kvp) => $"{seed} [{kvp.FollowerId} ; {kvp.FollowingId} ; {kvp.StartDate.ToString("dd/MM/yyyy hh:mm:ss")}]")}"); + + // Console.WriteLine("\t\tFollowers :"); + // Console.WriteLine("\t\t---------------------------------"); + + // foreach (var followers in athlete.Followers) + // { + // Console.WriteLine($"\t\t\t{followers.IdAthlete} - {followers.FirstName}, {followers.LastName}, {followers.DateOfBirth}, {followers.Sexe}, {followers.Weight}, {followers.IsCoach}"); + // } + + // Console.WriteLine("\t\tFollowings :"); + // Console.WriteLine("\t\t---------------------------------"); + + // foreach (var following in athlete.Followings) + // { + // // Console.WriteLine($"\t\t{following.Followings.Aggregate("", (seed, kvp) => $"{seed} [{kvp.ArtistEntityId} ; {kvp.CreatedOn.ToString("dd/MM/yyyy hh:mm:ss")}]")}"); + // Console.WriteLine($"\t\t\t{following.IdAthlete} - {following.FirstName}, {following.LastName}, {following.DateOfBirth}, {following.Sexe}, {following.Weight}, {following.IsCoach}"); + // } + + // using (MyDbContext db = new MyDbContext()) + // { + // WriteLine("Content of database (albums) : "); + // foreach (var al in db.Albums.Include(a => a.Artists)) + // { + // WriteLine($"\t{al}"); + // WriteLine($"\t\t{al.AlbumArtists.Aggregate("", (seed, kvp) => $"{seed} [{kvp.ArtistEntityId} ; {kvp.CreatedOn.ToString("dd/MM/yyyy hh:mm:ss")}]")}"); + // } + + // WriteLine("Content of database (artists) : "); + // foreach (var ar in db.Artists) + // { + // WriteLine($"\t{ar}"); + // WriteLine($"\t\t{ar.ArtistAlbums.Aggregate("", (seed, kvp) => $"{seed} [{kvp.AlbumEntityId} ; {kvp.CreatedOn.ToString("dd/MM/yyyy hh:mm:ss")}]")}"); + // } + // } + } + } + } \ No newline at end of file diff --git a/src/Tests/ConsoleTestRelationships/uca.HeartTrack.db b/src/Tests/ConsoleTestRelationships/uca.HeartTrack.db index d2d197ff27b42c3e1a26834b3a5ce553b6a5d43a..8625b454be3624c5c5fa7eac2746af23e068bcc2 100644 GIT binary patch delta 3925 zcmeHK+i%lW7|*d|J9gt9r!;l%^`fygT?^^D!A1wP4e1nRYgt+*kTzvm6TniI&^BA) z0fllYLI@3X#KxpaL%dD{ME-znJWkuh9;hZwd*}n}1&V1 z-*>*t@$b9%$PwnqMeb~e*ybw#{O7u3HTM|AU7;5!2p<%E(itEe8x=UYqXW!+ght&m zs3~r{dl_^I!DAbFPF}wr%srP+eway*)Z7q$T< zIPbQdv4m64&Up0g!T282;gUKWOE=M;p2AcRDWbpMzCSUT-=9h6(+OhPc?N`o7FJ(J zHwFLJC+NVjJWh!gCO*s9b`L9$^#GTOU&6uZ$&88}NPe8p>9ixpM6cZn3=pnKw;otEZWA>I0DWL7S6li9e4}=1AmA2;XL;HI_%Qi1`Nw#9|27@`BI73$7tpUwgdPCteUcz1PnTHWy}-^_)Bt14l)@NJMv&%4L*aYlSyf67lpz zTKyzFH62ZvMb7+t+z#0++0l_5k=;sQjfs7@#6OjdfHFFw1fF0CSO0+1y+AOx4z(|L zfd&*^j(|G!>2f#lqYW#~Xnwhe_Hi=W_}z=39UNJUfnazKfWjHB~>Jzq)@9cvg;d+m_2>M{Jams+cY z!xBbV$wsM47|7aXsIzW2RtTyp)EE2o=+uoWA+CZA>r%o>I6|;tuc~YreJvXNtg;3I z^%V_%86o(7Eh|sPo(g_eMdl%`g`iWw=k0fSv`PP1#)~Fb+Cgpc?8?u8-&CW|b^mkf z=+{Q1lh%&|wC!%XE7i=&eQjWtA+3XCXu_Og2;GJbFE&448f~;nPFUIj5k@fEguY#T z3ACcyi$i@gjhwu7J(z7G+O5$h$d`q6u>~cU+PetH=onVMW~;;vPRi)(rEbuSeqGv8 zm=zm1Iobnedx7}21nb7Lsg1T zl_FYYS7X`jf}=6xzD!<`2|YqqD%6hNOoWZST5x2g!uFuZXpohPKIH~Piqyqwc(c-? zjkfVGU6nqQfV=3v@etw%w#eT57gAOQwhi?f&B6s2d_m_E@_oVhuNYx1-ga*W)Yx4t;X$Z5mL zE-ov}*ycSs;eaS3*XFVV%#4$LxeO*RKPWhP2DAHQ0d^r3F3sjd4t8;QdB%3ZlEkE( z)ZmiDlFZ_g%w#x&bF(4SI!2Ic9-wL?c6M=9RmL{;$*-AZ8963%vb+Tws>&(~GZd(- zEsqUsd9VKFU+lM;fST1O*K%=g{>;V0%E-P+;3+?+k&&69xq+F1$>w+Re~`JK^#vU^ zvrPD_znSsEfBt0#i~{<+{684j*)$pWuJW(tea$u2 z$TQjEk;9M(lT*B`%N!U5WO#wj=VA|J;FIBr<;vq?;_T&=;aJI`%f6RAaI>I*DZ5UV zAiKD^EMp^YW?o8ag=a*3NKs;DUS?i;ykkj5PHIW2X9`S2Wb&IgQW|h!B?W&!1tplI zl7fa3LP|4FV6xU*ZARhAVQ-x{tN7W)?Nu2YWhXCuD=G$8<(FTQnUM-(6KK9U^ ck$W=VBTah65fhi@wg5&Jf$c0482{J<0IPNUdH?_b