Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add boundary and various other fixes #838

Merged
merged 13 commits into from
Apr 24, 2024
2 changes: 1 addition & 1 deletion .formatter.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[
import_deps: [:absinthe, :ecto, :ecto_sql, :phoenix],
import_deps: [:absinthe, :ecto, :ecto_sql, :phoenix, :mneme],
subdirectories: ["priv/*/migrations"],
plugins: [
Styler,
Expand Down
2 changes: 2 additions & 0 deletions assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { InfiniteScrollHook } from "./hooks/infinite-scroll"
import { DispatchValueChangeHook } from "./hooks/dispatch-value-change"
import { ImageSizeHook } from "./hooks/image-size"
import { ScrollMatchHook } from "./hooks/scroll-match"
import { PatchHackHook } from "./hooks/patch-hack"

const playerId = Math.random().toString(36).substring(2)

Expand All @@ -51,6 +52,7 @@ let liveSocket = new LiveSocket("/live", Socket, {
"dispatch-value-change": DispatchValueChangeHook,
"image-size": ImageSizeHook,
"scroll-match": ScrollMatchHook,
"patch-hack": PatchHackHook,
},
})

Expand Down
5 changes: 5 additions & 0 deletions assets/js/hooks/patch-hack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const PatchHackHook = {
mounted() {
history.replaceState({ id: this.liveSocket.main.id, type: "patch" }, "")
},
}
4 changes: 2 additions & 2 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ config :ambry, Ambry.Mailer, adapter: Swoosh.Adapters.Local

# Configure esbuild (the version is required)
config :esbuild,
version: "0.18.6",
version: "0.20.2",
default: [
args:
~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*),
Expand All @@ -43,7 +43,7 @@ config :esbuild,

# Configure tailwind (the version is required)
config :tailwind,
version: "3.3.2",
version: "3.4.3",
default: [
args: ~w(
--config=tailwind.config.js
Expand Down
15 changes: 12 additions & 3 deletions coveralls.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
{
"coverage_options": {
"treat_no_relevant_lines_as_covered": true,
"minimum_coverage": 30,
"html_filter_full_covered": true
}
"minimum_coverage": 30
},
"skip_files": [
"ambry_app/application.ex",
"ambry_scraping/audible/browser.ex",
"ambry_scraping/audible/client.ex",
"ambry_scraping/audnexus/client.ex",
"ambry_scraping/goodreads/browser.ex",
"ambry_scraping/marionette.ex",
"ambry_scraping/marionette",
"ambry/search/index_manager.ex"
]
}
16 changes: 16 additions & 0 deletions lib/ambry.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,20 @@ defmodule Ambry do
Contexts are also responsible for managing your data, regardless
if it comes from the database, an external API or others.
"""
use Boundary,
deps: [AmbryScraping],
exports: [
{Accounts, []},
{Books, []},
{FileBrowser, []},
{Hashids, []},
{Media, []},
{Metadata, []},
{Paths, []},
{People, []},
{PubSub, []},
{Repo, []},
{Search, []},
{Utils, []}
]
end
8 changes: 8 additions & 0 deletions lib/ambry/accounts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ defmodule Ambry.Accounts do
The Accounts context.
"""

use Boundary,
deps: [
Ambry.Mailer,
Ambry.Media,
Ambry.Repo
],
exports: [User]

import Ecto.Query, warn: false

alias Ambry.Accounts.User
Expand Down
2 changes: 1 addition & 1 deletion lib/ambry/accounts/user_flat.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Ambry.Accounts.UserFlat do
A flattened view of users.
"""

use Ambry.FlatSchema
use Ambry.Repo.FlatSchema

schema "users_flat" do
field :email, :string
Expand Down
26 changes: 0 additions & 26 deletions lib/ambry/authors.ex

This file was deleted.

183 changes: 180 additions & 3 deletions lib/ambry/books.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,34 @@ defmodule Ambry.Books do
Functions for dealing with Books.
"""

import Ambry.FileUtils
use Boundary,
deps: [Ambry],
exports: [
Book,
Series,
SeriesBook,
SeriesFlat,
SeriesBookType,
SeriesBookType.Type
]

import Ambry.Utils
import Ecto.Query

alias Ambry.Books.Book
alias Ambry.Books.BookFlat
alias Ambry.Books.Series
alias Ambry.Books.SeriesFlat
alias Ambry.Media.Media
alias Ambry.Paths
alias Ambry.PubSub
alias Ambry.Repo

require Logger

@book_direct_assoc_preloads [:authors, book_authors: [:author], series_books: [:series]]

def standard_preloads, do: @book_direct_assoc_preloads
def book_standard_preloads, do: @book_direct_assoc_preloads

@doc """
Returns a limited list of books and whether or not there are more.
Expand Down Expand Up @@ -148,6 +163,21 @@ defmodule Ambry.Books do
end
end

defp maybe_delete_image(nil), do: :noop

defp maybe_delete_image(web_path) do
book_count = Repo.aggregate(from(b in Book, where: b.image_path == ^web_path), :count)

if book_count == 0 do
disk_path = Paths.web_to_disk(web_path)

try_delete_file(disk_path)
else
Logger.warning(fn -> "Not deleting file because it's still in use: #{web_path}" end)
{:error, :still_in_use}
end
end

@doc """
Returns an `%Ecto.Changeset{}` for tracking book changes.

Expand Down Expand Up @@ -193,7 +223,7 @@ defmodule Ambry.Books do
@doc """
Returns all books for use in `Select` components.
"""
def for_select do
def books_for_select do
query = from b in Book, select: {b.title, b.id}, order_by: b.title

Repo.all(query)
Expand Down Expand Up @@ -229,4 +259,151 @@ defmodule Ambry.Books do

{books_to_return, books != books_to_return}
end

@series_direct_assoc_preloads [series_books: [book: [:authors]]]

def series_standard_preloads, do: @series_direct_assoc_preloads

@doc """
Returns a limited list of series and whether or not there are more.

By default, it will limit to the first 10 results. Supply `offset` and `limit`
to change this. Also can optionally filter by the given `filter` string.

## Examples

iex> list_series()
{[%SeriesFlat{}, ...], true}
"""
def list_series(offset \\ 0, limit \\ 10, filters \\ %{}, order \\ [asc: :name]) do
over_limit = limit + 1

series =
offset
|> SeriesFlat.paginate(over_limit)
|> SeriesFlat.filter(filters)
|> SeriesFlat.order(order)
|> Repo.all()

series_to_return = Enum.slice(series, 0, limit)

{series_to_return, series != series_to_return}
end

@doc """
Returns the number of series.

## Examples

iex> count_series()
1
"""
@spec count_series :: integer()
def count_series do
Repo.aggregate(Series, :count)
end

@doc """
Gets a single series.

Raises `Ecto.NoResultsError` if the Series does not exist.

## Examples

iex> get_series!(123)
%Series{}

iex> get_series!(456)
** (Ecto.NoResultsError)
"""
def get_series!(id) do
Series
|> preload(^@series_direct_assoc_preloads)
|> Repo.get!(id)
end

@doc """
Creates a series.

## Examples

iex> create_series(%{field: value})
{:ok, %Series{}}

iex> create_series(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_series(attrs) do
%Series{}
|> Series.changeset(attrs)
|> Repo.insert()
|> tap_ok(&PubSub.broadcast_create/1)
end

@doc """
Updates a series.

## Examples

iex> update_series(series, %{field: new_value})
{:ok, %Series{}}

iex> update_series(series, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_series(%Series{} = series, attrs) do
series
|> Series.changeset(attrs)
|> Repo.update()
|> tap_ok(&PubSub.broadcast_create/1)
end

@doc """
Deletes a series.

## Examples

iex> delete_series(series)
{:ok, %Series{}}

iex> delete_series(series)
{:error, %Ecto.Changeset{}}
"""
def delete_series(%Series{} = series) do
series
|> Repo.delete()
|> tap_ok(&PubSub.broadcast_delete/1)
end

@doc """
Returns an `%Ecto.Changeset{}` for tracking series changes.

## Examples

iex> change_series(series)
%Ecto.Changeset{data: %Series{}}
"""
def change_series(%Series{} = series, attrs \\ %{}) do
Series.changeset(series, attrs)
end

@doc """
Gets a series and all of its books.

Books are listed in ascending order based on series book number.
"""
def get_series_with_books!(series_id) do
Series
|> preload(series_books: [book: [:authors, series_books: :series]])
|> Repo.get!(series_id)
end

@doc """
Returns all series for use in `Select` components.
"""
def series_for_select do
query = from s in Series, select: {s.name, s.id}, order_by: s.name

Repo.all(query)
end
end
8 changes: 4 additions & 4 deletions lib/ambry/books/book.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ defmodule Ambry.Books.Book do

import Ecto.Changeset

alias Ambry.Authors.Author
alias Ambry.Authors.BookAuthor
alias Ambry.Books.Series
alias Ambry.Books.SeriesBook
alias Ambry.Media.Media
alias Ambry.Series.Series
alias Ambry.Series.SeriesBook
alias Ambry.People.Author
alias Ambry.People.BookAuthor

schema "books" do
has_many :media, Media
Expand Down
10 changes: 5 additions & 5 deletions lib/ambry/books/book_flat.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ defmodule Ambry.Books.BookFlat do
A flattened view of books.
"""

use Ambry.FlatSchema
use Ambry.Repo.FlatSchema

alias Ambry.Ecto.Types.PersonName
alias Ambry.Ecto.Types.SeriesBook
alias Ambry.Books.SeriesBookType
alias Ambry.People.PersonName

schema "books_flat" do
field :title, :string
field :published, :date
field :published_format, Ecto.Enum, values: [:full, :year_month, :year]
field :image_path, :string
field :authors, {:array, PersonName}
field :series, {:array, SeriesBook}
field :authors, {:array, PersonName.Type}
field :series, {:array, SeriesBookType.Type}
field :universe, :string
field :media, :integer
field :has_description, :boolean
Expand Down
Loading
Loading