diff --git a/README.md b/README.md --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ * Node.js version 5.0.0 or newer is required. * Install dependencies with `npm install` * Install babel presets: `npm install babel-preset-es2015 babel-preset-es2016` +* Initialize database: `mix amnesia.create -db KolabChat.Database --disk` * Start Phoenix endpoint with `mix phoenix.server` Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. diff --git a/config/config.exs b/config/config.exs --- a/config/config.exs +++ b/config/config.exs @@ -7,7 +7,6 @@ # General application configuration config :kolab_chat, - ecto_repos: [KolabChat.Repo], salts: [session_signing: "M7HpCp6W", session_encryption: nil] diff --git a/config/dev.exs b/config/dev.exs --- a/config/dev.exs +++ b/config/dev.exs @@ -32,12 +32,3 @@ # Set a higher stacktrace during development. Avoid configuring such # in production as building large stacktraces may be expensive. config :phoenix, :stacktrace_depth, 20 - -# Configure your database -config :kolab_chat, KolabChat.Repo, - adapter: Ecto.Adapters.MySQL, - username: "root", - password: "12345", - database: "kolab_chat_dev", - hostname: "localhost", - pool_size: 10 diff --git a/config/test.exs b/config/test.exs --- a/config/test.exs +++ b/config/test.exs @@ -8,12 +8,3 @@ # Print only warnings and errors during test config :logger, level: :warn - -# Configure your database -config :kolab_chat, KolabChat.Repo, - adapter: Ecto.Adapters.MySQL, - username: "root", - password: "12345", - database: "kolab_chat_test", - hostname: "localhost", - pool: Ecto.Adapters.SQL.Sandbox diff --git a/lib/kolab_chat.ex b/lib/kolab_chat.ex --- a/lib/kolab_chat.ex +++ b/lib/kolab_chat.ex @@ -8,8 +8,6 @@ # Define workers and child supervisors to be supervised children = [ - # Start the Ecto repository - supervisor(KolabChat.Repo, []), # Start the endpoint when the application starts supervisor(KolabChat.Endpoint, []), # Start phoenix presence module diff --git a/lib/kolab_chat/database.ex b/lib/kolab_chat/database.ex new file mode 100644 --- /dev/null +++ b/lib/kolab_chat/database.ex @@ -0,0 +1,19 @@ +use Amnesia + +defdatabase KolabChat.Database do + + deftable User, [{:id, autoincrement}, :username, :fullname], type: :ordered_set, index: [:username] do + + # Find a user by username + def find(username) do + Amnesia.transaction do + case User.read_at(username, :username) do + nil -> nil + users -> Enum.at(users, 0) + end + end + end + + end + +end diff --git a/lib/kolab_chat/repo.ex b/lib/kolab_chat/repo.ex deleted file mode 100644 --- a/lib/kolab_chat/repo.ex +++ /dev/null @@ -1,3 +0,0 @@ -defmodule KolabChat.Repo do - use Ecto.Repo, otp_app: :kolab_chat -end diff --git a/mix.exs b/mix.exs --- a/mix.exs +++ b/mix.exs @@ -19,7 +19,7 @@ def application do [mod: {KolabChat, []}, applications: [:phoenix, :phoenix_pubsub, :phoenix_html, :cowboy, :logger, :gettext, - :phoenix_ecto, :mariaex]] + :amnesia]] end # Specifies which paths to compile per environment. @@ -32,11 +32,10 @@ defp deps do [{:phoenix, "~> 1.2.1"}, {:phoenix_pubsub, "~> 1.0"}, - {:phoenix_ecto, "~> 3.0"}, - {:mariaex, "~> 0.7.9", override: true}, {:phoenix_html, "~> 2.6"}, {:phoenix_live_reload, "~> 1.0", only: :dev}, {:gettext, "~> 0.11"}, + {:amnesia, "~> 0.2.0"}, {:cowboy, "~> 1.0"}] end @@ -47,8 +46,6 @@ # # See the documentation for `Mix` for more info on aliases. defp aliases do - ["ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"], - "ecto.reset": ["ecto.drop", "ecto.setup"], - "test": ["ecto.create --quiet", "ecto.migrate", "test"]] + [] end end diff --git a/mix.lock b/mix.lock --- a/mix.lock +++ b/mix.lock @@ -1,19 +1,14 @@ -%{"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], []}, +%{"amnesia": {:hex, :amnesia, "0.2.5", "3202e0b01e380671274caea32fbe78bbd1989e1215215f41a2d97583e5c7d163", [:mix], [{:exquisite, "~> 0.1.6", [hex: :exquisite, optional: false]}]}, "cowboy": {:hex, :cowboy, "1.0.4", "a324a8df9f2316c833a470d918aaf73ae894278b8aa6226ce7a9bf699388f878", [:rebar, :make], [{:cowlib, "~> 1.0.0", [hex: :cowlib, optional: false]}, {:ranch, "~> 1.0", [hex: :ranch, optional: false]}]}, "cowlib": {:hex, :cowlib, "1.0.2", "9d769a1d062c9c3ac753096f868ca121e2730b9a377de23dec0f7e08b1df84ee", [:make], []}, - "db_connection": {:hex, :db_connection, "1.0.0", "63c03e520d54886a66104d34e32397ba960db6e74b596ce221592c07d6a40d8d", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, optional: true]}]}, - "decimal": {:hex, :decimal, "1.3.1", "157b3cedb2bfcb5359372a7766dd7a41091ad34578296e951f58a946fcab49c6", [:mix], []}, - "ecto": {:hex, :ecto, "2.0.6", "9dcbf819c2a77f67a66b83739b7fcc00b71aaf6c100016db4f798930fa4cfd47", [:mix], [{:db_connection, "~> 1.0", [hex: :db_connection, optional: true]}, {:decimal, "~> 1.1.2 or ~> 1.2", [hex: :decimal, optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, optional: true]}, {:poison, "~> 1.5 or ~> 2.0", [hex: :poison, optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, optional: false]}, {:postgrex, "~> 0.12.0", [hex: :postgrex, optional: true]}, {:sbroker, "~> 1.0-beta", [hex: :sbroker, optional: true]}]}, + "exquisite": {:hex, :exquisite, "0.1.7", "4106503e976f409246731b168cd76eb54262bd04f4facc5cba82c2f53982aaf0", [:mix], []}, "fs": {:hex, :fs, "0.9.2", "ed17036c26c3f70ac49781ed9220a50c36775c6ca2cf8182d123b6566e49ec59", [:rebar], []}, "gettext": {:hex, :gettext, "0.13.0", "daafbddc5cda12738bb93b01d84105fe75b916a302f1c50ab9fb066b95ec9db4", [:mix], []}, - "mariaex": {:hex, :mariaex, "0.7.9", "52f837cf1b0717f95a0e62624bb99707329cba599885cf3bd2fdecc0172a98ad", [:mix], [{:db_connection, "~> 1.0.0-rc", [hex: :db_connection, optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, optional: false]}]}, "mime": {:hex, :mime, "1.0.1", "05c393850524767d13a53627df71beeebb016205eb43bfbd92d14d24ec7a1b51", [:mix], []}, "phoenix": {:hex, :phoenix, "1.2.1", "6dc592249ab73c67575769765b66ad164ad25d83defa3492dc6ae269bd2a68ab", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, optional: true]}, {:phoenix_pubsub, "~> 1.0", [hex: :phoenix_pubsub, optional: false]}, {:plug, "~> 1.1", [hex: :plug, optional: false]}, {:poison, "~> 1.5 or ~> 2.0", [hex: :poison, optional: false]}]}, - "phoenix_ecto": {:hex, :phoenix_ecto, "3.0.1", "42eb486ef732cf209d0a353e791806721f33ff40beab0a86f02070a5649ed00a", [:mix], [{:ecto, "~> 2.0", [hex: :ecto, optional: false]}, {:phoenix_html, "~> 2.6", [hex: :phoenix_html, optional: true]}, {:plug, "~> 1.0", [hex: :plug, optional: false]}]}, - "phoenix_html": {:hex, :phoenix_html, "2.8.0", "777598a4b6609ad6ab8b180f7b25c9af2904644e488922bb9b9b03ce988d20b1", [:mix], [{:plug, "~> 1.0", [hex: :plug, optional: false]}]}, + "phoenix_html": {:hex, :phoenix_html, "2.9.2", "371160b30cf4e10443b015efce6f03e1f19aae98ff6487620477b13a5b2ef660", [:mix], [{:plug, "~> 1.0", [hex: :plug, optional: false]}]}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.0.6", "4490d588c4f60248b1c5f1f0dc0a7271e1aed4bddbd8b1542630f7bf6bc7b012", [:mix], [{:fs, "~> 0.9.1", [hex: :fs, optional: false]}, {:phoenix, "~> 1.0 or ~> 1.2-rc", [hex: :phoenix, optional: false]}]}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.0.1", "c10ddf6237007c804bf2b8f3c4d5b99009b42eca3a0dfac04ea2d8001186056a", [:mix], []}, "plug": {:hex, :plug, "1.3.0", "6e2b01afc5db3fd011ca4a16efd9cb424528c157c30a44a0186bcc92c7b2e8f3", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1", [hex: :cowboy, optional: true]}, {:mime, "~> 1.0", [hex: :mime, optional: false]}]}, "poison": {:hex, :poison, "2.2.0", "4763b69a8a77bd77d26f477d196428b741261a761257ff1cf92753a0d4d24a63", [:mix], []}, - "poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], []}, "ranch": {:hex, :ranch, "1.2.1", "a6fb992c10f2187b46ffd17ce398ddf8a54f691b81768f9ef5f461ea7e28c762", [:make], []}} diff --git a/web/channels/user_socket.ex b/web/channels/user_socket.ex --- a/web/channels/user_socket.ex +++ b/web/channels/user_socket.ex @@ -1,8 +1,7 @@ defmodule KolabChat.UserSocket do use Phoenix.Socket - alias KolabChat.Repo - alias KolabChat.User + alias KolabChat.Database ## Channels channel "room:*", KolabChat.RoomChannel @@ -21,7 +20,7 @@ def connect(%{"token" => token}, socket) do case Phoenix.Token.verify(socket, "user", token, max_age: 86400) do {:ok, user_id} -> - socket = assign(socket, :user, Repo.get!(User, user_id)) + socket = assign(socket, :user, Database.User.read!(user_id)) {:ok, socket} {:error, _} -> :error diff --git a/web/controllers/auth_controller.ex b/web/controllers/auth_controller.ex --- a/web/controllers/auth_controller.ex +++ b/web/controllers/auth_controller.ex @@ -1,6 +1,11 @@ defmodule KolabChat.AuthController do use KolabChat.Web, :controller + # FIXME: is there a better place to put these + # Both are required for using Amnesia.transaction + require Amnesia + require Amnesia.Helper + @doc """ Handler for the default logon form """ @@ -13,13 +18,12 @@ |> put_flash(:error, gettext("Invalid username!")) |> redirect(to: "/") true -> - changeset = User.changeset(%User{}, %{username: user}) - signin(conn, changeset) + signin(conn, user) end end - defp signin(conn, changeset) do - case insert_or_update_user(changeset) do + defp signin(conn, username) do + case insert_or_update_user(username) do {:ok, user} -> conn |> put_flash(:info, gettext("Signed in!")) @@ -32,10 +36,13 @@ end end - defp insert_or_update_user(changeset) do - case Repo.get_by(User, username: changeset.changes.username) do + defp insert_or_update_user(username) do + case Database.User.find(username) do nil -> - Repo.insert(changeset) + user = Amnesia.transaction do + Database.User.write!(%Database.User{username: username}) + end + {:ok, user} user -> {:ok, user} end diff --git a/web/controllers/plugs/set_user.ex b/web/controllers/plugs/set_user.ex --- a/web/controllers/plugs/set_user.ex +++ b/web/controllers/plugs/set_user.ex @@ -1,8 +1,7 @@ defmodule KolabChat.Plugs.SetUser do import Plug.Conn - alias KolabChat.Repo - alias KolabChat.User + use KolabChat.Database def init(params), do: params @@ -10,7 +9,7 @@ def call(%{"params": %{"token" => token}} = conn, _params) do case Phoenix.Token.verify(conn, "user", token, max_age: 86400) do {:ok, user_id} -> - assign(conn, :user, Repo.get!(User, user_id)) + assign(conn, :user, get_user_by_id(user_id)) _ -> assign(conn, :user, nil) end @@ -21,10 +20,17 @@ user_id = get_session(conn, :user_id) cond do - user = user_id && Repo.get(User, user_id) -> + user = user_id && get_user_by_id(user_id) -> assign(conn, :user, user) true -> assign(conn, :user, nil) end end + + def get_user_by_id(user_id) do + require Amnesia.Helper # FIXME: this is required by Amnesia.transaction, where to put it best? + Amnesia.transaction do + Database.User.read(user_id) + end + end end diff --git a/web/models/user.ex b/web/models/user.ex deleted file mode 100644 --- a/web/models/user.ex +++ /dev/null @@ -1,13 +0,0 @@ -defmodule KolabChat.User do - use KolabChat.Web, :model - - schema "users" do - field :username, :string - end - - def changeset(struct, params \\ %{}) do - struct - |> cast(params, [:username]) - |> validate_required([:username]) - end -end diff --git a/web/web.ex b/web/web.ex --- a/web/web.ex +++ b/web/web.ex @@ -16,25 +16,11 @@ below. """ - def model do - quote do - use Ecto.Schema - - import Ecto - import Ecto.Changeset - import Ecto.Query - end - end - def controller do quote do use Phoenix.Controller - alias KolabChat.Repo - alias KolabChat.User - - import Ecto - import Ecto.Query + alias KolabChat.Database import KolabChat.Router.Helpers import KolabChat.Gettext @@ -67,9 +53,6 @@ quote do use Phoenix.Channel - alias KolabChat.Repo - import Ecto - import Ecto.Query import KolabChat.Gettext end end