Compare commits

...

7 Commits

@ -179,11 +179,17 @@ defmodule DecentralisedBookIndex.Metadata.Book do
prepare fn query, context -> prepare fn query, context ->
author = query.arguments.author author = query.arguments.author
{:ok, author_ids} = Metadata.get_author_ids(author) author_ids =
case Metadata.get_author_ids(author) do
{:ok, ids} -> ids
{:error, _error} -> []
end
Metadata.Book query
|> Ash.Query.filter(expr(exists(author_roles, author_id in ^author_ids))) |> Ash.Query.filter(expr(exists(author_roles, author_id in ^author_ids)))
end end
pagination offset?: true, default_limit: 10
end end
read :search do read :search do
@ -373,7 +379,6 @@ defmodule DecentralisedBookIndex.Metadata.Book do
end end
belongs_to :publisher, Metadata.Publisher do belongs_to :publisher, Metadata.Publisher do
allow_nil? false
public? true public? true
end end

@ -10,7 +10,7 @@ defmodule DecentralisedBookIndexWeb.Components.MyComponents.AuthorCard do
def author_card(assigns) do def author_card(assigns) do
~H""" ~H"""
<div class="w-full max-w-sm bg-slate-100 border border-gray-200 rounded-lg shadow-sm dark:bg-gray-800 dark:border-gray-700 mx-auto my-3"> <div class="w-full max-w-sm bg-slate-100 border border-gray-200 rounded-lg shadow-sm dark:bg-gray-800 dark:border-gray-700 mx-auto my-3">
<%= if @current_user != nil and Role.can_moderate?(@current_user.role) and is_nil(@author.dbi_server) do %> <%= if @current_user != nil and Role.can_moderate?(@current_user.role) and is_nil(@author.dbi_server_id) do %>
<div class="flex justify-end px-4 pt-4"> <div class="flex justify-end px-4 pt-4">
<button <button
id={"dropdownButton#{@author.id}"} id={"dropdownButton#{@author.id}"}

@ -10,7 +10,7 @@ defmodule DecentralisedBookIndexWeb.Components.MyComponents.BookCard do
def book_card(assigns) do def book_card(assigns) do
~H""" ~H"""
<div class="w-full max-w-sm bg-slate-100 border border-gray-200 rounded-lg shadow-sm dark:bg-gray-800 dark:border-gray-700 mx-auto my-3"> <div class="w-full max-w-sm bg-slate-100 border border-gray-200 rounded-lg shadow-sm dark:bg-gray-800 dark:border-gray-700 mx-auto my-3">
<%= if @current_user != nil and Role.can_moderate?(@current_user.role) and is_nil(@book.dbi_server) do %> <%= if @current_user != nil and Role.can_moderate?(@current_user.role) and is_nil(@book.dbi_server_id) do %>
<div class="flex justify-end px-4 pt-4"> <div class="flex justify-end px-4 pt-4">
<button <button
id={"dropdownButton#{@book.id}"} id={"dropdownButton#{@book.id}"}

@ -2,6 +2,7 @@ defmodule DecentralisedBookIndexWeb.AuthorLive.Show do
use DecentralisedBookIndexWeb, :live_view use DecentralisedBookIndexWeb, :live_view
alias DecentralisedBookIndex.Accounts.Role alias DecentralisedBookIndex.Accounts.Role
alias DecentralisedBookIndex.Metadata
@impl true @impl true
def render(assigns) do def render(assigns) do
@ -96,6 +97,19 @@ defmodule DecentralisedBookIndexWeb.AuthorLive.Show do
</ul> </ul>
<% end %> <% end %>
<%= if not Enum.empty?(@page.results) do %>
<h2 class="mb-2 text-lg font-semibold text-gray-900 dark:text-white mt-10">
Books
</h2>
<div class="flex flex-wrap flex-[3_1_auto]">
<%= for book <- @page.results do %>
<.book_card book={book} current_user={@current_user} />
<% end %>
</div>
<.pagination endpoint={~p"/authors/#{@author}"} page={@page} page_params={@page_params} params={@params} />
<% end %>
<.back navigate={~p"/authors"}>Back to authors</.back> <.back navigate={~p"/authors"}>Back to authors</.back>
""" """
end end
@ -106,19 +120,30 @@ defmodule DecentralisedBookIndexWeb.AuthorLive.Show do
end end
@impl true @impl true
def handle_params(%{"id" => id}, _, socket) do def handle_params(%{"id" => id} = params, _, socket) do
author = author =
Ash.get!(DecentralisedBookIndex.Metadata.Author, id, Ash.get!(Metadata.Author, id,
load: [:dbi_server], load: [:dbi_server],
actor: socket.assigns.current_user actor: socket.assigns.current_user
) )
alternative_names = DecentralisedBookIndex.Metadata.get_author_alternative_names!(author) alternative_names = Metadata.get_author_alternative_names!(author)
page_params = AshPhoenix.LiveView.page_from_params(params, 10)
page =
Metadata.get_author_books!(author,
load: [:brief_description],
page: page_params ++ [count: true],
actor: socket.assigns.current_user
)
{:noreply, {:noreply,
socket socket
|> assign(:page_title, page_title(socket.assigns.live_action)) |> assign(:page_title, page_title(socket.assigns.live_action))
|> assign(:author, author) |> assign(:author, author)
|> assign(:page_params, page_params)
|> assign(:page, page)
|> assign(:params, params)
|> assign(:alternative_names, alternative_names)} |> assign(:alternative_names, alternative_names)}
end end

