Added endpoint and functionality for getting, retrieving and deleting bookmarks, and for adding and removing tags for a bookmark

This commit is contained in:
Carl Tibule
2023-01-28 00:48:48 -06:00
parent 08823de474
commit b9cd6b3c6a
34 changed files with 1148 additions and 42 deletions

View File

@ -32,12 +32,15 @@ namespace YABA.Data.Context
});
modelBuilder.Entity<BookmarkTag>()
.HasIndex(x => new { x.BookmarkId, x.TagId })
.IsUnique();
.HasKey(x => new { x.BookmarkId, x.TagId });
modelBuilder.Entity<User>()
.HasIndex(x => x.Auth0Id)
.IsUnique();
modelBuilder.Entity<Tag>()
.HasIndex(x => x.Name)
.IsUnique();
}
public DbSet<Bookmark> Bookmarks { get; set; }

View File

@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YABA.Models;
namespace YABA.Data.Extensions
{
public static class UsersDbSetExtensions
{
public static async Task<bool> UserExistsAsync(this DbSet<User> userDbSet, int userId)
{
return await userDbSet.AnyAsync(x => x.Id == userId);
}
public static bool UserExists(this DbSet<User> userDbSet, int userId)
{
return userDbSet.Any(x => x.Id == userId);
}
}
}

View File

@ -0,0 +1,226 @@
// <auto-generated />
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("20230126050046_AddedUrlToBookmark")]
partial class AddedUrlToBookmark
{
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<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<DateTimeOffset>("CreatedOn")
.HasColumnType("timestamp with time zone")
.HasColumnName("created_on");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("text")
.HasColumnName("description");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean")
.HasColumnName("is_deleted");
b.Property<bool>("IsHidden")
.HasColumnType("boolean")
.HasColumnName("is_hidden");
b.Property<DateTimeOffset>("LastModified")
.HasColumnType("timestamp with time zone")
.HasColumnName("last_modified");
b.Property<string>("Note")
.IsRequired()
.HasColumnType("text")
.HasColumnName("note");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("text")
.HasColumnName("title");
b.Property<string>("Url")
.IsRequired()
.HasColumnType("text")
.HasColumnName("url");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.HasKey("Id")
.HasName("pk_bookmarks");
b.HasIndex("UserId")
.HasDatabaseName("ix_bookmarks_user_id");
b.ToTable("bookmarks");
});
modelBuilder.Entity("YABA.Models.BookmarkTag", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("BookmarkId")
.HasColumnType("integer")
.HasColumnName("bookmark_id");
b.Property<int>("TagId")
.HasColumnType("integer")
.HasColumnName("tag_id");
b.HasKey("Id")
.HasName("pk_bookmark_tags");
b.HasIndex("TagId")
.HasDatabaseName("ix_bookmark_tags_tag_id");
b.HasIndex("BookmarkId", "TagId")
.IsUnique()
.HasDatabaseName("ix_bookmark_tags_bookmark_id_tag_id");
b.ToTable("bookmark_tags");
});
modelBuilder.Entity("YABA.Models.Tag", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<bool>("IsDeleted")
.HasColumnType("boolean")
.HasColumnName("is_deleted");
b.Property<bool>("IsHidden")
.HasColumnType("boolean")
.HasColumnName("is_hidden");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text")
.HasColumnName("name");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.HasKey("Id")
.HasName("pk_tags");
b.HasIndex("UserId")
.HasDatabaseName("ix_tags_user_id");
b.ToTable("tags");
});
modelBuilder.Entity("YABA.Models.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Auth0Id")
.IsRequired()
.HasColumnType("text")
.HasColumnName("auth0id");
b.Property<DateTimeOffset>("CreatedOn")
.HasColumnType("timestamp with time zone")
.HasColumnName("created_on");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean")
.HasColumnName("is_deleted");
b.Property<DateTimeOffset>("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
}
}
}

View File

@ -0,0 +1,24 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace YABA.Data.Migrations
{
public partial class AddedUrlToBookmark : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "url",
table: "bookmarks",
type: "text",
nullable: false,
defaultValue: "");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "url",
table: "bookmarks");
}
}
}

View File

