From 34d459cc586df83387a6a07e5f8a0b0b0d85d48b Mon Sep 17 00:00:00 2001 From: Carl Tibule Date: Sat, 4 Mar 2023 00:37:59 -0600 Subject: [PATCH] Fixed 403 Forbidden thrown when getting Website metadata - Add User-Agent to header to prevent 403 Forbidden when downloading webpage strings - Add Bookmark URL and User Id unique combo constraint - Add Tag Name and User Id unique combo constraint --- YABA.Data/Context/YABABaseContext.cs | 6 +- ...serIdComboConstraintToBookmark.Designer.cs | 214 ++++++++++++++++++ ...ueUrlAndUserIdComboConstraintToBookmark.cs | 43 ++++ .../YABABaseContextModelSnapshot.cs | 12 +- YABA.Service/BookmarkService.cs | 1 + 5 files changed, 271 insertions(+), 5 deletions(-) create mode 100644 YABA.Data/Migrations/20230304061552_AddUniqueNameAndUserIdComboConstraintToTagsTable_AddUniqueUrlAndUserIdComboConstraintToBookmark.Designer.cs create mode 100644 YABA.Data/Migrations/20230304061552_AddUniqueNameAndUserIdComboConstraintToTagsTable_AddUniqueUrlAndUserIdComboConstraintToBookmark.cs diff --git a/YABA.Data/Context/YABABaseContext.cs b/YABA.Data/Context/YABABaseContext.cs index 33237ca..13fcdb7 100644 --- a/YABA.Data/Context/YABABaseContext.cs +++ b/YABA.Data/Context/YABABaseContext.cs @@ -39,7 +39,11 @@ namespace YABA.Data.Context .IsUnique(); modelBuilder.Entity() - .HasIndex(x => x.Name) + .HasIndex(x => new { x.Name, x.UserId }) + .IsUnique(); + + modelBuilder.Entity() + .HasIndex(x => new { x.Url, x.UserId }) .IsUnique(); } diff --git a/YABA.Data/Migrations/20230304061552_AddUniqueNameAndUserIdComboConstraintToTagsTable_AddUniqueUrlAndUserIdComboConstraintToBookmark.Designer.cs b/YABA.Data/Migrations/20230304061552_AddUniqueNameAndUserIdComboConstraintToTagsTable_AddUniqueUrlAndUserIdComboConstraintToBookmark.Designer.cs new file mode 100644 index 0000000..a195395 --- /dev/null +++ b/YABA.Data/Migrations/20230304061552_AddUniqueNameAndUserIdComboConstraintToTagsTable_AddUniqueUrlAndUserIdComboConstraintToBookmark.Designer.cs @@ -0,0 +1,214 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using YABA.Data.Context; + +namespace YABA.Data.Migrations +{ + [DbContext(typeof(YABABaseContext))] + [Migration("20230304061552_AddUniqueNameAndUserIdComboConstraintToTagsTable_AddUniqueUrlAndUserIdComboConstraintToBookmark")] + partial class AddUniqueNameAndUserIdComboConstraintToTagsTable_AddUniqueUrlAndUserIdComboConstraintToBookmark + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Relational:MaxIdentifierLength", 63) + .HasAnnotation("ProductVersion", "5.0.17") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + modelBuilder.Entity("YABA.Models.Bookmark", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("IsHidden") + .HasColumnType("boolean") + .HasColumnName("is_hidden"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified"); + + b.Property("Note") + .HasColumnType("text") + .HasColumnName("note"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text") + .HasColumnName("title"); + + b.Property("Url") + .IsRequired() + .HasColumnType("text") + .HasColumnName("url"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.HasKey("Id") + .HasName("pk_bookmarks"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_bookmarks_user_id"); + + b.HasIndex("Url", "UserId") + .IsUnique() + .HasDatabaseName("ix_bookmarks_url_user_id"); + + b.ToTable("bookmarks"); + }); + + modelBuilder.Entity("YABA.Models.BookmarkTag", b => + { + b.Property("BookmarkId") + .HasColumnType("integer") + .HasColumnName("bookmark_id"); + + b.Property("TagId") + .HasColumnType("integer") + .HasColumnName("tag_id"); + + b.HasKey("BookmarkId", "TagId") + .HasName("pk_bookmark_tags"); + + b.HasIndex("TagId") + .HasDatabaseName("ix_bookmark_tags_tag_id"); + + b.ToTable("bookmark_tags"); + }); + + modelBuilder.Entity("YABA.Models.Tag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("IsHidden") + .HasColumnType("boolean") + .HasColumnName("is_hidden"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("user_id"); + + b.HasKey("Id") + .HasName("pk_tags"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_tags_user_id"); + + b.HasIndex("Name", "UserId") + .IsUnique() + .HasDatabaseName("ix_tags_name_user_id"); + + b.ToTable("tags"); + }); + + modelBuilder.Entity("YABA.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); + + b.Property("Auth0Id") + .IsRequired() + .HasColumnType("text") + .HasColumnName("auth0id"); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on"); + + b.Property("IsDeleted") + .HasColumnType("boolean") + .HasColumnName("is_deleted"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_modified"); + + b.HasKey("Id") + .HasName("pk_users"); + + b.HasIndex("Auth0Id") + .IsUnique() + .HasDatabaseName("ix_users_auth0id"); + + b.ToTable("users"); + }); + + modelBuilder.Entity("YABA.Models.Bookmark", b => + { + b.HasOne("YABA.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .HasConstraintName("fk_bookmarks_users_user_id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("YABA.Models.BookmarkTag", b => + { + b.HasOne("YABA.Models.Bookmark", "Bookmark") + .WithMany() + .HasForeignKey("BookmarkId") + .HasConstraintName("fk_bookmark_tags_bookmarks_bookmark_id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("YABA.Models.Tag", "Tag") + .WithMany() + .HasForeignKey("TagId") + .HasConstraintName("fk_bookmark_tags_tags_tag_id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Bookmark"); + + b.Navigation("Tag"); + }); + + modelBuilder.Entity("YABA.Models.Tag", b => + { + b.HasOne("YABA.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .HasConstraintName("fk_tags_users_user_id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/YABA.Data/Migrations/20230304061552_AddUniqueNameAndUserIdComboConstraintToTagsTable_AddUniqueUrlAndUserIdComboConstraintToBookmark.cs b/YABA.Data/Migrations/20230304061552_AddUniqueNameAndUserIdComboConstraintToTagsTable_AddUniqueUrlAndUserIdComboConstraintToBookmark.cs new file mode 100644 index 0000000..f712c27 --- /dev/null +++ b/YABA.Data/Migrations/20230304061552_AddUniqueNameAndUserIdComboConstraintToTagsTable_AddUniqueUrlAndUserIdComboConstraintToBookmark.cs @@ -0,0 +1,43 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace YABA.Data.Migrations +{ + public partial class AddUniqueNameAndUserIdComboConstraintToTagsTable_AddUniqueUrlAndUserIdComboConstraintToBookmark : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "ix_tags_name", + table: "tags"); + + migrationBuilder.CreateIndex( + name: "ix_tags_name_user_id", + table: "tags", + columns: new[] { "name", "user_id" }, + unique: true); + + migrationBuilder.CreateIndex( + name: "ix_bookmarks_url_user_id", + table: "bookmarks", + columns: new[] { "url", "user_id" }, + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "ix_tags_name_user_id", + table: "tags"); + + migrationBuilder.DropIndex( + name: "ix_bookmarks_url_user_id", + table: "bookmarks"); + + migrationBuilder.CreateIndex( + name: "ix_tags_name", + table: "tags", + column: "name", + unique: true); + } + } +} diff --git a/YABA.Data/Migrations/YABABaseContextModelSnapshot.cs b/YABA.Data/Migrations/YABABaseContextModelSnapshot.cs index 8de4ae5..dd6ba10 100644 --- a/YABA.Data/Migrations/YABABaseContextModelSnapshot.cs +++ b/YABA.Data/Migrations/YABABaseContextModelSnapshot.cs @@ -67,6 +67,10 @@ namespace YABA.Data.Migrations b.HasIndex("UserId") .HasDatabaseName("ix_bookmarks_user_id"); + b.HasIndex("Url", "UserId") + .IsUnique() + .HasDatabaseName("ix_bookmarks_url_user_id"); + b.ToTable("bookmarks"); }); @@ -113,13 +117,13 @@ namespace YABA.Data.Migrations b.HasKey("Id") .HasName("pk_tags"); - b.HasIndex("Name") - .IsUnique() - .HasDatabaseName("ix_tags_name"); - b.HasIndex("UserId") .HasDatabaseName("ix_tags_user_id"); + b.HasIndex("Name", "UserId") + .IsUnique() + .HasDatabaseName("ix_tags_name_user_id"); + b.ToTable("tags"); }); diff --git a/YABA.Service/BookmarkService.cs b/YABA.Service/BookmarkService.cs index 8fc333a..a4ec7af 100644 --- a/YABA.Service/BookmarkService.cs +++ b/YABA.Service/BookmarkService.cs @@ -253,6 +253,7 @@ namespace YABA.Service private void UpdateBookmarkWithMetaData(IBookmark bookmark) { var webClient = new WebClient(); + webClient.Headers.Add("User-Agent", "APIClient"); var sourceData = webClient.DownloadString(bookmark.Url); var title = Regex.Match(sourceData, @"\]*\>\s*(?[\s\S]*?)\</title\>", RegexOptions.IgnoreCase).Groups["Title"].Value; var description = string.Empty;