@ -64,12 +64,14 @@ defmodule DecentralisedBookIndexWeb.BookLive.Show do
<dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">Description</dt> <dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">Description</dt>
<dd class="mb-4 font-light text-gray-500 sm:mb-5 dark:text-gray-400">{@book.description}</dd> <dd class="mb-4 font-light text-gray-500 sm:mb-5 dark:text-gray-400">{@book.description}</dd>
</dl> </dl>
<dl> <%= if not is_nil(@book.publisher) do %>
<dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">Publisher</dt> <dl>
<dd class="mb-4 font-light text-gray-500 sm:mb-5 dark:text-gray-400"> <dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">Publisher</dt>
{@book.publisher.name} <dd class="mb-4 font-light text-gray-500 sm:mb-5 dark:text-gray-400">
</dd> {@book.publisher.name}
</dl> </dd>
</dl>
<% end %>
<dl> <dl>
<dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">Published</dt> <dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">Published</dt>
<dd class="mb-4 font-light text-gray-500 sm:mb-5 dark:text-gray-400">{@book.published}</dd> <dd class="mb-4 font-light text-gray-500 sm:mb-5 dark:text-gray-400">{@book.published}</dd>
@ -86,14 +88,16 @@ defmodule DecentralisedBookIndexWeb.BookLive.Show do
<dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">Language</dt> <dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">Language</dt>
<dd class="mb-4 font-light text-gray-500 sm:mb-5 dark:text-gray-400">{@book.language}</dd> <dd class="mb-4 font-light text-gray-500 sm:mb-5 dark:text-gray-400">{@book.language}</dd>
</dl> </dl>
<dl> <%= if not Enum.empty?(@book.bids) do %>
<dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">Identifiers</dt> <dl>
<%= for bid <- @book.bids do %> <dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">Identifiers</dt>
<dd class="mb-4 font-light text-gray-500 sm:mb-5 dark:text-gray-400"> <%= for bid <- @book.bids do %>
{bid.type}: {bid.bid} <dd class="mb-4 font-light text-gray-500 sm:mb-5 dark:text-gray-400">
</dd> {bid.type}: {bid.bid}
<% end %> </dd>
</dl> <% end %>
</dl>
<% end %>
<%= if not is_nil(@book.dbi_server) do %> <%= if not is_nil(@book.dbi_server) do %>
<dl> <dl>
<dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">From Server</dt> <dt class="mb-2 font-semibold leading-none text-gray-900 dark:text-white">From Server</dt>

@ -10,7 +10,7 @@ defmodule DecentralisedBookIndexWeb.DbiServerLive.Show do
{@dbi_server.name} {@dbi_server.name}
<:actions> <:actions>
<%= if is_nil(@dbi_server.dbi_server) and @current_user != nil and Role.can_administrate?(@current_user.role) do %> <%= if @current_user != nil and Role.can_administrate?(@current_user.role) do %>
<.link patch={~p"/servers/#{@dbi_server}/edit"} phx-click={JS.push_focus()}> <.link patch={~p"/servers/#{@dbi_server}/edit"} phx-click={JS.push_focus()}>
<.edit_button> <.edit_button>
Edit Edit

@ -0,0 +1,21 @@
defmodule DecentralisedBookIndex.Repo.Migrations.UpdateToAllowABookToHaveNoPublisher do
@moduledoc """
Updates resources based on their most recent snapshots.
This file was autogenerated with `mix ash_postgres.generate_migrations`
"""
use Ecto.Migration
def up do
alter table(:books) do
modify :publisher_id, :uuid, null: true
end
end
def down do
alter table(:books) do
modify :publisher_id, :uuid, null: false
end
end
end

