From 4a2f469c1cb9a93745015425e3f1b54a6569bc34 Mon Sep 17 00:00:00 2001 From: JayMar921 Date: Mon, 15 Jan 2024 16:09:24 +0800 Subject: [PATCH 1/8] Fix: Expired Token error is now fixed, it logs out user --- .../Controllers/AuthenticationController.cs | 8 +++-- .../sessionDb/QuizSession.db | Bin 0 -> 126976 bytes .../sessionDb/QuizSession.db-shm | Bin 0 -> 32768 bytes .../sessionDb/QuizSession.db-wal | Bin 0 -> 103032 bytes .../Utilities/JWTHelper.cs | 31 +++++++++++------- 5 files changed, 25 insertions(+), 14 deletions(-) create mode 100644 WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db create mode 100644 WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-shm create mode 100644 WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-wal diff --git a/WebApp/backend/QuizMaster.API.Authentication/Controllers/AuthenticationController.cs b/WebApp/backend/QuizMaster.API.Authentication/Controllers/AuthenticationController.cs index 2ce69203..a59d27bb 100644 --- a/WebApp/backend/QuizMaster.API.Authentication/Controllers/AuthenticationController.cs +++ b/WebApp/backend/QuizMaster.API.Authentication/Controllers/AuthenticationController.cs @@ -57,7 +57,7 @@ public async Task Logout() [Authorize] [HttpGet] [Route("info")] - public IActionResult GetCookieInfo() + public async Task GetCookieInfo() { // grab the claims identity var tokenClaim = User.Claims.ToList().FirstOrDefault(e => e.Type == "token"); @@ -69,7 +69,11 @@ public IActionResult GetCookieInfo() // get the AuthStore based on token var authStore = _authenticationServices.Validate(token); - if (authStore == null) return NotFound(new { Message = "No information found based on the token provided" }); + if (authStore == null) + { + await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + return NotFound(new { Message = "No information found based on the token provided" }); + } return Ok(new { Message = "Info", authStore }); } diff --git a/WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db b/WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db new file mode 100644 index 0000000000000000000000000000000000000000..683083afc374ffc19155a82984da14cb7ab3ab60 GIT binary patch literal 126976 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 X009sH0T2KI5C8!X009uV*986_dX&|i literal 0 HcmV?d00001 diff --git a/WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-shm b/WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-shm new file mode 100644 index 0000000000000000000000000000000000000000..cd5bf640ce4ff42eac0b6086b608a9133fe14658 GIT binary patch literal 32768 zcmeI)J4ysW6a~;b{{N2u9#I5y*I?ilWD*zP2Fwi%U52s7f(tNq3F%1PF{3n96JxvOM;i zLjv6vn9f`lv(oJ*bw_{z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs M0RjXF5Eu!30pUk0od5s; literal 0 HcmV?d00001 diff --git a/WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-wal b/WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-wal new file mode 100644 index 0000000000000000000000000000000000000000..3561060bbe54b97c19b17c5f4dc4e3e50676da29 GIT binary patch literal 103032 zcmeI(QD{|l90%}wy_>b=`j4WVrp=5NS`tLHASi-}ayDX&8?qAfArO3!^1Ah9s&di5FkK+009C72oNAZ;KCMYDzy}wqEd>=vQnv~rFNh-(V-Ue zg7NLu?e}&cSov2jFdO9pv*G9P(}jI-e?0*L1PBlyK!5-N0t5&USn>jKD$rai)&haJ zF6IJjYcidSxxmqpTOa)7tMYNVz>@!701zNRfB*pk1PBlyK!8BL1nRj!bDRs57IT5~ z<_O-YT>Hw?&%8Hojv!yncNzi&2oNAZfB*pk1PBlyP>7R(sQmXF!LxttxUDeJHSE5C z?}Y#X0t5&UAV7cs0RjXFY<2TB_sIov)q95_K!5-N0t5&UAV7cs z0Rr`0pwS$`>FIlV?*IPn>&+4PUfZzqd9`Mw+0v1J-_WExxiBYT%4Z(0RjXF5FkK+ z009C7awbsE1scr}j6Sis(!1{Ehs_b>tox2bfB*pk1PBlyK!5-N0t6Dw5sW?b!H&uO zJ705Oz~@4M009C72oNAZfB*pk1ac)%zc0{ej^LJop}E1kySn58x$3>c5FkK+009C7 z2oNAZfB=DdF7S^zf{q$Z=c!fwBLnOA9J^s}rCfPn#dT3G&=w9C!a|r2bD2N%JT>F)W009C72oNAZfB*pk1PBnwMxeP=EH<^pbwyk+iEC?AOD%D|IIb7P zb$L{mHUIk@!FjpBw)w02dVkx}E*HqAv34aufB*pk1PBlyK!5-N0tp17|MOGH1->}B z@nGfiCs)b^5_G{50t5&UAV7cs0RjXF5Fn6^Kx(?S009C7 z2oNAZfB*pk1QH0OmJ7Uea%6IF`1W7r0tvcc2>}8G2oNAZfB*pk1PBnwMj*9ZU~T!( z=+}?+pOXt@(^$I_AV7cs0RjXF5FkK+0D%MospSGM96faQ(;sf`kqac~f+Yk95FkK+ z009C72oNAZARB?ya)FuG-x%%azVS!7KsJrFD**xo2oNAZfB*pk1PBmFAdp%vu<6q3 z DecodeJsonWebToken(string secretKey, s var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.UTF8.GetBytes(secretKey); - tokenHandler.ValidateToken(jsonWebToken, new TokenValidationParameters + try { - ValidateIssuerSigningKey = true, - IssuerSigningKey = new SymmetricSecurityKey(key), - ValidateIssuer = false, - ValidateAudience = false, - // set clock skew to zero so token expire exactly at token expiration time - ClockSkew = TimeSpan.Zero - }, out SecurityToken validatedToken); + tokenHandler.ValidateToken(jsonWebToken, new TokenValidationParameters + { + ValidateIssuerSigningKey = true, + IssuerSigningKey = new SymmetricSecurityKey(key), + ValidateIssuer = false, + ValidateAudience = false, + // set clock skew to zero so token expire exactly at token expiration time + ClockSkew = TimeSpan.Zero + }, out SecurityToken validatedToken); - var jwtToken = (JwtSecurityToken)validatedToken; - Dictionary payload = new Dictionary(); + var jwtToken = (JwtSecurityToken)validatedToken; + Dictionary payload = new(); - jwtToken.Claims.ToList().ForEach(c => payload.Add(c.Type, c.Value)); + jwtToken.Claims.ToList().ForEach(c => payload.Add(c.Type, c.Value)); - return payload; + return payload; + } + catch + { + return new Dictionary(); + } } } } From d20b401e8e5051513ed0c89219f574694370df42 Mon Sep 17 00:00:00 2001 From: JayMar921 Date: Mon, 15 Jan 2024 16:32:36 +0800 Subject: [PATCH 2/8] Feature: Added Class Models for System CRUD modules --- .../Controllers/SystemController.cs | 9 +++++++ .../Models/System/AboutModel.cs | 22 ++++++++++++++++++ .../Models/System/ContactModel.cs | 18 ++++++++++++++ .../Models/System/ReviewModel.cs | 17 ++++++++++++++ .../Models/System/SubmitContactModel.cs | 20 ++++++++++++++++ .../sessionDb/QuizSession.db-wal | Bin 103032 -> 144232 bytes 6 files changed, 86 insertions(+) create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/Controllers/SystemController.cs create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/Models/System/AboutModel.cs create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/Models/System/ContactModel.cs create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/Models/System/ReviewModel.cs create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/Models/System/SubmitContactModel.cs diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Controllers/SystemController.cs b/WebApp/backend/QuizMaster.API.Gatewway/Controllers/SystemController.cs new file mode 100644 index 00000000..32b3f525 --- /dev/null +++ b/WebApp/backend/QuizMaster.API.Gatewway/Controllers/SystemController.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Mvc; + +namespace QuizMaster.API.Gateway.Controllers +{ + public class SystemController : Controller + { + + } +} diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Models/System/AboutModel.cs b/WebApp/backend/QuizMaster.API.Gatewway/Models/System/AboutModel.cs new file mode 100644 index 00000000..395f9623 --- /dev/null +++ b/WebApp/backend/QuizMaster.API.Gatewway/Models/System/AboutModel.cs @@ -0,0 +1,22 @@ +using System.ComponentModel.DataAnnotations; + +namespace QuizMaster.API.Gateway.Models.System +{ + public class AboutModel + { + public string Version { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + + public string Web_link { get; set; } = string.Empty; + public string Mobile_link { get; set; } = string.Empty; + public string Ios_link { get; set; } = string.Empty; + } + + public class SystemAbout : AboutModel + { + [Key] + public int Id { get; set; } = 0; + + public SystemAbout DEFAULT => new() { Id = 1, Description = "Lorem ipsum dolor sit amet consectetur. Pulvinar porta egestas molestie purus faucibus neque malesuada lectus. Lacus auctor sit felis sed ultrices nullam sapien ornare justo. Proin adipiscing viverra vestibulum arcu sit. Suscipit bibendum ullamcorper ut et dolor quisque nulla et.", Version = "1.0.0" }; + } +} diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Models/System/ContactModel.cs b/WebApp/backend/QuizMaster.API.Gatewway/Models/System/ContactModel.cs new file mode 100644 index 00000000..f22bb445 --- /dev/null +++ b/WebApp/backend/QuizMaster.API.Gatewway/Models/System/ContactModel.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; + +namespace QuizMaster.API.Gateway.Models.System +{ + public class ContactModel + { + public string Email { get; set; } = string.Empty; + public string Contact { get; set; } = string.Empty; + } + + public class SystemContact : ContactModel + { + [Key] + public int Id { get; set; } = 0; + + public SystemContact DEFAULT = new() { Id = 1, Email = "admin.quizmaster@gmail.com", Contact = "09205195701" }; + } +} diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Models/System/ReviewModel.cs b/WebApp/backend/QuizMaster.API.Gatewway/Models/System/ReviewModel.cs new file mode 100644 index 00000000..96779d58 --- /dev/null +++ b/WebApp/backend/QuizMaster.API.Gatewway/Models/System/ReviewModel.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace QuizMaster.API.Gateway.Models.System +{ + public class ReviewModel + { + public int? UserId { get; set; } = null; + public int StarRating { get; set; } = 0; + public string Comment { get; set; } = string.Empty; + } + + public class Reviews : ReviewModel + { + [Key] + public int Id { get; set; } = 0; + } +} diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Models/System/SubmitContactModel.cs b/WebApp/backend/QuizMaster.API.Gatewway/Models/System/SubmitContactModel.cs new file mode 100644 index 00000000..db0d1eca --- /dev/null +++ b/WebApp/backend/QuizMaster.API.Gatewway/Models/System/SubmitContactModel.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; + +namespace QuizMaster.API.Gateway.Models.System +{ + public class SubmitContactModel + { + public int? UserId { get; set; } = null; + public string Emai { get; set; } = string.Empty; + public string PhoneNumber { get; set;} = string.Empty; + public string Lastname { get; set; } = string.Empty; + public string Firstname { get; set;} = string.Empty; + public string Message { get; set; } = string.Empty; + } + + public class ContactReaching : SubmitContactModel + { + [Key] + public int Id { get; set; } + } +} diff --git a/WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-wal b/WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-wal index 3561060bbe54b97c19b17c5f4dc4e3e50676da29..bcaff9e8110e290725a1ad255bf44fde4d644b9e 100644 GIT binary patch delta 1086 zcmeydgzd#Mj)pCa6_fNB7#LWAnBll&$l_?FlHEa$+3PYD_-^n5#n}0$GVp)kzt4Y` z{}BIX{(1aUHwM=8*R!)Ti*g31mJ|!KF>5mhmZlb$Waj6&q?ROR<`nbtvNFrV1&diY zS(wEcLn;eWi`fL2nN=BGGSkvBlS^|-GEk8(#l<`e1YYzuGkCFcj1OJ(gfrt1bj2Jl?q@_8X88{e%@=Nnl6bzx1 zk%5tku7RPhp{atQnU$fTm5GI(k%@tksiiT{1R)@X`~2rTk!u^F=IxuE!` znR`z_f_w%rHu-044D8{rH)2AIPa{Zt8eznzshOU+sfnS1ff+T@z|4C)#THGl5o`jv zh=so$oCx@r@waabEa$J6W#M3C1SbR*Y$-vO879q)O`76lq=ZPTs&{t%=-KHFP7W;m zPr&Jj{|*0>je%GAUD#O|85voaSim$h6EnVa^=0?_7_sM!_Mmjd!v7kauJ}LlzXqnQ S+x()e%#4goEMSrup2z?zWd~gV delta 11 ScmaFyjN``=wuUW?6_Wrad Date: Mon, 15 Jan 2024 16:55:38 +0800 Subject: [PATCH 3/8] Feature: Added DB Context for System Info modules --- ..._Migration_1_SystemInformation.Designer.cs | 149 ++++++++++++++++++ ...115085238_Migration_1_SystemInformation.cs | 104 ++++++++++++ .../SystemDbContextModelSnapshot.cs | 146 +++++++++++++++++ .../Models/System/AboutModel.cs | 2 +- .../Models/System/ContactModel.cs | 2 +- .../QuizMaster.API.Gatewway/Program.cs | 12 +- .../QuizMaster.API.Gateway.csproj | 11 ++ .../Services/System/SystemRepository.cs | 6 + .../SystemData/Contexts/SystemDbContext.cs | 25 +++ .../SystemData/System.db | Bin 0 -> 32768 bytes 10 files changed, 454 insertions(+), 3 deletions(-) create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/Migrations/20240115085238_Migration_1_SystemInformation.Designer.cs create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/Migrations/20240115085238_Migration_1_SystemInformation.cs create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/Migrations/SystemDbContextModelSnapshot.cs create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/Services/System/SystemRepository.cs create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/SystemData/Contexts/SystemDbContext.cs create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/SystemData/System.db diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Migrations/20240115085238_Migration_1_SystemInformation.Designer.cs b/WebApp/backend/QuizMaster.API.Gatewway/Migrations/20240115085238_Migration_1_SystemInformation.Designer.cs new file mode 100644 index 00000000..2f720153 --- /dev/null +++ b/WebApp/backend/QuizMaster.API.Gatewway/Migrations/20240115085238_Migration_1_SystemInformation.Designer.cs @@ -0,0 +1,149 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using QuizMaster.API.Gateway.SystemData.Contexts; + +#nullable disable + +namespace QuizMaster.API.Gateway.Migrations +{ + [DbContext(typeof(SystemDbContext))] + [Migration("20240115085238_Migration_1_SystemInformation")] + partial class Migration_1_SystemInformation + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.15"); + + modelBuilder.Entity("QuizMaster.API.Gateway.Models.System.ContactReaching", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Emai") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Firstname") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Lastname") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Message") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("SystemReachingContacts"); + }); + + modelBuilder.Entity("QuizMaster.API.Gateway.Models.System.Reviews", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StarRating") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("SystemReviews"); + }); + + modelBuilder.Entity("QuizMaster.API.Gateway.Models.System.SystemAbout", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Ios_link") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Mobile_link") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Version") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Web_link") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("SystemAboutData"); + + b.HasData( + new + { + Id = 1, + Description = "Lorem ipsum dolor sit amet consectetur. Pulvinar porta egestas molestie purus faucibus neque malesuada lectus. Lacus auctor sit felis sed ultrices nullam sapien ornare justo. Proin adipiscing viverra vestibulum arcu sit. Suscipit bibendum ullamcorper ut et dolor quisque nulla et.", + Ios_link = "", + Mobile_link = "", + Version = "1.0.0", + Web_link = "" + }); + }); + + modelBuilder.Entity("QuizMaster.API.Gateway.Models.System.SystemContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Contact") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Email") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("SystemContactData"); + + b.HasData( + new + { + Id = 1, + Contact = "09205195701", + Email = "admin.quizmaster@gmail.com" + }); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Migrations/20240115085238_Migration_1_SystemInformation.cs b/WebApp/backend/QuizMaster.API.Gatewway/Migrations/20240115085238_Migration_1_SystemInformation.cs new file mode 100644 index 00000000..091de76e --- /dev/null +++ b/WebApp/backend/QuizMaster.API.Gatewway/Migrations/20240115085238_Migration_1_SystemInformation.cs @@ -0,0 +1,104 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace QuizMaster.API.Gateway.Migrations +{ + /// + public partial class Migration_1_SystemInformation : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "SystemAboutData", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Version = table.Column(type: "TEXT", nullable: false), + Description = table.Column(type: "TEXT", nullable: false), + Web_link = table.Column(type: "TEXT", nullable: false), + Mobile_link = table.Column(type: "TEXT", nullable: false), + Ios_link = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SystemAboutData", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "SystemContactData", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Email = table.Column(type: "TEXT", nullable: false), + Contact = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SystemContactData", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "SystemReachingContacts", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(type: "INTEGER", nullable: true), + Emai = table.Column(type: "TEXT", nullable: false), + PhoneNumber = table.Column(type: "TEXT", nullable: false), + Lastname = table.Column(type: "TEXT", nullable: false), + Firstname = table.Column(type: "TEXT", nullable: false), + Message = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SystemReachingContacts", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "SystemReviews", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(type: "INTEGER", nullable: true), + StarRating = table.Column(type: "INTEGER", nullable: false), + Comment = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SystemReviews", x => x.Id); + }); + + migrationBuilder.InsertData( + table: "SystemAboutData", + columns: new[] { "Id", "Description", "Ios_link", "Mobile_link", "Version", "Web_link" }, + values: new object[] { 1, "Lorem ipsum dolor sit amet consectetur. Pulvinar porta egestas molestie purus faucibus neque malesuada lectus. Lacus auctor sit felis sed ultrices nullam sapien ornare justo. Proin adipiscing viverra vestibulum arcu sit. Suscipit bibendum ullamcorper ut et dolor quisque nulla et.", "", "", "1.0.0", "" }); + + migrationBuilder.InsertData( + table: "SystemContactData", + columns: new[] { "Id", "Contact", "Email" }, + values: new object[] { 1, "09205195701", "admin.quizmaster@gmail.com" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "SystemAboutData"); + + migrationBuilder.DropTable( + name: "SystemContactData"); + + migrationBuilder.DropTable( + name: "SystemReachingContacts"); + + migrationBuilder.DropTable( + name: "SystemReviews"); + } + } +} diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Migrations/SystemDbContextModelSnapshot.cs b/WebApp/backend/QuizMaster.API.Gatewway/Migrations/SystemDbContextModelSnapshot.cs new file mode 100644 index 00000000..9f4abec9 --- /dev/null +++ b/WebApp/backend/QuizMaster.API.Gatewway/Migrations/SystemDbContextModelSnapshot.cs @@ -0,0 +1,146 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using QuizMaster.API.Gateway.SystemData.Contexts; + +#nullable disable + +namespace QuizMaster.API.Gateway.Migrations +{ + [DbContext(typeof(SystemDbContext))] + partial class SystemDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.15"); + + modelBuilder.Entity("QuizMaster.API.Gateway.Models.System.ContactReaching", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Emai") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Firstname") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Lastname") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Message") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("SystemReachingContacts"); + }); + + modelBuilder.Entity("QuizMaster.API.Gateway.Models.System.Reviews", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StarRating") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("SystemReviews"); + }); + + modelBuilder.Entity("QuizMaster.API.Gateway.Models.System.SystemAbout", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Ios_link") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Mobile_link") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Version") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Web_link") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("SystemAboutData"); + + b.HasData( + new + { + Id = 1, + Description = "Lorem ipsum dolor sit amet consectetur. Pulvinar porta egestas molestie purus faucibus neque malesuada lectus. Lacus auctor sit felis sed ultrices nullam sapien ornare justo. Proin adipiscing viverra vestibulum arcu sit. Suscipit bibendum ullamcorper ut et dolor quisque nulla et.", + Ios_link = "", + Mobile_link = "", + Version = "1.0.0", + Web_link = "" + }); + }); + + modelBuilder.Entity("QuizMaster.API.Gateway.Models.System.SystemContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Contact") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Email") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("SystemContactData"); + + b.HasData( + new + { + Id = 1, + Contact = "09205195701", + Email = "admin.quizmaster@gmail.com" + }); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Models/System/AboutModel.cs b/WebApp/backend/QuizMaster.API.Gatewway/Models/System/AboutModel.cs index 395f9623..5b48ff7e 100644 --- a/WebApp/backend/QuizMaster.API.Gatewway/Models/System/AboutModel.cs +++ b/WebApp/backend/QuizMaster.API.Gatewway/Models/System/AboutModel.cs @@ -17,6 +17,6 @@ public class SystemAbout : AboutModel [Key] public int Id { get; set; } = 0; - public SystemAbout DEFAULT => new() { Id = 1, Description = "Lorem ipsum dolor sit amet consectetur. Pulvinar porta egestas molestie purus faucibus neque malesuada lectus. Lacus auctor sit felis sed ultrices nullam sapien ornare justo. Proin adipiscing viverra vestibulum arcu sit. Suscipit bibendum ullamcorper ut et dolor quisque nulla et.", Version = "1.0.0" }; + public static SystemAbout DEFAULT => new() { Id = 1, Description = "Lorem ipsum dolor sit amet consectetur. Pulvinar porta egestas molestie purus faucibus neque malesuada lectus. Lacus auctor sit felis sed ultrices nullam sapien ornare justo. Proin adipiscing viverra vestibulum arcu sit. Suscipit bibendum ullamcorper ut et dolor quisque nulla et.", Version = "1.0.0" }; } } diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Models/System/ContactModel.cs b/WebApp/backend/QuizMaster.API.Gatewway/Models/System/ContactModel.cs index f22bb445..090a37a1 100644 --- a/WebApp/backend/QuizMaster.API.Gatewway/Models/System/ContactModel.cs +++ b/WebApp/backend/QuizMaster.API.Gatewway/Models/System/ContactModel.cs @@ -13,6 +13,6 @@ public class SystemContact : ContactModel [Key] public int Id { get; set; } = 0; - public SystemContact DEFAULT = new() { Id = 1, Email = "admin.quizmaster@gmail.com", Contact = "09205195701" }; + public static SystemContact DEFAULT = new() { Id = 1, Email = "admin.quizmaster@gmail.com", Contact = "09205195701" }; } } diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Program.cs b/WebApp/backend/QuizMaster.API.Gatewway/Program.cs index 616aa8d4..39901b4d 100644 --- a/WebApp/backend/QuizMaster.API.Gatewway/Program.cs +++ b/WebApp/backend/QuizMaster.API.Gatewway/Program.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.OpenApi.Models; using QuizMaster.API.Authentication.Configuration; @@ -11,6 +12,7 @@ using QuizMaster.API.Gateway.Configuration; using QuizMaster.API.Gateway.Hubs; using QuizMaster.API.Gateway.Services; +using QuizMaster.API.Gateway.SystemData.Contexts; using QuizMaster.API.Gatewway.Controllers; using QuizMaster.API.Quiz.Services.Workers; @@ -27,7 +29,7 @@ builder.Services.AddCors(o => o.AddDefaultPolicy(builder => builder.WithOrigins("http://localhost:5173", "http://localhost:3000", "http://localhost:3001", "https://localhost:7081").AllowAnyHeader().AllowAnyMethod().AllowCredentials())); - +builder.Services.AddDbContext(option => option.UseSqlite("Data Source=SystemData\\System.db")); builder.Services.AddScoped(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); @@ -139,4 +141,12 @@ app.MapControllers(); app.MapHub("/gateway/hub/session"); +// Initialize the Database +using(var scope = app.Services.CreateScope()) +{ + var services = scope.ServiceProvider; + var systemDbContext = services.GetRequiredService(); + systemDbContext.Database.EnsureCreated(); +} + app.Run(); diff --git a/WebApp/backend/QuizMaster.API.Gatewway/QuizMaster.API.Gateway.csproj b/WebApp/backend/QuizMaster.API.Gatewway/QuizMaster.API.Gateway.csproj index 6a8c0a0b..cb325cb0 100644 --- a/WebApp/backend/QuizMaster.API.Gatewway/QuizMaster.API.Gateway.csproj +++ b/WebApp/backend/QuizMaster.API.Gatewway/QuizMaster.API.Gateway.csproj @@ -18,6 +18,17 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Services/System/SystemRepository.cs b/WebApp/backend/QuizMaster.API.Gatewway/Services/System/SystemRepository.cs new file mode 100644 index 00000000..39364233 --- /dev/null +++ b/WebApp/backend/QuizMaster.API.Gatewway/Services/System/SystemRepository.cs @@ -0,0 +1,6 @@ +namespace QuizMaster.API.Gateway.Services.System +{ + public class SystemRepository + { + } +} diff --git a/WebApp/backend/QuizMaster.API.Gatewway/SystemData/Contexts/SystemDbContext.cs b/WebApp/backend/QuizMaster.API.Gatewway/SystemData/Contexts/SystemDbContext.cs new file mode 100644 index 00000000..6061f5ac --- /dev/null +++ b/WebApp/backend/QuizMaster.API.Gatewway/SystemData/Contexts/SystemDbContext.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore; +using QuizMaster.API.Gateway.Models.System; + +namespace QuizMaster.API.Gateway.SystemData.Contexts +{ + public class SystemDbContext: DbContext + { + // Define the DbSet for the SystemDb Entities + public DbSet SystemAboutData { get; set; } + public DbSet SystemContactData { get; set; } + public DbSet SystemReviews { get; set; } + public DbSet SystemReachingContacts { get; set; } + + public SystemDbContext(DbContextOptions options) : base(options) { } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + // Initialize the defaults + modelBuilder.Entity().HasData(SystemAbout.DEFAULT); + modelBuilder.Entity().HasData(SystemContact.DEFAULT); + + base.OnModelCreating(modelBuilder); + } + } +} diff --git a/WebApp/backend/QuizMaster.API.Gatewway/SystemData/System.db b/WebApp/backend/QuizMaster.API.Gatewway/SystemData/System.db new file mode 100644 index 0000000000000000000000000000000000000000..cbd07caa6cd26bd1e4402373f16a5c320dd5722b GIT binary patch literal 32768 zcmeI)O>Y`U7zglOu#Ih%P(_tcZzHNIu^eG=f*e^iAdskT4|Vh(fxSC3`|LhHmbG@*v-_Xbq!H{W zQUN#Yw)3u&NI3Tya~vl@?`3)q%OXuI3}@)KJ2pLUGU4PsH=X&*Nv-_hT>B;SWBP~m zNAEOOf2Ua#2tWV=5P$##AOL~?T;SPRDwVx)!~L#kc*hs}XWEFMDNd#MT2IU@?=&mr zR)w|7AJ-}@H_?`3H`A+(O0L??v1+|l`J~ch^}QCWAJl4WXRp5BYL=;<w5Cl-IBaqQ^NaTr9JYNb3I3rpGcb@#BJr9ScLG^(w|i4~zIre+r>GMs9> z8Gi`3Xvwwnon$Hw`TX9PT)7ij^U`fJyD$-R@Qod{UdC)};Wvss7D~$~oKhL?d=G^7 zlrsvLtmb(Cd*Y_DTU+k=USF}@t~}h8$BGUkQK&za z+C=JXW@TbhbY`EIuA`Xo!E55!!={dia{`SS58WCn>RQjt#--G%iKXlpTdpI+uJ~rK z8*yu*{(O7pdfLUA)k*qO(?7RQ(}bJ($)Oht1Rwwb2tWV=5P$##AOHafKmY>&cY%_d z6z^{qHt!UQ#ZuvJY4i5o_UIY~T?M$f>{bmg?)1~Okga?nUo5RsUT)@Rhh8WUfB*y_ z009U<00Izz00bZa0SH_XfsLeC`6pKa`uG2@{pQdM1p*L&00bZa0SG_<0uX=z1R!wb z1kOKnm!0hMd+Bt#NH@9*wMdD8$)2_W>qdU0n3jgo$P2?f8W$iuBaBsf*0BDm47p;x zNEyz=vCxKV7DPTxNWpqmS{Ol#r8ql{ zH=|>HN`ouU#1`yz-!p>uz#=P&<0o!^Qaj7f$BI z6-p1A3IPZ}00Izz00bZa0SG_<0uX?JtwJ$A|EGukqd))x5P$##AOHafKmY;|fB*y_@D>Z;{QoWfaFH4WAOHaf TKmY;|fB*y_009U Date: Mon, 15 Jan 2024 17:30:46 +0800 Subject: [PATCH 4/8] Feature: Added SystemRepository --- .../QuizMaster.API.Gatewway/Program.cs | 2 + .../Services/System/SystemRepository.cs | 66 ++++++++++++++++++- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Program.cs b/WebApp/backend/QuizMaster.API.Gatewway/Program.cs index 39901b4d..30293217 100644 --- a/WebApp/backend/QuizMaster.API.Gatewway/Program.cs +++ b/WebApp/backend/QuizMaster.API.Gatewway/Program.cs @@ -12,6 +12,7 @@ using QuizMaster.API.Gateway.Configuration; using QuizMaster.API.Gateway.Hubs; using QuizMaster.API.Gateway.Services; +using QuizMaster.API.Gateway.Services.System; using QuizMaster.API.Gateway.SystemData.Contexts; using QuizMaster.API.Gatewway.Controllers; using QuizMaster.API.Quiz.Services.Workers; @@ -33,6 +34,7 @@ builder.Services.AddScoped(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); +builder.Services.AddScoped(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Services/System/SystemRepository.cs b/WebApp/backend/QuizMaster.API.Gatewway/Services/System/SystemRepository.cs index 39364233..2394efc8 100644 --- a/WebApp/backend/QuizMaster.API.Gatewway/Services/System/SystemRepository.cs +++ b/WebApp/backend/QuizMaster.API.Gatewway/Services/System/SystemRepository.cs @@ -1,6 +1,70 @@ -namespace QuizMaster.API.Gateway.Services.System +using AutoMapper; +using Microsoft.EntityFrameworkCore; +using QuizMaster.API.Gateway.Models.System; +using QuizMaster.API.Gateway.SystemData.Contexts; + +namespace QuizMaster.API.Gateway.Services.System { public class SystemRepository { + private readonly SystemDbContext dbContext; + private readonly IMapper _mapper; + public SystemRepository(SystemDbContext dbContext, IMapper _mapper) + { + this.dbContext = dbContext; + this._mapper = _mapper; + } + + public async Task EditSystemAboutAsync(AboutModel model) + { + SystemAbout? systemAbout = await dbContext.SystemAboutData.FindAsync(new SystemAbout { Id = 1 }); + systemAbout ??= new SystemAbout { Id = 1 }; + + _mapper.Map(model, systemAbout); + + await dbContext.SaveChangesAsync(); + } + + public async Task EditSystemContactInformationAsync(ContactModel model) + { + SystemContact? systemContact = await dbContext.SystemContactData.FindAsync(new SystemContact { Id = 1 }); + systemContact ??= new SystemContact { Id = 1 }; + + _mapper.Map(model, systemContact); + + await dbContext.SaveChangesAsync(); + } + + public async Task GetSystemAboutAsync() + { + return _mapper.Map(await dbContext.SystemAboutData.FindAsync(new SystemAbout { Id = 1 })); + } + + public async Task GetContactInformationAsync() + { + return _mapper.Map(await dbContext.SystemContactData.FindAsync(new SystemContact { Id = 1 })); + } + + public async Task SaveReachingContactAsync(SubmitContactModel model) + { + await dbContext.SystemReachingContacts.AddAsync(_mapper.Map(model)); + await dbContext.SaveChangesAsync(); + } + + public async Task> GetContactReachingsAsync() + { + return await dbContext.SystemReachingContacts.ToListAsync(); + } + + public async Task SaveReviewsAsync(ReviewModel model) + { + await dbContext.SystemReviews.AddAsync(_mapper.Map(model)); + await dbContext.SaveChangesAsync(); + } + + public async Task> GetReviewsAsync() + { + return await dbContext.SystemReviews.ToListAsync(); + } } } From 338a798fe86ba18f05d5ae66f597743d243a50ca Mon Sep 17 00:00:00 2001 From: JayMar921 Date: Mon, 15 Jan 2024 20:57:13 +0800 Subject: [PATCH 5/8] Feature: Implemented SystemInformation, Feedback and ContactUs routes in the Gateway --- .../QuizMaster.API.Gatewway/AutoMapper.cs | 5 + .../Configuration/ApplicationSettings.cs | 10 ++ .../Controllers/SystemController.cs | 158 +++++++++++++++++- .../Helper/Email/EmailTemplate.cs | 32 ++++ .../QuizMaster.API.Gatewway/Program.cs | 5 +- .../Services/Email/EmailService.cs | 61 +++++++ .../SystemRepository.cs | 10 +- .../SystemData/System.db | Bin 32768 -> 32768 bytes .../QuizMaster.API.Gatewway/appsettings.json | 4 +- .../sessionDb/QuizSession.db | Bin 126976 -> 126976 bytes .../sessionDb/QuizSession.db-shm | Bin 32768 -> 0 bytes .../sessionDb/QuizSession.db-wal | Bin 144232 -> 0 bytes 12 files changed, 276 insertions(+), 9 deletions(-) create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/Configuration/ApplicationSettings.cs create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/Helper/Email/EmailTemplate.cs create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/Services/Email/EmailService.cs rename WebApp/backend/QuizMaster.API.Gatewway/Services/{System => SystemService}/SystemRepository.cs (89%) delete mode 100644 WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-shm delete mode 100644 WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-wal diff --git a/WebApp/backend/QuizMaster.API.Gatewway/AutoMapper.cs b/WebApp/backend/QuizMaster.API.Gatewway/AutoMapper.cs index 45016890..b79fca3a 100644 --- a/WebApp/backend/QuizMaster.API.Gatewway/AutoMapper.cs +++ b/WebApp/backend/QuizMaster.API.Gatewway/AutoMapper.cs @@ -2,6 +2,7 @@ using Newtonsoft.Json; using QuizMaster.API.Account.Models; using QuizMaster.API.Account.Proto; +using QuizMaster.API.Gateway.Models.System; using QuizMaster.API.Quiz.Models; using QuizMaster.API.Quiz.Protos; using QuizMaster.API.Quiz.SeedData; @@ -26,6 +27,10 @@ public AutoMapper() CreateMap().ReverseMap(); CreateMap(); CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); // CreateMap() //.ForMember(destination => destination.QAnswer, act => act.MapFrom(src => //src.QTypeId == QuestionTypes.MultipleChoiceSeedData.Id diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Configuration/ApplicationSettings.cs b/WebApp/backend/QuizMaster.API.Gatewway/Configuration/ApplicationSettings.cs new file mode 100644 index 00000000..7510b597 --- /dev/null +++ b/WebApp/backend/QuizMaster.API.Gatewway/Configuration/ApplicationSettings.cs @@ -0,0 +1,10 @@ +using QuizMaster.API.Authentication.Configuration; + +namespace QuizMaster.API.Gateway.Configuration +{ + public class ApplicationSettings: AppSettings + { + public string SMTP_EMAIL { get; set; } + public string SMTP_PASSWORD { get; set; } + } +} diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Controllers/SystemController.cs b/WebApp/backend/QuizMaster.API.Gatewway/Controllers/SystemController.cs index 32b3f525..cee13471 100644 --- a/WebApp/backend/QuizMaster.API.Gatewway/Controllers/SystemController.cs +++ b/WebApp/backend/QuizMaster.API.Gatewway/Controllers/SystemController.cs @@ -1,9 +1,163 @@ -using Microsoft.AspNetCore.Mvc; +using Grpc.Net.Client; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using Newtonsoft.Json; +using QuizMaster.API.Authentication.Models; +using QuizMaster.API.Authentication.Proto; +using QuizMaster.API.Gateway.Attributes; +using QuizMaster.API.Gateway.Configuration; +using QuizMaster.API.Gateway.Helper; +using QuizMaster.API.Gateway.Helper.Email; +using QuizMaster.API.Gateway.Models.System; +using QuizMaster.API.Gateway.Services.Email; +using QuizMaster.API.Gateway.Services.SystemService; +using QuizMaster.API.Gatewway.Controllers; namespace QuizMaster.API.Gateway.Controllers { + [Route("gateway/api/[controller]")] public class SystemController : Controller { - + private readonly SystemRepository systemRepository; + private readonly EmailService emailService; + private readonly GrpcChannel _authChannel; + private readonly AuthService.AuthServiceClient _authChannelClient; + + public SystemController(SystemRepository systemRepository, EmailService emailService, IOptions options) + { + this.systemRepository = systemRepository; + this.emailService = emailService; + + var handler = new HttpClientHandler(); + handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; + _authChannel = GrpcChannel.ForAddress(options.Value.Authentication_Service, new GrpcChannelOptions { HttpHandler = handler }); + _authChannelClient = new AuthService.AuthServiceClient(_authChannel); + } + + // Get System About + [HttpGet("information")] + public async Task GetSystemInformationAsync() + { + return Ok(new { Status = "Success", Message = "Retrieved System Information", Data = await systemRepository.GetSystemAboutAsync() }); + } + + // Update System About + [QuizMasterAdminAuthorization] + [HttpPost("information")] + public async Task UpdateSystemInformationAsync([FromBody] AboutModel model) + { + if(!ModelState.IsValid) + { + return BadRequest(ModelState); + } + await systemRepository.EditSystemAboutAsync(model); + return Ok(new { Status = "Success", Message = "Saved", Data = await systemRepository.GetSystemAboutAsync() }); + } + + // Get System Contact + [HttpGet("contact_information")] + public async Task GetContactInformationAsync() + { + return Ok(new { Status = "Success", Message = "Retrieved Contact Information", Data = await systemRepository.GetContactInformationAsync() }); + } + + // Update System Contact + [QuizMasterAdminAuthorization] + [HttpPost("contact_information")] + public async Task UpdateContactInformation([FromBody] ContactModel model) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + await systemRepository.EditSystemContactInformationAsync(model); + return Ok(new { Status = "Success", Message = "Saved", Data = await systemRepository.GetContactInformationAsync() }); + } + + // Submit Contact + [HttpPost("reachOut")] + public async Task ReachOutAsync([FromBody] SubmitContactModel model) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + await systemRepository.SaveReachingContactAsync(model); + + #region Send Email + Task.Run(() => + { + var clientEmail = EmailDefaults.SUBMIT_CONTACT_CLIENT(model.Emai); + var adminEmailCopy = EmailDefaults.SUBMIT_CONTACT_ADMIN("", model.Firstname + " " + model.Lastname, model.Message); + + emailService.SendEmail(clientEmail); + emailService.SendEmailToAdmin(adminEmailCopy); + }); + #endregion + + return Ok(new { Status = "Success", Message = "Successfully submitted a contact request." }); + } + + // Get All Submitted Contact + [QuizMasterAdminAuthorization] + [HttpGet("reachOut")] + public async Task GetAllReachOutAsync() + { + return Ok(new { Status = "Success", Message = "Retrieved Contacting Users", Data = await systemRepository.GetContactReachingsAsync() }); + } + + // Submit Review + [HttpPost("review")] + public async Task SubmitReviewAsync([FromBody] ReviewModel model) + { + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + await systemRepository.SaveReviewsAsync(model); + + #region Send Email + Task.Run(async () => + { + var token = this.GetToken(); + if(!string.IsNullOrEmpty(token)) + { + var AuthStore = await GetAuthStoreInfo(token); + + if (AuthStore != null) + { + var clientEmail = EmailDefaults.SUBMIT_REVIEW_CLIENT(AuthStore.UserData.Email, model.Comment, model.StarRating); + emailService.SendEmail(clientEmail); + } + } + + var adminEmailCopy = EmailDefaults.SUBMIT_REVIEW_ADMIN("", model.Comment, model.StarRating); + + + emailService.SendEmailToAdmin(adminEmailCopy); + }); + #endregion + + return Ok(new { Status = "Success", Message = "Successfully submitted a system review." }); + } + // Get All Submitted Review + [HttpGet("review")] + public async Task GetAllReviewsAsync() + { + return Ok(new { Status = "Success", Message = "Retrieved System Reviews", Data = await systemRepository.GetReviewsAsync() }); + } + + + private async Task GetAuthStoreInfo(string token) + { + var requestValidation = new ValidationRequest() + { + Token = token + }; + + var authStore = await _authChannelClient.ValidateAuthenticationAsync(requestValidation); + + return !string.IsNullOrEmpty(authStore?.AuthStore) ? JsonConvert.DeserializeObject(authStore.AuthStore) : null; + } } } diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Helper/Email/EmailTemplate.cs b/WebApp/backend/QuizMaster.API.Gatewway/Helper/Email/EmailTemplate.cs new file mode 100644 index 00000000..f7f7dc54 --- /dev/null +++ b/WebApp/backend/QuizMaster.API.Gatewway/Helper/Email/EmailTemplate.cs @@ -0,0 +1,32 @@ +namespace QuizMaster.API.Gateway.Helper.Email +{ + public class EmailTemplate + { + public string Body { get; set; } = string.Empty; + public string ToEmail { get; set; } = string.Empty; + public string Subject { get; set; } = string.Empty; + } + + public class EmailDefaults + { + public static EmailTemplate SUBMIT_REVIEW_ADMIN(string ToEmail, string Message, int Rating) + { + return new EmailTemplate { Body = $"Someone reviewed: {Message}, Rating: {Rating}/5", ToEmail = ToEmail, Subject = "[QuizMaster] System Review" }; + } + + public static EmailTemplate SUBMIT_REVIEW_CLIENT(string ToEmail, string Message, int Rating) + { + return new EmailTemplate { Body = $"You reviewed: {Message}, Rating: {Rating}/5", ToEmail = ToEmail, Subject = "[QuizMaster] System Review" }; + } + + public static EmailTemplate SUBMIT_CONTACT_ADMIN(string ToEmail, string Name, string Message) + { + return new EmailTemplate { Body = $"Hello admin, this {Name} would like to reach us out with a following message: {Message}", ToEmail = ToEmail, Subject = "[QuizMaster] Someone's reaching us" }; + } + + public static EmailTemplate SUBMIT_CONTACT_CLIENT(string ToEmail) + { + return new EmailTemplate { Body = $"Thank you for reaching us, we will reach you out soonest.", ToEmail = ToEmail, Subject = "[QuizMaster] Thanks for reaching us" }; + } + } +} diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Program.cs b/WebApp/backend/QuizMaster.API.Gatewway/Program.cs index 30293217..c5a9a090 100644 --- a/WebApp/backend/QuizMaster.API.Gatewway/Program.cs +++ b/WebApp/backend/QuizMaster.API.Gatewway/Program.cs @@ -12,7 +12,8 @@ using QuizMaster.API.Gateway.Configuration; using QuizMaster.API.Gateway.Hubs; using QuizMaster.API.Gateway.Services; -using QuizMaster.API.Gateway.Services.System; +using QuizMaster.API.Gateway.Services.Email; +using QuizMaster.API.Gateway.Services.SystemService; using QuizMaster.API.Gateway.SystemData.Contexts; using QuizMaster.API.Gatewway.Controllers; using QuizMaster.API.Quiz.Services.Workers; @@ -75,6 +76,7 @@ // Configuring strongly typed settings object builder.Services.Configure(builder.Configuration.GetSection("AppSettings")); +builder.Services.Configure(builder.Configuration.GetSection("AppSettings")); builder.Services.Configure(builder.Configuration.GetSection("GrpcServerConfiguration")); // register the services @@ -84,6 +86,7 @@ builder.Services.AddSingleton(); builder.Services.AddScoped(); builder.Services.AddSingleton>(o => new Dictionary()); +builder.Services.AddScoped(); // configure cookie authentication diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Services/Email/EmailService.cs b/WebApp/backend/QuizMaster.API.Gatewway/Services/Email/EmailService.cs new file mode 100644 index 00000000..91f0f296 --- /dev/null +++ b/WebApp/backend/QuizMaster.API.Gatewway/Services/Email/EmailService.cs @@ -0,0 +1,61 @@ +using System.Net.Mail; +using System.Net; +using QuizMaster.API.Gateway.Helper.Email; +using Microsoft.Extensions.Options; +using QuizMaster.API.Gateway.Configuration; + +namespace QuizMaster.API.Gateway.Services.Email +{ + public class EmailService + { + private readonly string SMTP_EMAIL; + private readonly string SMTP_PASS; + public EmailService(IOptions appSettings) + { + SMTP_EMAIL = appSettings.Value.SMTP_EMAIL; + SMTP_PASS = appSettings.Value.SMTP_PASSWORD; + } + + private void SendEmailRequest(EmailTemplate emailTemplate, bool toAdmin) + { + MailMessage mailMessage = new MailMessage(); + mailMessage.From = new MailAddress(SMTP_EMAIL, "🔎QuizMaster@no-reply", System.Text.Encoding.UTF8); + if(toAdmin) + { + mailMessage.To.Add(SMTP_EMAIL); + } + else + { + mailMessage.To.Add(emailTemplate.ToEmail); + } + mailMessage.Subject = emailTemplate.Subject; + mailMessage.Body = emailTemplate.Body; + mailMessage.IsBodyHtml = true; + + // Create the credentials to login to the gmail account associated with my custom domain + string sendEmailsFrom = SMTP_EMAIL; + string sendEmailsFromPassword = SMTP_PASS; + NetworkCredential cred = new NetworkCredential(sendEmailsFrom, sendEmailsFromPassword); + + SmtpClient mailClient = new SmtpClient("smtp.gmail.com", 587); + mailClient.EnableSsl = true; + mailClient.DeliveryMethod = SmtpDeliveryMethod.Network; + mailClient.UseDefaultCredentials = false; + mailClient.Timeout = 20000; + mailClient.Credentials = cred; + mailClient.Send(mailMessage); + } + + public void SendEmail(EmailTemplate emailTemplate) + { + SendEmailRequest(emailTemplate, false); + } + + public void SendEmailToAdmin(EmailTemplate emailTemplate) + { + SendEmailRequest(emailTemplate, true); + } + + + } +} diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Services/System/SystemRepository.cs b/WebApp/backend/QuizMaster.API.Gatewway/Services/SystemService/SystemRepository.cs similarity index 89% rename from WebApp/backend/QuizMaster.API.Gatewway/Services/System/SystemRepository.cs rename to WebApp/backend/QuizMaster.API.Gatewway/Services/SystemService/SystemRepository.cs index 2394efc8..070479cb 100644 --- a/WebApp/backend/QuizMaster.API.Gatewway/Services/System/SystemRepository.cs +++ b/WebApp/backend/QuizMaster.API.Gatewway/Services/SystemService/SystemRepository.cs @@ -3,7 +3,7 @@ using QuizMaster.API.Gateway.Models.System; using QuizMaster.API.Gateway.SystemData.Contexts; -namespace QuizMaster.API.Gateway.Services.System +namespace QuizMaster.API.Gateway.Services.SystemService { public class SystemRepository { @@ -17,7 +17,7 @@ public SystemRepository(SystemDbContext dbContext, IMapper _mapper) public async Task EditSystemAboutAsync(AboutModel model) { - SystemAbout? systemAbout = await dbContext.SystemAboutData.FindAsync(new SystemAbout { Id = 1 }); + SystemAbout? systemAbout = await dbContext.SystemAboutData.Where(s => s.Id == 1).FirstAsync(); systemAbout ??= new SystemAbout { Id = 1 }; _mapper.Map(model, systemAbout); @@ -27,7 +27,7 @@ public async Task EditSystemAboutAsync(AboutModel model) public async Task EditSystemContactInformationAsync(ContactModel model) { - SystemContact? systemContact = await dbContext.SystemContactData.FindAsync(new SystemContact { Id = 1 }); + SystemContact? systemContact = await dbContext.SystemContactData.Where(s => s.Id == 1).FirstAsync(); systemContact ??= new SystemContact { Id = 1 }; _mapper.Map(model, systemContact); @@ -37,12 +37,12 @@ public async Task EditSystemContactInformationAsync(ContactModel model) public async Task GetSystemAboutAsync() { - return _mapper.Map(await dbContext.SystemAboutData.FindAsync(new SystemAbout { Id = 1 })); + return _mapper.Map(await dbContext.SystemAboutData.Where(s => s.Id == 1).FirstAsync()); } public async Task GetContactInformationAsync() { - return _mapper.Map(await dbContext.SystemContactData.FindAsync(new SystemContact { Id = 1 })); + return _mapper.Map(await dbContext.SystemContactData.Where(s => s.Id == 1).FirstAsync()); } public async Task SaveReachingContactAsync(SubmitContactModel model) diff --git a/WebApp/backend/QuizMaster.API.Gatewway/SystemData/System.db b/WebApp/backend/QuizMaster.API.Gatewway/SystemData/System.db index cbd07caa6cd26bd1e4402373f16a5c320dd5722b..5284f283c6109c9228b2698b8c087591398c42f6 100644 GIT binary patch delta 338 zcmZo@U}|V!+Q4eS%Daw%cim<|fhD{GE&hxg4B{QRhP=FndIoxin_t*TFoFrCjFOUq zVk>?9^!)tvoK(H!{9IlJ1_l=X6%71u_^ t6`5EW7&)DpAnsPkELKQKO-xZpELO-*Q^?CNSFqAoU}R~L0sv`AV4B{=eyu7@IdIow1oA=pDF!Jy+FfcIj zUt{2Z!+&kFV89{%i2)pwulXCWTxHJpkRIF4`v6FOZECZ$rsjS5V zA3(6v&d$Ps>0+TESSaXnr;RrA!#DrOOlRbEM&1RtWQ&*3^}VCr&5HdA8``KEnyQH_rqMK}88>Q+ zab&`61=783>Bx>kOnyJ`h4M#sVLB!!yQ7p?!~%$3(=E(^OJTGij2N*|}FC@zA|9 e5%|PAUNLdb0~V$fk>qqLR<5p;){8A!|k delta 64 zcmZp8z~1nHeFKXFKO6r%2L2EH_xaEAAL8H4zg3a3mUpv)03XxldH!h*i&+u`7PBlU U*vzuwul#mK14iZrK;|EL0N45!=>Px# diff --git a/WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-shm b/WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-shm deleted file mode 100644 index cd5bf640ce4ff42eac0b6086b608a9133fe14658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 zcmeI)J4ysW6a~;b{{N2u9#I5y*I?ilWD*zP2Fwi%U52s7f(tNq3F%1PF{3n96JxvOM;i zLjv6vn9f`lv(oJ*bw_{z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs M0RjXF5Eu!30pUk0od5s; diff --git a/WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-wal b/WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-wal deleted file mode 100644 index bcaff9e8110e290725a1ad255bf44fde4d644b9e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 144232 zcmeI)Z){a(9S87x?zyGCxbl$U_|Muwz_`h5y8;u9%QCX)I*Hb%i(y;Fv@DHekhLtE zz93eUMVWIU5ZN1++Q^vEC3evb$c%`{7L}<9#LPbn{#lKz4lA*n*35HGZDS`k_XXE$ zFP|rurqqZsX!!o`kIqgG7Q%2YjD^uKlDshp5FkK+009C72oNAZfB=D+El`MyQ6Zh; zbjrtZv6vLJG%ac(FF1ME@Le~rdt||QE^s!@1tinW1la)C?!egQy$009C72oNAZfB*pk z)g>^Q3)Ez}Ks=EPOxZ{9js6vTKmD0+p0tmkx)xtG1PBlyK!5-N0t5&UAV46OB?Ia7 z-}e!G_RYK3=1#5J=XnA53jqQI2oNAZfB*pk1PBnQDuK!81*Y3a5Y68B%J3~$eLyZy zRco&p0t5&UAV7cs0RjXF5Fjv_3rx3<;Ds|A+CKQluf4-Q0yhi+0t5&UAV7cs0RjXF z5U4VN67~^%zU`5%3m4Bj<#~ZBTYKdYAV7cs0RjXF5FkK+z@;uQ`Mkh%`v~fv>>F$R z!kvfY0+;&jqJ9Dd2oNAZfB*pk1PBnQGJ(llV7h$-gFUzOZ*1IiyL|*zw))B;K!5-N z0t5&UAV7cs0RkoLBRG27x9&c@t9!ra1>7zK2oNAZfB*pk1PBlyK%lAwCZ89WZXZGG zrrjfbH?CSG7pSVWR}29H1PBlyK!5-N0t5&Un9K#Whzuh`lE>M|;byWfc z2oNAZfB*pk1PBlyP=Y}EcYaxNfuA0~`au6r9$X+7C}9v0m04IAro}zabYW zVHKQ0fB*pk1PBlyK!5-N0t6}}P_|rPS?9sQm$!7BmkU&8VO^B~0RjXF5FkK+009C7 z2$UdDwp`%h!v|k^{?(Q?xj+f4;1mJ`2oNAZfB*pk1PBlyP#J-;M|;byWfc2oNAZfB*pk1PBlyP=Y|&a)H%zhEMOSy{Rb{@ zf8qwYKnbhh6aoYY5FkK+009C72oNAp8G*9p0^c6Gwf$q8XWu6msLaB;Dggon2oNAZ zfB*pk1PBl)L7;58z*C(&JOA~+}1PBlyK!5-N0t5&UAV8op0v9tEs7XsW zv8ZEU)AHUU?Kgh%sqV%(Kd(=Y)rP&fa4x(YejL6Ro(}ty{~81c5FkK+009C72oNAZ zfIztgYHQ;wiXZLj?U^?#z9#y}j;@~G?rryO=<40vy|t&lz9w#%JlInx7UBg_$AjCu zdS=ay+!YLS0fy`e;DI zL@u!X@z34A_x^`&OLKuJ{3w^a3<3lQ5FkK+009C72oNAZUU^b-DI! zJMR5NWAnehv^2G}u5M~x-Mpr;dF}e<=Jl=DU)$2!)UxJ1*Cl0Lo|ZO|3%s%a?SGlO zqIPGR3*^J`T=;D=83YIrAV7cs0RjXF5FkK+!2hqn(tKT1EMAx70r{q;R>Wbr^Uf{!|sCj8&6S=^-7k_x{>)l@(P9Gx3hx57c_hd2%5FkK+009C72oNAZ zfB=E25tvnoicvmaC?s(~Qq+~nzsY?Bi#zXV*zuiR2gh@P(Oeh{qg7M5LI@BbK!5-N z0t5&UAV7csfmEOnC&@q@XSu+XzJqU$-SgV&A1t3U-gj`%)V_mz;1M7|fB*pk1PBly zK!5-N0_7H{OWF=bY1_g4|Gw{F$KcR{k;k5Ue!RcHzNGJ9*jMg){d@uh2oNAZfB*pk z1PBlyKwzpsOa3iA1Y5>?2)6u355YBSuU)sMwYjNj?ZxOj_}H%x&Hu`y@9Rr*fkJpF z>pK_@ByS7?1PBlyK!5-N0t5&UAV8p80?P_@QIvHKEL^B{;Ieq) Date: Mon, 15 Jan 2024 21:19:22 +0800 Subject: [PATCH 6/8] Refactor: Removed Unused Property in ReviewModel and Migrated --- ..._Migration_2_RemovedUnusedProp.Designer.cs | 146 ++++++++++++++++++ ...115131703_Migration_2_RemovedUnusedProp.cs | 28 ++++ .../SystemDbContextModelSnapshot.cs | 3 - .../Models/System/ReviewModel.cs | 1 - .../SystemData/System.db | Bin 32768 -> 36864 bytes .../SystemData/System.db-shm | Bin 0 -> 32768 bytes .../SystemData/System.db-wal | Bin 0 -> 8272 bytes .../sessionDb/QuizSession.db-shm | Bin 0 -> 32768 bytes .../sessionDb/QuizSession.db-wal | Bin 0 -> 103032 bytes 9 files changed, 174 insertions(+), 4 deletions(-) create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/Migrations/20240115131703_Migration_2_RemovedUnusedProp.Designer.cs create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/Migrations/20240115131703_Migration_2_RemovedUnusedProp.cs create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/SystemData/System.db-shm create mode 100644 WebApp/backend/QuizMaster.API.Gatewway/SystemData/System.db-wal create mode 100644 WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-shm create mode 100644 WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-wal diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Migrations/20240115131703_Migration_2_RemovedUnusedProp.Designer.cs b/WebApp/backend/QuizMaster.API.Gatewway/Migrations/20240115131703_Migration_2_RemovedUnusedProp.Designer.cs new file mode 100644 index 00000000..4d8028b7 --- /dev/null +++ b/WebApp/backend/QuizMaster.API.Gatewway/Migrations/20240115131703_Migration_2_RemovedUnusedProp.Designer.cs @@ -0,0 +1,146 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using QuizMaster.API.Gateway.SystemData.Contexts; + +#nullable disable + +namespace QuizMaster.API.Gateway.Migrations +{ + [DbContext(typeof(SystemDbContext))] + [Migration("20240115131703_Migration_2_RemovedUnusedProp")] + partial class Migration_2_RemovedUnusedProp + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.15"); + + modelBuilder.Entity("QuizMaster.API.Gateway.Models.System.ContactReaching", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Emai") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Firstname") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Lastname") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Message") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("SystemReachingContacts"); + }); + + modelBuilder.Entity("QuizMaster.API.Gateway.Models.System.Reviews", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Comment") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("StarRating") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("SystemReviews"); + }); + + modelBuilder.Entity("QuizMaster.API.Gateway.Models.System.SystemAbout", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Ios_link") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Mobile_link") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Version") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Web_link") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("SystemAboutData"); + + b.HasData( + new + { + Id = 1, + Description = "Lorem ipsum dolor sit amet consectetur. Pulvinar porta egestas molestie purus faucibus neque malesuada lectus. Lacus auctor sit felis sed ultrices nullam sapien ornare justo. Proin adipiscing viverra vestibulum arcu sit. Suscipit bibendum ullamcorper ut et dolor quisque nulla et.", + Ios_link = "", + Mobile_link = "", + Version = "1.0.0", + Web_link = "" + }); + }); + + modelBuilder.Entity("QuizMaster.API.Gateway.Models.System.SystemContact", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Contact") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Email") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("SystemContactData"); + + b.HasData( + new + { + Id = 1, + Contact = "09205195701", + Email = "admin.quizmaster@gmail.com" + }); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Migrations/20240115131703_Migration_2_RemovedUnusedProp.cs b/WebApp/backend/QuizMaster.API.Gatewway/Migrations/20240115131703_Migration_2_RemovedUnusedProp.cs new file mode 100644 index 00000000..32584438 --- /dev/null +++ b/WebApp/backend/QuizMaster.API.Gatewway/Migrations/20240115131703_Migration_2_RemovedUnusedProp.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace QuizMaster.API.Gateway.Migrations +{ + /// + public partial class Migration_2_RemovedUnusedProp : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "UserId", + table: "SystemReviews"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "UserId", + table: "SystemReviews", + type: "INTEGER", + nullable: true); + } + } +} diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Migrations/SystemDbContextModelSnapshot.cs b/WebApp/backend/QuizMaster.API.Gatewway/Migrations/SystemDbContextModelSnapshot.cs index 9f4abec9..92b1f4c3 100644 --- a/WebApp/backend/QuizMaster.API.Gatewway/Migrations/SystemDbContextModelSnapshot.cs +++ b/WebApp/backend/QuizMaster.API.Gatewway/Migrations/SystemDbContextModelSnapshot.cs @@ -64,9 +64,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("StarRating") .HasColumnType("INTEGER"); - b.Property("UserId") - .HasColumnType("INTEGER"); - b.HasKey("Id"); b.ToTable("SystemReviews"); diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Models/System/ReviewModel.cs b/WebApp/backend/QuizMaster.API.Gatewway/Models/System/ReviewModel.cs index 96779d58..2eaba533 100644 --- a/WebApp/backend/QuizMaster.API.Gatewway/Models/System/ReviewModel.cs +++ b/WebApp/backend/QuizMaster.API.Gatewway/Models/System/ReviewModel.cs @@ -4,7 +4,6 @@ namespace QuizMaster.API.Gateway.Models.System { public class ReviewModel { - public int? UserId { get; set; } = null; public int StarRating { get; set; } = 0; public string Comment { get; set; } = string.Empty; } diff --git a/WebApp/backend/QuizMaster.API.Gatewway/SystemData/System.db b/WebApp/backend/QuizMaster.API.Gatewway/SystemData/System.db index 5284f283c6109c9228b2698b8c087591398c42f6..21c14fb4e3b22242754d642fc4b4cbf5657e1fa8 100644 GIT binary patch delta 519 zcmZo@U}{*vG(lRBnSp_U6Nov0m=Q!z)G?N2X3$G!( zTb#c*o^5Q*;t1gX!T3eo+?=tQvm`MoCp9%Kz9cobAU?RV7)S@DmSv`v7h@IVbPjTL z3~^Nmadh%=RZxPdnJmVYJ^3J)*yIb`9FymA$!PL&X#(y4Bd)H_*lbvm2xNZ%+1FGF zv9B?fgB>K-R5|$tr#vI)WDc%MWc{13bLp~jF!4`f;6KSfX|td}8^5_J6LYGhk%5tk zfuW(Pp|PR4fpNTVW_nR#NoIatyit5mYHog6YD#EcX>n>wKv8~yxt@WZq3Pt4^436; z<}>hL;GYjPX)?c|0dp!NDF!iZzM$_Qz{KAR)LzFgrN;>KHcEIg39@cpnMF|K#2Et~|UzF(&?f4E*=`_W?yW@jJ;gu`oDuLd;OeELKQKO-xZpELO-* QQ^?CNSFqBTXC$Bi0Db72g8%>k delta 197 zcmZozz|_#dG(lRBiGhKE1BhXOb)t^3G!uhfG9xel4+eJ5dklP+_}B9G@LKT%aoys) zw^>jig;T4slAT>#U7fMnup}`lCpEaTxFj_QntKJa_wzkLj!{Z&t zaSy%$UOttpm~5{7I`nO*`gDDc&FeN4$NJJ$hkn?d+k5uN|9l_5TJrwMa``=MLXUHW z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1X2=++wOz_0RjXF5FkK+0D-gx x;&y8xK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!89R0v}koDaZf- literal 0 HcmV?d00001 diff --git a/WebApp/backend/QuizMaster.API.Gatewway/SystemData/System.db-wal b/WebApp/backend/QuizMaster.API.Gatewway/SystemData/System.db-wal new file mode 100644 index 0000000000000000000000000000000000000000..61c299e05af9ab60078046fa9cea598c80aab389 GIT binary patch literal 8272 zcmXr7XKP~6eI&uaAiw|uE9Fx1HZ086arRc+qdsr8AW(=ES==S?*WyKc1Y~%Df-L+i z82I1tU*q4+zk$tAtg02MIo_RAwNwaFTY&DN?)FlfC2z-=)CGXc$^R(}N z{>u09&oZgqdDTVLU-qNAw`|ofLVy4P0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0tEg=U^jc& z&#>nC9Ofv;Imv0xYEn)+e@6%qAV8p-0==wdBU{~UPFDm75FoHnU?u$wvc2$|Ljv6v zSj~Div(xP+bw_{z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF I5SR;m0U#qT{Qv*} literal 0 HcmV?d00001 diff --git a/WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-wal b/WebApp/backend/QuizMaster.API.QuizSession/sessionDb/QuizSession.db-wal new file mode 100644 index 0000000000000000000000000000000000000000..91b00a88e937486b090cb408fe5834f913ad4bab GIT binary patch literal 103032 zcmeI(Uuafk90&0C-TTM)b&Y4?g%-sq@5+T15~I3mU8Q$H!NOR9VUQtIG%#F7kkEw= zM53}B5$doNGx8>p1aU=-k|_U#%&3qt3@^07+vq(f_L5OA=fcCmv(LHsG0q-%_I!TN z&Ay!9{oAVB3%wUs6bjvi=$W6aotqf1%zbj{o0|uJdTdkk)vf=0zpL=(_R)3g%1fIs z%VD+<8sTcV-2A~qfB*pk1PBlyK!5-N0t5)$*aGEJy;zP)DJmVMQoY_h&~4G77V?6% z&)oa|w~zE4{W}+!iE@FNa3%bHV;|gKPk;ac0t5&UAV7cs0RjXTy+E7_R7%BWAQ0Du zT;TSmOwU3taK3Wz?2+kXa)CvET>uauK!5-N0t5&UAV7dX&IDSyKqbxvN(;HbHFE?< zSAF#E%%xw~nCxMAw>cjgFO7y<+c5FkK+009C72oNBUGl2wi1dku-d3a#!NWbp|a@Kpt zAwYlt0RjXF5FkK+0D;9W(E47W-5kN*i9_2y=;(M-F0k0Ii}Mp8K!5-N0t5&UAV7dX z&IDSyK)X4D{sU9PdrzMK*&IR6y6-py2oNAZfB*pk1PBlyKp?>!!NBU>UC)lKob$ba z>q3A40RjXF5FkK+009C7awX9EUZC9^!P?=*+dsU%H^sFxu1lj@s>ih!*ClbSMzy2z z-*W`lh+(1PBlyK!5-N0t5&o5QzTIPbC*v{%G&?`s#%{ zh+(1PBlyK!5-N z0t5&o5J)W-*fV``=*wN7HRJ*bx?l+b0t5&UAV7cs0RjXF5XeR#yRt?An zvT3Yc2@oJafB*pk1PBlyK!893fz)z=6Q}R_bpLaGRk=WdE?7c<009C72oNAZfB*pk z1hNrGEf;uYd~ohi=RmJqAe+Y8l>h+(1PBlyK!5-N0t5&o5J)W-*z@(N9m5;$J0=%M z&;?5f5FkK+009C72oNAZfIv0^spSHz?>;=ZX6(TiAl*=`{V-I zG}f*J2oNAZfB*pk1PBlyKp=rYYPrD3{MK7mHs<@~0tvcc2>}8G2oNAZfB*pk1PBnw KM&P>T0)GJ|o#jFR literal 0 HcmV?d00001 From 6e5c09298157bd4548c58a17ba4bafa39b72bd2a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 16 Jan 2024 16:15:27 +0800 Subject: [PATCH 7/8] Feature: Added GetReviews route for clients as requested by master Rodney, updated email sender admin email --- .../Controllers/SystemController.cs | 43 ++++++++++++++++--- .../Models/System/SubmitContactModel.cs | 2 +- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Controllers/SystemController.cs b/WebApp/backend/QuizMaster.API.Gatewway/Controllers/SystemController.cs index cee13471..36861820 100644 --- a/WebApp/backend/QuizMaster.API.Gatewway/Controllers/SystemController.cs +++ b/WebApp/backend/QuizMaster.API.Gatewway/Controllers/SystemController.cs @@ -85,13 +85,27 @@ public async Task ReachOutAsync([FromBody] SubmitContactModel mod await systemRepository.SaveReachingContactAsync(model); #region Send Email - Task.Run(() => + // I'll run this in a different thread + _ = Task.Run(async () => { - var clientEmail = EmailDefaults.SUBMIT_CONTACT_CLIENT(model.Emai); + // Lets try sending the email the the user authenticated, otherwise we'll send it to the email specified in the model + var token = this.GetToken(); + var email = model.Email; + if (!string.IsNullOrEmpty(token)) + { + var authStore = await GetAuthStoreInfo(token); + if (authStore != null) email = authStore.UserData.Email; + } + + // Create the templates and send the corresponding emails + var clientEmail = EmailDefaults.SUBMIT_CONTACT_CLIENT(model.Email); var adminEmailCopy = EmailDefaults.SUBMIT_CONTACT_ADMIN("", model.Firstname + " " + model.Lastname, model.Message); emailService.SendEmail(clientEmail); emailService.SendEmailToAdmin(adminEmailCopy); + + var registeredAdminContactCopy = EmailDefaults.SUBMIT_CONTACT_ADMIN((await systemRepository.GetContactInformationAsync()).Email, model.Firstname + " " + model.Lastname, model.Message); + emailService.SendEmail(registeredAdminContactCopy); }); #endregion @@ -117,7 +131,8 @@ public async Task SubmitReviewAsync([FromBody] ReviewModel model) await systemRepository.SaveReviewsAsync(model); #region Send Email - Task.Run(async () => + // I'll run this in a different thread + _ = Task.Run(async () => { var token = this.GetToken(); if(!string.IsNullOrEmpty(token)) @@ -128,25 +143,41 @@ public async Task SubmitReviewAsync([FromBody] ReviewModel model) { var clientEmail = EmailDefaults.SUBMIT_REVIEW_CLIENT(AuthStore.UserData.Email, model.Comment, model.StarRating); emailService.SendEmail(clientEmail); + } } - + /* + * + * This code right here will send an email to the SMTP account, which I commented it out first since we priority on + * the admin that will receive the email must be the email specified in the contact us var adminEmailCopy = EmailDefaults.SUBMIT_REVIEW_ADMIN("", model.Comment, model.StarRating); - - emailService.SendEmailToAdmin(adminEmailCopy); + */ + var registeredAdminContactCopy = EmailDefaults.SUBMIT_REVIEW_ADMIN((await systemRepository.GetContactInformationAsync()).Email, model.Comment, model.StarRating); + emailService.SendEmail(registeredAdminContactCopy); }); #endregion return Ok(new { Status = "Success", Message = "Successfully submitted a system review." }); } + // Get All Submitted Review + [QuizMasterAdminAuthorization] [HttpGet("review")] public async Task GetAllReviewsAsync() { return Ok(new { Status = "Success", Message = "Retrieved System Reviews", Data = await systemRepository.GetReviewsAsync() }); } + [HttpGet("review/client")] + public async Task GetAllReviewsClientCopyAsync() + { + var data = await systemRepository.GetReviewsAsync(); + data = data.Where(r => r.StarRating >= 4).ToList(); + return Ok(new { Status = "Success", Message = "Retrieved System Reviews", Data = data }); + } + + private async Task GetAuthStoreInfo(string token) { diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Models/System/SubmitContactModel.cs b/WebApp/backend/QuizMaster.API.Gatewway/Models/System/SubmitContactModel.cs index db0d1eca..5c80e0f8 100644 --- a/WebApp/backend/QuizMaster.API.Gatewway/Models/System/SubmitContactModel.cs +++ b/WebApp/backend/QuizMaster.API.Gatewway/Models/System/SubmitContactModel.cs @@ -5,7 +5,7 @@ namespace QuizMaster.API.Gateway.Models.System public class SubmitContactModel { public int? UserId { get; set; } = null; - public string Emai { get; set; } = string.Empty; + public string Email { get; set; } = string.Empty; public string PhoneNumber { get; set;} = string.Empty; public string Lastname { get; set; } = string.Empty; public string Firstname { get; set;} = string.Empty; From ac7d025e5307fe76674ef235ca8449e418451957 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 16 Jan 2024 17:26:57 +0800 Subject: [PATCH 8/8] Ref: ContactUs admin email will now receive a copy of users reaching out and reviews --- .../Controllers/SystemController.cs | 33 ++++++----- .../Services/Email/EmailService.cs | 56 +++++++++++-------- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Controllers/SystemController.cs b/WebApp/backend/QuizMaster.API.Gatewway/Controllers/SystemController.cs index 36861820..c4a81eb7 100644 --- a/WebApp/backend/QuizMaster.API.Gatewway/Controllers/SystemController.cs +++ b/WebApp/backend/QuizMaster.API.Gatewway/Controllers/SystemController.cs @@ -22,8 +22,9 @@ public class SystemController : Controller private readonly EmailService emailService; private readonly GrpcChannel _authChannel; private readonly AuthService.AuthServiceClient _authChannelClient; + private readonly ILogger logger; - public SystemController(SystemRepository systemRepository, EmailService emailService, IOptions options) + public SystemController(SystemRepository systemRepository, EmailService emailService, IOptions options, ILogger logger) { this.systemRepository = systemRepository; this.emailService = emailService; @@ -32,6 +33,7 @@ public SystemController(SystemRepository systemRepository, EmailService emailSer handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; _authChannel = GrpcChannel.ForAddress(options.Value.Authentication_Service, new GrpcChannelOptions { HttpHandler = handler }); _authChannelClient = new AuthService.AuthServiceClient(_authChannel); + this.logger = logger; } // Get System About @@ -85,8 +87,9 @@ public async Task ReachOutAsync([FromBody] SubmitContactModel mod await systemRepository.SaveReachingContactAsync(model); #region Send Email - // I'll run this in a different thread - _ = Task.Run(async () => + // I'll run this in a thread + var contactInformation = await systemRepository.GetContactInformationAsync(); + Task.Run(async () => { // Lets try sending the email the the user authenticated, otherwise we'll send it to the email specified in the model var token = this.GetToken(); @@ -98,17 +101,18 @@ public async Task ReachOutAsync([FromBody] SubmitContactModel mod } // Create the templates and send the corresponding emails - var clientEmail = EmailDefaults.SUBMIT_CONTACT_CLIENT(model.Email); - var adminEmailCopy = EmailDefaults.SUBMIT_CONTACT_ADMIN("", model.Firstname + " " + model.Lastname, model.Message); - + var clientEmail = EmailDefaults.SUBMIT_CONTACT_CLIENT(email); emailService.SendEmail(clientEmail); - emailService.SendEmailToAdmin(adminEmailCopy); - var registeredAdminContactCopy = EmailDefaults.SUBMIT_CONTACT_ADMIN((await systemRepository.GetContactInformationAsync()).Email, model.Firstname + " " + model.Lastname, model.Message); + logger.LogInformation("Sending Email Copy to: " + contactInformation.Email); + var registeredAdminContactCopy = EmailDefaults.SUBMIT_CONTACT_ADMIN(contactInformation.Email, model.Firstname + " " + model.Lastname, model.Message); emailService.SendEmail(registeredAdminContactCopy); + emailService.SendEmailToAdmin(registeredAdminContactCopy); }); #endregion + + return Ok(new { Status = "Success", Message = "Successfully submitted a contact request." }); } @@ -131,11 +135,12 @@ public async Task SubmitReviewAsync([FromBody] ReviewModel model) await systemRepository.SaveReviewsAsync(model); #region Send Email - // I'll run this in a different thread - _ = Task.Run(async () => + var contactInformation = await systemRepository.GetContactInformationAsync(); + // I'll run this in a separate thread + Task.Run(async () => { var token = this.GetToken(); - if(!string.IsNullOrEmpty(token)) + if (!string.IsNullOrEmpty(token)) { var AuthStore = await GetAuthStoreInfo(token); @@ -143,7 +148,7 @@ public async Task SubmitReviewAsync([FromBody] ReviewModel model) { var clientEmail = EmailDefaults.SUBMIT_REVIEW_CLIENT(AuthStore.UserData.Email, model.Comment, model.StarRating); emailService.SendEmail(clientEmail); - + } } /* @@ -153,8 +158,10 @@ public async Task SubmitReviewAsync([FromBody] ReviewModel model) var adminEmailCopy = EmailDefaults.SUBMIT_REVIEW_ADMIN("", model.Comment, model.StarRating); emailService.SendEmailToAdmin(adminEmailCopy); */ - var registeredAdminContactCopy = EmailDefaults.SUBMIT_REVIEW_ADMIN((await systemRepository.GetContactInformationAsync()).Email, model.Comment, model.StarRating); + var registeredAdminContactCopy = EmailDefaults.SUBMIT_REVIEW_ADMIN(contactInformation.Email, model.Comment, model.StarRating); + logger.LogInformation("Sending Email Copy to: " + contactInformation.Email); emailService.SendEmail(registeredAdminContactCopy); + emailService.SendEmailToAdmin(registeredAdminContactCopy); }); #endregion diff --git a/WebApp/backend/QuizMaster.API.Gatewway/Services/Email/EmailService.cs b/WebApp/backend/QuizMaster.API.Gatewway/Services/Email/EmailService.cs index 91f0f296..4d3cdbad 100644 --- a/WebApp/backend/QuizMaster.API.Gatewway/Services/Email/EmailService.cs +++ b/WebApp/backend/QuizMaster.API.Gatewway/Services/Email/EmailService.cs @@ -10,40 +10,48 @@ public class EmailService { private readonly string SMTP_EMAIL; private readonly string SMTP_PASS; - public EmailService(IOptions appSettings) + private readonly ILogger logger; + public EmailService(IOptions appSettings, ILogger logger) { SMTP_EMAIL = appSettings.Value.SMTP_EMAIL; SMTP_PASS = appSettings.Value.SMTP_PASSWORD; + this.logger = logger; } private void SendEmailRequest(EmailTemplate emailTemplate, bool toAdmin) { - MailMessage mailMessage = new MailMessage(); - mailMessage.From = new MailAddress(SMTP_EMAIL, "🔎QuizMaster@no-reply", System.Text.Encoding.UTF8); - if(toAdmin) + try { - mailMessage.To.Add(SMTP_EMAIL); - } - else + MailMessage mailMessage = new MailMessage(); + mailMessage.From = new MailAddress(SMTP_EMAIL, "🔎QuizMaster@no-reply", System.Text.Encoding.UTF8); + if (toAdmin) + { + mailMessage.To.Add(SMTP_EMAIL); + } + else + { + mailMessage.To.Add(emailTemplate.ToEmail); + } + mailMessage.Subject = emailTemplate.Subject; + mailMessage.Body = emailTemplate.Body; + mailMessage.IsBodyHtml = true; + + // Create the credentials to login to the gmail account associated with my custom domain + string sendEmailsFrom = SMTP_EMAIL; + string sendEmailsFromPassword = SMTP_PASS; + NetworkCredential cred = new NetworkCredential(sendEmailsFrom, sendEmailsFromPassword); + + SmtpClient mailClient = new SmtpClient("smtp.gmail.com", 587); + mailClient.EnableSsl = true; + mailClient.DeliveryMethod = SmtpDeliveryMethod.Network; + mailClient.UseDefaultCredentials = false; + mailClient.Timeout = 20000; + mailClient.Credentials = cred; + mailClient.Send(mailMessage); + }catch(Exception err) { - mailMessage.To.Add(emailTemplate.ToEmail); + logger.LogError("Error Sending Email: " + err.Message); } - mailMessage.Subject = emailTemplate.Subject; - mailMessage.Body = emailTemplate.Body; - mailMessage.IsBodyHtml = true; - - // Create the credentials to login to the gmail account associated with my custom domain - string sendEmailsFrom = SMTP_EMAIL; - string sendEmailsFromPassword = SMTP_PASS; - NetworkCredential cred = new NetworkCredential(sendEmailsFrom, sendEmailsFromPassword); - - SmtpClient mailClient = new SmtpClient("smtp.gmail.com", 587); - mailClient.EnableSsl = true; - mailClient.DeliveryMethod = SmtpDeliveryMethod.Network; - mailClient.UseDefaultCredentials = false; - mailClient.Timeout = 20000; - mailClient.Credentials = cred; - mailClient.Send(mailMessage); } public void SendEmail(EmailTemplate emailTemplate)