initial handling of blog content and serving of blog content files/assets
This commit is contained in:
parent
8269f1f24f
commit
80da842416
7 changed files with 209 additions and 2 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -40,7 +40,7 @@ npm-debug.log
|
||||||
/.elixir_ls
|
/.elixir_ls
|
||||||
|
|
||||||
# blog content repo folder
|
# blog content repo folder
|
||||||
/priv/content/*
|
/priv/content/
|
||||||
|
|
||||||
# dev
|
# dev
|
||||||
TODO.md
|
TODO.md
|
||||||
|
|
|
@ -12,9 +12,10 @@ defmodule Home73k.Application do
|
||||||
# Start the PubSub system
|
# Start the PubSub system
|
||||||
{Phoenix.PubSub, name: Home73k.PubSub},
|
{Phoenix.PubSub, name: Home73k.PubSub},
|
||||||
# Start the Endpoint (http/https)
|
# Start the Endpoint (http/https)
|
||||||
Home73kWeb.Endpoint
|
Home73kWeb.Endpoint,
|
||||||
# Start a worker by calling: Home73k.Worker.start_link(arg)
|
# Start a worker by calling: Home73k.Worker.start_link(arg)
|
||||||
# {Home73k.Worker, arg}
|
# {Home73k.Worker, arg}
|
||||||
|
Home73k.Blog
|
||||||
]
|
]
|
||||||
|
|
||||||
# See https://hexdocs.pm/elixir/Supervisor.html
|
# See https://hexdocs.pm/elixir/Supervisor.html
|
||||||
|
|
116
lib/home73k/blog.ex
Normal file
116
lib/home73k/blog.ex
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
defmodule Home73k.Blog do
|
||||||
|
use GenServer
|
||||||
|
|
||||||
|
#
|
||||||
|
# Setup
|
||||||
|
#
|
||||||
|
Application.ensure_all_started(:earmark)
|
||||||
|
|
||||||
|
@repo Home73k.Repo.get()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Client
|
||||||
|
#
|
||||||
|
|
||||||
|
def start_link(_opts) do
|
||||||
|
GenServer.start_link(__MODULE__, %{posts: [], tags: [], files: []}, name: __MODULE__)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_posts() do
|
||||||
|
GenServer.call(__MODULE__, :get_posts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_files() do
|
||||||
|
GenServer.call(__MODULE__, :get_files)
|
||||||
|
end
|
||||||
|
|
||||||
|
# def push(pid, element) do
|
||||||
|
# GenServer.cast(pid, {:push, element})
|
||||||
|
# end
|
||||||
|
|
||||||
|
# def pop(pid) do
|
||||||
|
# GenServer.call(pid, :pop)
|
||||||
|
# end
|
||||||
|
|
||||||
|
# def put(server, key, value) do
|
||||||
|
# GenServer.cast(server, {:put, key, value})
|
||||||
|
# end
|
||||||
|
|
||||||
|
# def get(server, key) do
|
||||||
|
# GenServer.call(server, {:get, key})
|
||||||
|
# end
|
||||||
|
|
||||||
|
#
|
||||||
|
# Server
|
||||||
|
#
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def init(state) do
|
||||||
|
repo_all_paths = @repo.path |> Path.join("**/*.*") |> Path.wildcard()
|
||||||
|
repo_post_paths = repo_all_paths |> Enum.filter(fn f -> String.ends_with?(f, ".md") end)
|
||||||
|
repo_file_paths = repo_all_paths |> Enum.filter(fn f -> !String.ends_with?(f, ".md") end)
|
||||||
|
{:ok, %{state | posts: repo_post_paths, files: repo_file_paths}}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_call(:get_posts, _from, %{posts: posts} = state) do
|
||||||
|
{:reply, posts, state}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_call(:get_files, _from, %{files: files} = state) do
|
||||||
|
{:reply, files, state}
|
||||||
|
end
|
||||||
|
|
||||||
|
# @impl true
|
||||||
|
# def handle_call(:pop, _from, [head | tail]) do
|
||||||
|
# {:reply, head, tail}
|
||||||
|
# end
|
||||||
|
|
||||||
|
# @impl true
|
||||||
|
# def handle_cast({:push, element}, state) do
|
||||||
|
# {:noreply, [element | state]}
|
||||||
|
# end
|
||||||
|
|
||||||
|
# def handle_cast({:put, key, value}, state) do
|
||||||
|
# {:noreply, Map.put(state, key, value)}
|
||||||
|
# end
|
||||||
|
|
||||||
|
# def handle_call({:get, key}, _from, state) do
|
||||||
|
# {:reply, Map.fetch!(state, key), state}
|
||||||
|
# end
|
||||||
|
|
||||||
|
# alias Home73k.Blog.Post
|
||||||
|
|
||||||
|
# @posts_dir Application.compile_env(:home73k, :blog_posts_dir, "posts")
|
||||||
|
|
||||||
|
# posts_paths =
|
||||||
|
# @posts_dir
|
||||||
|
# |> Path.join("**/*.md")
|
||||||
|
# |> Path.wildcard()
|
||||||
|
# |> Enum.sort()
|
||||||
|
|
||||||
|
# posts =
|
||||||
|
# for post_path <- posts_paths do
|
||||||
|
# @external_resource Path.relative_to_cwd(post_path)
|
||||||
|
# Post.parse!(post_path)
|
||||||
|
# end
|
||||||
|
|
||||||
|
# @posts Enum.sort_by(posts, & &1.date, {:desc, Date})
|
||||||
|
|
||||||
|
# @tags posts |> Enum.flat_map(& &1.tags) |> Enum.uniq() |> Enum.sort()
|
||||||
|
|
||||||
|
# def list_posts, do: @posts
|
||||||
|
# def list_tags, do: @tags
|
||||||
|
|
||||||
|
# defmodule NotFoundError do
|
||||||
|
# defexception [:message, plug_status: 404]
|
||||||
|
# end
|
||||||
|
|
||||||
|
# def get_posts_by_tag!(tag) do
|
||||||
|
# case Enum.filter(list_posts(), &(tag in &1.tags)) do
|
||||||
|
# [] -> raise NotFoundError, "posts with tag=#{tag} not found"
|
||||||
|
# posts -> posts
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
end
|
43
lib/home73k/repo.ex
Normal file
43
lib/home73k/repo.ex
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
defmodule Home73k.Repo do
|
||||||
|
@repo_url Application.compile_env(:home73k, [:content_repo, :url], nil)
|
||||||
|
@content_path Application.compile_env(:home73k, [:content_repo, :path], "./priv/content")
|
||||||
|
|> Path.expand()
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# REPO SETUP
|
||||||
|
######################################################################
|
||||||
|
def get do
|
||||||
|
@content_path |> File.exists?() |> init_repo()
|
||||||
|
end
|
||||||
|
|
||||||
|
def content_path, do: @content_path
|
||||||
|
|
||||||
|
# If content path is absent, clone repo if url is present
|
||||||
|
defp init_repo(false) do
|
||||||
|
if @repo_url do
|
||||||
|
{:ok, repo} = Git.clone([@repo_url, @content_path])
|
||||||
|
repo
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# If content path exists, check for .git child and pull or return nil
|
||||||
|
defp init_repo(true) do
|
||||||
|
if git_data_dir_ok?() do
|
||||||
|
Git.new(@content_path)
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp git_data_dir_ok? do
|
||||||
|
git_data_dir = Path.join(@content_path, ".git")
|
||||||
|
File.exists?(git_data_dir) && File.dir?(git_data_dir)
|
||||||
|
end
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# REPO OPERATIONS
|
||||||
|
######################################################################
|
||||||
|
def update(repo), do: Git.pull(repo)
|
||||||
|
end
|
30
lib/home73k_web/controllers/blog_file_controller.ex
Normal file
30
lib/home73k_web/controllers/blog_file_controller.ex
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
defmodule Home73kWeb.BlogFileController do
|
||||||
|
use Home73kWeb, :controller
|
||||||
|
|
||||||
|
@moduledoc """
|
||||||
|
This controller handles path requests that didn't match an existing route,
|
||||||
|
including the main Plug.Static for the / root path.
|
||||||
|
|
||||||
|
To handle this situation, we'll check if the requested resource exists as
|
||||||
|
a file under the blog content repo folder, by querying the Blog genserve.
|
||||||
|
|
||||||
|
If it exists, we'll redirect to the blog content static path under /_
|
||||||
|
Otherwise, we'll return 404 not found.
|
||||||
|
"""
|
||||||
|
|
||||||
|
alias Home73k.Repo
|
||||||
|
alias Home73k.Blog
|
||||||
|
|
||||||
|
def index(conn, _params) do
|
||||||
|
# What would be the content path of this requested resource?
|
||||||
|
content_path = Repo.content_path() |> Path.join(conn.request_path)
|
||||||
|
|
||||||
|
# Check if it exists in the Blog's known files
|
||||||
|
Blog.get_files()
|
||||||
|
|> Enum.member?(content_path)
|
||||||
|
|> case do
|
||||||
|
true -> redirect(conn, to: "/_#{conn.request_path}")
|
||||||
|
false -> send_resp(conn, 404, "not found")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -26,6 +26,18 @@ defmodule Home73kWeb.Endpoint do
|
||||||
gzip: true,
|
gzip: true,
|
||||||
only: ~w(css fonts images js favicon.ico robots.txt DF185CEE29A3D443_public_key.asc)
|
only: ~w(css fonts images js favicon.ico robots.txt DF185CEE29A3D443_public_key.asc)
|
||||||
|
|
||||||
|
# Blog static path handler
|
||||||
|
if File.dir?(Home73k.Repo.content_path()) do
|
||||||
|
plug Plug.Static,
|
||||||
|
at: "/_",
|
||||||
|
from: Home73k.Repo.content_path(),
|
||||||
|
gzip: false,
|
||||||
|
only:
|
||||||
|
Home73k.Repo.content_path()
|
||||||
|
|> File.ls!()
|
||||||
|
|> Enum.filter(fn f -> !String.starts_with?(f, ".") end)
|
||||||
|
end
|
||||||
|
|
||||||
# Code reloading can be explicitly enabled under the
|
# Code reloading can be explicitly enabled under the
|
||||||
# :code_reloader configuration of your endpoint.
|
# :code_reloader configuration of your endpoint.
|
||||||
if code_reloading? do
|
if code_reloading? do
|
||||||
|
|
|
@ -43,4 +43,9 @@ defmodule Home73kWeb.Router do
|
||||||
live_dashboard "/dashboard", metrics: Home73kWeb.Telemetry
|
live_dashboard "/dashboard", metrics: Home73kWeb.Telemetry
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Wildcard path for handling Blog Files from repo
|
||||||
|
scope "/", Home73kWeb do
|
||||||
|
get "/*path", BlogFileController, :index
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue