This commit is contained in:
zack 2024-10-22 16:51:56 -04:00
parent e2967f68b2
commit ef2a6c41b4
No known key found for this signature in database
GPG key ID: 5F873416BCF59F35
39 changed files with 2349 additions and 30 deletions

View file

@ -0,0 +1,25 @@
defmodule ZoeyscomputerWeb.ChangesetJSON do
@doc """
Renders changeset errors.
"""
def error(%{changeset: changeset}) do
# When encoded, the changeset returns its errors
# as a JSON object. So we just pass it forward.
%{errors: Ecto.Changeset.traverse_errors(changeset, &translate_error/1)}
end
defp translate_error({msg, opts}) do
# You can make use of gettext to translate error messages by
# uncommenting and adjusting the following code:
# if count = opts[:count] do
# Gettext.dngettext(ZoeyscomputerWeb.Gettext, "errors", msg, msg, count, opts)
# else
# Gettext.dgettext(ZoeyscomputerWeb.Gettext, "errors", msg, opts)
# end
Enum.reduce(opts, msg, fn {key, value}, acc ->
String.replace(acc, "%{#{key}}", fn _ -> to_string(value) end)
end)
end
end

View file

@ -0,0 +1,24 @@
defmodule ZoeyscomputerWeb.FallbackController do
@moduledoc """
Translates controller action results into valid `Plug.Conn` responses.
See `Phoenix.Controller.action_fallback/1` for more details.
"""
use ZoeyscomputerWeb, :controller
# This clause handles errors returned by Ecto's insert/update/delete.
def call(conn, {:error, %Ecto.Changeset{} = changeset}) do
conn
|> put_status(:unprocessable_entity)
|> put_view(json: ZoeyscomputerWeb.ChangesetJSON)
|> render(:error, changeset: changeset)
end
# This clause is an example of how to handle resources that cannot be found.
def call(conn, {:error, :not_found}) do
conn
|> put_status(:not_found)
|> put_view(html: ZoeyscomputerWeb.ErrorHTML, json: ZoeyscomputerWeb.ErrorJSON)
|> render(:"404")
end
end

View file

@ -0,0 +1,103 @@
defmodule ZoeyscomputerWeb.ImageController do
use ZoeyscomputerWeb, :controller
alias Zoeyscomputer.Images
alias Zoeyscomputer.Images.Image
action_fallback ZoeyscomputerWeb.FallbackController
def index(conn, _params) do
images = Images.list_images()
render(conn, :index, images: images)
end
def create(conn, %{"file" => upload}) do
user = conn.assigns.current_user
case handle_upload(upload) do
{:ok, s3_key} ->
# Fixed: create_image takes one argument (the params map)
case Images.create_image(%{file: s3_key, user_id: user.id}) do
{:ok, image} ->
conn
|> put_status(:created)
|> put_resp_header("location", ~p"/api/images/#{image}")
|> json(%{
message: "File uploaded successfully",
url: get_public_url(s3_key),
image: image
})
{:error, changeset} ->
conn
|> put_status(:unprocessable_entity)
|> json(%{
error: "Database save failed",
details: changeset_error_to_string(changeset)
})
end
{:error, reason} ->
conn
|> put_status(:unprocessable_entity)
|> json(%{
error: "Upload failed",
reason: inspect(reason)
})
end
end
defp changeset_error_to_string(changeset) do
Ecto.Changeset.traverse_errors(changeset, fn {msg, opts} ->
Enum.reduce(opts, msg, fn {key, value}, acc ->
String.replace(acc, "%{#{key}}", to_string(value))
end)
end)
end
defp handle_upload(upload) do
extension = Path.extname(upload.filename)
id = Nanoid.generate(7)
key = "uploads/#{id}#{extension}"
bucket = "imgs"
{:ok, file_binary} = File.read(upload.path)
case ExAws.S3.put_object(bucket, key, file_binary)
|> ExAws.request() do
{:ok, _response} -> {:ok, id}
{:error, reason} -> {:error, reason}
end
end
defp get_public_url(key) do
"https://zoeys.computer/images/#{key}"
end
def show(conn, %{"id" => id}) do
image = Images.get_image!(id)
render(conn, :show, image: image)
end
def update(conn, %{"id" => id, "image" => image_params}) do
image = Images.get_image!(id)
with {:ok, %Image{} = image} <- Images.update_image(image, image_params) do
render(conn, :show, image: image)
end
end
def delete(conn, %{"id" => id}) do
image = Images.get_image!(id)
case ExAws.S3.delete_object("imgs", image.file)
|> ExAws.request() do
{:ok, _response} -> {:ok, image.file}
{:error, reason} -> {:error, reason}
end
with {:ok, %Image{}} <- Images.delete_image(image) do
send_resp(conn, :no_content, "")
end
end
end

View file

@ -0,0 +1,24 @@
defmodule ZoeyscomputerWeb.ImageJSON do
alias Zoeyscomputer.Images.Image
@doc """
Renders a list of images.
"""
def index(%{images: images}) do
%{data: for(image <- images, do: data(image))}
end
@doc """
Renders a single image.
"""
def show(%{image: image}) do
%{data: data(image)}
end
defp data(%Image{} = image) do
%{
id: image.id,
file: image.file
}
end
end