Merge branch 'f-content' into 'master'
feat: Add basic content management system See merge request mythic-insight/legendary!5
This commit is contained in:
		
						commit
						5a629a3860
					
				
					 136 changed files with 2073 additions and 501 deletions
				
			
		| 
						 | 
				
			
			@ -1,9 +1,15 @@
 | 
			
		|||
image: "elixir:1.10"
 | 
			
		||||
 | 
			
		||||
cache:
 | 
			
		||||
  paths:
 | 
			
		||||
    - _build
 | 
			
		||||
    - deps
 | 
			
		||||
 | 
			
		||||
variables:
 | 
			
		||||
  POSTGRES_PASSWORD: "postgres"
 | 
			
		||||
  POSTGRES_USER: "postgres"
 | 
			
		||||
  DATABASE_URL: "postgres"
 | 
			
		||||
  MIX_ENV: "test"
 | 
			
		||||
 | 
			
		||||
services: 
 | 
			
		||||
- name: postgres:12
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
defmodule Auth.Users.User do
 | 
			
		||||
defmodule Auth.User do
 | 
			
		||||
  @moduledoc """
 | 
			
		||||
  The baseline user schema module.
 | 
			
		||||
  """
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +13,8 @@ defmodule Auth.Users.User do
 | 
			
		|||
 | 
			
		||||
  schema "users" do
 | 
			
		||||
    field :roles, {:array, :string}
 | 
			
		||||
    field :display_name, :string
 | 
			
		||||
    field :homepage_url, :string
 | 
			
		||||
 | 
			
		||||
    pow_user_fields()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ defmodule Mix.Tasks.Legendary.CreateAdmin do
 | 
			
		|||
  """
 | 
			
		||||
  use Mix.Task
 | 
			
		||||
 | 
			
		||||
  alias Auth.Users.User
 | 
			
		||||
  alias Auth.User
 | 
			
		||||
  alias Auth.Repo
 | 
			
		||||
  alias Ecto.Changeset
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
defmodule Auth.Repo.Migrations.AddNicenameToUsers do
 | 
			
		||||
  use Ecto.Migration
 | 
			
		||||
 | 
			
		||||
  def change do
 | 
			
		||||
    alter table(:users) do
 | 
			
		||||
      add :display_name, :string, default: nil
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
defmodule Auth.Repo.Migrations.AddUrlToUsers do
 | 
			
		||||
  use Ecto.Migration
 | 
			
		||||
 | 
			
		||||
  def change do
 | 
			
		||||
    alter table(:users) do
 | 
			
		||||
      add :homepage_url, :string, default: nil
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										2
									
								
								apps/content/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								apps/content/.gitignore
									
									
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -20,7 +20,7 @@ erl_crash.dump
 | 
			
		|||
*.ez
 | 
			
		||||
 | 
			
		||||
# Ignore package tarball (built via "mix hex.build").
 | 
			
		||||
auth_web-*.tar
 | 
			
		||||
content-*.tar
 | 
			
		||||
 | 
			
		||||
# If NPM crashes, it generates a log, let's ignore it too.
 | 
			
		||||
npm-debug.log
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
		 Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB  | 
| 
		 Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB  | 
| 
						 | 
				
			
			@ -18,7 +18,7 @@ config :logger, :console,
 | 
			
		|||
 | 
			
		||||
config :content, Content.Scheduler,
 | 
			
		||||
  jobs: [
 | 
			
		||||
    {"@hourly", {ContentWeb.Sitemaps, :generate, []}}
 | 
			
		||||
    {"@hourly", {Content.Sitemaps, :generate, []}}
 | 
			
		||||
  ]
 | 
			
		||||
 | 
			
		||||
# Import environment specific config. This must remain at the bottom
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ use Mix.Config
 | 
			
		|||
config :content, Content.Repo,
 | 
			
		||||
  username: "postgres",
 | 
			
		||||
  password: "postgres",
 | 
			
		||||
  database: "content_dev",
 | 
			
		||||
  database: "legendary_dev",
 | 
			
		||||
  hostname: "localhost",
 | 
			
		||||
  show_sensitive_data_on_connection_error: true,
 | 
			
		||||
  pool_size: 10
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ config :content, Content.Repo,
 | 
			
		|||
# The watchers configuration can be used to run external
 | 
			
		||||
# watchers to your application. For example, we use it
 | 
			
		||||
# with webpack to recompile .js and .css sources.
 | 
			
		||||
config :content, ContentWeb.Endpoint,
 | 
			
		||||
config :content, Content.Endpoint,
 | 
			
		||||
  http: [port: 4000],
 | 
			
		||||
  debug_errors: true,
 | 
			
		||||
  code_reloader: true,
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +55,7 @@ config :content, ContentWeb.Endpoint,
 | 
			
		|||
# different ports.
 | 
			
		||||
 | 
			
		||||
# Watch static and templates for browser reloading.
 | 
			
		||||
config :content, ContentWeb.Endpoint,
 | 
			
		||||
config :content, Content.Endpoint,
 | 
			
		||||
  live_reload: [
 | 
			
		||||
    patterns: [
 | 
			
		||||
      ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,11 +2,3 @@ use Mix.Config
 | 
			
		|||
 | 
			
		||||
# Print only warnings and errors during test
 | 
			
		||||
config :logger, level: :warn
 | 
			
		||||
 | 
			
		||||
config :content, Content.Repo,
 | 
			
		||||
  username: "postgres",
 | 
			
		||||
  password: "postgres",
 | 
			
		||||
  database: "content_test#{System.get_env("MIX_TEST_PARTITION")}",
 | 
			
		||||
  hostname: System.get_env("DATABASE_URL") || "localhost",
 | 
			
		||||
  show_sensitive_data_on_connection_error: true,
 | 
			
		||||
  pool: Ecto.Adapters.SQL.Sandbox
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
defmodule Content.Application do
 | 
			
		||||
  @moduledoc """
 | 
			
		||||
  The base module of the CMS application.
 | 
			
		||||
  The base module of the Content application.
 | 
			
		||||
  """
 | 
			
		||||
  use Application
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -17,6 +17,8 @@ defmodule Content.Application do
 | 
			
		|||
      # Start your own worker by calling: Content.Worker.start_link(arg1, arg2, arg3)
 | 
			
		||||
      # worker(Content.Worker, [arg1, arg2, arg3]),
 | 
			
		||||
      worker(Content.Scheduler, []),
 | 
			
		||||
      Content.Telemetry,
 | 
			
		||||
      Content.Endpoint,
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    # See https://hexdocs.pm/elixir/Supervisor.html
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +30,7 @@ defmodule Content.Application do
 | 
			
		|||
  # Tell Phoenix to update the endpoint configuration
 | 
			
		||||
  # whenever the application is updated.
 | 
			
		||||
  def config_change(changed, _new, removed) do
 | 
			
		||||
    Endpoint.config_change(changed, removed)
 | 
			
		||||
    Content.Endpoint.config_change(changed, removed)
 | 
			
		||||
    :ok
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -37,7 +37,7 @@ defmodule Content.Post do
 | 
			
		|||
    has_many :categories, through: [:term_relationships, :category, :term]
 | 
			
		||||
    has_many :tags, through: [:term_relationships, :tag, :term]
 | 
			
		||||
    has_one :post_format, through: [:term_relationships, :post_format, :term]
 | 
			
		||||
    belongs_to :author, Content.User, foreign_key: :post_author, references: :ID
 | 
			
		||||
    belongs_to :author, Auth.User, foreign_key: :post_author
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def changeset(struct, params \\ %{}) do
 | 
			
		||||
| 
						 | 
				
			
			@ -123,14 +123,14 @@ defmodule Content.Post do
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def maybe_put_guid(changeset) do
 | 
			
		||||
    import ContentWeb.Router.Helpers, only: [posts_url: 3]
 | 
			
		||||
    import Content.Router.Helpers, only: [posts_url: 3]
 | 
			
		||||
    slug = changeset |> get_field(:post_name)
 | 
			
		||||
 | 
			
		||||
    case slug do
 | 
			
		||||
      nil -> changeset
 | 
			
		||||
      _ ->
 | 
			
		||||
        changeset
 | 
			
		||||
        |> put_default(:guid, posts_url(ContentWeb.Endpoint, :show, slug))
 | 
			
		||||
        |> put_default(:guid, posts_url(CoreWeb.Endpoint, :show, slug))
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -159,6 +159,18 @@ defmodule Content.Posts do
 | 
			
		|||
 | 
			
		||||
  """
 | 
			
		||||
  def get_posts!(slug) do
 | 
			
		||||
    slug
 | 
			
		||||
    |> get_post_scope()
 | 
			
		||||
    |> Repo.one!()
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def get_post(slug) do
 | 
			
		||||
    slug
 | 
			
		||||
    |> get_post_scope()
 | 
			
		||||
    |> Repo.one()
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp get_post_scope(slug) do
 | 
			
		||||
    id_filter = fn scope, id ->
 | 
			
		||||
 | 
			
		||||
      case Integer.parse(id, 10) do
 | 
			
		||||
| 
						 | 
				
			
			@ -172,7 +184,6 @@ defmodule Content.Posts do
 | 
			
		|||
    post_scope()
 | 
			
		||||
    |> where([p], p.post_type != "nav_menu_item")
 | 
			
		||||
    |> id_filter.(slug)
 | 
			
		||||
    |> Repo.one!()
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  @doc """
 | 
			
		||||
| 
						 | 
				
			
			@ -1,12 +1,12 @@
 | 
			
		|||
defmodule ContentWeb do
 | 
			
		||||
defmodule Content do
 | 
			
		||||
  @moduledoc """
 | 
			
		||||
  The entrypoint for defining your web interface, such
 | 
			
		||||
  as controllers, views, channels and so on.
 | 
			
		||||
 | 
			
		||||
  This can be used in your application as:
 | 
			
		||||
 | 
			
		||||
      use ContentWeb, :controller
 | 
			
		||||
      use ContentWeb, :view
 | 
			
		||||
      use Content, :controller
 | 
			
		||||
      use Content, :view
 | 
			
		||||
 | 
			
		||||
  The definitions below will be executed for every view,
 | 
			
		||||
  controller, etc, so keep them short and clean, focused
 | 
			
		||||
