8.5 KiB
ArcologyWeb Phoenix Frontend
ArcologyWeb
– global helpersArcologyWeb.Endpoint
– OTP application, Phoenix EntrypointArcologyWeb.Router
maps HTTP requests to Controllers and Views.- Translations in
ArcologyWeb.Gettext
ArcologyWeb
– global helpers
This module is use
'd in the submodules, views load from the view
definition, etc. See the moduledoc
for more information. For now this is just what the auto-gen gives me, eventually we'll have more Helper modules to integrate here. Try to keep them cross-referenced.
defmodule ArcologyWeb 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 ArcologyWeb, :controller
use ArcologyWeb, :view
The definitions below will be executed for every view,
controller, etc, so keep them short and clean, focused
on imports, uses and aliases.
Do NOT define functions inside the quoted expressions
below. Instead, define any helper function in modules
and import those modules here.
"""
<<controller>>
<<view>>
<<router>>
<<channel>>
@doc """
When used, dispatch to the appropriate controller/view/etc.
"""
defmacro __using__(which) when is_atom(which) do
apply(__MODULE__, which, [])
end
end
def controller do
quote do
use Phoenix.Controller, namespace: ArcologyWeb
import Plug.Conn
import ArcologyWeb.Gettext
alias ArcologyWeb.Router.Helpers, as: Routes
end
end
def view do
quote do
use Phoenix.View,
root: "lib/arcology_web/templates",
namespace: ArcologyWeb
# Import convenience functions from controllers
import Phoenix.Controller, only: [get_flash: 1, get_flash: 2, view_module: 1]
# Use all HTML functionality (forms, tags, etc)
use Phoenix.HTML
import ArcologyWeb.ErrorHelpers
import ArcologyWeb.Gettext
alias ArcologyWeb.Router.Helpers, as: Routes
end
end
def router do
quote do
use Phoenix.Router
import Plug.Conn
import Phoenix.Controller
end
end
def channel do
quote do
use Phoenix.Channel
import ArcologyWeb.Gettext
end
end
ArcologyWeb.Endpoint
– OTP application, Phoenix Entrypoint
The Endpoint is where web requests start to pass through the system, Plugs are how this works. Read this entire document, but at least this section to understand how this is put together and how the Plug system works.
defmodule ArcologyWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :arcology
<<ArcologyWeb_UserSocket>>
<<plug-configurations>>
<<plug-session>>
<<plug-static>>
plug ArcologyWeb.Router
end
Serve at "/" the static files from "priv/static" directory. Since we will use phx.digest
we can gzip
the assets.
plug Plug.Static,
at: "/",
from: :arcology,
gzip: true,
only: ~w(css fonts images js favicon.ico robots.txt appmanifest.json)
Code Reloading is enabled in local development by inserting some plugs if the code_reloading?/0
function from Phoenix.Endpoint
returns true based on Mix configuration.
if code_reloading? do
socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket
plug Phoenix.LiveReloader
plug Phoenix.CodeReloader
end
plug Plug.RequestId
plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint]
plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
json_decoder: Phoenix.json_library()
plug Plug.MethodOverride
plug Plug.Head
Session configuration is still the default, I'm going to want to change and extract that singing_salt
at some point.
The session will be stored in the cookie and signed, this means its contents can be read but not tampered with. Set :encryption_salt if you would also like to encrypt it.
plug Plug.Session,
store: :cookie,
key: "_arcology_key",
signing_salt: "ruJdL/3g"
The arcology client/server push socket will be useful some time, I'm sure of it:
socket "/socket", ArcologyWeb.UserSocket,
websocket: true,
longpoll: false
ArcologyWeb.Router
maps HTTP requests to Controllers and Views.
The router is a set of pipelines and a set of scopes.
defmodule ArcologyWeb.Router do
use ArcologyWeb, :router
<<browser-pipeline>>
<<site_extractor>>
<<base-scope>>
end
My browser scope is simple, still built around the defaults. CSRF, session, secure headers and HTML.
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
end
There is a pipeline called site_extractor
which populates a site
key on the connection object based on the host presented in the connection, and it populates a site_key
on the connection object containing a guess at an ARCOLOGY_KEY
for the page. this is what we actually route on!
def domain_to_site(conn, _) do
site = Arcology.KeyMaps.domain_to_site(conn.host)
Map.merge(conn, site)
end
def build_site_key(conn, _) do
Map.put(conn, :site_key, "#{conn.site}#{conn.request_path}")
end
pipeline :site_extractor do
plug(:domain_to_site)
plug(:build_site_key)
end
Phoenix gives a single controller, PageController, /
routes to the Arcology Sitemap endpoints, and then to ArcologyWeb.PageController with the site_key
populated. This works only for localhost
connections, actually, I should need to implement multiple build_site_key
for DNS-based routing.
scope "/", ArcologyWeb do
pipe_through :browser
pipe_through(:site_extractor)
# XXX: extract this in to a noweb ref
get("/sitemap", SitemapController, :sitemap)
get("/sigma_network", SitemapController, :sigma_network)
<<local-site-routing>>
end
Local Site Routing
scope "/", local_wiki: true do
get("/", PageController, :index)
get("/:site/*slug", PageController, :local)
end
Translations in ArcologyWeb.Gettext
I probably will care about translations some day, but I am going to leave this in its default state for now.
defmodule ArcologyWeb.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 ArcologyWeb.Gettext
# Simple translation
gettext("Here is the string to translate")
# Plural translation
ngettext("Here is the string to translate",
"Here are the strings to translate",
3)
# Domain-based translation
dgettext("errors", "Here is the error message to translate")
See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.
"""
use Gettext, otp_app: :arcology
end
For now, the POT
and PO
files are kept illiterate. From the comment at the top of the POT file:
This is a PO Template file.
=msgid=s here are often extracted from source code. Add new translations manually only if they're dynamic translations that can't be statically extracted.
Run
mix gettext.extract
to bring this file up to date. Leavemsgstr
's empty as changing them here has no effect: edit them in PO (.po
) files instead.
Since this is a semi-automated process, and frankly not a high priority for a little bit, I'm going to keep the translations managed outside. Eventually I would love to generate the PO files from a table rather than an ugly plain-text mono-space representation.