From c839aa9cc1313278ba7c9777fde3dbb6f160ba32 Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 11 Nov 2023 19:40:29 -0800 Subject: [PATCH] Add notification service --- devblog/devblog/ClientApp/src/global.css | 2 +- .../Controllers/NotificationController.cs | 23 ++ .../devblog/Controllers/PostsController.cs | 20 +- devblog/devblog/Data/AppDbContext.cs | 4 +- .../Interfaces/INotificationService.cs | 10 + ...31111193006_noticication table.Designer.cs | 203 +++++++++++++++++ .../20231111193006_noticication table.cs | 36 +++ ...3550_noticication table column.Designer.cs | 207 ++++++++++++++++++ ...0231111193550_noticication table column.cs | 29 +++ ...umn 'username' to appdbcontext.Designer.cs | 205 +++++++++++++++++ ...ation column 'username' to appdbcontext.cs | 75 +++++++ ...ange notification table casing.Designer.cs | 205 +++++++++++++++++ ...200125_change notification table casing.cs | 28 +++ .../Migrations/AppDbContextModelSnapshot.cs | 16 ++ devblog/devblog/Models/Notification.cs | 9 + devblog/devblog/Program.cs | 1 + .../devblog/Services/NotificationService.cs | 41 ++++ devblog/devblog/Services/PostService.cs | 22 +- 18 files changed, 1110 insertions(+), 26 deletions(-) create mode 100644 devblog/devblog/Controllers/NotificationController.cs create mode 100644 devblog/devblog/Interfaces/INotificationService.cs create mode 100644 devblog/devblog/Migrations/20231111193006_noticication table.Designer.cs create mode 100644 devblog/devblog/Migrations/20231111193006_noticication table.cs create mode 100644 devblog/devblog/Migrations/20231111193550_noticication table column.Designer.cs create mode 100644 devblog/devblog/Migrations/20231111193550_noticication table column.cs create mode 100644 devblog/devblog/Migrations/20231111193658_add noticication column 'username' to appdbcontext.Designer.cs create mode 100644 devblog/devblog/Migrations/20231111193658_add noticication column 'username' to appdbcontext.cs create mode 100644 devblog/devblog/Migrations/20231111200125_change notification table casing.Designer.cs create mode 100644 devblog/devblog/Migrations/20231111200125_change notification table casing.cs create mode 100644 devblog/devblog/Models/Notification.cs create mode 100644 devblog/devblog/Services/NotificationService.cs diff --git a/devblog/devblog/ClientApp/src/global.css b/devblog/devblog/ClientApp/src/global.css index 6c74b463..42f755e3 100644 --- a/devblog/devblog/ClientApp/src/global.css +++ b/devblog/devblog/ClientApp/src/global.css @@ -5,7 +5,7 @@ button:hover { main { width: 1100px; - margin: auto + margin: auto; } @media (max-width: 1000px) { diff --git a/devblog/devblog/Controllers/NotificationController.cs b/devblog/devblog/Controllers/NotificationController.cs new file mode 100644 index 00000000..87c02edb --- /dev/null +++ b/devblog/devblog/Controllers/NotificationController.cs @@ -0,0 +1,23 @@ +using devblog.Interfaces; +using devblog.Services; +using Microsoft.AspNetCore.Mvc; + +namespace devblog.Controllers +{ + [ApiController] + [Route("api/[controller]")] + public class NotificationController : ControllerBase + { + private readonly INotificationService _notifications; + + public NotificationController(NotificationService notifications) + { + _notifications = notifications; + } + + public async Task Get() + { + + } + } +} diff --git a/devblog/devblog/Controllers/PostsController.cs b/devblog/devblog/Controllers/PostsController.cs index afa7ba57..432d2f88 100644 --- a/devblog/devblog/Controllers/PostsController.cs +++ b/devblog/devblog/Controllers/PostsController.cs @@ -10,25 +10,13 @@ namespace devblog.Controllers public class PostsController : ControllerBase { private readonly IPostService _posts; - private readonly IImgService _imgService; - - public PostsController(IPostService posts, IImgService imgService) + private readonly IImgService _imgs; + public PostsController(IPostService posts, IImgService imgs) { _posts = posts; - _imgService = imgService; + _imgs = imgs; } - /// - /// Retrieves all posts - /// - /// List - //[HttpGet] - //public async Task> Get() - //{ - // var posts = await _posts.Get(); - // return posts; - //} - [HttpGet("page/{pageNum}")] public async Task> GetPage(int pageNum) { @@ -107,7 +95,7 @@ public async Task Update(int id, [FromBody] string description) public async Task Delete(int id) { var imgs = _posts.Get(id).Result.Imgs; - await _imgService.DeleteImgFromDropBox(imgs); + await _imgs.DeleteImgFromDropBox(imgs); await _posts.Delete(id); } } diff --git a/devblog/devblog/Data/AppDbContext.cs b/devblog/devblog/Data/AppDbContext.cs index c0a8754d..16a55cc7 100644 --- a/devblog/devblog/Data/AppDbContext.cs +++ b/devblog/devblog/Data/AppDbContext.cs @@ -1,5 +1,4 @@ using devblog.Models; -using Discord; using Microsoft.EntityFrameworkCore; namespace devblog.Data @@ -12,6 +11,7 @@ public class AppDbContext : DbContext public DbSet DownVote { get; set; } public DbSet Img { get; set; } public DbSet YtVideo { get; set; } + public DbSet Notification { get; set; } public AppDbContext(DbContextOptions opt) : base(opt) { @@ -21,6 +21,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); + modelBuilder.Entity().HasKey(e => new { e.PostId, e.UserName }); + modelBuilder.Entity().HasKey(e => new { e.PostId, e.UserName }); modelBuilder.Entity().HasKey(e => new { e.PostId, e.UserName }); diff --git a/devblog/devblog/Interfaces/INotificationService.cs b/devblog/devblog/Interfaces/INotificationService.cs new file mode 100644 index 00000000..b91cf877 --- /dev/null +++ b/devblog/devblog/Interfaces/INotificationService.cs @@ -0,0 +1,10 @@ +namespace devblog.Interfaces +{ + public interface INotificationService + { + /// + /// Creates a noticication for a new post to every user + /// + Task Create(int PostId); + } +} diff --git a/devblog/devblog/Migrations/20231111193006_noticication table.Designer.cs b/devblog/devblog/Migrations/20231111193006_noticication table.Designer.cs new file mode 100644 index 00000000..0aa5c668 --- /dev/null +++ b/devblog/devblog/Migrations/20231111193006_noticication table.Designer.cs @@ -0,0 +1,203 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using devblog.Data; + +#nullable disable + +namespace devblog.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20231111193006_noticication table")] + partial class noticicationtable + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("devblog.Models.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Content") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.ToTable("Comment"); + }); + + modelBuilder.Entity("devblog.Models.DownVote", b => + { + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserName") + .HasColumnType("varchar(255)"); + + b.HasKey("PostId", "UserName"); + + b.ToTable("DownVote"); + }); + + modelBuilder.Entity("devblog.Models.Img", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("PostId") + .HasColumnType("int"); + + b.Property("Url") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.ToTable("Img"); + }); + + modelBuilder.Entity("devblog.Models.Notification", b => + { + b.Property("PostId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Seen") + .HasColumnType("tinyint(1)"); + + b.HasKey("PostId"); + + b.ToTable("Notification"); + }); + + modelBuilder.Entity("devblog.Models.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Post"); + }); + + modelBuilder.Entity("devblog.Models.UpVote", b => + { + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserName") + .HasColumnType("varchar(255)"); + + b.HasKey("PostId", "UserName"); + + b.ToTable("UpVote"); + }); + + modelBuilder.Entity("devblog.Models.YtVideo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Url") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("Url") + .IsUnique(); + + b.ToTable("YtVideo"); + + b.HasData( + new + { + Id = 1, + Url = "https://www.youtube.com/embed/DtuqZ11RhIc" + }); + }); + + modelBuilder.Entity("devblog.Models.Comment", b => + { + b.HasOne("devblog.Models.Post", null) + .WithMany("Comments") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("devblog.Models.DownVote", b => + { + b.HasOne("devblog.Models.Post", null) + .WithMany("DownVotes") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("devblog.Models.Img", b => + { + b.HasOne("devblog.Models.Post", null) + .WithMany("Imgs") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("devblog.Models.UpVote", b => + { + b.HasOne("devblog.Models.Post", null) + .WithMany("UpVotes") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("devblog.Models.Post", b => + { + b.Navigation("Comments"); + + b.Navigation("DownVotes"); + + b.Navigation("Imgs"); + + b.Navigation("UpVotes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/devblog/devblog/Migrations/20231111193006_noticication table.cs b/devblog/devblog/Migrations/20231111193006_noticication table.cs new file mode 100644 index 00000000..9da29a39 --- /dev/null +++ b/devblog/devblog/Migrations/20231111193006_noticication table.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace devblog.Migrations +{ + /// + public partial class noticicationtable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Notification", + columns: table => new + { + PostId = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Seen = table.Column(type: "tinyint(1)", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Notification", x => x.PostId); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Notification"); + } + } +} diff --git a/devblog/devblog/Migrations/20231111193550_noticication table column.Designer.cs b/devblog/devblog/Migrations/20231111193550_noticication table column.Designer.cs new file mode 100644 index 00000000..faa31173 --- /dev/null +++ b/devblog/devblog/Migrations/20231111193550_noticication table column.Designer.cs @@ -0,0 +1,207 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using devblog.Data; + +#nullable disable + +namespace devblog.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20231111193550_noticication table column")] + partial class noticicationtablecolumn + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("devblog.Models.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Content") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.ToTable("Comment"); + }); + + modelBuilder.Entity("devblog.Models.DownVote", b => + { + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserName") + .HasColumnType("varchar(255)"); + + b.HasKey("PostId", "UserName"); + + b.ToTable("DownVote"); + }); + + modelBuilder.Entity("devblog.Models.Img", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("PostId") + .HasColumnType("int"); + + b.Property("Url") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.ToTable("Img"); + }); + + modelBuilder.Entity("devblog.Models.Notification", b => + { + b.Property("PostId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Seen") + .HasColumnType("tinyint(1)"); + + b.Property("Username") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("PostId"); + + b.ToTable("Notification"); + }); + + modelBuilder.Entity("devblog.Models.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Post"); + }); + + modelBuilder.Entity("devblog.Models.UpVote", b => + { + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserName") + .HasColumnType("varchar(255)"); + + b.HasKey("PostId", "UserName"); + + b.ToTable("UpVote"); + }); + + modelBuilder.Entity("devblog.Models.YtVideo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Url") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("Url") + .IsUnique(); + + b.ToTable("YtVideo"); + + b.HasData( + new + { + Id = 1, + Url = "https://www.youtube.com/embed/DtuqZ11RhIc" + }); + }); + + modelBuilder.Entity("devblog.Models.Comment", b => + { + b.HasOne("devblog.Models.Post", null) + .WithMany("Comments") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("devblog.Models.DownVote", b => + { + b.HasOne("devblog.Models.Post", null) + .WithMany("DownVotes") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("devblog.Models.Img", b => + { + b.HasOne("devblog.Models.Post", null) + .WithMany("Imgs") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("devblog.Models.UpVote", b => + { + b.HasOne("devblog.Models.Post", null) + .WithMany("UpVotes") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("devblog.Models.Post", b => + { + b.Navigation("Comments"); + + b.Navigation("DownVotes"); + + b.Navigation("Imgs"); + + b.Navigation("UpVotes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/devblog/devblog/Migrations/20231111193550_noticication table column.cs b/devblog/devblog/Migrations/20231111193550_noticication table column.cs new file mode 100644 index 00000000..ebdfe413 --- /dev/null +++ b/devblog/devblog/Migrations/20231111193550_noticication table column.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace devblog.Migrations +{ + /// + public partial class noticicationtablecolumn : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Username", + table: "Notification", + type: "longtext", + nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Username", + table: "Notification"); + } + } +} diff --git a/devblog/devblog/Migrations/20231111193658_add noticication column 'username' to appdbcontext.Designer.cs b/devblog/devblog/Migrations/20231111193658_add noticication column 'username' to appdbcontext.Designer.cs new file mode 100644 index 00000000..88a54303 --- /dev/null +++ b/devblog/devblog/Migrations/20231111193658_add noticication column 'username' to appdbcontext.Designer.cs @@ -0,0 +1,205 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using devblog.Data; + +#nullable disable + +namespace devblog.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20231111193658_add noticication column 'username' to appdbcontext")] + partial class addnoticicationcolumnusernametoappdbcontext + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("devblog.Models.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Content") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.ToTable("Comment"); + }); + + modelBuilder.Entity("devblog.Models.DownVote", b => + { + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserName") + .HasColumnType("varchar(255)"); + + b.HasKey("PostId", "UserName"); + + b.ToTable("DownVote"); + }); + + modelBuilder.Entity("devblog.Models.Img", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("PostId") + .HasColumnType("int"); + + b.Property("Url") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.ToTable("Img"); + }); + + modelBuilder.Entity("devblog.Models.Notification", b => + { + b.Property("PostId") + .HasColumnType("int"); + + b.Property("Username") + .HasColumnType("varchar(255)"); + + b.Property("Seen") + .HasColumnType("tinyint(1)"); + + b.HasKey("PostId", "Username"); + + b.ToTable("Notification"); + }); + + modelBuilder.Entity("devblog.Models.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Post"); + }); + + modelBuilder.Entity("devblog.Models.UpVote", b => + { + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserName") + .HasColumnType("varchar(255)"); + + b.HasKey("PostId", "UserName"); + + b.ToTable("UpVote"); + }); + + modelBuilder.Entity("devblog.Models.YtVideo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Url") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("Url") + .IsUnique(); + + b.ToTable("YtVideo"); + + b.HasData( + new + { + Id = 1, + Url = "https://www.youtube.com/embed/DtuqZ11RhIc" + }); + }); + + modelBuilder.Entity("devblog.Models.Comment", b => + { + b.HasOne("devblog.Models.Post", null) + .WithMany("Comments") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("devblog.Models.DownVote", b => + { + b.HasOne("devblog.Models.Post", null) + .WithMany("DownVotes") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("devblog.Models.Img", b => + { + b.HasOne("devblog.Models.Post", null) + .WithMany("Imgs") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("devblog.Models.UpVote", b => + { + b.HasOne("devblog.Models.Post", null) + .WithMany("UpVotes") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("devblog.Models.Post", b => + { + b.Navigation("Comments"); + + b.Navigation("DownVotes"); + + b.Navigation("Imgs"); + + b.Navigation("UpVotes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/devblog/devblog/Migrations/20231111193658_add noticication column 'username' to appdbcontext.cs b/devblog/devblog/Migrations/20231111193658_add noticication column 'username' to appdbcontext.cs new file mode 100644 index 00000000..0b7b8a04 --- /dev/null +++ b/devblog/devblog/Migrations/20231111193658_add noticication column 'username' to appdbcontext.cs @@ -0,0 +1,75 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace devblog.Migrations +{ + /// + public partial class addnoticicationcolumnusernametoappdbcontext : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropPrimaryKey( + name: "PK_Notification", + table: "Notification"); + + migrationBuilder.AlterColumn( + name: "Username", + table: "Notification", + type: "varchar(255)", + nullable: false, + oldClrType: typeof(string), + oldType: "longtext") + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "PostId", + table: "Notification", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .OldAnnotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AddPrimaryKey( + name: "PK_Notification", + table: "Notification", + columns: new[] { "PostId", "Username" }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropPrimaryKey( + name: "PK_Notification", + table: "Notification"); + + migrationBuilder.AlterColumn( + name: "Username", + table: "Notification", + type: "longtext", + nullable: false, + oldClrType: typeof(string), + oldType: "varchar(255)") + .Annotation("MySql:CharSet", "utf8mb4") + .OldAnnotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.AlterColumn( + name: "PostId", + table: "Notification", + type: "int", + nullable: false, + oldClrType: typeof(int), + oldType: "int") + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn); + + migrationBuilder.AddPrimaryKey( + name: "PK_Notification", + table: "Notification", + column: "PostId"); + } + } +} diff --git a/devblog/devblog/Migrations/20231111200125_change notification table casing.Designer.cs b/devblog/devblog/Migrations/20231111200125_change notification table casing.Designer.cs new file mode 100644 index 00000000..3e87f4cb --- /dev/null +++ b/devblog/devblog/Migrations/20231111200125_change notification table casing.Designer.cs @@ -0,0 +1,205 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using devblog.Data; + +#nullable disable + +namespace devblog.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20231111200125_change notification table casing")] + partial class changenotificationtablecasing + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("devblog.Models.Comment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Content") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.ToTable("Comment"); + }); + + modelBuilder.Entity("devblog.Models.DownVote", b => + { + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserName") + .HasColumnType("varchar(255)"); + + b.HasKey("PostId", "UserName"); + + b.ToTable("DownVote"); + }); + + modelBuilder.Entity("devblog.Models.Img", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("PostId") + .HasColumnType("int"); + + b.Property("Url") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("PostId"); + + b.ToTable("Img"); + }); + + modelBuilder.Entity("devblog.Models.Notification", b => + { + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserName") + .HasColumnType("varchar(255)"); + + b.Property("Seen") + .HasColumnType("tinyint(1)"); + + b.HasKey("PostId", "UserName"); + + b.ToTable("Notification"); + }); + + modelBuilder.Entity("devblog.Models.Post", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("Description") + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Post"); + }); + + modelBuilder.Entity("devblog.Models.UpVote", b => + { + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserName") + .HasColumnType("varchar(255)"); + + b.HasKey("PostId", "UserName"); + + b.ToTable("UpVote"); + }); + + modelBuilder.Entity("devblog.Models.YtVideo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Url") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("Url") + .IsUnique(); + + b.ToTable("YtVideo"); + + b.HasData( + new + { + Id = 1, + Url = "https://www.youtube.com/embed/DtuqZ11RhIc" + }); + }); + + modelBuilder.Entity("devblog.Models.Comment", b => + { + b.HasOne("devblog.Models.Post", null) + .WithMany("Comments") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("devblog.Models.DownVote", b => + { + b.HasOne("devblog.Models.Post", null) + .WithMany("DownVotes") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("devblog.Models.Img", b => + { + b.HasOne("devblog.Models.Post", null) + .WithMany("Imgs") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("devblog.Models.UpVote", b => + { + b.HasOne("devblog.Models.Post", null) + .WithMany("UpVotes") + .HasForeignKey("PostId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("devblog.Models.Post", b => + { + b.Navigation("Comments"); + + b.Navigation("DownVotes"); + + b.Navigation("Imgs"); + + b.Navigation("UpVotes"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/devblog/devblog/Migrations/20231111200125_change notification table casing.cs b/devblog/devblog/Migrations/20231111200125_change notification table casing.cs new file mode 100644 index 00000000..13a2578b --- /dev/null +++ b/devblog/devblog/Migrations/20231111200125_change notification table casing.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace devblog.Migrations +{ + /// + public partial class changenotificationtablecasing : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "Username", + table: "Notification", + newName: "UserName"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "UserName", + table: "Notification", + newName: "Username"); + } + } +} diff --git a/devblog/devblog/Migrations/AppDbContextModelSnapshot.cs b/devblog/devblog/Migrations/AppDbContextModelSnapshot.cs index b83793a4..acf35547 100644 --- a/devblog/devblog/Migrations/AppDbContextModelSnapshot.cs +++ b/devblog/devblog/Migrations/AppDbContextModelSnapshot.cs @@ -79,6 +79,22 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Img"); }); + modelBuilder.Entity("devblog.Models.Notification", b => + { + b.Property("PostId") + .HasColumnType("int"); + + b.Property("UserName") + .HasColumnType("varchar(255)"); + + b.Property("Seen") + .HasColumnType("tinyint(1)"); + + b.HasKey("PostId", "UserName"); + + b.ToTable("Notification"); + }); + modelBuilder.Entity("devblog.Models.Post", b => { b.Property("Id") diff --git a/devblog/devblog/Models/Notification.cs b/devblog/devblog/Models/Notification.cs new file mode 100644 index 00000000..da71f4b4 --- /dev/null +++ b/devblog/devblog/Models/Notification.cs @@ -0,0 +1,9 @@ +namespace devblog.Models +{ + public class Notification + { + public required string UserName { get; set; } + public int PostId { get; set; } + public bool Seen { get; set; } + } +} diff --git a/devblog/devblog/Program.cs b/devblog/devblog/Program.cs index 13c995fc..f565f957 100644 --- a/devblog/devblog/Program.cs +++ b/devblog/devblog/Program.cs @@ -35,6 +35,7 @@ builder.Services.AddSingleton(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/devblog/devblog/Services/NotificationService.cs b/devblog/devblog/Services/NotificationService.cs new file mode 100644 index 00000000..c77acbcb --- /dev/null +++ b/devblog/devblog/Services/NotificationService.cs @@ -0,0 +1,41 @@ +using devblog.Data; +using devblog.Interfaces; +using devblog.Models; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; + +namespace devblog.Services +{ + public class NotificationService : INotificationService + { + public UserManager _userMgr { get; } + private readonly AppDbContext _db; + + public NotificationService(AppDbContext db, UserManager usermgr) + { + _userMgr = usermgr; + _db = db; + } + + /// + /// Creates a noticication for a new post to every user + /// + public async Task Create(int PostId) + { + var allUsers = await _userMgr.Users.ToListAsync(); + + allUsers.ForEach(async user => + { + var notification = new Notification + { + UserName = user.UserName, + PostId = PostId, + Seen = false + }; + + await _db.Notification.AddAsync(notification); + await _db.SaveChangesAsync(); + }); + } + } +} diff --git a/devblog/devblog/Services/PostService.cs b/devblog/devblog/Services/PostService.cs index ee82ce9a..f6d84edb 100644 --- a/devblog/devblog/Services/PostService.cs +++ b/devblog/devblog/Services/PostService.cs @@ -7,21 +7,22 @@ using Mastonet; using System.Net; using devblog.Controllers; -using Microsoft.Extensions.Hosting; namespace devblog.Services { public class PostService : IPostService { private readonly AppDbContext _db; - private readonly IImgService _imgService; + private readonly IImgService _imgs; private readonly IConfiguration _config; private readonly DiscordSocketClient _discordClient; + private readonly INotificationService _notifications; - public PostService(AppDbContext context, IImgService imgService, DiscordSocketClient discordClient, IConfiguration config) + public PostService(AppDbContext context, IImgService imgService, DiscordSocketClient discordClient, IConfiguration config, INotificationService notificationService) { _db = context; - _imgService = imgService; + _imgs = imgService; + _notifications = notificationService; _config = config; // set up discord client @@ -59,7 +60,10 @@ public async Task Create(PostUpload post) { var res = _db.Post.Add(newPost).Entity; await _db.SaveChangesAsync(); - uploadStatus.DevBlogStatus = await _imgService.Create(post.files, res.Id); + uploadStatus.DevBlogStatus = await _imgs.Create(post.files, res.Id); + + // create notifications for new post + await _notifications.Create(res.Id); } return uploadStatus; @@ -205,7 +209,8 @@ private async Task PostToDiscord(string description, IFormF if (i == 1) { await channel.SendFilesAsync(attachments, part + descriptions[i - 1]); - } else + } + else { await channel.SendMessageAsync(part + descriptions[i - 1]); } @@ -256,7 +261,7 @@ private async Task PostToMastodon(string description, IForm { string part = $"(Part {i}/{descriptions.Count}) "; - if(i == 1) + if (i == 1) { foreach (var file in files) { @@ -265,7 +270,8 @@ private async Task PostToMastodon(string description, IForm attachments.Add(mediaId.Id); } await client.PublishStatus(part + descriptions[i - 1], mediaIds: attachments); - } else + } + else { await client.PublishStatus(part + descriptions[i - 1]); }