Реєстрація і авторизація (частина 2)
створимо /web/views/session_view.ex
defmodule Blog.SessionView do
use Blog.Web, :view
use Blog.Web, :controller
end
тут
use Blog.Web, :controller
означає що десь в шаблоні ми хочемо викликати функцію з контроллера (конкретно тут, здається, воно зайве,, крім того - є інший, напевно кращий спосіб це зробити -- прописати модуль-функції у модулі \web\web.ex)
створимо Session модуль (web/models/session.ex)
defmodule Blog.Session do
#use Blog.Web, :model
alias Blog.User
def login(params, repo) do
user = repo.get_by(User, email: String.downcase(params["email"]))
case authenticate(user, params["password"]) do
true -> {:ok, user}
_ -> :error
end
end
defp authenticate(user, password) do
case user do
nil -> false
_ -> Comeonin.Bcrypt.checkpw(password, user.crypted_password)
end
end
def current_user(conn) do
id = Plug.Conn.get_session(conn, :uid)
if id, do: Blog.Repo.get(User, id)
end
#def logged_in?(conn), do: !!current_user(conn)
def logged_in?(session_user) do
case session_user do
nil -> false
_ -> true
end
end
end
зробимо функції з контроллера доступними у view
для цього допишемо у \web\web.ex в функцію view наступне
import Blog.Session, only: [current_user: 1, logged_in?: 1]
тепер ми можемо дописати провірку у шаблоні \web\template\layout\app.html.eex --
на предмет того, залогінений користувач чи ні, показувати йому посилання на реєстрацію чи на вихід
зверху пропишемо
<% sess_user = current_user(@conn) %>
і нижче власне саму перевірку
<%= if logged_in?(sess_user) do %>
<span><%= sess_user.email %></span>
<span><%= link "Logout", to: session_path(@conn, :delete), method: :delete %></span>
<% else %>
<span><%= link "Login", to: "/login" %></span>
<span><%= link "Register", to: registration_path(@conn, :new) %></span>
<% end %>
щоб передати дані нижче по шаблону - пропишемо
<%= render @view_module, @view_template, Map.put(assigns, :sess_user, sess_user) %>
зміни до написаного раніше --
написання постів -
додав перевірку(пост може видаляти, писати, редагувати лише адмін)
для того щоб працювала така переадресація-заглушка
put_status(conn, 403)
|> render(Blog.ErrorView, "403.html", %{})
потрібно додати функцію в модуль \web\views\error_view.ex
def render("403.html", _assigns) do
"Access forbidden"
end
загалом код для функціоналу цих змін ми уже написали, а про таблицю бд - забули
додамо новий стовпчик у таблицю users
для цього згенеруємо міграцію
$ mix ecto.gen.migration add_fields_to_users
знайдемо де вона згенерувалася і відредагуємо
(\blog\priv\repo\migrations\xxxxxxxxx_add_fields_to_users.exs)
defmodule Blog.Repo.Migrations.AddFieldsToUsers do
use Ecto.Migration
def change do
alter table(:users) do
add :type, :smallint, null: false, default: 1
end
end
end
застосуємо зміни
у результаті у нас зявиться ще один стовпчик -- отакий получиться дамп якщо зробимо його зараз
DROP TABLE "public"."users";
CREATE TABLE "public"."users" (
"id" int4 DEFAULT nextval('users_id_seq'::regclass) NOT NULL,
"email" varchar(255),
"crypted_password" varchar(255),
"inserted_at" timestamp(6) NOT NULL,
"updated_at" timestamp(6) NOT NULL,
"type" int2 DEFAULT 1 NOT NULL
)
WITH (OIDS=FALSE);
для тесту додамо ще один стовпчик
$ mix ecto.gen.migration add_test_to_users
defmodule Blog.Repo.Migrations.AddTestToUsers do
use Ecto.Migration
def change do
alter table(:users) do
add :test, :bigint, default: 1
end
end
end
застосуємо зміни
у результаті у нас зявиться ще один стовпчик -- отакий получиться дамп якщо зробимо його зараз
DROP TABLE "public"."users";
CREATE TABLE "public"."users" (
"id" int4 DEFAULT nextval('users_id_seq'::regclass) NOT NULL,
"email" varchar(255),
"crypted_password" varchar(255),
"inserted_at" timestamp(6) NOT NULL,
"updated_at" timestamp(6) NOT NULL,
"type" int2 DEFAULT 1 NOT NULL,
"test" int8 DEFAULT 1
)
WITH (OIDS=FALSE);
тепер видалимо цей тестовий стовпчик
$ mix ecto.gen.migration del_test_to_users
defmodule Blog.Repo.Migrations.DelTestToUsers do
use Ecto.Migration
def change do
alter table(:users) do
remove :test
end
end
end
застосуємо зміни
очікуваний результат
DROP TABLE "public"."users";
CREATE TABLE "public"."users" (
"id" int4 DEFAULT nextval('users_id_seq'::regclass) NOT NULL,
"email" varchar(255),
"crypted_password" varchar(255),
"inserted_at" timestamp(6) NOT NULL,
"updated_at" timestamp(6) NOT NULL,
"type" int2 DEFAULT 1 NOT NULL
)
WITH (OIDS=FALSE);
зробимо користувача з id 1 адміном
$ mix ecto.gen.migration make_adm
defmodule Blog.Repo.Migrations.MakeAdm do
use Ecto.Migration
def change do
#Blog.Repo.update_all("users", set: [type: 1])
%Blog.User{id: 1}
|> Ecto.Changeset.change(type: 9)
|> Blog.Repo.update
end
end
застосуємо зміни
ще трошки про зміни написано раніше --
у роутері (\web\router.ex) було вирішено зробити такі зміни
#resources "/posts", PostController do
# post "/comment", PostController, :add_comment
#end
resources "/posts", PostController
post "/posts/:post_id/comment", PostController, :add_comment
щоб позбутися "неапетитного" шляху post_post_path (його ви можете побачити у web\templates\post\show.html.eex) та для більшої прозорості
такс, наче нічого важливо не забув,
а решту дрібних зміни ви можете подивитись на гітхабі
загалом отакий комміт получився -- https://github.com/221V/mini-blog/commi … b170189dc9
за матеріалами -
http://nithinbekal.com/posts/phoenix-authentication/
http://meatherly.github.io/2015/05/11/p … ntication/
http://www.phoenixframework.org/docs/
https://hexdocs.pm/phoenix/Phoenix.html
https://hexdocs.pm/ecto/Ecto.html
https://hexdocs.pm/phoenix_html/Phoenix.HTML.html
та з допомогою Neb0 -
http://www.cyberforum.ru/blogs/12078/
Дякую за увагу
далі буде... (напевно наступне - оцінка постів, лайки комментів, рейтинги якісь [роздуми у спостеріганні структури пікабу,хабра,анекдот.ру,різних блогів,...] )
(+ поправлю ще реєстрацію і написання коментарі -- а то зараз просто база для спамера получається )