@ -0,0 +1,212 @@
// <auto-generated />
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("20230128064541_ModifiedBookmarkTagsPK_RemovedSoftDeleteFromTagsAndBookmarks")]
partial class ModifiedBookmarkTagsPK_RemovedSoftDeleteFromTagsAndBookmarks
{
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<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<DateTimeOffset>("CreatedOn")
.HasColumnType("timestamp with time zone")
.HasColumnName("created_on");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("text")
.HasColumnName("description");
b.Property<bool>("IsHidden")
.HasColumnType("boolean")
.HasColumnName("is_hidden");
b.Property<DateTimeOffset>("LastModified")
.HasColumnType("timestamp with time zone")
.HasColumnName("last_modified");
b.Property<string>("Note")
.IsRequired()
.HasColumnType("text")
.HasColumnName("note");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("text")
.HasColumnName("title");
b.Property<string>("Url")
.IsRequired()
.HasColumnType("text")
.HasColumnName("url");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.HasKey("Id")
.HasName("pk_bookmarks");
b.HasIndex("UserId")
.HasDatabaseName("ix_bookmarks_user_id");
b.ToTable("bookmarks");
});
modelBuilder.Entity("YABA.Models.BookmarkTag", b =>
{
b.Property<int>("BookmarkId")
.HasColumnType("integer")
.HasColumnName("bookmark_id");
b.Property<int>("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<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<bool>("IsHidden")
.HasColumnType("boolean")
.HasColumnName("is_hidden");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text")
.HasColumnName("name");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
b.HasKey("Id")
.HasName("pk_tags");
b.HasIndex("Name")
.IsUnique()
.HasDatabaseName("ix_tags_name");
b.HasIndex("UserId")
.HasDatabaseName("ix_tags_user_id");
b.ToTable("tags");
});
modelBuilder.Entity("YABA.Models.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Auth0Id")
.IsRequired()
.HasColumnType("text")
.HasColumnName("auth0id");
b.Property<DateTimeOffset>("CreatedOn")
.HasColumnType("timestamp with time zone")
.HasColumnName("created_on");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean")
.HasColumnName("is_deleted");
b.Property<DateTimeOffset>("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
}
}
}

View File

@ -0,0 +1,86 @@
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace YABA.Data.Migrations
{
public partial class ModifiedBookmarkTagsPK_RemovedSoftDeleteFromTagsAndBookmarks : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropPrimaryKey(
name: "pk_bookmark_tags",
table: "bookmark_tags");
migrationBuilder.DropIndex(
name: "ix_bookmark_tags_bookmark_id_tag_id",
table: "bookmark_tags");
migrationBuilder.DropColumn(
name: "is_deleted",
table: "tags");
migrationBuilder.DropColumn(
name: "is_deleted",
table: "bookmarks");
migrationBuilder.DropColumn(
name: "id",
table: "bookmark_tags");
migrationBuilder.AddPrimaryKey(
name: "pk_bookmark_tags",
table: "bookmark_tags",
columns: new[] { "bookmark_id", "tag_id" });
migrationBuilder.CreateIndex(
name: "ix_tags_name",
table: "tags",
column: "name",
unique: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "ix_tags_name",
table: "tags");
migrationBuilder.DropPrimaryKey(
name: "pk_bookmark_tags",
table: "bookmark_tags");
migrationBuilder.AddColumn<bool>(
name: "is_deleted",
table: "tags",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "is_deleted",
table: "bookmarks",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<int>(
name: "id",
table: "bookmark_tags",
type: "integer",
nullable: false,
defaultValue: 0)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
migrationBuilder.AddPrimaryKey(
name: "pk_bookmark_tags",
table: "bookmark_tags",
column: "id");
migrationBuilder.CreateIndex(
name: "ix_bookmark_tags_bookmark_id_tag_id",
table: "bookmark_tags",
columns: new[] { "bookmark_id", "tag_id" },
unique: true);
}
}
}

View File

@ -36,10 +36,6 @@ namespace YABA.Data.Migrations
.HasColumnType("text")
.HasColumnName("description");
b.Property<bool>("IsDeleted")
.HasColumnType("boolean")
.HasColumnName("is_deleted");
b.Property<bool>("IsHidden")
.HasColumnType("boolean")
.HasColumnName("is_hidden");
@ -58,6 +54,11 @@ namespace YABA.Data.Migrations
.HasColumnType("text")
.HasColumnName("title");
b.Property<string>("Url")
.IsRequired()
.HasColumnType("text")
.HasColumnName("url");
b.Property<int>("UserId")
.HasColumnType("integer")
.HasColumnName("user_id");
@ -73,12 +74,6 @@ namespace YABA.Data.Migrations
modelBuilder.Entity("YABA.Models.BookmarkTag", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("BookmarkId")
.HasColumnType("integer")
.HasColumnName("bookmark_id");
@ -87,16 +82,12 @@ namespace YABA.Data.Migrations
.HasColumnType("integer")
.HasColumnName("tag_id");
b.HasKey("Id")
b.HasKey("BookmarkId", "TagId")
.HasName("pk_bookmark_tags");
b.HasIndex("TagId")
.HasDatabaseName("ix_bookmark_tags_tag_id");
b.HasIndex("BookmarkId", "TagId")
.IsUnique()
.HasDatabaseName("ix_bookmark_tags_bookmark_id_tag_id");
b.ToTable("bookmark_tags");
});
@ -108,10 +99,6 @@ namespace YABA.Data.Migrations
.HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<bool>("IsDeleted")
.HasColumnType("boolean")
.HasColumnName("is_deleted");
b.Property<bool>("IsHidden")
.HasColumnType("boolean")
.HasColumnName("is_hidden");
@ -128,6 +115,10 @@ 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");

View File

@ -18,6 +18,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\YABA.Common\YABA.Common.csproj" />
<ProjectReference Include="..\YABA.Models\YABA.Models.csproj" />
</ItemGroup>