Skip to content

Commit

Permalink
Merge pull request #4 from bluzky/import-export
Browse files Browse the repository at this point in the history
Import export
  • Loading branch information
bluzky authored Jan 21, 2020
2 parents 9c38528 + 58d52fc commit 7656283
Show file tree
Hide file tree
Showing 35 changed files with 381 additions and 89 deletions.
2 changes: 1 addition & 1 deletion lib/chubi/content.ex
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ defmodule Chubi.Content do
end

defp parse_content(%{"content" => content} = params) do
format = Application.get_env(:chubi, :post_format) || "html"
format = params["format"] || Application.get_env(:chubi, :post_format) || "markdown"
parser = Keyword.get(@content_parser_map, String.to_atom(format))
attrs = parser.parse(content, params)
Map.merge(params, attrs)
Expand Down
121 changes: 121 additions & 0 deletions lib/chubi/content_file_store.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
defmodule Chubi.ContentFileStore do
alias Chubi.Content.Post
alias Chubi.Content.Page
@content_dir "./priv/content"

def content_directory(suffix \\ "") do
@content_dir
|> Path.join(suffix)
|> Path.absname()
end

def ensure_directory(path) do
if File.dir?(path) do
path
else
File.mkdir_p!(path)
path
end
end

defp directory(post) do
case post do
%Post{} ->
ensure_directory(content_directory("posts"))

%Page{} ->
ensure_directory(content_directory("pages"))

_ ->
nil
end
end

defp extension(post) do
case post.format do
"markdown" -> "md"
_ -> "json"
end
end

defp content(%Post{} = post) do
case post.format do
"markdown" ->
post.content

_ ->
post
|> Map.drop([:__meta__, :__struct__])
|> Map.merge(%{
categories: Enum.map(post.categories, & &1.name),
tags: Enum.map(post.tags, & &1.name)
})
|> Jason.encode!()
end
end

defp content(%Page{} = post) do
case post.format do
"markdown" ->
post.content

_ ->
post
|> Map.drop([:__meta__, :__struct__])
|> Jason.encode!()
end
end

defp file_name(post) do
date = Timex.format!(post.date || post.inserted_at, "{YYYY}-{0M}-{0D}")
"#{date}-#{post.slug}.#{extension(post)}"
end

defp file_path(post) do
Path.join(directory(post), file_name(post))
end

def write(post) do
File.write(file_path(post), content(post), [:write])
end

def write_mem(post) do
{file_name(post), content(post)}
end

def delete(post) do
File.rm(file_path(post))
end

def read_all_posts() do
ensure_directory(content_directory("/posts"))
|> read_directory
end

def read_all_pages() do
ensure_directory(content_directory("/pages"))
|> read_directory
end

def read_directory(path) do
with {:ok, files} <- File.ls(path) do
Enum.map(files, fn file ->
Path.join(path, file)
|> read_file
end)
|> Enum.filter(&(not is_nil(&1)))
else
_ -> []
end
end

def read_file(file_path) do
with {:ok, content} <- File.read(file_path) do
case Path.extname(file_path) do
".md" -> %{"content" => content, "format" => "markdown"}
".json" -> Jason.decode!(content)
_ -> nil
end
end
end
end
4 changes: 2 additions & 2 deletions lib/chubi_web.ex
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ defmodule ChubiWeb do

import Plug.Conn
import ChubiWeb.Gettext
alias ChubiWeb.Router.Helpers, as: Routes
alias ChubiWeb.AdminRouter.Helpers, as: Routes
end
end

Expand Down Expand Up @@ -86,7 +86,7 @@ defmodule ChubiWeb do
import ChubiWeb.Admin.InputHelpers
import ChubiWeb.Admin.ViewHelpers
import ChubiWeb.Gettext
alias ChubiWeb.Router.Helpers, as: Routes
alias ChubiWeb.AdminRouter.Helpers, as: Routes
end
end

Expand Down
46 changes: 46 additions & 0 deletions lib/chubi_web/admin_router.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
defmodule ChubiWeb.AdminRouter do
use ChubiWeb, :router

pipeline :browser do
plug(:accepts, ["html"])
plug(:fetch_session)
plug(:fetch_flash)
plug(:protect_from_forgery)
plug(:put_secure_browser_headers)
end