| 
						 | 
				
			
			@ -19,11 +19,11 @@ defmodule ContentWeb do
 | 
			
		|||
 | 
			
		||||
  def controller do
 | 
			
		||||
    quote do
 | 
			
		||||
      use Phoenix.Controller, namespace: ContentWeb
 | 
			
		||||
      use Phoenix.Controller, namespace: Content
 | 
			
		||||
 | 
			
		||||
      import Plug.Conn
 | 
			
		||||
      import ContentWeb.Gettext
 | 
			
		||||
      alias ContentWeb.Router.Helpers, as: Routes
 | 
			
		||||
      import Content.Gettext
 | 
			
		||||
      alias Content.Router.Helpers, as: Routes
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -31,13 +31,21 @@ defmodule ContentWeb do
 | 
			
		|||
    quote do
 | 
			
		||||
      use Phoenix.View,
 | 
			
		||||
        root: "lib/content_web/templates",
 | 
			
		||||
        namespace: ContentWeb,
 | 
			
		||||
        namespace: Content,
 | 
			
		||||
        pattern: "**/*"
 | 
			
		||||
 | 
			
		||||
      use PhoenixHtmlSanitizer, :basic_html
 | 
			
		||||
 | 
			
		||||
      # Import convenience functions from controllers
 | 
			
		||||
      import Phoenix.Controller,
 | 
			
		||||
        only: [get_flash: 1, get_flash: 2, view_module: 1, view_template: 1]
 | 
			
		||||
 | 
			
		||||
      def process_content(text) do
 | 
			
		||||
        text
 | 
			
		||||
        |> Content.Shortcodes.expand_shortcodes()
 | 
			
		||||
        |> Earmark.as_html!()
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Include shared imports and aliases for views
 | 
			
		||||
      unquote(view_helpers())
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +63,7 @@ defmodule ContentWeb do
 | 
			
		|||
  def channel do
 | 
			
		||||
    quote do
 | 
			
		||||
      use Phoenix.Channel
 | 
			
		||||
      import ContentWeb.Gettext
 | 
			
		||||
      import Content.Gettext
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -67,9 +75,9 @@ defmodule ContentWeb do
 | 
			
		|||
      # Import basic rendering functionality (render, render_layout, etc)
 | 
			
		||||
      import Phoenix.View
 | 
			
		||||
 | 
			
		||||
      import ContentWeb.ErrorHelpers
 | 
			
		||||
      import ContentWeb.Gettext
 | 
			
		||||
      alias ContentWeb.Router.Helpers, as: Routes
 | 
			
		||||
      import Content.ErrorHelpers
 | 
			
		||||
      import Content.Gettext
 | 
			
		||||
      alias Content.Router.Helpers, as: Routes
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
defmodule ContentWeb.UserSocket do
 | 
			
		||||
