Compare commits
3 commits
118922be50
...
339d075edd
Author | SHA1 | Date | |
---|---|---|---|
339d075edd | |||
56730540b7 | |||
dee1bef5bf |
19 changed files with 295 additions and 107 deletions
.envrc.formatter.exs
config
lib
mix.exsmix.locktest/support
1
.envrc
Normal file
1
.envrc
Normal file
|
@ -0,0 +1 @@
|
|||
export PASSWORD_HASH='$argon2id$v=19$m=65536,t=3,p=4$ctxMPSfgu5i28J0bjRl2yg$D7+qs+R7caAe5lw5m7s+k9M0t75R4XBhkwG1dv6MGOQ'
|
|
@ -1,6 +1,6 @@
|
|||
[
|
||||
import_deps: [:ecto, :ecto_sql, :phoenix],
|
||||
subdirectories: ["priv/*/migrations"],
|
||||
plugins: [Phoenix.LiveView.HTMLFormatter],
|
||||
plugins: [Styler, Phoenix.LiveView.HTMLFormatter],
|
||||
inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"]
|
||||
]
|
||||
|
|
|
@ -7,11 +7,6 @@
|
|||
# General application configuration
|
||||
import Config
|
||||
|
||||
config :cms,
|
||||
namespace: CMS,
|
||||
ecto_repos: [CMS.Repo],
|
||||
generators: [timestamp_type: :utc_datetime, binary_id: true]
|
||||
|
||||
# Configures the endpoint
|
||||
config :cms, CMSWeb.Endpoint,
|
||||
url: [host: "localhost"],
|
||||
|
@ -23,28 +18,20 @@ config :cms, CMSWeb.Endpoint,
|
|||
pubsub_server: CMS.PubSub,
|
||||
live_view: [signing_salt: "afQxdsCJ"]
|
||||
|
||||
config :cms,
|
||||
namespace: CMS,
|
||||
ecto_repos: [CMS.Repo],
|
||||
generators: [timestamp_type: :utc_datetime, binary_id: true]
|
||||
|
||||
# Configure esbuild (the version is required)
|
||||
config :esbuild,
|
||||
version: "0.17.11",
|
||||
cms: [
|
||||
args:
|
||||
~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*),
|
||||
args: ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*),
|
||||
cd: Path.expand("../assets", __DIR__),
|
||||
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
|
||||
]
|
||||
|
||||
# Configure tailwind (the version is required)
|
||||
config :tailwind,
|
||||
version: "3.4.3",
|
||||
cms: [
|
||||
args: ~w(
|
||||
--config=tailwind.config.js
|
||||
--input=css/app.css
|
||||
--output=../priv/static/assets/app.css
|
||||
),
|
||||
cd: Path.expand("../assets", __DIR__)
|
||||
]
|
||||
|
||||
# Configures Elixir's Logger
|
||||
config :logger, :console,
|
||||
format: "$time $metadata[$level] $message\n",
|
||||
|
@ -53,6 +40,19 @@ config :logger, :console,
|
|||
# Use Jason for JSON parsing in Phoenix
|
||||
config :phoenix, :json_library, Jason
|
||||
|
||||
# Import environment specific config. This must remain at the bottom
|
||||
# of this file so it overrides the configuration defined above.
|
||||
# Configure tailwind (the version is required)
|
||||
config :tailwind,
|
||||
version: "3.4.3",
|
||||
cms: [
|
||||
args: ~w(
|
||||
--config=tailwind.config.js
|
||||
--input=css/app.css
|
||||
--output=../priv/static/assets/app.css
|
||||
),
|
||||
|
||||
# Import environment specific config. This must remain at the bottom
|
||||
# of this file so it overrides the configuration defined above.
|
||||
cd: Path.expand("../assets", __DIR__)
|
||||
]
|
||||
|
||||
import_config "#{config_env()}.exs"
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
import Config
|
||||
|
||||
# Configure your database
|
||||
# For development, we disable any cache and enable
|
||||
# debugging and code reloading.
|
||||
#
|
||||
# The watchers configuration can be used to run external
|
||||
# watchers to your application. For example, we can use it
|
||||
# to bundle .js and .css sources.
|
||||
# Binding to loopback ipv4 address prevents access from other machines.
|
||||
config :cms, CMS.Repo,
|
||||
username: "postgres",
|
||||
password: "postgres",
|
||||
|
@ -10,13 +17,6 @@ config :cms, CMS.Repo,
|
|||
show_sensitive_data_on_connection_error: true,
|
||||
pool_size: 10
|
||||
|
||||
# For development, we disable any cache and enable
|
||||
# debugging and code reloading.
|
||||
#
|
||||
# The watchers configuration can be used to run external
|
||||
# watchers to your application. For example, we can use it
|
||||
# to bundle .js and .css sources.
|
||||
# Binding to loopback ipv4 address prevents access from other machines.
|
||||
config :cms, CMSWeb.Endpoint,
|
||||
# Change to `ip: {0, 0, 0, 0}` to allow access from other machines.
|
||||
http: [ip: {127, 0, 0, 1}, port: 4000],
|
||||
|
@ -29,29 +29,6 @@ config :cms, CMSWeb.Endpoint,
|
|||
tailwind: {Tailwind, :install_and_run, [:cms, ~w(--watch)]}
|
||||
]
|
||||
|
||||
# ## SSL Support
|
||||
#
|
||||
# In order to use HTTPS in development, a self-signed
|
||||
# certificate can be generated by running the following
|
||||
# Mix task:
|
||||
#
|
||||
# mix phx.gen.cert
|
||||
#
|
||||
# Run `mix help phx.gen.cert` for more information.
|
||||
#
|
||||
# The `http:` config above can be replaced with:
|
||||
#
|
||||
# https: [
|
||||
# port: 4001,
|
||||
# cipher_suite: :strong,
|
||||
# keyfile: "priv/cert/selfsigned_key.pem",
|
||||
# certfile: "priv/cert/selfsigned.pem"
|
||||
# ],
|
||||
#
|
||||
# If desired, both `http:` and `https:` keys can be
|
||||
# configured to run both http and https servers on
|
||||
# different ports.
|
||||
|
||||
# Watch static and templates for browser reloading.
|
||||
config :cms, CMSWeb.Endpoint,
|
||||
live_reload: [
|
||||
|
@ -61,21 +38,45 @@ config :cms, CMSWeb.Endpoint,
|
|||
]
|
||||
]
|
||||
|
||||
# ## SSL Support
|
||||
#
|
||||
|
||||
# Enable dev routes for dashboard and mailbox
|
||||
# In order to use HTTPS in development, a self-signed
|
||||
# certificate can be generated by running the following
|
||||
# Mix task:
|
||||
#
|
||||
config :cms, dev_routes: true
|
||||
|
||||
# Do not include metadata nor timestamps in development logs
|
||||
# mix phx.gen.cert
|
||||
#
|
||||
# Run `mix help phx.gen.cert` for more information.
|
||||
#
|
||||
config :logger, :console, format: "[$level] $message\n"
|
||||
|
||||
# Set a higher stacktrace during development. Avoid configuring such
|
||||
# in production as building large stacktraces may be expensive.
|
||||
config :phoenix, :stacktrace_depth, 20
|
||||
|
||||
# Initialize plugs at runtime for faster development compilation
|
||||
# The `http:` config above can be replaced with:
|
||||
#
|
||||
# https: [
|
||||
config :phoenix, :plug_init_mode, :runtime
|
||||
|
||||
# Set a higher stacktrace during development. Avoid configuring such
|
||||
# port: 4001,
|
||||
# in production as building large stacktraces may be expensive.
|
||||
# cipher_suite: :strong,
|
||||
# keyfile: "priv/cert/selfsigned_key.pem",
|
||||
# certfile: "priv/cert/selfsigned.pem"
|
||||
config :phoenix, :stacktrace_depth, 20
|
||||
|
||||
config :phoenix_live_view,
|
||||
# Include HEEx debug annotations as HTML comments in rendered markup
|
||||
# ],
|
||||
#
|
||||
debug_heex_annotations: true,
|
||||
# Enable helpful, but potentially expensive runtime checks
|
||||
# If desired, both `http:` and `https:` keys can be
|
||||
# configured to run both http and https servers on
|
||||
# different ports.
|
||||
|
||||
enable_expensive_runtime_checks: true
|
||||
|
|
|
@ -20,6 +20,15 @@ if System.get_env("PHX_SERVER") do
|
|||
config :cms, CMSWeb.Endpoint, server: true
|
||||
end
|
||||
|
||||
config :cms,
|
||||
password_hash:
|
||||
System.get_env("PASSWORD_HASH") ||
|
||||
raise("""
|
||||
environment variable PASSWORD_HASH is missing.
|
||||
|
||||
Generate a hashed password using `mix cms.gen.password_hash`
|
||||
""")
|
||||
|
||||
if config_env() == :prod do
|
||||
database_url =
|
||||
System.get_env("DATABASE_URL") ||
|
||||
|
@ -30,12 +39,6 @@ if config_env() == :prod do
|
|||
|
||||
maybe_ipv6 = if System.get_env("ECTO_IPV6") in ~w(true 1), do: [:inet6], else: []
|
||||
|
||||
config :cms, CMS.Repo,
|
||||
# ssl: true,
|
||||
url: database_url,
|
||||
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
|
||||
socket_options: maybe_ipv6
|
||||
|
||||
# The secret key base is used to sign/encrypt cookies and other secrets.
|
||||
# A default value is used in config/dev.exs and config/test.exs but you
|
||||
# want to use a different value for prod and you most likely don't want
|
||||
|
@ -51,7 +54,11 @@ if config_env() == :prod do
|
|||
host = System.get_env("PHX_HOST") || "example.com"
|
||||
port = String.to_integer(System.get_env("PORT") || "4000")
|
||||
|
||||
config :cms, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY")
|
||||
config :cms, CMS.Repo,
|
||||
# ssl: true,
|
||||
url: database_url,
|
||||
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
|
||||
socket_options: maybe_ipv6
|
||||
|
||||
config :cms, CMSWeb.Endpoint,
|
||||
url: [host: host, port: 443, scheme: "https"],
|
||||
|
@ -65,6 +72,8 @@ if config_env() == :prod do
|
|||
],
|
||||
secret_key_base: secret_key_base
|
||||
|
||||
config :cms, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY")
|
||||
|
||||
# ## SSL Support
|
||||
#
|
||||
# To get SSL working, you will need to add the `https` key
|
||||
|
|
|
@ -23,10 +23,11 @@ defmodule CMSWeb do
|
|||
quote do
|
||||
use Phoenix.Router, helpers: false
|
||||
|
||||
# Import common connection and controller functions to use in pipelines
|
||||
import Plug.Conn
|
||||
import Phoenix.Controller
|
||||
import Phoenix.LiveView.Router
|
||||
|
||||
# Import common connection and controller functions to use in pipelines
|
||||
import Plug.Conn
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -80,10 +81,10 @@ defmodule CMSWeb do
|
|||
|
||||
defp html_helpers do
|
||||
quote do
|
||||
import CMSWeb.CoreComponents
|
||||
# HTML escaping functionality
|
||||
import Phoenix.HTML
|
||||
# Core UI components
|
||||
import CMSWeb.CoreComponents
|
||||
|
||||
# Shortcut for generating JS commands
|
||||
alias Phoenix.LiveView.JS
|
||||
|
|
|
@ -1,14 +1,30 @@
|
|||
<div class="flex flex-col md:flex-row mx-auto max-w-3xl">
|
||||
<section class="flex flex-col p-2 gap-y-1 border-slate-100 border-b md:border-b-0">
|
||||
<.link navigate={~p"/"} class="font-bold hover:underline">sloanelybutsurely.com</.link>
|
||||
<div :if={@admin?} class="flex flex-row justify-between py-1 px-3 mb-2 border-b border-slate-100">
|
||||
<section class="flex flex-row gap-x-2">
|
||||
<div class="pr-2 border-r border-slate-100">
|
||||
<.link navigate={~p"/admin"} class="font-bold">admin mode</.link>
|
||||
</div>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><.link navigate={~p"/writing"} class="hover:underline">writing</.link></li>
|
||||
<li><.link navigate={~p"/microblog"} class="hover:underline">microblog</.link></li>
|
||||
<ul class="flex flex-row">
|
||||
<.link href="#" class="hover:underline">new post</.link>
|
||||
</ul>
|
||||
</nav>
|
||||
</section>
|
||||
<main>
|
||||
|
||||
<section class="flex flex-row">
|
||||
<.link href={~p"/admin/session"} method="delete" class="hover:underline">sign out</.link>
|
||||
</section>
|
||||
</div>
|
||||
<div class="flex flex-col md:flex-row mx-auto max-w-4xl">
|
||||
<section class="flex flex-col p-2 gap-y-1 border-slate-100 border-b md:border-b-0">
|
||||
<.link href={~p"/"} class="font-bold hover:underline">sloanelybutsurely.com</.link>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><.link href={~p"/writing"} class="hover:underline">writing</.link></li>
|
||||
<li><.link href={~p"/microblog"} class="hover:underline">microblog</.link></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</section>
|
||||
<main class="p-2">
|
||||
{@inner_content}
|
||||
</main>
|
||||
</div>
|
||||
|
|
40
lib/cms_web/controllers/admin_auth.ex
Normal file
40
lib/cms_web/controllers/admin_auth.ex
Normal file
|
@ -0,0 +1,40 @@
|
|||
defmodule CMSWeb.AdminAuth do
|
||||
@moduledoc false
|
||||
use CMSWeb, :verified_routes
|
||||
|
||||
import Phoenix.Controller
|
||||
import Plug.Conn
|
||||
|
||||
def log_in_admin(conn) do
|
||||
conn
|
||||
|> renew_session()
|
||||
|> put_session(:admin?, true)
|
||||
|> redirect(to: ~p"/")
|
||||
end
|
||||
|
||||
def log_out_admin(conn) do
|
||||
if live_socket_id = get_session(conn, :live_socket_id) do
|
||||
CMSWeb.Endpoint.broadcast(live_socket_id, "disconnect", %{})
|
||||
end
|
||||
|
||||
conn
|
||||
|> renew_session()
|
||||
|> redirect(to: ~p"/")
|
||||
end
|
||||
|
||||
def correct_password?(password) do
|
||||
password_hash = Application.fetch_env!(:cms, :password_hash)
|
||||
|
||||
Argon2.verify_pass(password, password_hash)
|
||||
end
|
||||
|
||||
## private
|
||||
|
||||
defp renew_session(conn) do
|
||||
delete_csrf_token()
|
||||
|
||||
conn
|
||||
|> configure_session(renew: true)
|
||||
|> clear_session()
|
||||
end
|
||||
end
|
18
lib/cms_web/controllers/admin_mode.ex
Normal file
18
lib/cms_web/controllers/admin_mode.ex
Normal file
|
@ -0,0 +1,18 @@
|
|||
defmodule CMSWeb.AdminMode do
|
||||
@moduledoc false
|
||||
use CMSWeb, :live_view
|
||||
|
||||
def admin_mode(%Plug.Conn{} = conn, _opts) do
|
||||
Plug.Conn.assign(conn, :admin?, admin?(conn))
|
||||
end
|
||||
|
||||
def on_mount(:default, _params, session, socket) do
|
||||
{:cont, assign(socket, :admin?, admin?(session))}
|
||||
end
|
||||
|
||||
defp admin?(%Plug.Conn{} = conn) do
|
||||
Plug.Conn.get_session(conn, :admin?, false) == true
|
||||
end
|
||||
|
||||
defp admin?(%{} = session), do: Map.get(session, :admin?, false) == true
|
||||
end
|
23
lib/cms_web/controllers/admin_session_controller.ex
Normal file
23
lib/cms_web/controllers/admin_session_controller.ex
Normal file
|
@ -0,0 +1,23 @@
|
|||
defmodule CMSWeb.AdminSessionController do
|
||||
use CMSWeb, :controller
|
||||
|
||||
alias CMSWeb.AdminAuth
|
||||
|
||||
def create(conn, %{"password" => password}) do
|
||||
if AdminAuth.correct_password?(password) do
|
||||
AdminAuth.log_in_admin(conn)
|
||||
else
|
||||
redirect(conn, to: ~p"/admin/sign-in")
|
||||
end
|
||||
end
|
||||
|
||||
def create(conn, _params) do
|
||||
redirect(conn, to: ~p"/admin/sign-in")
|
||||
end
|
||||
|
||||
def destroy(conn, _params) do
|
||||
conn
|
||||
|> AdminAuth.log_out_admin()
|
||||
|> redirect(to: ~p"/")
|
||||
end
|
||||
end
|
16
lib/cms_web/live/admin_live.ex
Normal file
16
lib/cms_web/live/admin_live.ex
Normal file
|
@ -0,0 +1,16 @@
|
|||
defmodule CMSWeb.AdminLive do
|
||||
@moduledoc false
|
||||
use CMSWeb, :live_view
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
{:ok, socket}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<h1>AdminLive</h1>
|
||||
"""
|
||||
end
|
||||
end
|
29
lib/cms_web/live/admin_login_live.ex
Normal file
29
lib/cms_web/live/admin_login_live.ex
Normal file
|
@ -0,0 +1,29 @@
|
|||
defmodule CMSWeb.AdminLoginLive do
|
||||
@moduledoc false
|
||||
use CMSWeb, :live_view
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
socket = assign(socket, :form, to_form(%{"password" => ""}))
|
||||
|
||||
{:ok, socket}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<h1 class="font-bold text-lg mb-4">Sign in</h1>
|
||||
|
||||
<.form for={@form} action={~p"/admin/session"}>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="password"
|
||||
id={@form[:password].id}
|
||||
name={@form[:password].name}
|
||||
value={@form[:password].value}
|
||||
required
|
||||
/>
|
||||
</.form>
|
||||
"""
|
||||
end
|
||||
end
|
|
@ -1,6 +1,10 @@
|
|||
defmodule CMSWeb.Router do
|
||||
use CMSWeb, :router
|
||||
|
||||
import CMSWeb.AdminMode
|
||||
|
||||
alias CMSWeb.AdminMode
|
||||
|
||||
pipeline :browser do
|
||||
plug :accepts, ["html"]
|
||||
plug :fetch_session
|
||||
|
@ -8,25 +12,26 @@ defmodule CMSWeb.Router do
|
|||
plug :put_root_layout, html: {CMSWeb.Layouts, :root}
|
||||
plug :protect_from_forgery
|
||||
plug :put_secure_browser_headers
|
||||
plug :admin_mode
|
||||
end
|
||||
|
||||
pipeline :api do
|
||||
plug :accepts, ["json"]
|
||||
live_session :default, on_mount: AdminMode do
|
||||
scope "/", CMSWeb do
|
||||
pipe_through :browser
|
||||
|
||||
get "/", PageController, :home
|
||||
get "/writing", PageController, :writing
|
||||
get "/microblog", PageController, :microblog
|
||||
|
||||
live "/admin", AdminLive
|
||||
|
||||
live "/admin/sign-in", AdminLoginLive
|
||||
|
||||
post "/admin/session", AdminSessionController, :create
|
||||
delete "/admin/session", AdminSessionController, :destroy
|
||||
end
|
||||
end
|
||||
|
||||
scope "/", CMSWeb do
|
||||
pipe_through :browser
|
||||
|
||||
get "/", PageController, :home
|
||||
get "/writing", PageController, :writing
|
||||
get "/microblog", PageController, :microblog
|
||||
end
|
||||
|
||||
# Other scopes may use custom stacks.
|
||||
# scope "/api", CMSWeb do
|
||||
# pipe_through :api
|
||||
# end
|
||||
|
||||
# Enable LiveDashboard in development
|
||||
if Application.compile_env(:cms, :dev_routes) do
|
||||
# If you want to use the LiveDashboard in production, you should put
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
defmodule CMSWeb.Telemetry do
|
||||
@moduledoc false
|
||||
use Supervisor
|
||||
|
||||
import Telemetry.Metrics
|
||||
|
||||
def start_link(arg) do
|
||||
|
@ -70,8 +72,7 @@ defmodule CMSWeb.Telemetry do
|
|||
),
|
||||
summary("cms.repo.query.idle_time",
|
||||
unit: {:native, :millisecond},
|
||||
description:
|
||||
"The time the connection spent waiting before being checked out for the query"
|
||||
description: "The time the connection spent waiting before being checked out for the query"
|
||||
),
|
||||
|
||||
# VM Metrics
|
||||
|
|
23
lib/mix/tasks/cms.gen.password_hash.ex
Normal file
23
lib/mix/tasks/cms.gen.password_hash.ex
Normal file
|
@ -0,0 +1,23 @@
|
|||
defmodule Mix.Tasks.Cms.Gen.PasswordHash do
|
||||
@shortdoc @moduledoc
|
||||
@moduledoc """
|
||||
Hashes a password for the admin account
|
||||
"""
|
||||
use Mix.Task
|
||||
|
||||
@impl Mix.Task
|
||||
def run(_args) do
|
||||
password = Mix.shell().prompt("Password: ")
|
||||
password = String.trim_trailing(password)
|
||||
|
||||
password_confirmation = Mix.shell().prompt("Confirm password: ")
|
||||
password_confirmation = String.trim_trailing(password_confirmation)
|
||||
|
||||
if password == password_confirmation do
|
||||
hashed = Argon2.hash_pwd_salt(password)
|
||||
Mix.shell().info(hashed)
|
||||
else
|
||||
Mix.shell().error("Passwords do not match")
|
||||
end
|
||||
end
|
||||
end
|
13
mix.exs
13
mix.exs
|
@ -44,17 +44,16 @@ defmodule CMS.MixProject do
|
|||
{:esbuild, "~> 0.8", runtime: Mix.env() == :dev},
|
||||
{:tailwind, "~> 0.2", runtime: Mix.env() == :dev},
|
||||
{:heroicons,
|
||||
github: "tailwindlabs/heroicons",
|
||||
tag: "v2.1.1",
|
||||
sparse: "optimized",
|
||||
app: false,
|
||||
compile: false,
|
||||
depth: 1},
|
||||
github: "tailwindlabs/heroicons", tag: "v2.1.1", sparse: "optimized", app: false, compile: false, depth: 1},
|
||||
{:telemetry_metrics, "~> 1.0"},
|
||||
{:telemetry_poller, "~> 1.0"},
|
||||
{:jason, "~> 1.2"},
|
||||
{:dns_cluster, "~> 0.1.1"},
|
||||
{:bandit, "~> 1.5"}
|
||||
{:bandit, "~> 1.5"},
|
||||
{:argon2_elixir, "~> 4.1"},
|
||||
|
||||
# dev/test only
|
||||
{:styler, "~> 1.4", only: [:dev, :test], runtime: false}
|
||||
]
|
||||
end
|
||||
|
||||
|
|
4
mix.lock
4
mix.lock
|
@ -1,11 +1,14 @@
|
|||
%{
|
||||
"argon2_elixir": {:hex, :argon2_elixir, "4.1.2", "1160a3ccd59b951175525882240651f5ed3303b75c616204713f8b31c76b37bd", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "9222341e1b0d9aa5ca7e26a1c77bd1bd92d2314c92b57ca3e2c7ed847223b51d"},
|
||||
"bandit": {:hex, :bandit, "1.6.7", "42f30e37a1c89a2a12943c5dca76f731a2313e8a2e21c1a95dc8241893e922d1", [:mix], [{:hpax, "~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "551ba8ff5e4fc908cbeb8c9f0697775fb6813a96d9de5f7fe02e34e76fd7d184"},
|
||||
"castore": {:hex, :castore, "1.0.11", "4bbd584741601eb658007339ea730b082cc61f3554cf2e8f39bf693a11b49073", [:mix], [], "hexpm", "e03990b4db988df56262852f20de0f659871c35154691427a5047f4967a16a62"},
|
||||
"comeonin": {:hex, :comeonin, "5.5.1", "5113e5f3800799787de08a6e0db307133850e635d34e9fab23c70b6501669510", [:mix], [], "hexpm", "65aac8f19938145377cee73973f192c5645873dcf550a8a6b18187d17c13ccdb"},
|
||||
"db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},
|
||||
"decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"},
|
||||
"dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"},
|
||||
"ecto": {:hex, :ecto, "3.12.5", "4a312960ce612e17337e7cefcf9be45b95a3be6b36b6f94dfb3d8c361d631866", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6eb18e80bef8bb57e17f5a7f068a1719fbda384d40fc37acb8eb8aeca493b6ea"},
|
||||
"ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"},
|
||||
"elixir_make": {:hex, :elixir_make, "0.9.0", "6484b3cd8c0cee58f09f05ecaf1a140a8c97670671a6a0e7ab4dc326c3109726", [:mix], [], "hexpm", "db23d4fd8b757462ad02f8aa73431a426fe6671c80b200d9710caf3d1dd0ffdb"},
|
||||
"esbuild": {:hex, :esbuild, "0.9.0", "f043eeaca4932ca8e16e5429aebd90f7766f31ac160a25cbd9befe84f2bc068f", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b415027f71d5ab57ef2be844b2a10d0c1b5a492d431727f43937adce22ba45ae"},
|
||||
"file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"},
|
||||
"floki": {:hex, :floki, "0.37.0", "b83e0280bbc6372f2a403b2848013650b16640cd2470aea6701f0632223d719e", [:mix], [], "hexpm", "516a0c15a69f78c47dc8e0b9b3724b29608aa6619379f91b1ffa47109b5d0dd3"},
|
||||
|
@ -24,6 +27,7 @@
|
|||
"plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"},
|
||||
"plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"},
|
||||
"postgrex": {:hex, :postgrex, "0.20.0", "363ed03ab4757f6bc47942eff7720640795eb557e1935951c1626f0d303a3aed", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "d36ef8b36f323d29505314f704e21a1a038e2dc387c6409ee0cd24144e187c0f"},
|
||||
"styler": {:hex, :styler, "1.4.0", "5944723d08afe4d38210b674d7e97dd1137a75968a85a633983cc308e86dc5f2", [:mix], [], "hexpm", "07de0e89c27490c8e469bb814d77ddaaa3283d7d8038501021d80a7705cf13e9"},
|
||||
"tailwind": {:hex, :tailwind, "0.2.4", "5706ec47182d4e7045901302bf3a333e80f3d1af65c442ba9a9eed152fb26c2e", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "c6e4a82b8727bab593700c998a4d98cf3d8025678bfde059aed71d0000c3e463"},
|
||||
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
|
||||
"telemetry_metrics": {:hex, :telemetry_metrics, "1.1.0", "5bd5f3b5637e0abea0426b947e3ce5dd304f8b3bc6617039e2b5a008adc02f8f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e7b79e8ddfde70adb6db8a6623d1778ec66401f366e9a8f5dd0955c56bc8ce67"},
|
||||
|
|
|
@ -19,15 +19,15 @@ defmodule CMSWeb.ConnCase do
|
|||
|
||||
using do
|
||||
quote do
|
||||
use CMSWeb, :verified_routes
|
||||
|
||||
import CMSWeb.ConnCase
|
||||
import Phoenix.ConnTest
|
||||
import Plug.Conn
|
||||
# The default endpoint for testing
|
||||
@endpoint CMSWeb.Endpoint
|
||||
|
||||
use CMSWeb, :verified_routes
|
||||
|
||||
# Import conveniences for testing with connections
|
||||
import Plug.Conn
|
||||
import Phoenix.ConnTest
|
||||
import CMSWeb.ConnCase
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -16,14 +16,16 @@ defmodule CMS.DataCase do
|
|||
|
||||
use ExUnit.CaseTemplate
|
||||
|
||||
alias Ecto.Adapters.SQL.Sandbox
|
||||
|
||||
using do
|
||||
quote do
|
||||
alias CMS.Repo
|
||||
|
||||
import CMS.DataCase
|
||||
import Ecto
|
||||
import Ecto.Changeset
|
||||
import Ecto.Query
|
||||
import CMS.DataCase
|
||||
|
||||
alias CMS.Repo
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -36,8 +38,8 @@ defmodule CMS.DataCase do
|
|||
Sets up the sandbox based on the test tags.
|
||||
"""
|
||||
def setup_sandbox(tags) do
|
||||
pid = Ecto.Adapters.SQL.Sandbox.start_owner!(CMS.Repo, shared: not tags[:async])
|
||||
on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
|
||||
pid = Sandbox.start_owner!(CMS.Repo, shared: not tags[:async])
|
||||
on_exit(fn -> Sandbox.stop_owner(pid) end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
|
Loading…
Reference in a new issue