Initial commit

This commit is contained in:
Mikko Ahlroth 2023-01-20 21:09:11 +02:00
commit 03027baa11
14 changed files with 313 additions and 0 deletions

4
.formatter.exs Normal file
View file

@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

26
.gitignore vendored Normal file
View file

@ -0,0 +1,26 @@
# The directory Mix will write compiled artifacts to.
/_build/
# If you run "mix test --cover", coverage assets end up here.
/cover/
# The directory Mix downloads your dependencies sources to.
/deps/
# Where third-party dependencies like ExDoc output generated docs.
/doc/
# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch
# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
# Ignore package tarball (built via "mix hex.build").
feeniks-*.tar
# Temporary files, for example, from tests.
/tmp/

2
.tool-versions Normal file
View file

@ -0,0 +1,2 @@
elixir 1.14.3-otp-25
erlang 25.1.1

21
README.md Normal file
View file

@ -0,0 +1,21 @@
# Feeniks
**TODO: Add description**
## Installation
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `feeniks` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:feeniks, "~> 0.1.0"}
]
end
```
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at <https://hexdocs.pm/feeniks>.

22
config/config.exs Normal file
View file

@ -0,0 +1,22 @@
import Config
# Configures the endpoint
config :feeniks, Feeniks.Endpoint,
render_errors: [accepts: ~w(html json)],
pubsub_server: Feeniks.PubSub,
code_reloader: config_env() == :dev,
debug_errors: config_env() == :dev,
check_origin: config_env() == :prod
# Configures Elixir's Logger
config :logger, :console,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]
# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason
# Do not print debug messages in production
if config_env() == :prod do
config :logger, level: :error
end

View file

@ -0,0 +1,19 @@
defmodule Feeniks.Application do
# See https://hexdocs.pm/elixir/Application.html
# for more information on OTP Applications
@moduledoc false
use Application
@impl true
def start(_type, _args) do
children = [
{Bandit, plug: Feeniks.Endpoint, scheme: :http, options: [port: 31545]}
]
# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: Feeniks.Supervisor]
Supervisor.start_link(children, opts)
end
end

View file

@ -0,0 +1,5 @@
defmodule Feeniks.Controller do
def index(conn, params) do
Phoenix.Controller.text(conn, inspect(params))
end
end

58
lib/feeniks/endpoint.ex Normal file
View file

@ -0,0 +1,58 @@
defmodule Feeniks.Endpoint do
import PlugHelpers
@behaviour Plug
@config Phoenix.Endpoint.Supervisor.config(:feeniks, __MODULE__)
@code_reloading @config[:code_reloader]
@session_options [
store: :cookie,
key: "_feeniks_key",
signing_salt: "örgölbörgöl"
]
@plugs pipeline([
&__MODULE__.set_endpoint/1,
module_plug(Plug.Static,
at: "/",
from: :feeniks,
gzip: true,
only: ~w(app.css favicon.ico robots.txt)
),
if @code_reloading do
[
module_plug(Phoenix.LiveReloader),
module_plug(Phoenix.CodeReloader)
]
end,
module_plug(Plug.RequestId),
module_plug(Plug.Logger),
module_plug(Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
json_decoder: Jason
),
module_plug(Plug.MethodOverride),
module_plug(Plug.Head),
module_plug(
Plug.Session,
@session_options
),
module_plug(Feeniks.Router)
])
@impl Plug
def init(opts), do: opts
@impl Plug
def call(conn, _opts) do
run_plugs(conn, @plugs)
end
def config(key) do
@config[key]
end
def set_endpoint(conn), do: Plug.Conn.put_private(conn, :phoenix_endpoint, __MODULE__)
end

60
lib/feeniks/router.ex Normal file
View file

@ -0,0 +1,60 @@
defmodule Feeniks.Router do
import PlugHelpers
import RouterHelpers
@behaviour Plug
@common_browser pipeline([
&Plug.Conn.fetch_session/1,
&Phoenix.Controller.fetch_flash/1,
&__MODULE__.put_root_layout/1,
&Phoenix.Controller.put_secure_browser_headers/1,
&Phoenix.Controller.protect_from_forgery/1
])
@common_api pipeline([
&__MODULE__.accepts_json/1
])
@index @common_browser ++ [build_action(&Feeniks.Controller.index/1)]
@impl Plug
def init(opts), do: opts
@impl Plug
def call(conn, _opts) do
path_info = Plug.Router.Utils.decode_path_info!(conn)
match(conn, conn.method, path_info)
end
def put_root_layout(conn) do
Phoenix.Controller.put_root_layout(conn, {Feeniks.LayoutView, :root})
end
def accepts_json(conn) do
Phoenix.Controller.accepts(conn, ["json"])
end
@spec match(Plug.Conn.t(), Plug.Conn.method(), Plug.Conn.segments()) :: Plug.Conn.t()
defp match(conn, method, path_info)
defp match(conn, "GET", _) do
conn
|> common_browser()
|> Feeniks.Controller.index(conn.params)
end
defp match(conn, "POST", _) do
conn
|> run_plugs(@common_api)
|> Feeniks.Controller.index(conn.params)
end
defp match(conn, _, _) do
conn |> common_browser() |> Plug.Conn.put_status(200) |> Phoenix.Controller.text("Not found")
end
defp common_browser(conn) do
run_plugs(conn, @common_browser)
end
end

39
lib/plug_helpers.ex Normal file
View file

@ -0,0 +1,39 @@
defmodule PlugHelpers do
@typep plug_definition() :: {module(), term()}
@typep plug_function() :: (Plug.Conn.t() -> Plug.Conn.t())
@spec module_plug(module(), term()) :: plug_definition()
def module_plug(plug, opts \\ []) do
{plug, plug.init(opts)}
end
@spec pipeline(list()) :: [plug_definition() | plug_function()]
def pipeline(plugs) do
plugs
|> List.flatten()
|> Enum.filter(fn
{mod, _opts} when is_atom(mod) -> true
fun when is_function(fun, 1) -> true
_ -> false
end)
end
@spec run_plugs(Plug.Conn.t(), [plug_definition() | plug_function()]) ::
Plug.Conn.t()
def run_plugs(conn, plugs) do
for plug <- plugs, reduce: conn do
%Plug.Conn{halted: true} = c ->
c
%Plug.Conn{} = c ->
case plug do
p when is_function(p) -> p.(c)
{p, opts} -> p.call(c, opts)
what -> raise "Unknown plug type #{inspect(what)} in plug list"
end
other ->
"Expected plugs to return Plug.Conn, got: #{inspect(other)}"
end
end
end

7
lib/router_helpers.ex Normal file
View file

@ -0,0 +1,7 @@
defmodule RouterHelpers do
@spec build_action((Plug.Conn.t(), Plug.Conn.params() -> Plug.Conn.t())) ::
(Plug.Conn.t() -> Plug.Conn.t())
def build_action(action) do
fn conn -> action.(conn, conn.params) end
end
end

31
mix.exs Normal file
View file

@ -0,0 +1,31 @@
defmodule Feeniks.MixProject do
use Mix.Project
def project do
[
app: :feeniks,
version: "0.1.0",
elixir: "~> 1.14",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger],
mod: {Feeniks.Application, []}
]
end
# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:phoenix, "~> 1.6.15"},
{:bandit, "~> 0.6.7"},
{:jason, "~> 1.4"},
{:phoenix_live_reload, "~> 1.4"}
]
end
end

18
mix.lock Normal file
View file

@ -0,0 +1,18 @@
%{
"bandit": {:hex, :bandit, "0.6.7", "8d768a512ecbda9bd4e71fe223fce8d57c30899ede61dc70a0d4d34407910a8e", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:thousand_island, "~> 0.5.14", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.4.3", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "0f1e9ac0e09714ee54c76001fe9d973aa25bff9cd058668c8f6cd0152f8ca3cf"},
"castore": {:hex, :castore, "1.0.0", "c25cd0794c054ebe6908a86820c8b92b5695814479ec95eeff35192720b71eec", [:mix], [], "hexpm", "577d0e855983a97ca1dfa33cbb8a3b6ece6767397ffb4861514343b078fc284b"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
"jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"},
"mime": {:hex, :mime, "2.0.3", "3676436d3d1f7b81b5a2d2bd8405f412c677558c81b1c92be58c00562bb59095", [:mix], [], "hexpm", "27a30bf0db44d25eecba73755acf4068cbfe26a4372f9eb3e4ea3a45956bff6b"},
"phoenix": {:hex, :phoenix, "1.6.15", "0a1d96bbc10747fd83525370d691953cdb6f3ccbac61aa01b4acb012474b047d", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d70ab9fbf6b394755ea88b644d34d79d8b146e490973151f248cacd122d20672"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"},
"phoenix_template": {:hex, :phoenix_template, "1.0.0", "c57bc5044f25f007dc86ab21895688c098a9f846a8dda6bc40e2d0ddc146e38f", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "1b066f99a26fd22064c12b2600a9a6e56700f591bf7b20b418054ea38b4d4357"},
"phoenix_view": {:hex, :phoenix_view, "2.0.2", "6bd4d2fd595ef80d33b439ede6a19326b78f0f1d8d62b9a318e3d9c1af351098", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "a929e7230ea5c7ee0e149ffcf44ce7cf7f4b6d2bfe1752dd7c084cdff152d36f"},
"plug": {:hex, :plug, "1.14.0", "ba4f558468f69cbd9f6b356d25443d0b796fbdc887e03fa89001384a9cac638f", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bf020432c7d4feb7b3af16a0c2701455cbbbb95e5b6866132cb09eb0c29adc14"},
"plug_crypto": {:hex, :plug_crypto, "1.2.3", "8f77d13aeb32bfd9e654cb68f0af517b371fb34c56c9f2b58fe3df1235c1251a", [:mix], [], "hexpm", "b5672099c6ad5c202c45f5a403f21a3411247f164e4a8fab056e5cd8a290f4a2"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"thousand_island": {:hex, :thousand_island, "0.5.15", "3163c8b61c5e985a80e330d8544c4409e6039a1796587b812385051291b25361", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e7347a922f7c8ae3f36737455c6539bba37e3e37c17cde20f9bac3fd0367a52f"},
"websock": {:hex, :websock, "0.4.3", "184ac396bdcd3dfceb5b74c17d221af659dd559a95b1b92041ecb51c9b728093", [:mix], [], "hexpm", "5e4dd85f305f43fd3d3e25d70bec4a45228dfed60f0f3b072d8eddff335539cf"},
}

1
priv/static/app.css Normal file
View file

@ -0,0 +1 @@
@charset "utf-8";