Sample for phoenix(elixir)-postgres
Signed-off-by: Manolis Kousanakis <ekousanakis@gmail.com>
This commit is contained in:
9
phoenix-postgres/app/lib/app.ex
Normal file
9
phoenix-postgres/app/lib/app.ex
Normal file
@@ -0,0 +1,9 @@
|
||||
defmodule App do
|
||||
@moduledoc """
|
||||
App keeps the contexts that define your domain
|
||||
and business logic.
|
||||
|
||||
Contexts are also responsible for managing your data, regardless
|
||||
if it comes from the database, an external API or others.
|
||||
"""
|
||||
end
|
31
phoenix-postgres/app/lib/app/application.ex
Normal file
31
phoenix-postgres/app/lib/app/application.ex
Normal file
@@ -0,0 +1,31 @@
|
||||
defmodule App.Application do
|
||||
# See https://hexdocs.pm/elixir/Application.html
|
||||
# for more information on OTP Applications
|
||||
@moduledoc false
|
||||
|
||||
use Application
|
||||
|
||||
def start(_type, _args) do
|
||||
# List all child processes to be supervised
|
||||
children = [
|
||||
# Start the Ecto repository
|
||||
App.Repo,
|
||||
# Start the endpoint when the application starts
|
||||
AppWeb.Endpoint
|
||||
# Starts a worker by calling: App.Worker.start_link(arg)
|
||||
# {App.Worker, arg},
|
||||
]
|
||||
|
||||
# See https://hexdocs.pm/elixir/Supervisor.html
|
||||
# for other strategies and supported options
|
||||
opts = [strategy: :one_for_one, name: App.Supervisor]
|
||||
Supervisor.start_link(children, opts)
|
||||
end
|
||||
|
||||
# Tell Phoenix to update the endpoint configuration
|
||||
# whenever the application is updated.
|
||||
def config_change(changed, _new, removed) do
|
||||
AppWeb.Endpoint.config_change(changed, removed)
|
||||
:ok
|
||||
end
|
||||
end
|
55
phoenix-postgres/app/lib/app/db/release.ex
Normal file
55
phoenix-postgres/app/lib/app/db/release.ex
Normal file
@@ -0,0 +1,55 @@
|
||||
defmodule App.Db.Release do
|
||||
@doc """
|
||||
Release script for running migrations. migrate function runs all migrations
|
||||
"""
|
||||
|
||||
@app Mix.Project.config()[:app]
|
||||
@seed_script "seed.exs"
|
||||
|
||||
def migrate do
|
||||
# Get all repos and run ecto migrate
|
||||
for repo <- repos() do
|
||||
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
|
||||
end
|
||||
end
|
||||
|
||||
def rollback(repo, version) do
|
||||
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
|
||||
end
|
||||
|
||||
def seed() do
|
||||
for repo <- repos() do
|
||||
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &run_seeds_for/1)
|
||||
end
|
||||
end
|
||||
|
||||
defp run_seeds_for(repo) do
|
||||
# Run the seed script if it exists
|
||||
seed_script = priv_path_for(repo, @seed_script)
|
||||
|
||||
if File.exists?(seed_script) do
|
||||
IO.puts("Running seed script..")
|
||||
Code.eval_file(seed_script)
|
||||
end
|
||||
end
|
||||
|
||||
defp priv_path_for(repo, filename) do
|
||||
app = Keyword.get(repo.config(), :otp_app)
|
||||
|
||||
repo_underscore =
|
||||
repo
|
||||
|> Module.split()
|
||||
|> List.last()
|
||||
|> Macro.underscore()
|
||||
|
||||
priv_dir = "#{:code.priv_dir(app)}"
|
||||
|
||||
Path.join([priv_dir, repo_underscore, filename])
|
||||
end
|
||||
|
||||
# loads all repos for our app
|
||||
defp repos do
|
||||
Application.load(@app)
|
||||
Application.fetch_env!(@app, :ecto_repos)
|
||||
end
|
||||
end
|
5
phoenix-postgres/app/lib/app/repo.ex
Normal file
5
phoenix-postgres/app/lib/app/repo.ex
Normal file
@@ -0,0 +1,5 @@
|
||||
defmodule App.Repo do
|
||||
use Ecto.Repo,
|
||||
otp_app: :app,
|
||||
adapter: Ecto.Adapters.Postgres
|
||||
end
|
69
phoenix-postgres/app/lib/app_web.ex
Normal file
69
phoenix-postgres/app/lib/app_web.ex
Normal file
@@ -0,0 +1,69 @@
|
||||
defmodule AppWeb 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 AppWeb, :controller
|
||||
use AppWeb, :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.
|
||||
"""
|
||||
|
||||
def controller do
|
||||
quote do
|
||||
use Phoenix.Controller, namespace: AppWeb
|
||||
|
||||
import Plug.Conn
|
||||
import AppWeb.Gettext
|
||||
alias AppWeb.Router.Helpers, as: Routes
|
||||
end
|
||||
end
|
||||
|
||||
def view do
|
||||
quote do
|
||||
use Phoenix.View,
|
||||
root: "lib/app_web/templates",
|
||||
namespace: AppWeb
|
||||
|
||||
# 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 AppWeb.ErrorHelpers
|
||||
import AppWeb.Gettext
|
||||
alias AppWeb.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 AppWeb.Gettext
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
When used, dispatch to the appropriate controller/view/etc.
|
||||
"""
|
||||
defmacro __using__(which) when is_atom(which) do
|
||||
apply(__MODULE__, which, [])
|
||||
end
|
||||
end
|
33
phoenix-postgres/app/lib/app_web/channels/user_socket.ex
Normal file
33
phoenix-postgres/app/lib/app_web/channels/user_socket.ex
Normal file
@@ -0,0 +1,33 @@
|
||||
defmodule AppWeb.UserSocket do
|
||||
use Phoenix.Socket
|
||||
|
||||
## Channels
|
||||
# channel "room:*", AppWeb.RoomChannel
|
||||
|
||||
# Socket params are passed from the client and can
|
||||
# be used to verify and authenticate a user. After
|
||||
# verification, you can put default assigns into
|
||||
# the socket that will be set for all channels, ie
|
||||
#
|
||||
# {:ok, assign(socket, :user_id, verified_user_id)}
|
||||
#
|
||||
# To deny connection, return `:error`.
|
||||
#
|
||||
# See `Phoenix.Token` documentation for examples in
|
||||
# performing token verification on connect.
|
||||
def connect(_params, socket, _connect_info) do
|
||||
{:ok, socket}
|
||||
end
|
||||
|
||||
# Socket id's are topics that allow you to identify all sockets for a given user:
|
||||
#
|
||||
# def id(socket), do: "user_socket:#{socket.assigns.user_id}"
|
||||
#
|
||||
# Would allow you to broadcast a "disconnect" event and terminate
|
||||
# all active sockets and channels for a given user:
|
||||
#
|
||||
# AppWeb.Endpoint.broadcast("user_socket:#{user.id}", "disconnect", %{})
|
||||
#
|
||||
# Returning `nil` makes this socket anonymous.
|
||||
def id(_socket), do: nil
|
||||
end
|
@@ -0,0 +1,7 @@
|
||||
defmodule AppWeb.PageController do
|
||||
use AppWeb, :controller
|
||||
|
||||
def index(conn, _params) do
|
||||
render(conn, "index.html")
|
||||
end
|
||||
end
|
47
phoenix-postgres/app/lib/app_web/endpoint.ex
Normal file
47
phoenix-postgres/app/lib/app_web/endpoint.ex
Normal file
@@ -0,0 +1,47 @@
|
||||
defmodule AppWeb.Endpoint do
|
||||
use Phoenix.Endpoint, otp_app: :app
|
||||
|
||||
# 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.
|
||||
@session_options [
|
||||
store: :cookie,
|
||||
key: "_app_key",
|
||||
signing_salt: "We1SV0Zh"
|
||||
]
|
||||
|
||||
socket "/socket", AppWeb.UserSocket,
|
||||
websocket: true,
|
||||
longpoll: false
|
||||
|
||||
# Serve at "/" the static files from "priv/static" directory.
|
||||
#
|
||||
# You should set gzip to true if you are running phx.digest
|
||||
# when deploying your static files in production.
|
||||
plug Plug.Static,
|
||||
at: "/",
|
||||
from: :app,
|
||||
gzip: false,
|
||||
only: ~w(css fonts images js favicon.ico robots.txt)
|
||||
|
||||
# Code reloading can be explicitly enabled under the
|
||||
# :code_reloader configuration of your endpoint.
|
||||
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
|
||||
plug Plug.Session, @session_options
|
||||
plug AppWeb.Router
|
||||
end
|
24
phoenix-postgres/app/lib/app_web/gettext.ex
Normal file
24
phoenix-postgres/app/lib/app_web/gettext.ex
Normal file
@@ -0,0 +1,24 @@
|
||||
defmodule AppWeb.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 AppWeb.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: :app
|
||||
end
|
26
phoenix-postgres/app/lib/app_web/router.ex
Normal file
26
phoenix-postgres/app/lib/app_web/router.ex
Normal file
@@ -0,0 +1,26 @@
|
||||
defmodule AppWeb.Router do
|
||||
use AppWeb, :router
|
||||
|
||||
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
|
||||
|
||||
scope "/", AppWeb do
|
||||
pipe_through :browser
|
||||
|
||||
get "/", PageController, :index
|
||||
end
|
||||
|
||||
# Other scopes may use custom stacks.
|
||||
# scope "/api", AppWeb do
|
||||
# pipe_through :api
|
||||
# end
|
||||
end
|
@@ -0,0 +1,31 @@
|
||||
<!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.0"/>
|
||||
<title><%= assigns[:page_title] || "App · Phoenix Framework" %></title>
|
||||
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
|
||||
<%= csrf_meta_tag() %>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<section class="container">
|
||||
<nav role="navigation">
|
||||
<ul>
|
||||
<li><a href="https://hexdocs.pm/phoenix/overview.html">Get Started</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<a href="https://phoenixframework.org/" class="phx-logo">
|
||||
<img src="<%= Routes.static_path(@conn, "/images/phoenix.png") %>" alt="Phoenix Framework Logo"/>
|
||||
</a>
|
||||
</section>
|
||||
</header>
|
||||
<main role="main" class="container">
|
||||
<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
|
||||
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
|
||||
<%= render @view_module, @view_template, assigns %>
|
||||
</main>
|
||||
<script type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
|
||||
</body>
|
||||
</html>
|
@@ -0,0 +1,35 @@
|
||||
<section class="phx-hero">
|
||||
<h1><%= gettext "Welcome to %{name}!", name: "Phoenix" %></h1>
|
||||
<p>A productive web framework that<br/>does not compromise speed or maintainability.</p>
|
||||
</section>
|
||||
|
||||
<section class="row">
|
||||
<article class="column">
|
||||
<h2>Resources</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://hexdocs.pm/phoenix/overview.html">Guides & Docs</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/phoenixframework/phoenix">Source</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/phoenixframework/phoenix/blob/v1.4/CHANGELOG.md">v1.4 Changelog</a>
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
||||
<article class="column">
|
||||
<h2>Help</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://elixirforum.com/c/phoenix-forum">Forum</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://webchat.freenode.net/?channels=elixir-lang">#elixir-lang on Freenode IRC</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://twitter.com/elixirphoenix">Twitter @elixirphoenix</a>
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
||||
</section>
|
47
phoenix-postgres/app/lib/app_web/views/error_helpers.ex
Normal file
47
phoenix-postgres/app/lib/app_web/views/error_helpers.ex
Normal file
@@ -0,0 +1,47 @@
|
||||
defmodule AppWeb.ErrorHelpers do
|
||||
@moduledoc """
|
||||
Conveniences for translating and building error messages.
|
||||
"""
|
||||
|
||||
use Phoenix.HTML
|
||||
|
||||
@doc """
|
||||
Generates tag for inlined form input errors.
|
||||
"""
|
||||
def error_tag(form, field) do
|
||||
Enum.map(Keyword.get_values(form.errors, field), fn error ->
|
||||
content_tag(:span, translate_error(error),
|
||||
class: "help-block",
|
||||
data: [phx_error_for: input_id(form, field)]
|
||||
)
|
||||
end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Translates an error message using gettext.
|
||||
"""
|
||||
def translate_error({msg, opts}) do
|
||||
# When using gettext, we typically pass the strings we want
|
||||
# to translate as a static argument:
|
||||
#
|
||||
# # Translate "is invalid" in the "errors" domain
|
||||
# dgettext("errors", "is invalid")
|
||||
#
|
||||
# # Translate the number of files with plural rules
|
||||
# dngettext("errors", "1 file", "%{count} files", count)
|
||||
#
|
||||
# Because the error messages we show in our forms and APIs
|
||||
# are defined inside Ecto, we need to translate them dynamically.
|
||||
# This requires us to call the Gettext module passing our gettext
|
||||
# backend as first argument.
|
||||
#
|
||||
# Note we use the "errors" domain, which means translations
|
||||
# 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(AppWeb.Gettext, "errors", msg, msg, count, opts)
|
||||
else
|
||||
Gettext.dgettext(AppWeb.Gettext, "errors", msg, opts)
|
||||
end
|
||||
end
|
||||
end
|
16
phoenix-postgres/app/lib/app_web/views/error_view.ex
Normal file
16
phoenix-postgres/app/lib/app_web/views/error_view.ex
Normal file
@@ -0,0 +1,16 @@
|
||||
defmodule AppWeb.ErrorView do
|
||||
use AppWeb, :view
|
||||
|
||||
# If you want to customize a particular status code
|
||||
# for a certain format, you may uncomment below.
|
||||
# def render("500.html", _assigns) do
|
||||
# "Internal Server Error"
|
||||
# end
|
||||
|
||||
# By default, Phoenix returns the status message from
|
||||
# the template name. For example, "404.html" becomes
|
||||
# "Not Found".
|
||||
def template_not_found(template, _assigns) do
|
||||
Phoenix.Controller.status_message_from_template(template)
|
||||
end
|
||||
end
|
3
phoenix-postgres/app/lib/app_web/views/layout_view.ex
Normal file
3
phoenix-postgres/app/lib/app_web/views/layout_view.ex
Normal file
@@ -0,0 +1,3 @@
|
||||
defmodule AppWeb.LayoutView do
|
||||
use AppWeb, :view
|
||||
end
|
3
phoenix-postgres/app/lib/app_web/views/page_view.ex
Normal file
3
phoenix-postgres/app/lib/app_web/views/page_view.ex
Normal file
@@ -0,0 +1,3 @@
|
||||
defmodule AppWeb.PageView do
|
||||
use AppWeb, :view
|
||||
end
|
Reference in New Issue
Block a user