diff --git a/lib/chiya/notes.ex b/lib/chiya/notes.ex
index d214935..5fd7cb4 100644
--- a/lib/chiya/notes.ex
+++ b/lib/chiya/notes.ex
@@ -6,9 +6,9 @@ defmodule Chiya.Notes do
import Ecto.Query, warn: false
alias Chiya.Repo
- alias Chiya.Notes.Note
+ alias Chiya.Notes.{Note, NoteImage}
- @preloads [:channels]
+ @preloads [:channels, :images]
@doc """
Returns the list of notes.
@@ -129,4 +129,28 @@ defmodule Chiya.Notes do
def change_note(%Note{} = note, attrs \\ %{}) do
Note.changeset(note, attrs)
end
+
+ @doc """
+ Creates a note image and attaches it to a note
+ """
+ def create_note_image(attrs) do
+ case %NoteImage{}
+ |> NoteImage.insert_changeset(attrs)
+ |> Repo.insert() do
+ {:ok, note_image} ->
+ note_image
+ |> change_note_image(attrs)
+ |> Repo.update()
+
+ {:error, changeset} ->
+ {:error, changeset}
+ end
+ end
+
+ @doc """
+ Returns an `%Ecto.Changeset{}` for tracking note_image changes.
+ """
+ def change_note_image(%NoteImage{} = note_image, attrs \\ %{}) do
+ NoteImage.changeset(note_image, attrs)
+ end
end
diff --git a/lib/chiya/notes/note.ex b/lib/chiya/notes/note.ex
index e785246..8128fbb 100644
--- a/lib/chiya/notes/note.ex
+++ b/lib/chiya/notes/note.ex
@@ -11,11 +11,13 @@ defmodule Chiya.Notes.Note do
field :url, :string
many_to_many :channels, Chiya.Channels.Channel,
- # join_through: Chiya.Channels.ChannelNote,
+ # join_through: Chiya.Channels.ChannelNote,
join_through: "channels_notes",
join_keys: [note: :id, channel: :id],
on_replace: :delete
+ has_many :images, Chiya.Notes.NoteImage
+
timestamps()
end
diff --git a/lib/chiya/notes/note_image.ex b/lib/chiya/notes/note_image.ex
new file mode 100644
index 0000000..aa7c9c8
--- /dev/null
+++ b/lib/chiya/notes/note_image.ex
@@ -0,0 +1,28 @@
+defmodule Chiya.Notes.NoteImage do
+ use Ecto.Schema
+ use Waffle.Ecto.Schema
+ import Ecto.Changeset
+
+ schema "note_images" do
+ field :content, :string, default: ""
+ field :path, Chiya.Uploaders.NoteImage.Type
+ field :note_id, :id
+
+ timestamps()
+ end
+
+ @doc false
+ def changeset(note_image, attrs) do
+ note_image
+ |> cast(attrs, [:content, :note_id])
+ |> cast_attachments(attrs, [:path], allow_paths: true)
+ |> validate_required([:path, :note_id])
+ end
+
+ @doc false
+ def insert_changeset(note_image, attrs) do
+ note_image
+ |> cast(attrs, [:note_id])
+ |> validate_required([:note_id])
+ end
+end
diff --git a/lib/chiya_web.ex b/lib/chiya_web.ex
index 5b9c497..b314bf8 100644
--- a/lib/chiya_web.ex
+++ b/lib/chiya_web.ex
@@ -44,6 +44,7 @@ defmodule ChiyaWeb do
import Plug.Conn
import ChiyaWeb.Gettext
+ import Phoenix.LiveView.Controller
unquote(verified_routes())
end
diff --git a/lib/chiya_web/controllers/note_controller.ex b/lib/chiya_web/controllers/note_controller.ex
index 091029b..83bd2ce 100644
--- a/lib/chiya_web/controllers/note_controller.ex
+++ b/lib/chiya_web/controllers/note_controller.ex
@@ -29,8 +29,9 @@ defmodule ChiyaWeb.NoteController do
end
def show(conn, %{"id" => id}) do
- note = Notes.get_note!(id)
- render(conn, :show, note: note)
+ # note = Notes.get_note!(id)
+ # render(conn, :show, note: note)
+ live_render(conn, NoteShowLive, session: %{ "note_id" => id })
end
def edit(conn, %{"id" => id}) do
diff --git a/lib/chiya_web/live/note_show_live.ex b/lib/chiya_web/live/note_show_live.ex
new file mode 100644
index 0000000..e71f6d6
--- /dev/null
+++ b/lib/chiya_web/live/note_show_live.ex
@@ -0,0 +1,106 @@
+defmodule ChiyaWeb.NoteShowLive do
+ use ChiyaWeb, :live_view
+
+ alias Chiya.Notes
+
+ @impl true
+ def render(assigns) do
+ ~H"""
+ <.header>
+ Note <%= @note.id %>
+ <:subtitle>This is a note record from your database.
+ <:actions>
+ <.link href={~p"/admin/notes/#{@note}/edit"}>
+ <.button>Edit note
+
+
+
+
+ <.list>
+ <:item title="Name"><%= @note.name %>
+ <:item title="Content"><%= @note.content %>
+ <:item title="Slug"><%= @note.slug %>
+ <:item title="Published at"><%= @note.published_at %>
+ <:item title="Kind"><%= @note.kind %>
+ <:item title="Url"><%= @note.url %>
+
+
+ <.line />
+
+
+ <%= for image <- @note.images do %>
+
+
+ Delete image
+
+ <% end %>
+
+
+ <.line />
+
+ <.header>
+ Note Images
+ <:subtitle>Add images here
+
+
+ <.simple_form
+ for={@image_form}
+ id="image_form"
+ phx-submit="update_image"
+ phx-change="validate_image"
+ multipart={true}
+ >
+ <.live_upload upload={@uploads.note_images} />
+
+ <:actions>
+ <.button phx-disable-with="Changing...">Add Images
+
+
+
+ <.back navigate={~p"/admin/notes"}>Back to notes
+ """
+ end
+
+ @impl true
+ def mount(%{"id" => note_id}, _session, socket) do
+ image_changeset = Notes.change_note_image(%Chiya.Notes.NoteImage{})
+
+ {:ok,
+ socket
+ |> assign(:note, Notes.get_note_preloaded!(note_id))
+ |> assign(:uploaded_files, [])
+ |> assign(:image_form, to_form(image_changeset))
+ |> allow_upload(:note_images, accept: ~w(.jpg .jpeg .gif .png), max_entries: 100)}
+ end
+
+ def handle_event("validate_image", _params, socket) do
+ {:noreply, socket}
+ end
+
+ @impl Phoenix.LiveView
+ def handle_event("cancel-upload", %{"ref" => ref}, socket) do
+ {:noreply, cancel_upload(socket, :note_images, ref)}
+ end
+
+ @impl Phoenix.LiveView
+ def handle_event("update_image", _params, socket) do
+ uploaded_files =
+ consume_uploaded_entries(socket, :note_images, fn %{path: path}, _entry ->
+ {:ok, _note_image} =
+ Notes.create_note_image(%{
+ path: path,
+ note_id: socket.assigns.note.id
+ })
+
+ {:ok, path}
+ end)
+
+ {:noreply,
+ socket
+ |> update(:uploaded_files, &(&1 ++ uploaded_files))
+ |> assign(:note, Notes.get_note_preloaded!(socket.assigns.note.id))}
+ end
+end
diff --git a/lib/chiya_web/live/user_settings_live.ex b/lib/chiya_web/live/user_settings_live.ex
index ae0bad8..57973ad 100644
--- a/lib/chiya_web/live/user_settings_live.ex
+++ b/lib/chiya_web/live/user_settings_live.ex
@@ -143,7 +143,10 @@ defmodule ChiyaWeb.UserSettingsLive do
{:ok, path}
end)
- {:noreply, update(socket, :uploaded_files, &(&1 ++ uploaded_files))}
+ {:noreply,
+ socket
+ |> update(:uploaded_files, &(&1 ++ uploaded_files))
+ |> assign(:user, Accounts.get_user!(user.id))}
end
def handle_event("validate_email", params, socket) do
diff --git a/lib/chiya_web/router.ex b/lib/chiya_web/router.ex
index a9cebf0..db48a3f 100644
--- a/lib/chiya_web/router.ex
+++ b/lib/chiya_web/router.ex
@@ -51,8 +51,10 @@ defmodule ChiyaWeb.Router do
pipe_through [:browser, :require_authenticated_user]
resources "/channels", ChannelController
- resources "/notes", NoteController
+ resources "/notes", NoteController, except: [:show]
resources "/settings", SettingController, singleton: true
+
+ live "/notes/:id", NoteShowLive, :show
end
## Authentication routes
diff --git a/lib/chiya_web/uploaders/note_image.ex b/lib/chiya_web/uploaders/note_image.ex
index d6ad52b..90670f5 100644
--- a/lib/chiya_web/uploaders/note_image.ex
+++ b/lib/chiya_web/uploaders/note_image.ex
@@ -5,12 +5,11 @@ defmodule Chiya.Uploaders.NoteImage do
# Include ecto support (requires package waffle_ecto installed):
# use Waffle.Ecto.Definition
- @versions [:original, :dithered, :thumb, :thumb_dithered]
+ @versions [:original, :full, :full_dithered, :thumb, :thumb_dithered]
# Whitelist file extensions:
- def validate({file, _}) do
- _file_extension = file.file_name |> Path.extname() |> String.downcase()
-
+ def validate({_file, _}) do
+ # _file_extension = file.file_name |> Path.extname() |> String.downcase()
# case Enum.member?(~w(.jpg .jpeg .gif .png), file_extension) do
# true -> :ok
# false -> {:error, "invalid file type"}
@@ -20,8 +19,12 @@ defmodule Chiya.Uploaders.NoteImage do
:ok
end
+ def transform(:full, _) do
+ {:convert, "-strip -resize 1500000@ -gravity center -format png", :png}
+ end
+
# Define a resize transformation:
- def transform(:dithered, _) do
+ def transform(:full_dithered, _) do
{:convert, "-strip -resize 1500000@ -colors 24 -dither FloydSteinberg -format png", :png}
end
@@ -43,21 +46,12 @@ defmodule Chiya.Uploaders.NoteImage do
end
# Override the storage directory:
- def storage_dir(_version, {_file, _scope}) do
- "uploads/user/avatar"
+ def storage_dir(_version, {_file, %{id: image_id, note_id: note_id}}) do
+ "uploads/note/#{note_id}/#{image_id}"
end
# Provide a default URL if there hasn't been a file uploaded
# def default_url(version, scope) do
# "/images/avatars/default_#{version}.png"
# end
-
- # Specify custom headers for s3 objects
- # Available options are [:cache_control, :content_disposition,
- # :content_encoding, :content_length, :content_type,
- # :expect, :expires, :storage_class, :website_redirect_location]
- #
- # def s3_object_headers(version, {file, scope}) do
- # [content_type: MIME.from_path(file.file_name)]
- # end
end
diff --git a/priv/repo/migrations/20230308191004_create_note_images.exs b/priv/repo/migrations/20230308191004_create_note_images.exs
new file mode 100644
index 0000000..77e0c6c
--- /dev/null
+++ b/priv/repo/migrations/20230308191004_create_note_images.exs
@@ -0,0 +1,15 @@
+defmodule Chiya.Repo.Migrations.CreateNoteImages do
+ use Ecto.Migration
+
+ def change do
+ create table(:note_images) do
+ add :path, :string
+ add :content, :text
+ add :note_id, references(:notes, on_delete: :nothing)
+
+ timestamps()
+ end
+
+ create index(:note_images, [:note_id])
+ end
+end