pipeline :admin do
plug(:put_layout, {ChubiWeb.Admin.LayoutView, "app.html"})
plug(BasicAuth, use_config: {:chubi, :auth_config})
plug(ChubiWeb.Plugs.PutSiteSetting)
plug(ChubiWeb.Plugs.LoadSiteParams)
end

pipeline :preview do
plug(BasicAuth, use_config: {:chubi, :auth_config})
end

pipeline :app do
plug(ChubiWeb.Plugs.PutSiteSetting)
plug(ChubiWeb.Plugs.LoadSiteParams)
# put this at end of pipeline
plug(ChubiWeb.Plugs.PutSiteLayout)
end

scope "/", ChubiWeb.Admin, path: "/admin" do
pipe_through([:browser, :admin])
get("/", PostController, :index)
resources("/tags", TagController)
resources("/categories", CategoryController)
resources("/posts", PostController)
resources("/pages", PageController)

post("/upload", UploadController, :create)
delete("/upload", UploadController, :delete)

get("/settings/set_theme", SettingController, :set_theme)
get("/settings/export", SettingController, :export_content)
get("/settings/select_import", SettingController, :select_import)
post("/settings/import", SettingController, :import_content)
end
end
6 changes: 3 additions & 3 deletions lib/chubi_web/controllers/admin/category_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ defmodule ChubiWeb.Admin.CategoryController do
{:ok, category} ->
conn
|> put_flash(:info, "Category created successfully.")
|> redirect(to: Routes.admin_category_path(conn, :show, category))
|> redirect(to: Routes.category_path(conn, :show, category))

{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "new.html", changeset: changeset)
Expand All @@ -44,7 +44,7 @@ defmodule ChubiWeb.Admin.CategoryController do
{:ok, category} ->
conn
|> put_flash(:info, "Category updated successfully.")
|> redirect(to: Routes.admin_category_path(conn, :show, category))
|> redirect(to: Routes.category_path(conn, :show, category))

{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "edit.html", category: category, changeset: changeset)
Expand All @@ -57,6 +57,6 @@ defmodule ChubiWeb.Admin.CategoryController do

conn
|> put_flash(:info, "Category deleted successfully.")
|> redirect(to: Routes.admin_category_path(conn, :index))
|> redirect(to: Routes.category_path(conn, :index))
end
end
6 changes: 3 additions & 3 deletions lib/chubi_web/controllers/admin/page_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ defmodule ChubiWeb.Admin.PageController do
{:ok, page} ->
conn
|> put_flash(:info, "Page created successfully.")
|> redirect(to: Routes.admin_page_path(conn, :show, page))
|> redirect(to: Routes.page_path(conn, :show, page))

{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "new.html", changeset: changeset)
Expand All @@ -54,7 +54,7 @@ defmodule ChubiWeb.Admin.PageController do
{:ok, page} ->
conn
|> put_flash(:info, "Page updated successfully.")
|> redirect(to: Routes.admin_page_path(conn, :show, page))
|> redirect(to: Routes.page_path(conn, :show, page))

{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "edit.html", page: page, changeset: changeset)
Expand All @@ -67,6 +67,6 @@ defmodule ChubiWeb.Admin.PageController do

conn
|> put_flash(:info, "Page deleted successfully.")
|> redirect(to: Routes.admin_page_path(conn, :index))
|> redirect(to: Routes.page_path(conn, :index))
end
end
6 changes: 3 additions & 3 deletions lib/chubi_web/controllers/admin/post_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ defmodule ChubiWeb.Admin.PostController do
{:ok, post} ->
conn
|> put_flash(:info, "Post created successfully.")
|> redirect(to: Routes.admin_post_path(conn, :show, post))
|> redirect(to: Routes.post_path(conn, :show, post))

{:error, %Ecto.Changeset{} = changeset} ->
conn
Expand Down Expand Up @@ -75,7 +75,7 @@ defmodule ChubiWeb.Admin.PostController do
{:ok, post} ->
conn
|> put_flash(:info, "Post updated successfully.")
|> redirect(to: Routes.admin_post_path(conn, :show, post))
|> redirect(to: Routes.post_path(conn, :show, post))