@ -0,0 +1,227 @@
{
"attributes": [
{
"allow_nil?": false,
"default": "fragment(\"gen_random_uuid()\")",
"generated?": false,
"primary_key?": true,
"references": null,
"size": null,
"source": "id",
"type": "uuid"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "title",
"type": "text"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "description",
"type": "text"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "published",
"type": "date"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "language",
"type": "text"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "format",
"type": "text"
},
{
"allow_nil?": false,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "page_count",
"type": "bigint"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "cover_image_url",
"type": "text"
},
{
"allow_nil?": false,
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "inserted_at",
"type": "utc_datetime_usec"
},
{
"allow_nil?": false,
"default": "fragment(\"(now() AT TIME ZONE 'utc')\")",
"generated?": false,
"primary_key?": false,
"references": null,
"size": null,
"source": "updated_at",
"type": "utc_datetime_usec"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": {
"deferrable": false,
"destination_attribute": "id",
"destination_attribute_default": null,
"destination_attribute_generated": null,
"index?": false,
"match_type": null,
"match_with": null,
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"name": "books_dbi_server_id_fkey",
"on_delete": null,
"on_update": null,
"primary_key?": true,
"schema": "public",
"table": "dbi_servers"
},
"size": null,
"source": "dbi_server_id",
"type": "uuid"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": {
"deferrable": false,
"destination_attribute": "id",
"destination_attribute_default": null,
"destination_attribute_generated": null,
"index?": false,
"match_type": null,
"match_with": null,
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"name": "books_book_editions_registry_id_fkey",
"on_delete": null,
"on_update": null,
"primary_key?": true,
"schema": "public",
"table": "book_editions_registries"
},
"size": null,
"source": "book_editions_registry_id",
"type": "uuid"
},
{
"allow_nil?": true,
"default": "nil",
"generated?": false,
"primary_key?": false,
"references": {
"deferrable": false,
"destination_attribute": "id",
"destination_attribute_default": null,
"destination_attribute_generated": null,
"index?": false,
"match_type": null,
"match_with": null,
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"name": "books_publisher_id_fkey",
"on_delete": null,
"on_update": null,
"primary_key?": true,
"schema": "public",
"table": "publishers"
},
"size": null,
"source": "publisher_id",
"type": "uuid"
}
],
"base_filter": null,
"check_constraints": [],
"custom_indexes": [
{
"all_tenants?": false,
"concurrently": false,
"error_fields": [],
"fields": [
{
"type": "string",
"value": "title gin_trgm_ops"
}
],
"include": null,
"message": null,
"name": "book_title_gin_index",
"nulls_distinct": true,
"prefix": null,
"table": null,
"unique": false,
"using": "GIN",
"where": null
}
],
"custom_statements": [],
"has_create_action": true,
"hash": "AA67DC03E5D78606517F268BD28B58521F2000DE3BA531FA48363CCD08CE4475",
"identities": [],
"multitenancy": {
"attribute": null,
"global": null,
"strategy": null
},
"repo": "Elixir.DecentralisedBookIndex.Repo",
"schema": null,
"table": "books"
}

@ -202,7 +202,7 @@ defmodule DecentralisedBookIndex.Metadata.BookTest do
%{order: 1, author_id: author.id, role: ""} %{order: 1, author_id: author.id, role: ""}
] ]
{:ok, _book} = {:ok, book} =
Metadata.create_book( Metadata.create_book(
"Book", "Book",
"An description", "An description",
@ -218,7 +218,10 @@ defmodule DecentralisedBookIndex.Metadata.BookTest do
actor: user actor: user
) )
assert {:ok, _books} = Metadata.get_author_books(author) assert {:ok, books} = Metadata.get_author_books(author)
book_ids = Enum.map(books.results, & &1.id)
assert book.id in book_ids
end end
test "get the list contains aliases' books", %{user: user} do test "get the list contains aliases' books", %{user: user} do
@ -248,7 +251,7 @@ defmodule DecentralisedBookIndex.Metadata.BookTest do
assert {:ok, books} = Metadata.get_author_books(author) assert {:ok, books} = Metadata.get_author_books(author)
book_ids = Enum.map(books, & &1.id) book_ids = Enum.map(books.results, & &1.id)
assert book.id in book_ids assert book.id in book_ids
assert book2.id in book_ids assert book2.id in book_ids

@ -119,7 +119,7 @@ defmodule DecentralisedBookIndex.Generators do
count = count =
opts[:count] || 2 opts[:count] || 2
types = ["isbn10", "isbn13", "asin"] types = ["isbn", "isbn13", "asin"]
if count > length(types), do: count = length(types) if count > length(types), do: count = length(types)

Loading…
Cancel
Save