defmodule Content.UserSocket do
 | 
			
		||||
  use Phoenix.Socket
 | 
			
		||||
 | 
			
		||||
  ## Channels
 | 
			
		||||
  # channel "room:*", ContentWeb.RoomChannel
 | 
			
		||||
  # channel "room:*", Content.RoomChannel
 | 
			
		||||
 | 
			
		||||
  # Socket params are passed from the client and can
 | 
			
		||||
  # be used to verify and authenticate a user. After
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ defmodule ContentWeb.UserSocket do
 | 
			
		|||
  # Would allow you to broadcast a "disconnect" event and terminate
 | 
			
		||||
  # all active sockets and channels for a given user:
 | 
			
		||||
  #
 | 
			
		||||
  #     ContentWeb.Endpoint.broadcast("user_socket:#{user.id}", "disconnect", %{})
 | 
			
		||||
  #     Content.Endpoint.broadcast("user_socket:#{user.id}", "disconnect", %{})
 | 
			
		||||
  #
 | 
			
		||||
  # Returning `nil` makes this socket anonymous.
 | 
			
		||||
  @impl true
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
defmodule Content.AdminHomeController do
 | 
			
		||||
  use Content, :controller
 | 
			
		||||
 | 
			
		||||
  def index(conn, _params) do
 | 
			
		||||
    render conn, "index.html"
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
defmodule Content.AdminPostsController do
 | 
			
		||||
  use Content, :controller
 | 
			
		||||
 | 
			
		||||
  alias Content.Posts
 | 
			
		||||
 | 
			
		||||
  require Ecto.Query
 | 
			
		||||
 | 
			
		||||
  def index(conn, %{"page" => page, "post_type" => post_type}) do
 | 
			
		||||
    posts = Posts.list_admin_posts(page, post_type)
 | 
			
		||||
    thumbs = posts |> Posts.thumbs_for_posts()
 | 
			
		||||
    last_page = Posts.last_page
 | 
			
		||||
    render(
 | 
			
		||||
      conn,
 | 
			
		||||
      "index.html",
 | 
			
		||||
      [
 | 
			
		||||
        posts: posts,
 | 
			
		||||
        page: String.to_integer(page),
 | 
			
		||||
        last_page: last_page,
 | 
			
		||||
        thumbs: thumbs,
 | 
			
		||||
        post_type: post_type,
 | 
			
		||||
      ]
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
  def index(conn, %{"page" => page} = params), do: index(conn, params |> Map.merge(%{"page" => page, "post_type" => "post"}))
 | 
			
		||||
  def index(conn, %{"post_type" => post_type} = params), do: index(conn, params |> Map.merge(%{"page" => "1", "post_type" => post_type}))
 | 
			
		||||
  def index(conn, params), do: index(conn, params |> Map.merge(%{"page" => "1", "post_type" => "post"}))
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,71 @@
 | 
			
		|||
defmodule Content.CommentController do
 | 
			
		||||
  use Content, :controller
 | 
			
		||||
 | 
			
		||||
  alias Content
 | 
			
		||||
  alias Content.Comments
 | 
			
		||||
  alias Content.Post
 | 
			
		||||
  alias Content.Repo
 | 
			
		||||
 | 
			
		||||
  import Ecto.Query
 | 
			
		||||
 | 
			
		||||
  def create(conn, %{"comment" => comment_params}) do
 | 
			
		||||
    comment_params = comment_params |> Map.merge(%{"comment_author_IP" => to_string(:inet_parse.ntoa(conn.remote_ip))})
 | 
			
		||||
 | 
			
		||||
    case Comments.create_comment(comment_params) do
 | 
			
		||||
      {:ok, comment} ->
 | 
			
		||||
        post =
 | 
			
		||||
          Post
 | 
			
		||||
          |> where([p], p.'ID' == ^comment.comment_post_ID)
 | 
			
		||||
          |> Repo.one()
 | 
			
		||||
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_flash(:info, "Comment created successfully.")
 | 
			
		||||
        |> redirect(to: Routes.posts_path(conn, :show, post))
 | 
			
		||||
      {:error, _} ->
 | 
			
		||||
        post =
 | 
			
		||||
          Post
 | 
			
		||||
          |> where([p], p.'ID' == ^comment_params["comment_post_ID"])
 | 
			
		||||
          |> Repo.one()
 | 
			
		||||
 | 
			
		||||
        conn
 | 
			
		||||
        |> redirect(to: Routes.posts_path(conn, :show, post))
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update(conn, %{"id" => id, "comment" => comment_params}) do
 | 
			
		||||
    comment = Comments.get_comment!(id)
 | 
			
		||||
 | 
			
		||||
    case Comments.update_comment(comment, comment_params) do
 | 
			
		||||
      {:ok, comment} ->
 | 
			
		||||
        post =
 | 
			
		||||
          Post
 | 
			
		||||
          |> where([p], p.'ID' == ^comment.comment_post_ID)
 | 
			
		||||
          |> Repo.one()
 | 
			
		||||
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_flash(:info, "Comment updated successfully.")
 | 
			
		||||
        |> redirect(to: Routes.posts_path(conn, :show, post))
 | 
			
		||||
      {:error, _} ->
 | 
			
		||||
        post =
 | 
			
		||||
          Post
 | 
			
		||||
          |> where([p], p.'ID' == ^comment_params["comment_post_ID"])
 | 
			
		||||
          |> Repo.one()
 | 
			
		||||
 | 
			
		||||
        conn
 | 
			
		||||
        |> redirect(to: Routes.posts_path(conn, :show, post))
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def delete(conn, %{"id" => id}) do
 | 
			
		||||
    comment = Comments.get_comment!(id)
 | 
			
		||||
    {:ok, comment} = Comments.delete_comment(comment)
 | 
			
		||||
    post =
 | 
			
		||||
      Post
 | 
			
		||||
      |> where([p], p.'ID' == ^comment.comment_post_ID)
 | 
			
		||||
      |> Repo.one()
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> put_flash(:info, "Comment deleted successfully.")
 | 
			
		||||
    |> redirect(to: Routes.posts_path(conn, :show, post))
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										33
									
								
								apps/content/lib/content_web/controllers/feeds_controller.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								apps/content/lib/content_web/controllers/feeds_controller.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,33 @@
 | 
			
		|||
defmodule Content.FeedsController do
 | 
			
		||||
  use Content, :controller
 | 
			
		||||
 | 
			
		||||
  alias Content.{Posts}
 | 
			
		||||
 | 
			
		||||
  plug :put_layout, false when action in [:preview]
 | 
			
		||||
 | 
			
		||||
  def index(conn, params) do
 | 
			
		||||
    category = params |> Map.get("category")
 | 
			
		||||
    posts =  Posts.list_posts(params)
 | 
			
		||||
    thumbs = posts |> Posts.thumbs_for_posts()
 | 
			
		||||
 | 
			
		||||
    feed_url =
 | 
			
		||||
      case category do
 | 
			
		||||
        nil ->
 | 
			
		||||
          Routes.index_feed_path(conn, :index)
 | 
			
		||||
        _ ->
 | 
			
		||||
          Routes.category_feed_path(conn, :index, category)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> put_resp_content_type("text/xml")
 | 
			
		||||
    |> render(
 | 
			
		||||
      "index.rss",
 | 
			
		||||
      [
 | 
			
		||||
        posts: posts,
 | 
			
		||||
        thumbs: thumbs,
 | 
			
		||||
        category: category,
 | 
			
		||||
        feed_url: feed_url,
 | 
			
		||||
      ]
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										39
									
								
								apps/content/lib/content_web/controllers/menus_controller.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								apps/content/lib/content_web/controllers/menus_controller.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
defmodule Content.MenusController do
 | 
			
		||||
  use Content, :controller
 | 
			
		||||
 | 
			
		||||
  alias Content.Repo
 | 
			
		||||
 | 
			
		||||
  def edit(conn, %{"id" => id}) do
 | 
			
		||||
    menu = id |> Content.Menu.get_menu_from_id()
 | 
			
		||||
    posts =
 | 
			
		||||
      Content.Posts.post_scope
 | 
			
		||||
      |> Repo.all()
 | 
			
		||||
      |> Enum.map(fn post ->
 | 
			
		||||
        post |> Map.take([:ID, :post_title, :post_name])
 | 
			
		||||
      end)
 | 
			
		||||
    categories =
 | 
			
		||||
      Content.Terms.categories
 | 
			
		||||
      |> Repo.all()
 | 
			
		||||
      |> Enum.map(fn cat ->
 | 
			
		||||
        cat |> Map.take([:name, :slug, :term_group, :term_id])
 | 
			
		||||
      end)
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> render(
 | 
			
		||||
      "edit.html",
 | 
			
		||||
      [
 | 
			
		||||
        id: id,
 | 
			
		||||
        menu: menu,
 | 
			
		||||
        posts: posts,
 | 
			
		||||
        categories: categories,
 | 
			
		||||
      ]
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update(conn, %{"id" => id, "menu" => menu}) do
 | 
			
		||||
    Content.UpdateMenu.run(id, menu |> Phoenix.json_library().decode!())
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> redirect(to: Routes.menus_path(conn, :edit, id))
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
defmodule ContentWeb.PageController do
 | 
			
		||||
  use ContentWeb, :controller
 | 
			
		||||
defmodule Content.PageController do
 | 
			
		||||
  use Content, :controller
 | 
			
		||||
 | 
			
		||||
  def index(conn, _params) do
 | 
			
		||||
    render(conn, "index.html")
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
defmodule Content.PostPasswordController do
 | 
			
		||||
  use Content, :controller
 | 
			
		||||
 | 
			
		||||
  def create(conn, %{"post_password" => post_password}) do
 | 
			
		||||
    conn = put_session(conn, "post_password", post_password)
 | 
			
		||||
 | 
			
		||||
    redirect_path =
 | 
			
		||||
      if Enum.count(get_req_header(conn, "referer")) > 0 do
 | 
			
		||||
        conn
 | 
			
		||||
        |> get_req_header("referer")
 | 
			
		||||
        |> Enum.at(0)
 | 
			
		||||
        |> URI.parse()
 | 
			
		||||
        |> (&(&1.path)).()
 | 
			
		||||
      else
 | 
			
		||||
        "/"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    redirect conn, to: redirect_path
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										176
									
								
								apps/content/lib/content_web/controllers/posts_controller.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								apps/content/lib/content_web/controllers/posts_controller.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,176 @@
 | 
			
		|||
defmodule Content.PostsController do
 | 
			
		||||
  use Content, :controller
 | 
			
		||||
 | 
			
		||||
  alias Auth.User
 | 
			
		||||
  alias Content.{Options, Post, Posts, Repo}
 | 
			
		||||
 | 
			
		||||
  plug :put_layout, false when action in [:preview]
 | 
			
		||||
 | 
			
		||||
  def index(conn, params) do
 | 
			
		||||
    show_on_front = Options.get_value("show_on_front") || "posts"
 | 
			
		||||
 | 
			
		||||
    case show_on_front do
 | 
			
		||||
      "posts" ->
 | 
			
		||||
        conn |> index_posts(params)
 | 
			
		||||
      "page" ->
 | 
			
		||||
        conn |> index_page(params)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def index_posts(conn, params) do
 | 
			
		||||
    page = params |> Map.get("page", "1")
 | 
			
		||||
    params = params |> Map.merge(%{"page" => page})
 | 
			
		||||
    category = params |> Map.get("category")
 | 
			
		||||
    posts =  Posts.list_posts(params)
 | 
			
		||||
    thumbs = posts |> Posts.thumbs_for_posts()
 | 
			
		||||
    last_page = Posts.last_page(params)
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> render(
 | 
			
		||||
      "index.html",
 | 
			
		||||
      [
 | 
			
		||||
        posts: posts,
 | 
			
		||||
        page: String.to_integer(page),
 | 
			
		||||
        last_page: last_page,
 | 
			
		||||
        thumbs: thumbs,
 | 
			
		||||
        category: category,
 | 
			
		||||
      ]
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def index_page(conn, _params) do
 | 
			
		||||
    page_id = Options.get("page_on_front") |> (&(&1.option_value)).()
 | 
			
		||||
 | 
			
		||||
    post = Posts.get_posts!(page_id)
 | 
			
		||||
    page = String.to_integer("1")
 | 
			
		||||
    thumbs = [post] |> Posts.thumbs_for_posts()
 | 
			
		||||
    render(conn, "front.html", post: post, page: page, thumbs: thumbs)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def new(conn, params) do
 | 
			
		||||
    changeset = Posts.change_posts(%Post{})
 | 
			
		||||
    render(
 | 
			
		||||
      conn,
 | 
			
		||||
      "new.html",
 | 
			
		||||
      changeset: changeset,
 | 
			
		||||
      post_type: params["post_type"] || "post",
 | 
			
		||||
      author_options: User |> Repo.all()
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create(conn, %{"post" => post_params}) do
 | 
			
		||||
    case Posts.create_posts(post_params) do
 | 
			
		||||
      {:ok, post} ->
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_flash(:info, "Posts created successfully.")
 | 
			
		||||
        |> redirect(to: Routes.posts_path(conn, :show, post))
 | 
			
		||||
      {:error, %Ecto.Changeset{} = changeset} ->
 | 
			
		||||
        render(
 | 
			
		||||
          conn,
 | 
			
		||||
          "new.html",
 | 
			
		||||
          changeset: changeset,
 | 
			
		||||
          post_type: post_params["post_type"] || "post",
 | 
			
		||||
          author_options: User |> Repo.all()
 | 
			
		||||
        )
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def preview(conn, %{"post" => post_params}) do
 | 
			
		||||
    post = Posts.preview_post(post_params)
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> render("show.html", post: post, page: 1, thumbs: [])
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show(conn, %{"id" => id, "page" => page_string}) do
 | 
			
		||||
    {page_id_for_posts, _} = Options.get_value_as_int("page_for_posts")
 | 
			
		||||
 | 
			
		||||
    post = Posts.get_post(id)
 | 
			
		||||
 | 
			
		||||
    if is_nil(post) do
 | 
			
		||||
      try_static_post(conn, id)
 | 
			
		||||
    else
 | 
			
		||||
      if post.'ID' == page_id_for_posts do
 | 
			
		||||
        conn |> index_posts(%{"id" => id, "page" => page_string})
 | 
			
		||||
      else
 | 
			
		||||
        conn |> show_one(post, page_string)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
  def show(conn, %{"id" => id}), do: show(conn, %{"id" => id, "page" => "1"})
 | 
			
		||||
 | 
			
		||||
  defp try_static_post(conn, id) do
 | 
			
		||||
    try do
 | 
			
		||||
      render(conn, "static_pages/#{id}.html")
 | 
			
		||||
    rescue
 | 
			
		||||
      Phoenix.Template.UndefinedError ->
 | 
			
		||||
      raise Phoenix.Router.NoRouteError.exception(conn: conn, router: Content.Router)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show_one(conn, post, page_string) do
 | 
			
		||||
    {front_page_id, _} = Options.get_value_as_int("page_on_front")
 | 
			
		||||
 | 
			
		||||
    template =
 | 
			
		||||
      if post.'ID' == front_page_id do
 | 
			
		||||
        "front.html"
 | 
			
		||||
      else
 | 
			
		||||
        "show.html"
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    page = String.to_integer(page_string)
 | 
			
		||||
    thumbs = [post] |> Posts.thumbs_for_posts()
 | 
			
		||||
    case post.post_type do
 | 
			
		||||
      "attachment" ->
 | 
			
		||||
        {:ok, decoded} = post.post_content |> Base.decode64
 | 
			
		||||
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_resp_content_type(post.post_mime_type, "binary")
 | 
			
		||||
        |> send_resp(conn.status || 200, decoded)
 | 
			
		||||
      _ ->
 | 
			
		||||
        render(conn, template, post: post, page: page, thumbs: thumbs)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def edit(conn, %{"id" => id}) do
 | 
			
		||||
    posts = Posts.get_post_with_drafts!(id)
 | 
			
		||||
    changeset = Posts.change_posts(posts)
 | 
			
		||||
    render(
 | 
			
		||||
      conn,
 | 
			
		||||
      "edit.html",
 | 
			
		||||
      posts: posts,
 | 
			
		||||
      changeset: changeset,
 | 
			
		||||
      post_type: posts.post_type || "post",
 | 
			
		||||
      author_options: User |> Repo.all()
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update(conn, %{"id" => id, "post" => posts_params}) do
 | 
			
		||||
    posts = Posts.get_post_with_drafts!(id)
 | 
			
		||||
 | 
			
		||||
    case Posts.update_posts(posts, posts_params) do
 | 
			
		||||
      {:ok, posts} ->
 | 
			
		||||
        conn
 | 
			
		||||
        |> put_flash(:info, "Posts updated successfully.")
 | 
			
		||||
        |> redirect(to: Routes.posts_path(conn, :edit, posts))
 | 
			
		||||
      {:error, %Ecto.Changeset{} = changeset} ->
 | 
			
		||||
        render(
 | 
			
		||||
          conn,
 | 
			
		||||
          "edit.html",
 | 
			
		||||
          posts: posts,
 | 
			
		||||
          changeset: changeset,
 | 
			
		||||
          post_type: posts.post_type || "post",
 | 
			
		||||
          author_options: User |> Repo.all()
 | 
			
		||||
        )
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def delete(conn, %{"id" => id}) do
 | 
			
		||||
    posts = Posts.get_post_with_drafts!(id)
 | 
			
		||||
    {:ok, _posts} = Posts.delete_posts(posts)
 | 
			
		||||
 | 
			
		||||
    conn
 | 
			
		||||
    |> put_flash(:info, "Posts deleted successfully.")
 | 
			
		||||
    |> redirect(to: Routes.admin_posts_path(conn, :index))
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
defmodule Content.SitemapController do
 | 
			
		||||
  use Content, :controller
 | 
			
		||||
 | 
			
		||||
  alias Content.{Posts, Repo, Terms}
 | 
			
		||||
 | 
			
		||||
  import Ecto.Query
 | 
			
		||||
 | 
			
		||||
  def index(conn, _params) do
 | 
			
		||||
    posts =
 | 
			
		||||
      Posts.post_scope
 | 
			
		||||
      |> where([p], p.post_type not in ["nav_menu_item", "attachment"])
 | 
			
		||||
      |> Repo.all()
 | 
			
		||||
 | 
			
		||||
    categories =
 | 
			
		||||
      Terms.categories
 | 
			
		||||
        |> Repo.all()
 | 
			
		||||
 | 
			
		||||
    render(conn, "index.html", conn: conn, posts: posts, categories: categories)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
defmodule ContentWeb.Endpoint do
 | 
			
		||||
  use Phoenix.Endpoint, otp_app: :content_web
 | 
			
		||||
defmodule Content.Endpoint do
 | 
			
		||||
  use Phoenix.Endpoint, otp_app: :content
 | 
			
		||||
 | 
			
		||||
  # The session will be stored in the cookie and signed,
 | 
			
		||||
  # this means its contents can be read but not tampered with.
 | 
			
		||||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ defmodule ContentWeb.Endpoint do
 | 
			
		|||
    signing_salt: "wfYQp84C"
 | 
			
		||||
  ]
 | 
			
		||||
 | 
			
		||||
  socket "/socket", ContentWeb.UserSocket,
 | 
			
		||||
  socket "/socket", Content.UserSocket,
 | 
			
		||||
    websocket: true,
 | 
			
		||||
    longpoll: false
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ defmodule ContentWeb.Endpoint do
 | 
			
		|||
  # when deploying your static files in production.
 | 
			
		||||
  plug Plug.Static,
 | 
			
		||||
    at: "/",
 | 
			
		||||
    from: :content_web,
 | 
			
		||||
    from: :content,
 | 
			
		||||
    gzip: false,
 | 
			
		||||
    only: ~w(css fonts images js favicon.ico robots.txt)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -32,7 +32,7 @@ defmodule ContentWeb.Endpoint do
 | 
			
		|||
    socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket
 | 
			
		||||
    plug Phoenix.LiveReloader
 | 
			
		||||
    plug Phoenix.CodeReloader
 | 
			
		||||
    plug Phoenix.Ecto.CheckRepoStatus, otp_app: :content_web
 | 
			
		||||
    plug Phoenix.Ecto.CheckRepoStatus, otp_app: :content
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  plug Phoenix.LiveDashboard.RequestLogger,
 | 
			
		||||
| 
						 | 
				
			
			@ -50,6 +50,6 @@ defmodule ContentWeb.Endpoint do
 | 
			
		|||
  plug Plug.MethodOverride
 | 
			
		||||
  plug Plug.Head
 | 
			
		||||
  plug Plug.Session, @session_options
 | 
			
		||||
  plug Pow.Plug.Session, otp_app: :content_web
 | 
			
		||||
  plug ContentWeb.Router
 | 
			
		||||
  plug Pow.Plug.Session, otp_app: :content
 | 
			
		||||
  plug Content.Router
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,11 +1,11 @@
 | 
			
		|||
defmodule ContentWeb.Gettext do
 | 
			
		||||
defmodule Content.Gettext do
 | 
			
		||||
  @moduledoc """
 | 
			
		||||
  A module providing Internationalization with a gettext-based API.
 | 
			
		||||
 | 
			
		||||
  By using [Gettext](https://hexdocs.pm/gettext),
 | 
			
		||||
  your module gains a set of macros for translations, for example:
 | 
			
		||||
 | 
			
		||||
      import ContentWeb.Gettext
 | 
			
		||||
      import Content.Gettext
 | 
			
		||||
 | 
			
		||||
      # Simple translation
 | 
			
		||||
      gettext("Here is the string to translate")
 | 
			
		||||
| 
						 | 
				
			
			@ -20,5 +20,5 @@ defmodule ContentWeb.Gettext do
 | 
			
		|||
 | 
			
		||||
  See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.
 | 
			
		||||
  """
 | 
			
		||||
  use Gettext, otp_app: :content_web
 | 
			
		||||
  use Gettext, otp_app: :content
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										36
									
								
								apps/content/lib/content_web/plugs/load_user.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								apps/content/lib/content_web/plugs/load_user.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,36 @@
 | 
			
		|||
defmodule Content.LoadUser do
 | 
			
		||||
  @moduledoc """
 | 
			
		||||
  Loads user into connection if user has session
 | 
			
		||||
  """
 | 
			
		||||
 | 
			
		||||
  import Plug.Conn
 | 
			
		||||
  alias Content.Users
 | 
			
		||||
 | 
			
		||||
  def init(opts) do
 | 
			
		||||
    opts
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def call(conn, _) do
 | 
			
		||||
    handle_auth(conn)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp handle_auth(conn) do
 | 
			
		||||
    user_id = get_session(conn, :user_id)
 | 
			
		||||
 | 
			
		||||
    if user = (user_id && Users.get_user(user_id)) do
 | 
			
		||||
      build_conn(conn, user)
 | 
			
		||||
    else
 | 
			
		||||
      build_conn(conn, nil)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp build_conn(conn, nil) do
 | 
			
		||||
    conn
 | 
			
		||||
    |> assign(:current_user, nil)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  defp build_conn(conn, user) do
 | 
			
		||||
    conn
 | 
			
		||||
    |> assign(:current_user, user)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										22
									
								
								apps/content/lib/content_web/plugs/require_admin.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								apps/content/lib/content_web/plugs/require_admin.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
defmodule Content.RequireAdmin do
 | 
			
		||||
  @moduledoc """
 | 
			
		||||
  A plug that returns 403 unauthorized if the user is not an admin. Used
 | 
			
		||||
  to block out logged-in-only routes.
 | 
			
		||||
  """
 | 
			
		||||
  import Plug.Conn
 | 
			
		||||
  alias Auth.User
 | 
			
		||||
 | 
			
		||||
  def init(opts) do
 | 
			
		||||
    opts
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def call(conn, _opts) do
 | 
			
		||||
    if conn.assigns[:current_user] && User.is_admin?(conn.assigns[:current_user]) do
 | 
			
		||||
      conn
 | 
			
		||||
    else
 | 
			
		||||
      conn
 | 
			
		||||
      |> send_resp(403, "Unauthorized")
 | 
			
		||||
      |> halt()
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										22
									
								
								apps/content/lib/content_web/plugs/require_auth.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								apps/content/lib/content_web/plugs/require_auth.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
defmodule Content.RequireAuth do
 | 
			
		||||
  @moduledoc """
 | 
			
		||||
  A plug that returns 403 unauthorized if the user is not authenticated. Used
 | 
			
		||||
  to block out logged-in-only routes.
 | 
			
		||||
  """
 | 
			
		||||
  import Plug.Conn
 | 
			
		||||
 | 
			
		||||
  def init(opts) do
 | 
			
		||||
    opts
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def call(conn, _) do
 | 
			
		||||
    case conn.assigns[:current_user] do
 | 
			
		||||
      nil ->
 | 
			
		||||
        conn
 | 
			
		||||
        |> send_resp(403, "Unauthorized")
 | 
			
		||||
        |> halt()
 | 
			
		||||
      _user ->
 | 
			
		||||
        conn
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										72
									
								
								apps/content/lib/content_web/router.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								apps/content/lib/content_web/router.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,72 @@
 | 
			
		|||
defmodule Content.Router do
 | 
			
		||||
  use Content, :router
 | 
			
		||||
  alias Content.{RequireAdmin, RequireAuth}
 | 
			
		||||
 | 
			
		||||
  pipeline :browser do
 | 
			
		||||
    plug :accepts, ["html"]
 | 
			
		||||
    plug :fetch_session
 | 
			
		||||
    plug :fetch_flash
 | 
			
		||||
    plug :protect_from_forgery
 | 
			
		||||
    plug :put_secure_browser_headers
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  pipeline :api do
 | 
			
		||||
    plug :accepts, ["json"]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  pipeline :feed do
 | 
			
		||||
    plug :accepts, ["rss"]
 | 
			
		||||
    plug :fetch_session
 | 
			
		||||
    plug :protect_from_forgery
 | 
			
		||||
    plug :put_secure_browser_headers
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  pipeline :require_auth do
 | 
			
		||||
    plug(RequireAuth)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  pipeline :require_admin do
 | 
			
		||||
    plug(RequireAdmin)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  pipeline :admin_layout do
 | 
			
		||||
    plug :put_layout, {Content.LayoutView, :admin}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  scope "/", Content do
 | 
			
		||||
    pipe_through([:browser, :require_auth, :require_admin, :admin_layout])
 | 
			
		||||
 | 
			
		||||
    get "/wp-admin/", AdminHomeController, :index
 | 
			
		||||
    get "/posts", AdminPostsController, :index, as: :admin_posts
 | 
			
		||||
    post "/posts", PostsController, :create
 | 
			
		||||
    get "/posts/new", PostsController, :new
 | 
			
		||||
    put "/posts/preview", PostsController, :preview
 | 
			
		||||
    post "/posts/preview", PostsController, :preview
 | 
			
		||||
    get "/posts/:id/edit", PostsController, :edit
 | 
			
		||||
    put "/posts/:id", PostsController, :update
 | 
			
		||||
    delete "/posts/:id", PostsController, :delete
 | 
			
		||||
    get "/menus/:id/edit", MenusController, :edit
 | 
			
		||||
    put "/menus/:id", MenusController, :update
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  scope "/", Content do
 | 
			
		||||
    pipe_through :feed # Use the default browser stack
 | 
			
		||||
 | 
			
		||||
    get "/category/:category/feed.rss", FeedsController, :index, as: :category_feed
 | 
			
		||||
    get "/feed.rss", FeedsController, :index, as: :index_feed
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  scope "/", Content do
 | 
			
		||||
    pipe_through :browser # Use the default browser stack
 | 
			
		||||
 | 
			
		||||
    resources "/comments", CommentController, as: :comment, only: [:create, :delete, :update]
 | 
			
		||||
    get "/page/:page", PostsController, :index_posts, as: :blog_page
 | 
			
		||||
    get "/category/:category", PostsController, :index_posts, as: :category
 | 
			
		||||
    get "/category/:category/page/:page", PostsController, :index, as: :category_page
 | 
			
		||||
    post "/wp-login.php", PostPasswordController, :create
 | 
			
		||||
    get "/", PostsController, :index
 | 
			
		||||
    resources "/sitemap", SitemapController, only: [:index]
 | 
			
		||||
    get "/:id", PostsController, :show
 | 
			
		||||
    get "/:id/:page", PostsController, :show, as: :paged_post
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
defmodule ContentWeb.Telemetry do
 | 
			
		||||
defmodule Content.Telemetry do
 | 
			
		||||
  @moduledoc """
 | 
			
		||||
  Collects metrics for the application and allows them to be transmitted using the Telemetry framework.
 | 
			
		||||
  """
 | 
			
		||||
| 
						 | 
				
			
			@ -34,11 +34,11 @@ defmodule ContentWeb.Telemetry do
 | 
			
		|||
      ),
 | 
			
		||||
 | 
			
		||||
      # Database Metrics
 | 
			
		||||
      summary("content_web.repo.query.total_time", unit: {:native, :millisecond}),
 | 
			
		||||
      summary("content_web.repo.query.decode_time", unit: {:native, :millisecond}),
 | 
			
		||||
      summary("content_web.repo.query.query_time", unit: {:native, :millisecond}),
 | 
			
		||||
      summary("content_web.repo.query.queue_time", unit: {:native, :millisecond}),
 | 
			
		||||
      summary("content_web.repo.query.idle_time", unit: {:native, :millisecond}),
 | 
			
		||||
      summary("content.repo.query.total_time", unit: {:native, :millisecond}),
 | 
			
		||||
      summary("content.repo.query.decode_time", unit: {:native, :millisecond}),
 | 
			
		||||
      summary("content.repo.query.query_time", unit: {:native, :millisecond}),
 | 
			
		||||
      summary("content.repo.query.queue_time", unit: {:native, :millisecond}),
 | 
			
		||||
      summary("content.repo.query.idle_time", unit: {:native, :millisecond}),
 | 
			
		||||
 | 
			
		||||
      # VM Metrics
 | 
			
		||||
      summary("vm.memory.total", unit: {:byte, :kilobyte}),
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +52,7 @@ defmodule ContentWeb.Telemetry do
 | 
			
		|||
    [
 | 
			
		||||
      # A module, function and arguments to be invoked periodically.
 | 
			
		||||
      # This function must call :telemetry.execute/3 and a metric must be added above.
 | 
			
		||||
      # {ContentWeb, :count_users, []}
 | 
			
		||||
      # {Content, :count_users, []}
 | 
			
		||||
    ]
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
<h1>Dashboard</h1>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,93 @@
 | 
			
		|||
<div class="grid">
 | 
			
		||||
  <div class="column">
 | 
			
		||||
    <h1>
 | 
			
		||||
      <%= humanize(@post_type) %>s
 | 
			
		||||
    </h1>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="column admin-actions">
 | 
			
		||||
    <%= link "New " <> humanize(@post_type), to: Routes.posts_path(@conn, :new, post_type: @post_type), class: "button" %>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<table class="admin-table small">
 | 
			
		||||
  <thead>
 | 
			
		||||
    <tr>
 | 
			
		||||
      <th>Title</th>
 | 
			
		||||
      <th>Author</th>
 | 
			
		||||
      <th>Categories</th>
 | 
			
		||||
      <th>Tags</th>
 | 
			
		||||
      <th>Comments</th>
 | 
			
		||||
      <th>Date</th>
 | 
			
		||||
    </tr>
 | 
			
		||||
  </thead>
 | 
			
		||||
  <tbody>
 | 
			
		||||
    <%= for post <- @posts do %>
 | 
			
		||||
      <tr>
 | 
			
		||||
        <td>
 | 
			
		||||
          <%= link post.post_title, to: Routes.posts_path(@conn, :edit, post) %>
 | 
			
		||||
        </td>
 | 
			
		||||
        <td>
 | 
			
		||||
          <%= if !is_nil(post.author) do %>
 | 
			
		||||
            <%= post.author.display_name %>
 | 
			
		||||
          <% end %>
 | 
			
		||||
        </td>
 | 
			
		||||
        <td>
 | 
			
		||||
          <%= post.categories |> Enum.map(&(&1.name)) |> Enum.join(", ") %>
 | 
			
		||||
        </td>
 | 
			
		||||
        <td>
 | 
			
		||||
          <%= post.tags |> Enum.map(&(&1.name)) |> Enum.join(", ") %>
 | 
			
		||||
        </td>
 | 
			
		||||
        <td>
 | 
			
		||||
          <%= post.comments |> Enum.count() %>
 | 
			
		||||
        </td>
 | 
			
		||||
        <td>
 | 
			
		||||
          <%= case post.post_status do %>
 | 
			
		||||
            <% "publish" -> %>
 | 
			
		||||
              <%= "Published" %>
 | 
			
		||||
            <% "future" ->  %>
 | 
			
		||||
              <%= "Scheduled" %>
 | 
			
		||||
            <% "draft" -> %>
 | 
			
		||||
              <%= "Last Modified" %>
 | 
			
		||||
            <% "pending" ->  %>
 | 
			
		||||
              <%= "Scheduled" %>
 | 
			
		||||
            <% "private" ->  %>
 | 
			
		||||
              <%= "Published Privately" %>
 | 
			
		||||
            <% "inherit" ->  %>
 | 
			
		||||
              <%= "Inherit" %>
 | 
			
		||||
          <% end %>
 | 
			
		||||
          <div>
 | 
			
		||||
            <%= post.post_date |> Timex.format!("%F", :strftime) %>
 | 
			
		||||
          </div>
 | 
			
		||||
        </td>
 | 
			
		||||
      </tr>
 | 
			
		||||
    <% end %>
 | 
			
		||||
  </tbody>
 | 
			
		||||
</table>
 | 
			
		||||
 | 
			
		||||
<hr />
 | 
			
		||||
 | 
			
		||||
<%= if @page > 1 do %>
 | 
			
		||||
  <%= link 1, to: Routes.admin_posts_path(@conn, :index, page: 1) %>
 | 
			
		||||
<% end %>
 | 
			
		||||
 | 
			
		||||
<%= if @page > 3 do %>
 | 
			
		||||
  ...
 | 
			
		||||
<% end %>
 | 
			
		||||
 | 
			
		||||
<%= if @page > 2 do %>
 | 
			
		||||
  <%= link @page - 1, to: Routes.admin_posts_path(@conn, :index, page: @page - 1) %>
 | 
			
		||||
<% end %>
 | 
			
		||||
 | 
			
		||||
<%= @page %>
 | 
			
		||||
 | 
			
		||||
<%= if @page + 1 < @last_page do %>
 | 
			
		||||
  <%= link @page + 1, to: Routes.admin_posts_path(@conn, :index, page: @page + 1) %>
 | 
			
		||||
<% end %>
 | 
			
		||||
 | 
			
		||||
<%= if @page + 2 < @last_page do %>
 | 
			
		||||
  ...
 | 
			
		||||
<% end %>
 | 
			
		||||
 | 
			
		||||
<%= if @page < @last_page do %>
 | 
			
		||||
  <%= link @last_page, to: Routes.admin_posts_path(@conn, :index, page: @last_page) %>
 | 
			
		||||
<% end %>
 | 
			
		||||
							
								
								
									
										24
									
								
								apps/content/lib/content_web/templates/feeds/index.rss.eex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								apps/content/lib/content_web/templates/feeds/index.rss.eex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
 | 
			
		||||
  <channel>
 | 
			
		||||
    <title><%= LayoutView.title(@view_module, @view_template, assigns) %></title>
 | 
			
		||||
    <description><%= LayoutView.excerpt(@view_module, @view_template, assigns) %></description>
 | 
			
		||||
    <link>https://pre.hn</link>
 | 
			
		||||
    <atom:link href="https://pre.hn<%= @feed_url %>" rel="self" type="application/rss+xml" />
 | 
			
		||||
 | 
			
		||||
<%= for post <- @posts do %>
 | 
			
		||||
    <item>
 | 
			
		||||
      <title><%= post.post_title |> HtmlSanitizeEx.strip_tags() %></title>
 | 
			
		||||
      <description>
 | 
			
		||||
        <%= post.post_content |> process_content |> html_escape |> safe_to_string %>
 | 
			
		||||
      </description>
 | 
			
		||||
      <pubDate><%=
 | 
			
		||||
        post.post_date
 | 
			
		||||
        |> DateTime.from_naive!("Etc/UTC")
 | 
			
		||||
        |> Timex.format!("{WDshort}, {D} {Mshort} {YYYY} {h24}:{m}:{s} {Z}")
 | 
			
		||||
      %></pubDate>
 | 
			
		||||
      <guid isPermaLink="true"><%= post.guid %></guid>
 | 
			
		||||
    </item>
 | 
			
		||||
<% end %>
 | 
			
		||||
  </channel>
 | 
			
		||||
</rss>
 | 
			
		||||
							
								
								
									
										61
									
								
								apps/content/lib/content_web/templates/layout/admin.html.eex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								apps/content/lib/content_web/templates/layout/admin.html.eex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,61 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
  <head>
 | 
			
		||||
    <meta charset="utf-8">
 | 
			
		||||
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
			
		||||
    <meta name="description" content="">
 | 
			
		||||
    <meta name="author" content="">
 | 
			
		||||
 | 
			
		||||
    <title><%= title(@view_module, @view_template, assigns) %></title>
 | 
			
		||||
    <link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>">
 | 
			
		||||
    <link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/admin.css") %>">
 | 
			
		||||
  </head>
 | 
			
		||||
 | 
			
		||||
  <body>
 | 
			
		||||
    <div class="container">
 | 
			
		||||
      <main role="main" class="grid">
 | 
			
		||||
        <nav class="column admin-nav">
 | 
			
		||||
          <menu type="list">
 | 
			
		||||
            <li>
 | 
			
		||||
              <%= link "🏠 Home", to: Routes.admin_home_path(@conn, :index) %>
 | 
			
		||||
            </li>
 | 
			
		||||
            <li>
 | 
			
		||||
              <%= link "📝 Posts", to: Routes.admin_posts_path(@conn, :index) %>
 | 
			
		||||
            </li>
 | 
			
		||||
            <li>
 | 
			
		||||
              <%= link "📄 Pages", to: Routes.admin_posts_path(@conn, :index, post_type: "page") %>
 | 
			
		||||
            </li>
 | 
			
		||||
            <li>
 | 
			
		||||
              <%= link "👋 Logout", to: AuthWeb.Router.Helpers.pow_session_path(@conn, :delete), method: :delete %>
 | 
			
		||||
            </li>
 | 
			
		||||
          </menu>
 | 
			
		||||
        </nav>
 | 
			
		||||
        <section class="column four with-gutters ">
 | 
			
		||||
          <%= if get_flash(@conn, :info) do %>
 | 
			
		||||
            <input type="checkbox" id="dismiss-alert-info" class="alert-dismisser" />
 | 
			
		||||
            <div class="alert alert-info" role="alert">
 | 
			
		||||
              <p class="alert-text">
 | 
			
		||||
                <%= get_flash(@conn, :info) %>
 | 
			
		||||
                <label for="dismiss-alert-info">Dismiss</label>
 | 
			
		||||
              </p>
 | 
			
		||||
            </div>
 | 
			
		||||
          <% end %>
 | 
			
		||||
          <%= if get_flash(@conn, :error) do %>
 | 
			
		||||
            <input type="checkbox" id="dismiss-alert-error" class="alert-dismisser" />
 | 
			
		||||
            <div class="alert alert-error" role="alert">
 | 
			
		||||
              <p class="alert-text">
 | 
			
		||||
                <%= get_flash(@conn, :error) %>
 | 
			
		||||
                <label for="dismiss-alert-error">Dismiss</label>
 | 
			
		||||
              </p>
 | 
			
		||||
            </div>
 | 
			
		||||
          <% end %>
 | 
			
		||||
          <%= @inner_content %>
 | 
			
		||||
        </section>
 | 
			
		||||
      </main>
 | 
			
		||||
 | 
			
		||||
    </div> <!-- /container -->
 | 
			
		||||
    <script src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
 | 
			
		||||
    <script src="<%= Routes.static_path(@conn, "/js/admin.js") %>"></script>
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
<div data-react-component="MenuEditor" data-react-props="<%= %{menu: @menu, posts: @posts, categories: @categories, id: @id} |> Phoenix.json_library().encode!() |> Base.encode64() %>">
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<%= form_for @conn, Routes.menus_path(@conn, :update, @id), [method: :put], fn _f -> %>
 | 
			
		||||
<% end %>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
<%= Enum.map(Content.Comments.children(@parent_id, @post.comments), fn comment -> %>
 | 
			
		||||
  <li class="Comment">
 | 
			
		||||
    <div class="Comment-topmatter">
 | 
			
		||||
      <span class="Gravatar" style="background-image: url(<%= comment.comment_author_email |> gravatar_url_for_email %>)">
 | 
			
		||||
      </span>
 | 
			
		||||
      <h4>
 | 
			
		||||
        <%= comment.comment_author  || "Anonymous" %>
 | 
			
		||||
      </h4>
 | 
			
		||||
      <h5>
 | 
			
		||||
        <%= comment.comment_date |> Timex.format!("%F", :strftime) %>
 | 
			
		||||
      </h5>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="Comment-content">
 | 
			
		||||
      <%= sanitize comment.comment_content |> auto_paragraph_tags |> elem(1) |> IO.iodata_to_binary() %>
 | 
			
		||||
      <p class="Comment-actions">
 | 
			
		||||
        <a href="#reply-to-<%= comment.comment_ID %>" class="Comment--replyLink">
 | 
			
		||||
          ➦ Reply
 | 
			
		||||
        </a>
 | 
			
		||||
      </p>
 | 
			
		||||
    </div>
 | 
			
		||||
    <ul class="CommentList">
 | 
			
		||||
      <%= render "comments.html", post: @post, parent_id: comment.comment_ID, conn: @conn %>
 | 
			
		||||
      <li class="Comment Comment--replyForm" id="reply-to-<%= comment.comment_ID %>">
 | 
			
		||||
        <h4>
 | 
			
		||||
          Reply to <%= comment.comment_author  || "Anonymous" %>
 | 
			
		||||
        </h4>
 | 
			
		||||
        <%=
 | 
			
		||||
          render "reply_form.html",
 | 
			
		||||
            comment_changeset: comment_changeset_for_parent(comment),
 | 
			
		||||
            conn: @conn
 | 
			
		||||
        %>
 | 
			
		||||
      </li>
 | 
			
		||||
    </ul>
 | 
			
		||||
  </li>
 | 
			
		||||
<% end) %>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
<%= render "form.html", Map.put(assigns, :action, Routes.posts_path(@conn, :update, @posts)) %>
 | 
			
		||||
							
								
								
									
										82
									
								
								apps/content/lib/content_web/templates/posts/form.html.eex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								apps/content/lib/content_web/templates/posts/form.html.eex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,82 @@
 | 
			
		|||
<%= form_for @changeset, @action, fn f -> %>
 | 
			
		||||
  <div class="grid">
 | 
			
		||||
    <div class="column three">
 | 
			
		||||
      <%= if @changeset.action do %>
 | 
			
		||||
        <div class="alert alert-danger">
 | 
			
		||||
          <p>Oops, something went wrong! Please check the errors below.</p>
 | 
			
		||||
        </div>
 | 
			
		||||
        <ul>
 | 
			
		||||
          <%= for {error_key, error} <- @changeset.errors |> Keyword.drop([:post_title, :post_content]) do %>
 | 
			
		||||
            <%= if error do %>
 | 
			
		||||
              <li><%= error_key %>: <%= error_tag f, error_key %></li>
 | 
			
		||||
            <% end %>
 | 
			
		||||
          <% end %>
 | 
			
		||||
        </ul>
 | 
			
		||||
      <% end %>
 | 
			
		||||
 | 
			
		||||
      <%= label f, :post_title do %>
 | 
			
		||||
        Title
 | 
			
		||||
        <%= text_input f, :post_title %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
 | 
			
		||||
      <%= label f, :post_content, "data-react-class": "Editor" do %>
 | 
			
		||||
        Content
 | 
			
		||||
        <%= textarea f, :post_content, "data-simplemde": true %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
      <div class="grid">
 | 
			
		||||
        <div class="form-group input-group column uLeft">
 | 
			
		||||
          <%= submit "Delete", class: "btn btn-warning", form: "deleteForm" %>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="form-group input-group column">
 | 
			
		||||
          <%= submit "Save", class: "btn btn-primary" %>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="column post-admin-sidebar">
 | 
			
		||||
      <%= label f, :post_status, class: "column input-group" do %>
 | 
			
		||||
        <div>Status</div>
 | 
			
		||||
        <%= select f, :post_status, [{"Publish", :publish}, {"Draft", :draft}] %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
      <%= label f, :post_author, class: "input-group" do %>
 | 
			
		||||
        <div>Author</div>
 | 
			
		||||
        <%= select f, :post_author, @author_options |> Enum.map(&({&1.display_name, &1."ID"})) %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
      <%= label f, :post_excerpt, class: "input-group" do %>
 | 
			
		||||
        <div>Excerpt</div>
 | 
			
		||||
        <%= textarea f, :post_excerpt %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
      <%= label f, :sticky, class: "input-group" do %>
 | 
			
		||||
        <div>Sticky?</div>
 | 
			
		||||
        <%= checkbox f, :sticky %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
      <%= label f, :comment_status, class: "input-group" do %>
 | 
			
		||||
        <div>Comment Status</div>
 | 
			
		||||
        <%= select f, :comment_status, ["open", "closed"] %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
      <%= label f, :ping_status, class: "input-group" do %>
 | 
			
		||||
        <div>Ping Status</div>
 | 
			
		||||
        <%= select f, :ping_status, ["open", "closed"] %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
      <%= label f, :post_password, class: "input-group" do %>
 | 
			
		||||
        <div>Post Password</div>
 | 
			
		||||
        <%= text_input f, :post_password %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
      <%= label f, :post_name, class: "input-group" do %>
 | 
			
		||||
        <div>Slug</div>
 | 
			
		||||
        <%= text_input f, :post_name %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
      <%= label f, :post_order, class: "input-group" do %>
 | 
			
		||||
        <div>Post Order</div>
 | 
			
		||||
        <%= number_input f, :post_order %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <%= hidden_input f, :post_type, value: @post_type %>
 | 
			
		||||
<% end %>
 | 
			
		||||
 | 
			
		||||
<%= if assigns[:posts] do %>
 | 
			
		||||
  <%= form_for @changeset, Routes.posts_path(@conn, :delete, @posts), [method: :delete, id: "deleteForm"], fn _f -> %>
 | 
			
		||||
  <% end %>
 | 
			
		||||
<% end %>
 | 
			
		||||
							
								
								
									
										15
									
								
								apps/content/lib/content_web/templates/posts/front.html.eex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								apps/content/lib/content_web/templates/posts/front.html.eex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
<article class="<%= post_class(@post) %> h-entry">
 | 
			
		||||
  <div class="uHidden">
 | 
			
		||||
    <h1 class="p-name">
 | 
			
		||||
      <%= link to: Routes.posts_path(@conn, :show, @post), class: "u-url" do %>
 | 
			
		||||
        <%= raw @post.post_title %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
    </h1>
 | 
			
		||||
    <%= post_topmatter(@conn, @post) %>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="Article-content <%= if @post.post_format, do: @post.post_format.slug %> e-content">
 | 
			
		||||
    <%= render "thumb.html", post: @post, thumbs: @thumbs %>
 | 
			
		||||
    <%= @post |> Content.Post.content_page(@page) |> process_content |> raw %>
 | 
			
		||||
  </div>
 | 
			
		||||
  <%= render "pagination.html", conn: @conn, post: @post, current_page: @page %>
 | 
			
		||||
</article>
 | 
			
		||||
							
								
								
									
										62
									
								
								apps/content/lib/content_web/templates/posts/index.html.eex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								apps/content/lib/content_web/templates/posts/index.html.eex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,62 @@
 | 
			
		|||
<%= for post <- @posts do %>
 | 
			
		||||
  <article class="<%= post_class(post) %> h-entry">
 | 
			
		||||
    <h2 class="entry-title p-name">
 | 
			
		||||
      <%= link to: Routes.posts_path(@conn, :show, post), class: "u-url" do %>
 | 
			
		||||
        <%= raw post.post_title %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
    </h2>
 | 
			
		||||
    <%= post_topmatter(@conn, post) %>
 | 
			
		||||
    <div class="Article-content <%= if post.post_format, do: post.post_format.slug %> e-content">
 | 
			
		||||
      <%= if authenticated_for_post?(@conn, post) do %>
 | 
			
		||||
        <%= render "thumb.html", post: post, thumbs: @thumbs %>
 | 
			
		||||
        <div class="Article-content-words">
 | 
			
		||||
          <%= raw post |> Content.Post.content_page(1) |> Content.Post.before_more |> process_content |> raw %>
 | 
			
		||||
          <%= if post.post_content =~ "<!--more-->" do %>
 | 
			
		||||
            <p>
 | 
			
		||||
              <%= link "Keep Reading", to: Routes.posts_path(@conn, :show, post) %>
 | 
			
		||||
            </p>
 | 
			
		||||
          <% end %>
 | 
			
		||||
          <%= render "pagination.html", conn: @conn, post: post %>
 | 
			
		||||
        </div>
 | 
			
		||||
      <% else %>
 | 
			
		||||
        <%= render "password_form.html", post: post, conn: @conn %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
    </div>
 | 
			
		||||
    <p class="CategoryBlock">
 | 
			
		||||
      Categories:
 | 
			
		||||
      <%= for term <- post.categories do %>
 | 
			
		||||
        <%= link term.name, to: Routes.category_path(@conn, :index_posts, term.slug), class: "p-category" %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
    </p>
 | 
			
		||||
    <hr />
 | 
			
		||||
  </article>
 | 
			
		||||
<% end %>
 | 
			
		||||
 | 
			
		||||
<nav class="paginator">
 | 
			
		||||
  Page:
 | 
			
		||||
  <%= if @page > 1 do %>
 | 
			
		||||
    <%= link 1, to: paginated_posts_path(@conn, @category, 1) %>
 | 
			
		||||
  <% end %>
 | 
			
		||||
 | 
			
		||||
  <%= if @page > 3 do %>
 | 
			
		||||
    <span class="paginator-page">...</span>
 | 
			
		||||
  <% end %>
 | 
			
		||||
 | 
			
		||||
  <%= if @page > 2 do %>
 | 
			
		||||
    <%= link @page - 1, to: paginated_posts_path(@conn, @category, @page - 1) %>
 | 
			
		||||
  <% end %>
 | 
			
		||||
 | 
			
		||||
  <span class="paginator-page"><%= @page %></span>
 | 
			
		||||
 | 
			
		||||
  <%= if @page + 1 < @last_page do %>
 | 
			
		||||
    <%= link @page + 1, to: paginated_posts_path(@conn, @category, @page + 1) %>
 | 
			
		||||
  <% end %>
 | 
			
		||||
 | 
			
		||||
  <%= if @page + 2 < @last_page do %>
 | 
			
		||||
    <span class="paginator-page">...</span>
 | 
			
		||||
  <% end %>
 | 
			
		||||
 | 
			
		||||
  <%= if @page < @last_page do %>
 | 
			
		||||
    <%= link @last_page, to: paginated_posts_path(@conn, @category, @last_page) %>
 | 
			
		||||
  <% end %>
 | 
			
		||||
</nav>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
<%= render "form.html", Map.put(assigns, :action, Routes.posts_path(@conn, :create)) %>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
<%= if Content.Post.paginated_post?(@post) do %>
 | 
			
		||||
  <nav class="paginator">
 | 
			
		||||
    Page:
 | 
			
		||||
      <%= Enum.map(
 | 
			
		||||
        1..Content.Post.content_page_count(@post),
 | 
			
		||||
        fn page ->
 | 
			
		||||
          if assigns[:current_page] == nil || assigns[:current_page] != page do
 | 
			
		||||
            link page, to: Routes.paged_post_path(@conn, :show, @post, page)
 | 
			
		||||
          else
 | 
			
		||||
            content_tag :span, page, class: "paginator-page"
 | 
			
		||||
          end
 | 
			
		||||
      end) %>
 | 
			
		||||
  </nav>
 | 
			
		||||
<% end %>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
<%= form_for @conn, "/wp-login.php?action=postpass", [class: "post-password-form"], fn f -> %>
 | 
			
		||||
  <p>This content is password protected. To view it please enter your password below:</p>
 | 
			
		||||
  <p>
 | 
			
		||||
    <%= label f, :post_password do %>
 | 
			
		||||
      Password: <input name="post_password" id="pwbox-131" type="password" size="20">
 | 
			
		||||
    <% end %>
 | 
			
		||||
  </p>
 | 
			
		||||
  <p class="form-group">
 | 
			
		||||
    <input type="submit" name="Submit" value="Enter">
 | 
			
		||||
  </p>
 | 
			
		||||
<% end %>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
 | 
			
		||||
<%= form_for @comment_changeset, Routes.comment_path(@conn, :create), fn f -> %>
 | 
			
		||||
  <%= hidden_input f, :comment_parent %>
 | 
			
		||||
  <%= hidden_input f, :comment_post_ID %>
 | 
			
		||||
  <%= label f, :comment_author do %>
 | 
			
		||||
    Your Name
 | 
			
		||||
    <%= text_input f, :comment_author %>
 | 
			
		||||
  <% end %>
 | 
			
		||||
  <%= label f, :comment_author_email do %>
 | 
			
		||||
    Your Email
 | 
			
		||||
    <%= email_input f, :comment_author_email %>
 | 
			
		||||
  <% end %>
 | 
			
		||||
  <%= label f, :comment_author_url do %>
 | 
			
		||||
    Your Website
 | 
			
		||||
    <%= text_input f, :comment_author_url %>
 | 
			
		||||
  <% end %>
 | 
			
		||||
  <%= label f, :comment_content do %>
 | 
			
		||||
    Comment
 | 
			
		||||
    <%= textarea f, :comment_content %>
 | 
			
		||||
  <% end %>
 | 
			
		||||
  <div class="form-group">
 | 
			
		||||
    <%= submit "\u27A6 Reply", class: "btn btn-primary" %>
 | 
			
		||||
  </div>
 | 
			
		||||
<% end %>
 | 
			
		||||
							
								
								
									
										39
									
								
								apps/content/lib/content_web/templates/posts/show.html.eex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								apps/content/lib/content_web/templates/posts/show.html.eex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
<article class="<%= post_class(@post) %> h-entry">
 | 
			
		||||
  <div>
 | 
			
		||||
    <h1 class="p-name">
 | 
			
		||||
      <%= link to: Routes.posts_path(@conn, :show, @post), class: "u-url" do %>
 | 
			
		||||
        <%= raw @post.post_title %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
    </h1>
 | 
			
		||||
    <%= post_topmatter(@conn, @post) %>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div class="Article-content <%= if @post.post_format, do: @post.post_format.slug %> e-content">
 | 
			
		||||
    <%= render "thumb.html", post: @post, thumbs: @thumbs %>
 | 
			
		||||
    <%= @post |> Content.Post.content_page(@page) |> process_content |> raw %>
 | 
			
		||||
    <p class="CategoryBlock">
 | 
			
		||||
      Categories:
 | 
			
		||||
      <%= for term <- @post.categories do %>
 | 
			
		||||
        <%= link term.name, to: Routes.category_path(@conn, :index_posts, term.slug), class: "p-category" %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
    </p>
 | 
			
		||||
  </div>
 | 
			
		||||
  <%= render "pagination.html", conn: @conn, post: @post, current_page: @page %>
 | 
			
		||||
  <%= if @post.comment_status == "open" do %>
 | 
			
		||||
    <h3>Comments</h3>
 | 
			
		||||
    <a href="#reply-to-post">
 | 
			
		||||
      ➦ Reply to "<%= @post.post_title %>"
 | 
			
		||||
    </a>
 | 
			
		||||
    <ul class="CommentList">
 | 
			
		||||
      <%= render "comments.html", post: @post, parent_id: 0, conn: @conn %>
 | 
			
		||||
      <li class="Comment" id="reply-to-post">
 | 
			
		||||
        <%=
 | 
			
		||||
          render "reply_form.html",
 | 
			
		||||
            comment_changeset: comment_changeset_for_post(@post),
 | 
			
		||||
            post: @post,
 | 
			
		||||
            conn: @conn
 | 
			
		||||
        %>
 | 
			
		||||
      </li>
 | 
			
		||||
    </ul>
 | 
			
		||||
  <% end %>
 | 
			
		||||
  <hr />
 | 
			
		||||
</article>
 | 
			
		||||
							
								
								
									
										13
									
								
								apps/content/lib/content_web/templates/posts/thumb.html.eex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								apps/content/lib/content_web/templates/posts/thumb.html.eex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
<%= case @thumbs[@post.'ID'] do %>
 | 
			
		||||
  <% thumb = %Content.Post{} -> %>
 | 
			
		||||
    <%= if thumb |> Content.Attachment.vertical?() do %>
 | 
			
		||||
      <div class="post-thumbnail post-thumbnail--vertical">
 | 
			
		||||
        <%= img_tag thumb.guid %>
 | 
			
		||||
      </div>
 | 
			
		||||
    <% else %>
 | 
			
		||||
      <div class="post-thumbnail">
 | 
			
		||||
        <%= img_tag thumb.guid %>
 | 
			
		||||
      </div>
 | 
			
		||||
    <% end %>
 | 
			
		||||
  <% nil -> %>
 | 
			
		||||
<% end %>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,21 @@
 | 
			
		|||
<h1>Site Index</h1>
 | 
			
		||||
<h2>Posts and Pages</h2>
 | 
			
		||||
<ul>
 | 
			
		||||
  <%= for post <- @posts do %>
 | 
			
		||||
    <li>
 | 
			
		||||
      <%= link to: Routes.posts_path(@conn, :show, post) do %>
 | 
			
		||||
        <%= raw post.post_title %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
    </li>
 | 
			
		||||
  <% end %>
 | 
			
		||||
</ul>
 | 
			
		||||
<h2>Categories</h2>
 | 
			
		||||
<ul>
 | 
			
		||||
  <%= for category <- @categories do %>
 | 
			
		||||
    <li>
 | 
			
		||||
      <%= link to: Routes.category_path(@conn, :index_posts, category.slug)do %>
 | 
			
		||||
        <%= raw category.name %>
 | 
			
		||||
      <% end %>
 | 
			
		||||
    </li>
 | 
			
		||||
  <% end %>
 | 
			
		||||
</ul>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
<h2>Edit comment</h2>
 | 
			
		||||
 | 
			
		||||
<%= render "form.html", Map.put(assigns, :action, Routes.comment_path(@conn, :update, @comment)) %>
 | 
			
		||||
 | 
			
		||||
<span><%= link "Back", to: Routes.comment_path(@conn, :index) %></span>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
<%= form_for @changeset, @action, fn f -> %>
 | 
			
		||||
  <%= if @changeset.action do %>
 | 
			
		||||
    <div class="alert alert-danger">
 | 
			
		||||
      <p>Oops, something went wrong! Please check the errors below.</p>
 | 
			
		||||
    </div>
 | 
			
		||||
  <% end %>
 | 
			
		||||
 | 
			
		||||
  <div class="form-group">
 | 
			
		||||
    <%= submit "Submit", class: "btn btn-primary" %>
 | 
			
		||||
  </div>
 | 
			
		||||
<% end %>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
<h2>Listing comments</h2>
 | 
			
		||||
 | 
			
		||||
<table class="table">
 | 
			
		||||
  <thead>
 | 
			
		||||
    <tr>
 | 
			
		||||
 | 
			
		||||
      <th></th>
 | 
			
		||||
    </tr>
 | 
			
		||||
  </thead>
 | 
			
		||||
  <tbody>
 | 
			
		||||
<%= for comment <- @comments do %>
 | 
			
		||||
    <tr>
 | 
			
		||||
 | 
			
		||||
      <td class="text-right">
 | 
			
		||||
        <span><%= link "Show", to: Routes.comment_path(@conn, :show, comment), class: "btn btn-default btn-xs" %></span>
 | 
			
		||||
        <span><%= link "Edit", to: Routes.comment_path(@conn, :edit, comment), class: "btn btn-default btn-xs" %></span>
 | 
			
		||||
        <span><%= link "Delete", to: Routes.comment_path(@conn, :delete, comment), method: :delete, data: [confirm: "Are you sure?"], class: "btn btn-danger btn-xs" %></span>
 | 
			
		||||
      </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
<% end %>
 | 
			
		||||
  </tbody>
 | 
			
		||||
</table>
 | 
			
		||||
 | 
			
		||||
<span><%= link "New comment", to: Routes.comment_path(@conn, :new) %></span>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
<h2>New comment</h2>
 | 
			
		||||
 | 
			
		||||
<%= render "form.html", Map.put(assigns, :action, Routes.comment_path(@conn, :create)) %>
 | 
			
		||||
 | 
			
		||||
<span><%= link "Back", to: Routes.comment_path(@conn, :index) %></span>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
<h2>Show comment</h2>
 | 
			
		||||
 | 
			
		||||
<ul>
 | 
			
		||||
 | 
			
		||||
</ul>
 | 
			
		||||
 | 
			
		||||
<span><%= link "Edit", to: Routes.comment_path(@conn, :edit, @comment) %></span>
 | 
			
		||||
<span><%= link "Back", to: Routes.comment_path(@conn, :index) %></span>
 | 
			
		||||
							
								
								
									
										3
									
								
								apps/content/lib/content_web/views/admin_home_view.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								apps/content/lib/content_web/views/admin_home_view.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
defmodule Content.AdminHomeView do
 | 
			
		||||
  use Content, :view
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										3
									
								
								apps/content/lib/content_web/views/admin_posts_view.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								apps/content/lib/content_web/views/admin_posts_view.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
defmodule Content.AdminPostsView do
 | 
			
		||||
  use Content, :view
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
defmodule ContentWeb.ErrorHelpers do
 | 
			
		||||
defmodule Content.ErrorHelpers do
 | 
			
		||||
  @moduledoc """
 | 
			
		||||
  Conveniences for translating and building error messages.
 | 
			
		||||
  """
 | 
			
		||||
| 
						 | 
				
			
			@ -39,9 +39,9 @@ defmodule ContentWeb.ErrorHelpers do
 | 
			
		|||
    # should be written to the errors.po file. The :count option is
 | 
			
		||||
    # set by Ecto and indicates we should also apply plural rules.
 | 
			
		||||
    if count = opts[:count] do
 | 
			
		||||
      Gettext.dngettext(ContentWeb.Gettext, "errors", msg, msg, count, opts)
 | 
			
		||||
      Gettext.dngettext(Content.Gettext, "errors", msg, msg, count, opts)
 | 
			
		||||
    else
 | 
			
		||||
      Gettext.dgettext(ContentWeb.Gettext, "errors", msg, opts)
 | 
			
		||||
      Gettext.dgettext(Content.Gettext, "errors", msg, opts)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
defmodule ContentWeb.ErrorView do
 | 
			
		||||
  use ContentWeb, :view
 | 
			
		||||
defmodule Content.ErrorView do
 | 
			
		||||
  use Content, :view
 | 
			
		||||
 | 
			
		||||
  # If you want to customize a particular status code
 | 
			
		||||
  # for a certain format, you may uncomment below.
 | 
			
		||||
							
								
								
									
										70
									
								
								apps/content/lib/content_web/views/feeds_view.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								apps/content/lib/content_web/views/feeds_view.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,70 @@
 | 
			
		|||
defmodule Content.FeedsView do
 | 
			
		||||
  use Content, :view
 | 
			
		||||
  use Phoenix.HTML
 | 
			
		||||
  alias Phoenix.HTML
 | 
			
		||||
  alias Phoenix.HTML.Tag
 | 
			
		||||
  alias Content.LayoutView
 | 
			
		||||
 | 
			
		||||
  def gravatar_url_for_email(email) do
 | 
			
		||||
    email
 | 
			
		||||
    |> Kernel.||("noreply@example.com")
 | 
			
		||||
    |> String.trim()
 | 
			
		||||
    |> String.downcase()
 | 
			
		||||
    |> (&(:crypto.hash(:md5, &1))).()
 | 
			
		||||
    |> Base.encode16()
 | 
			
		||||
    |> String.downcase()
 | 
			
		||||
    |> (&("https://www.gravatar.com/avatar/#{&1}")).()
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def auto_paragraph_tags(string) do
 | 
			
		||||
    string
 | 
			
		||||
    |> Kernel.||("")
 | 
			
		||||
    |> String.split(["\n\n", "\r\n\r\n"], trim: true)
 | 
			
		||||
    |> Enum.map(fn text ->
 | 
			
		||||
      [Tag.content_tag(:p, text |> HTML.raw(), []), ?\n]
 | 
			
		||||
    end)
 | 
			
		||||
    |> HTML.html_escape()
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def post_class(post) do
 | 
			
		||||
    sticky =
 | 
			
		||||
      if post.sticky do
 | 
			
		||||
        "sticky"
 | 
			
		||||
      end
 | 
			
		||||
    "post post-#{post.'ID'} #{sticky}"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def post_topmatter(conn, post) do
 | 
			
		||||
    author =
 | 
			
		||||
      post.author ||
 | 
			
		||||
      %Auth.User{
 | 
			
		||||
        email: "example@example.org",
 | 
			
		||||
        display_name: "Anonymous",
 | 
			
		||||
        homepage_url: "#"
 | 
			
		||||
      }
 | 
			
		||||
    assigns = %{post: post, author: author, conn: conn}
 | 
			
		||||
    ~E"""
 | 
			
		||||
      <% _ = assigns # suppress unused assigns warning %>
 | 
			
		||||
      <div class="Comment-topmatter">
 | 
			
		||||
 | 
			
		||||
        <h4>
 | 
			
		||||
          <%= link to: author.homepage_url, rel: "author", class: "p-author h-card" do %>
 | 
			
		||||
            <%= author.display_name %>
 | 
			
		||||
            <%= img_tag gravatar_url_for_email(author.email), alt: "Photo of #{author.display_name}", class: "Gravatar u-photo" %>
 | 
			
		||||
          <% end %>
 | 
			
		||||
        </h4>
 | 
			
		||||
        <h5>
 | 
			
		||||
          <%= link to: Routes.posts_path(conn, :show, post) do %>
 | 
			
		||||
            <time class="dt-published" datetime="<%= post.post_date %>">
 | 
			
		||||
              <%= post.post_date |> Timex.format!("%F", :strftime) %>
 | 
			
		||||
            </time>
 | 
			
		||||
          <% end %>
 | 
			
		||||
        </h5>
 | 
			
		||||
      </div>
 | 
			
		||||
    """
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def unauthenticated_post?(_conn, post) do
 | 
			
		||||
    post.post_password == nil || String.length(post.post_password) == 0
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										92
									
								
								apps/content/lib/content_web/views/layout_view.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								apps/content/lib/content_web/views/layout_view.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,92 @@
 | 
			
		|||
defmodule Content.LayoutView do
 | 
			
		||||
  use Content, :view
 | 
			
		||||
 | 
			
		||||
  alias Content.{Option, Options}
 | 
			
		||||
 | 
			
		||||
  def title(Content.PostsView, "index.html", assigns) do
 | 
			
		||||
    "Page #{assigns.page} | #{title(nil, nil, nil)}"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def title(Content.FeedsView, "index.rss", %{category: category}) do
 | 
			
		||||
    "#{category} | #{title(nil, nil, nil)}"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def title(Content.PostsView, "show.html", assigns) do
 | 
			
		||||
    (assigns.post.post_title |> HtmlSanitizeEx.strip_tags()) <> " | " <> title(nil, nil, nil)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def title(_, _, _) do
 | 
			
		||||
    case Options.get("blogname") do
 | 
			
		||||
      opt = %Option{} ->
 | 
			
		||||
        opt.option_value
 | 
			
		||||
      _ ->
 | 
			
		||||
        "Hello"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def excerpt(Content.PostsView, "show.html", assigns) do
 | 
			
		||||
    assigns.post.post_excerpt
 | 
			
		||||
    |> HtmlSanitizeEx.strip_tags()
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def excerpt(Content.FeedsView, "index.rss", %{category: category}) do
 | 
			
		||||
    "#{category} | #{excerpt(nil, nil, nil)}"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def excerpt(_, _, _) do
 | 
			
		||||
    case Options.get("blogdescription") do
 | 
			
		||||
      opt = %Option{} ->
 | 
			
		||||
        opt.option_value
 | 
			
		||||
      _ ->
 | 
			
		||||
        "Yet another website"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def author(Content.PostsView, "show.html", assigns) do
 | 
			
		||||
    case assigns do
 | 
			
		||||
      %{author: %{display_name: name}} ->
 | 
			
		||||
        name
 | 
			
		||||
      _ ->
 | 
			
		||||
        "Anonymous"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def author(_, _, _) do
 | 
			
		||||
    "Anonymous"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def corresponding_feed_url(conn, _, _, %{category: nil}) do
 | 
			
		||||
    Routes.index_feed_url(conn, :index)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def corresponding_feed_url(conn, Content.PostsView, "index.html", %{category: category}) do
 | 
			
		||||
    Routes.category_feed_url(conn, :index, category)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def corresponding_feed_url(conn, _, _, _) do
 | 
			
		||||
    Routes.index_feed_url(conn, :index)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def menu_markup(menu_items, conn), do: menu_markup(menu_items, conn, 0)
 | 
			
		||||
  def menu_markup(nil, _, _), do: ""
 | 
			
		||||
  def menu_markup([], _, _), do: ""
 | 
			
		||||
  def menu_markup(menu_items, conn, level) do
 | 
			
		||||
    ~E"""
 | 
			
		||||
      <ul style="--menu-level: <%= level %>;">
 | 
			
		||||
        <%= for item <- menu_items do %>
 | 
			
		||||
          <li>
 | 
			
		||||
            <label>
 | 
			
		||||
            <%= case item[:type] do %>
 | 
			
		||||
              <% "category" -> %>
 | 
			
		||||
              <%= link item[:related_item].title, to: Routes.category_path(conn, :index_posts, item[:related_item].slug) %>
 | 
			
		||||
              <% _ -> %>
 | 
			
		||||
              <%= link item[:related_item].title, to: Routes.posts_path(conn, :show, item[:related_item].slug) %>
 | 
			
		||||
            <% end %>
 | 
			
		||||
            <%= menu_markup(item[:children], conn, level + 1) %>
 | 
			
		||||
            </label>
 | 
			
		||||
          </li>
 | 
			
		||||
        <% end %>
 | 
			
		||||
      </ul>
 | 
			
		||||
    """
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										3
									
								
								apps/content/lib/content_web/views/menus_view.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								apps/content/lib/content_web/views/menus_view.ex
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
defmodule Content.MenusView do
 | 
			
		||||
  use Content, :view
 | 
			
		||||
end
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
		Reference in a new issue