{:error, %Ecto.Changeset{} = changeset} ->
conn
Expand All @@ -90,7 +90,7 @@ defmodule ChubiWeb.Admin.PostController do

conn
|> put_flash(:info, "Post deleted successfully.")
|> redirect(to: Routes.admin_post_path(conn, :index))
|> redirect(to: Routes.post_path(conn, :index))
end

defp put_meta(conn) do
Expand Down
81 changes: 79 additions & 2 deletions lib/chubi_web/controllers/admin/setting_controller.ex
Original file line number Diff line number Diff line change
@@ -1,9 +1,86 @@
defmodule ChubiWeb.Admin.SettingController do
use ChubiWeb, :controller
use ChubiWeb, :admin_controller
alias Chubi.Content

def set_theme(conn, %{"theme" => theme}) do
conn
|> put_session(:theme, theme)
|> redirect(to: Routes.admin_post_path(conn, :index))
|> redirect(to: Routes.post_path(conn, :index))
end

def export_content(conn, _params) do
posts =
Content.list_posts()
|> Enum.map(&Chubi.ContentFileStore.write_mem(&1))
|> Enum.map(fn {file_name, content} ->
{String.to_charlist(Path.join("posts/", file_name)), content}
end)

pages =
Content.list_pages()
|> Enum.map(&Chubi.ContentFileStore.write_mem(&1))
|> Enum.map(fn {file_name, content} ->
{String.to_charlist(Path.join("pages/", file_name)), content}
end)

with {:ok, {filename, data}} = :zip.create("blog-content.zip", posts ++ pages, [:memory]) do
# download file
conn
|> Plug.Conn.put_resp_content_type("application/octet-stream")
|> Plug.Conn.put_resp_header(
"content-disposition",
"attachment; filename=\"#{filename}\""
)
|> Plug.Conn.send_resp(:ok, data)
else
_ ->
conn
|> put_flash(:error, gettext("Cannot generate template"))
|> redirect(to: Routes.post_path(conn, :index))
end
end

def select_import(conn, _) do
render(conn, "select_import.html")
end

def import_content(conn, %{"file" => %{path: path}}) do
with {:ok, files} <- :zip.extract(String.to_charlist(path), [:memory]) do
rs =
Enum.map(files, fn {file_path, content} ->
file_path =
to_string(file_path)
|> IO.inspect()

attrs =
case Path.extname(file_path) do
".md" ->
%{"content" => content, "format" => "markdown"}

_ext ->
Jason.decode!(content)
end

if String.starts_with?(file_path, "posts") do
Content.create_post(attrs)
else
Content.create_page(attrs)
end
end)

success = Enum.filter(rs, &(elem(&1, 0) == :ok))

conn
|> put_flash(
:info,
gettext("%{success}/%{total} is imported", %{success: length(success), total: length(rs)})
)
|> redirect(to: Routes.post_path(conn, :index))
else
err ->
conn
|> put_flash(:error, gettext("Cannot import content"))
|> redirect(to: Routes.setting_path(conn, :select_import))
end
end
end
6 changes: 3 additions & 3 deletions lib/chubi_web/controllers/admin/tag_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ defmodule ChubiWeb.Admin.TagController do
{:ok, tag} ->
conn
|> put_flash(:info, "Tag created successfully.")
|> redirect(to: Routes.admin_tag_path(conn, :show, tag))
|> redirect(to: Routes.tag_path(conn, :show, tag))

{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "new.html", changeset: changeset)
Expand All @@ -44,7 +44,7 @@ defmodule ChubiWeb.Admin.TagController do
{:ok, tag} ->
conn
|> put_flash(:info, "Tag updated successfully.")
|> redirect(to: Routes.admin_tag_path(conn, :show, tag))
|> redirect(to: Routes.tag_path(conn, :show, tag))

{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "edit.html", tag: tag, changeset: changeset)
Expand All @@ -57,6 +57,6 @@ defmodule ChubiWeb.Admin.TagController do

conn
|> put_flash(:info, "Tag deleted successfully.")
|> redirect(to: Routes.admin_tag_path(conn, :index))
|> redirect(to: Routes.tag_path(conn, :index))
end
end
Loading

0 comments on commit 7656283

Please sign in to comment.