From dcb81315bf5fa1d6996e3a0a33d7269376b99153 Mon Sep 17 00:00:00 2001 From: James Tombleson Date: Sat, 29 Jul 2023 10:02:43 -0700 Subject: [PATCH] Adding the calls to track authors for metrics but also to attempt to find AI writers. --- .../Startup/DatabaseStartup.cs | 1 + Newsbot.Collector.Database/DatabaseContext.cs | 1 + ...0729170139_Adding Author Table.Designer.cs | 579 ++++++++++++++++++ .../20230729170139_Adding Author Table.cs | 66 ++ .../DatabaseContextModelSnapshot.cs | 36 ++ .../Repositories/AuthorsTable.cs | 47 ++ .../Interfaces/IAuthorTable.cs | 11 + 7 files changed, 741 insertions(+) create mode 100644 Newsbot.Collector.Database/Migrations/20230729170139_Adding Author Table.Designer.cs create mode 100644 Newsbot.Collector.Database/Migrations/20230729170139_Adding Author Table.cs create mode 100644 Newsbot.Collector.Database/Repositories/AuthorsTable.cs create mode 100644 Newsbot.Collector.Domain/Interfaces/IAuthorTable.cs diff --git a/Newsbot.Collector.Api/Startup/DatabaseStartup.cs b/Newsbot.Collector.Api/Startup/DatabaseStartup.cs index f5f60c3..1c2ca1b 100644 --- a/Newsbot.Collector.Api/Startup/DatabaseStartup.cs +++ b/Newsbot.Collector.Api/Startup/DatabaseStartup.cs @@ -31,6 +31,7 @@ public class DatabaseStartup services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); } public static void InjectIdentityService(IServiceCollection services) diff --git a/Newsbot.Collector.Database/DatabaseContext.cs b/Newsbot.Collector.Database/DatabaseContext.cs index 338da9c..fa4cb77 100644 --- a/Newsbot.Collector.Database/DatabaseContext.cs +++ b/Newsbot.Collector.Database/DatabaseContext.cs @@ -15,6 +15,7 @@ public class DatabaseContext : IdentityDbContext public DbSet DiscordWebhooks { get; set; } = null!; public DbSet Icons { get; set; } = null!; public DbSet Sources { get; set; } = null!; + public DbSet Authors { get; set; } = null!; public DbSet UserSourceSubscription { get; set; } = null!; diff --git a/Newsbot.Collector.Database/Migrations/20230729170139_Adding Author Table.Designer.cs b/Newsbot.Collector.Database/Migrations/20230729170139_Adding Author Table.Designer.cs new file mode 100644 index 0000000..fd07e06 --- /dev/null +++ b/Newsbot.Collector.Database/Migrations/20230729170139_Adding Author Table.Designer.cs @@ -0,0 +1,579 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Newsbot.Collector.Database; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Newsbot.Collector.Database.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20230729170139_Adding Author Table")] + partial class AddingAuthorTable + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Newsbot.Collector.Domain.Entities.ArticlesEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AuthorImage") + .HasColumnType("text"); + + b.Property("AuthorName") + .IsRequired() + .HasColumnType("text"); + + b.Property("CodeIsCommit") + .HasColumnType("boolean"); + + b.Property("CodeIsRelease") + .HasColumnType("boolean"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("PubDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SourceId") + .HasColumnType("uuid"); + + b.Property("Tags") + .IsRequired() + .HasColumnType("text"); + + b.Property("Thumbnail") + .IsRequired() + .HasColumnType("text"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.Property("Url") + .HasColumnType("text"); + + b.Property("Video") + .IsRequired() + .HasColumnType("text"); + + b.Property("VideoHeight") + .HasColumnType("integer"); + + b.Property("VideoWidth") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("Articles"); + }); + + modelBuilder.Entity("Newsbot.Collector.Domain.Entities.AuthorEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SourceId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Authors"); + }); + + modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordNotificationEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CodeAllowCommits") + .HasColumnType("boolean"); + + b.Property("CodeAllowReleases") + .HasColumnType("boolean"); + + b.Property("DiscordWebHookId") + .HasColumnType("uuid"); + + b.Property("SourceId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("DiscordNotification"); + }); + + modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordQueueEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("ArticleId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("DiscordQueue"); + }); + + modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordWebhookEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Channel") + .IsRequired() + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Server") + .IsRequired() + .HasColumnType("text"); + + b.Property("Url") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("DiscordWebhooks"); + }); + + modelBuilder.Entity("Newsbot.Collector.Domain.Entities.IconEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Site") + .IsRequired() + .HasColumnType("text"); + + b.Property("SourceId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Icons"); + }); + + modelBuilder.Entity("Newsbot.Collector.Domain.Entities.RefreshTokenEntity", b => + { + b.Property("Token") + .HasColumnType("text"); + + b.Property("CreatedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiryDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Invalidated") + .HasColumnType("boolean"); + + b.Property("JwtId") + .HasColumnType("text"); + + b.Property("Used") + .HasColumnType("boolean"); + + b.Property("UserId") + .HasColumnType("text"); + + b.HasKey("Token"); + + b.HasIndex("UserId"); + + b.ToTable("RefreshTokens"); + }); + + modelBuilder.Entity("Newsbot.Collector.Domain.Entities.SourceEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Deleted") + .HasColumnType("boolean"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Site") + .IsRequired() + .HasColumnType("text"); + + b.Property("Source") + .IsRequired() + .HasColumnType("text"); + + b.Property("Tags") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.Property("Url") + .IsRequired() + .HasColumnType("text"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.Property("YoutubeId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Sources"); + }); + + modelBuilder.Entity("Newsbot.Collector.Domain.Entities.UserSourceSubscriptionEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateAdded") + .HasColumnType("timestamp with time zone"); + + b.Property("SourceId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserSourceSubscription"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordWebhookEntity", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Newsbot.Collector.Domain.Entities.RefreshTokenEntity", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Newsbot.Collector.Domain.Entities.UserSourceSubscriptionEntity", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("User"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Newsbot.Collector.Database/Migrations/20230729170139_Adding Author Table.cs b/Newsbot.Collector.Database/Migrations/20230729170139_Adding Author Table.cs new file mode 100644 index 0000000..e4c0e31 --- /dev/null +++ b/Newsbot.Collector.Database/Migrations/20230729170139_Adding Author Table.cs @@ -0,0 +1,66 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Newsbot.Collector.Database.Migrations +{ + /// + public partial class AddingAuthorTable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "UserId", + table: "DiscordWebhooks", + type: "text", + nullable: true); + + migrationBuilder.CreateTable( + name: "Authors", + columns: table => new + { + Id = table.Column(type: "uuid", nullable: false), + SourceId = table.Column(type: "uuid", nullable: false), + Name = table.Column(type: "text", nullable: false), + Image = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Authors", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_DiscordWebhooks_UserId", + table: "DiscordWebhooks", + column: "UserId"); + + migrationBuilder.AddForeignKey( + name: "FK_DiscordWebhooks_AspNetUsers_UserId", + table: "DiscordWebhooks", + column: "UserId", + principalTable: "AspNetUsers", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_DiscordWebhooks_AspNetUsers_UserId", + table: "DiscordWebhooks"); + + migrationBuilder.DropTable( + name: "Authors"); + + migrationBuilder.DropIndex( + name: "IX_DiscordWebhooks_UserId", + table: "DiscordWebhooks"); + + migrationBuilder.DropColumn( + name: "UserId", + table: "DiscordWebhooks"); + } + } +} diff --git a/Newsbot.Collector.Database/Migrations/DatabaseContextModelSnapshot.cs b/Newsbot.Collector.Database/Migrations/DatabaseContextModelSnapshot.cs index 4462cdc..8677532 100644 --- a/Newsbot.Collector.Database/Migrations/DatabaseContextModelSnapshot.cs +++ b/Newsbot.Collector.Database/Migrations/DatabaseContextModelSnapshot.cs @@ -277,6 +277,28 @@ namespace Newsbot.Collector.Database.Migrations b.ToTable("Articles"); }); + modelBuilder.Entity("Newsbot.Collector.Domain.Entities.AuthorEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Image") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SourceId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Authors"); + }); + modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordNotificationEntity", b => { b.Property("Id") @@ -338,8 +360,13 @@ namespace Newsbot.Collector.Database.Migrations .IsRequired() .HasColumnType("text"); + b.Property("UserId") + .HasColumnType("text"); + b.HasKey("Id"); + b.HasIndex("UserId"); + b.ToTable("DiscordWebhooks"); }); @@ -517,6 +544,15 @@ namespace Newsbot.Collector.Database.Migrations .IsRequired(); }); + modelBuilder.Entity("Newsbot.Collector.Domain.Entities.DiscordWebhookEntity", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("User"); + }); + modelBuilder.Entity("Newsbot.Collector.Domain.Entities.RefreshTokenEntity", b => { b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "User") diff --git a/Newsbot.Collector.Database/Repositories/AuthorsTable.cs b/Newsbot.Collector.Database/Repositories/AuthorsTable.cs new file mode 100644 index 0000000..0d24a3a --- /dev/null +++ b/Newsbot.Collector.Database/Repositories/AuthorsTable.cs @@ -0,0 +1,47 @@ +using Newsbot.Collector.Domain.Entities; +using Newsbot.Collector.Domain.Interfaces; + +namespace Newsbot.Collector.Database.Repositories; + +public class AuthorsTable : IAuthorTable +{ + private readonly DatabaseContext _context; + + public AuthorsTable(string connectionString) + { + //_connectionString = connectionString; + _context = new DatabaseContext(connectionString); + } + + public AuthorsTable(DatabaseContext context) + { + _context = context; + } + + public AuthorEntity New(AuthorEntity entity) + { + entity.Id = Guid.NewGuid(); + _context.Authors.Add(entity); + _context.SaveChanges(); + return entity; + } + + public List ListBySourceId(Guid sourceId) + { + return _context.Authors + .Where(s => s.SourceId.Equals(sourceId)).ToList(); + } + + public int TotalPosts(Guid id) + { + return _context.Authors.Count(x => x.Id.Equals(id)); + } + + public AuthorEntity? GetBySourceIdAndName(Guid sourceId, string name) + { + return _context.Authors + .Where(s => s.SourceId.Equals(sourceId)) + .FirstOrDefault(n => n.Name.Equals(name)); + + } +} \ No newline at end of file diff --git a/Newsbot.Collector.Domain/Interfaces/IAuthorTable.cs b/Newsbot.Collector.Domain/Interfaces/IAuthorTable.cs new file mode 100644 index 0000000..6c777a2 --- /dev/null +++ b/Newsbot.Collector.Domain/Interfaces/IAuthorTable.cs @@ -0,0 +1,11 @@ +using Newsbot.Collector.Domain.Entities; + +namespace Newsbot.Collector.Domain.Interfaces; + +public interface IAuthorTable +{ + AuthorEntity New(AuthorEntity entity); + List ListBySourceId(Guid sourceId); + int TotalPosts(Guid id); + AuthorEntity? GetBySourceIdAndName(Guid sourceId, string name); +} \ No newline at end of file