From 6ac974f1e3215b9344fc8ce10652265bef7a2738 Mon Sep 17 00:00:00 2001 From: optclblast Date: Sun, 8 Sep 2024 15:35:20 +0300 Subject: [PATCH 01/11] tmp, rreuqest and related decoding behaviour implemented. need to implement repository interaction logic --- Makefile | 11 +++++ README.md | 7 +++ docker-compose.yaml | 36 +++++++-------- lib/draincloud_core/auth/users.ex | 18 ++++++++ lib/draincloud_core/rtc.ex | 45 +++++++++++-------- .../components/layouts/root.html.heex | 9 +++- .../auth_controller/auth_controller.ex | 29 +++++++++--- .../main_controller/main_controller.ex | 1 - lib/draincloud_core_web/router.ex | 9 +--- mix.exs | 1 + mix.lock | 1 + priv/repo/migrations/20240901221317_users.exs | 7 --- .../migrations/20240908091209_add_users.exs | 15 +++++++ schemas/users.sql | 5 --- .../controllers/error_html_test.exs | 3 +- .../controllers/error_json_test.exs | 4 +- 16 files changed, 134 insertions(+), 67 deletions(-) create mode 100644 Makefile create mode 100644 lib/draincloud_core/auth/users.ex delete mode 100644 priv/repo/migrations/20240901221317_users.exs create mode 100644 priv/repo/migrations/20240908091209_add_users.exs delete mode 100644 schemas/users.sql diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..86a113e --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +up: + sudo docker compose up -d + make migrate-up + mix phx.server + +migrate-up: + mix ecto.migrate + +migrate-down: + mix ecto.rollback + diff --git a/README.md b/README.md index 0b50ae0..b420bcb 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,13 @@ Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. Ready to run in production? Please [check our deployment guides](https://hexdocs.pm/phoenix/deployment.html). +### Dev DB creds +From *./config/dev.exs* +Host: localhost:5432 +Database: draincloud_core_dev +Username: postgres +Password: postgres + ### Some phoenix related links * Official website: https://www.phoenixframework.org/ diff --git a/docker-compose.yaml b/docker-compose.yaml index 5f06def..d2bf9b9 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -9,24 +9,24 @@ services: ports: - 5432:5432 - minio: - image: quay.io/minio/minio:RELEASE.2024-08-29T01-40-52Z - command: server --console-address ":9001" http://minio/data{1...2} - hostname: minio - volumes: - - data-1:/data1 - - data-2:/data2 - expose: - - "9000" - - "9001" - environment: - MINIO_ROOT_USER: minioadmin - MINIO_ROOT_PASSWORD: minioadmin - healthcheck: - test: ["CMD", "mc", "ready", "local"] - interval: 5s - timeout: 5s - retries: 5 + # minio: + # image: quay.io/minio/minio:RELEASE.2024-08-29T01-40-52Z + # command: server --console-address ":9001" http://minio/data{1...2} + # hostname: minio + # volumes: + # - data-1:/data1 + # - data-2:/data2 + # expose: + # - "9000" + # - "9001" + # environment: + # MINIO_ROOT_USER: minioadmin + # MINIO_ROOT_PASSWORD: minioadmin + # healthcheck: + # test: ["CMD", "mc", "ready", "local"] + # interval: 5s + # timeout: 5s + # retries: 5 volumes: draincore-data: diff --git a/lib/draincloud_core/auth/users.ex b/lib/draincloud_core/auth/users.ex new file mode 100644 index 0000000..0f8229e --- /dev/null +++ b/lib/draincloud_core/auth/users.ex @@ -0,0 +1,18 @@ +defmodule DrainCloudCore.Auth.Users do + use Ecto.Schema + import Ecto.Changeset + + schema "users" do + field :login, :string + field :passwoed, :string, redact: true + field :crated_at, :utc_datetime + field :updated_at, :utc_datetime + field :deleted_at, :utc_datetime + end + + def changeset(user, params \\ %{}) do + user + |> cast(params, [:id, :login, :password, :updated_at, :deleted_at]) + |> validate_required([:id]) + end +end diff --git a/lib/draincloud_core/rtc.ex b/lib/draincloud_core/rtc.ex index 22e62f5..21aa64a 100644 --- a/lib/draincloud_core/rtc.ex +++ b/lib/draincloud_core/rtc.ex @@ -10,6 +10,7 @@ defmodule DrainCloudCore.Rtc.Application do type: :supervisor } end + def start_link(_) do children = [ DrainCloudCore.Rtc @@ -27,27 +28,32 @@ defmodule DrainCloudCore.Rtc do use GenServer # Real-time config table schemas - @config_web [attributes: [ - :host, - :enable_https, - :port, - ]] + @config_web [ + attributes: [ + :host, + :enable_https, + :port + ] + ] - @config_pg [attributes: [ - :host, - :port, - :ssl, - :user, - :password, - :db, - ]] + @config_pg [ + attributes: [ + :host, + :port, + :ssl, + :user, + :password, + :db + ] + ] - - @config_s3 [attributes: [ - :host, - :port, - # user / secret / secrets etc... - ]] + @config_s3 [ + attributes: [ + :host, + :port + # user / secret / secrets etc... + ] + ] # def child_spec(opts) do # %{ @@ -81,6 +87,7 @@ defmodule DrainCloudCore.Rtc do def fetch_config() do # Mnesia.read() end + def init() do Log.info("[#{__MODULE__}] start initializin RTC subsystems") diff --git a/lib/draincloud_core_web/components/layouts/root.html.heex b/lib/draincloud_core_web/components/layouts/root.html.heex index 90e81b6..f4782bc 100644 --- a/lib/draincloud_core_web/components/layouts/root.html.heex +++ b/lib/draincloud_core_web/components/layouts/root.html.heex @@ -8,8 +8,13 @@ <%= assigns[:page_title] || "DrainCloudCore" %> - - + diff --git a/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex b/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex index e8e681b..dcb0b24 100644 --- a/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex +++ b/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex @@ -1,12 +1,29 @@ defmodule DrainCloudCoreWeb.AuthController do use DrainCloudCoreWeb, :controller - alias DrainCloudCoreWeb.Request, as: Request - - def logon(conn, _params) do - if Request.hs_token?(conn) do - # TODO validate token here - end + alias DrainCloudCoreWeb.AuthController.RegisterRequest, as: Request + + def register(conn, _params) do + req = Request.from_request(conn) + :logger.warning(req) + json(conn, req) + end +end + +defmodule DrainCloudCoreWeb.AuthController.RegisterRequest do + @derive [Poison.Encoder, Jason.Encoder] + defstruct login: "", password: "" + + alias DrainCloudCoreWeb.AuthController.RegisterRequest, as: RegisterRequest + def from_request(conn) do + res = Plug.Conn.read_body(conn) + + case res do + {:error, _} -> raise "failed to read request body: #{:error}" + {_, data, _} -> + Poison.decode!(data, as: %RegisterRequest{}) + _ -> raise "failed to read request body. uexpected result: #{res}" + end end end diff --git a/lib/draincloud_core_web/controllers/main_controller/main_controller.ex b/lib/draincloud_core_web/controllers/main_controller/main_controller.ex index 7a93c37..6e2f0da 100644 --- a/lib/draincloud_core_web/controllers/main_controller/main_controller.ex +++ b/lib/draincloud_core_web/controllers/main_controller/main_controller.ex @@ -7,5 +7,4 @@ defmodule DrainCloudCoreWeb.MainController do |> put_root_layout(false) |> json(%{data: %{name: "Some Name"}}) end - end diff --git a/lib/draincloud_core_web/router.ex b/lib/draincloud_core_web/router.ex index 9ed3551..b787062 100644 --- a/lib/draincloud_core_web/router.ex +++ b/lib/draincloud_core_web/router.ex @@ -14,17 +14,12 @@ defmodule DrainCloudCoreWeb.Router do plug :accepts, ["json"] end - scope "/", DrainCloudCoreWeb do + scope "/api", DrainCloudCoreWeb do pipe_through :api - get "/api", MainController, :test + post "/register", AuthController, :register end - # Other scopes may use custom stacks. - # scope "/api", DrainCloudCoreWeb do - # pipe_through :api - # end - # Enable LiveDashboard in development if Application.compile_env(:draincloud_core, :dev_routes) do # If you want to use the LiveDashboard in production, you should put diff --git a/mix.exs b/mix.exs index 54fa208..48c6cd5 100644 --- a/mix.exs +++ b/mix.exs @@ -44,6 +44,7 @@ defmodule DrainCloudCore.MixProject do {:phoenix_live_dashboard, "~> 0.8.3"}, {:esbuild, "~> 0.8", runtime: Mix.env() == :dev}, {:tailwind, "~> 0.2", runtime: Mix.env() == :dev}, + {:poison, "~> 6.0"}, {:heroicons, github: "tailwindlabs/heroicons", tag: "v2.1.1", diff --git a/mix.lock b/mix.lock index 04c3e61..13d2b03 100644 --- a/mix.lock +++ b/mix.lock @@ -27,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_cowboy": {:hex, :plug_cowboy, "2.7.1", "87677ffe3b765bc96a89be7960f81703223fe2e21efa42c125fcd0127dd9d6b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "02dbd5f9ab571b864ae39418db7811618506256f6d13b4a45037e5fe78dc5de3"}, "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, + "poison": {:hex, :poison, "6.0.0", "9bbe86722355e36ffb62c51a552719534257ba53f3271dacd20fbbd6621a583a", [:mix], [{:decimal, "~> 2.1", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "bb9064632b94775a3964642d6a78281c07b7be1319e0016e1643790704e739a2"}, "postgrex": {:hex, :postgrex, "0.19.1", "73b498508b69aded53907fe48a1fee811be34cc720e69ef4ccd568c8715495ea", [: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", "8bac7885a18f381e091ec6caf41bda7bb8c77912bb0e9285212829afe5d8a8f8"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "tailwind": {:hex, :tailwind, "0.2.3", "277f08145d407de49650d0a4685dc062174bdd1ae7731c5f1da86163a24dfcdb", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "8e45e7a34a676a7747d04f7913a96c770c85e6be810a1d7f91e713d3a3655b5d"}, diff --git a/priv/repo/migrations/20240901221317_users.exs b/priv/repo/migrations/20240901221317_users.exs deleted file mode 100644 index 8395c5a..0000000 --- a/priv/repo/migrations/20240901221317_users.exs +++ /dev/null @@ -1,7 +0,0 @@ -defmodule DrainCloudCore.Repo.Migrations.Users do - use Ecto.Migration - - def change do - # TODO users table migration - end -end diff --git a/priv/repo/migrations/20240908091209_add_users.exs b/priv/repo/migrations/20240908091209_add_users.exs new file mode 100644 index 0000000..11df9b1 --- /dev/null +++ b/priv/repo/migrations/20240908091209_add_users.exs @@ -0,0 +1,15 @@ +defmodule DrainCloudCore.Repo.Migrations.AddUsers do + use Ecto.Migration + + def change do + create table(:users) do + add :login, :string, [size: 120] + add :password, :string + add :created_at, :utc_datetime, [null: false, default: fragment("CURRENT_TIMESTAMP")] + add :updated_at, :utc_datetime, [null: false, default: fragment("CURRENT_TIMESTAMP")] + add :deleted_at, :utc_datetime, [null: true, default: nil] + end + + create unique_index(:users, :login) + end +end diff --git a/schemas/users.sql b/schemas/users.sql deleted file mode 100644 index c2ae31e..0000000 --- a/schemas/users.sql +++ /dev/null @@ -1,5 +0,0 @@ -create table users ( - id bigserial, - login varchar(50), - password varchar(256) -); \ No newline at end of file diff --git a/test/draincloud_core_web/controllers/error_html_test.exs b/test/draincloud_core_web/controllers/error_html_test.exs index 73599fb..d24cdc6 100644 --- a/test/draincloud_core_web/controllers/error_html_test.exs +++ b/test/draincloud_core_web/controllers/error_html_test.exs @@ -9,6 +9,7 @@ defmodule DrainCloudCoreWeb.ErrorHTMLTest do end test "renders 500.html" do - assert render_to_string(DrainCloudCoreWeb.ErrorHTML, "500", "html", []) == "Internal Server Error" + assert render_to_string(DrainCloudCoreWeb.ErrorHTML, "500", "html", []) == + "Internal Server Error" end end diff --git a/test/draincloud_core_web/controllers/error_json_test.exs b/test/draincloud_core_web/controllers/error_json_test.exs index 20aa6b0..a44ef0b 100644 --- a/test/draincloud_core_web/controllers/error_json_test.exs +++ b/test/draincloud_core_web/controllers/error_json_test.exs @@ -2,7 +2,9 @@ defmodule DrainCloudCoreWeb.ErrorJSONTest do use DrainCloudCoreWeb.ConnCase, async: true test "renders 404" do - assert DrainCloudCoreWeb.ErrorJSON.render("404.json", %{}) == %{errors: %{detail: "Not Found"}} + assert DrainCloudCoreWeb.ErrorJSON.render("404.json", %{}) == %{ + errors: %{detail: "Not Found"} + } end test "renders 500" do -- 2.45.2 From 709fb2ce307a582a668235ac7094aaf5e60218bf Mon Sep 17 00:00:00 2001 From: optclblast Date: Mon, 9 Sep 2024 01:16:48 +0300 Subject: [PATCH 02/11] some exceptions and validation logic implemented --- calls.api | 11 ++++ lib/draincloud_core/auth/users.ex | 4 +- .../auth_controller/auth_controller.ex | 57 ++++++++++++++++--- .../controllers/errors/errors.ex | 13 +++++ 4 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 calls.api create mode 100644 lib/draincloud_core_web/controllers/errors/errors.ex diff --git a/calls.api b/calls.api new file mode 100644 index 0000000..1b34a2d --- /dev/null +++ b/calls.api @@ -0,0 +1,11 @@ +{ + "body": { + "content": "", + "file": false, + "fileSize": false + }, + "headers": {}, + "method": "GET", + "title": "New HTTP Request", + "url": "" +} \ No newline at end of file diff --git a/lib/draincloud_core/auth/users.ex b/lib/draincloud_core/auth/users.ex index 0f8229e..de1d1d3 100644 --- a/lib/draincloud_core/auth/users.ex +++ b/lib/draincloud_core/auth/users.ex @@ -4,8 +4,8 @@ defmodule DrainCloudCore.Auth.Users do schema "users" do field :login, :string - field :passwoed, :string, redact: true - field :crated_at, :utc_datetime + field :password, :string, redact: true + field :created_at, :utc_datetime field :updated_at, :utc_datetime field :deleted_at, :utc_datetime end diff --git a/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex b/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex index dcb0b24..7909a67 100644 --- a/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex +++ b/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex @@ -1,29 +1,70 @@ defmodule DrainCloudCoreWeb.AuthController do use DrainCloudCoreWeb, :controller + alias DrainCloudCoreWeb.AuthController.RegisterRequest, as: Request + alias :logger, as: Log + alias DrainCloudCore.Repo, as: Repo - - def register(conn, _params) do + def register(conn = %Plug.Conn{}, _params) do req = Request.from_request(conn) - :logger.warning(req) + Log.debug("new register request: #{req}") + + model = Request.to_model req + + try do + Repo.insert(model) + rescue + e in RuntimeError -> Log.error("failed to insert new user: #{e}") + end + json(conn, req) end end defmodule DrainCloudCoreWeb.AuthController.RegisterRequest do - @derive [Poison.Encoder, Jason.Encoder] + @derive [Poison.Encoder,Jason.Encoder] + defstruct login: "", password: "" - alias DrainCloudCoreWeb.AuthController.RegisterRequest, as: RegisterRequest + alias __MODULE__, as: Request + alias DrainCloudCore.Auth.Users, as: User + alias DrainCloudCoreWeb.Errors.InvalidArgumentException, as: InvalidArgumentException def from_request(conn) do res = Plug.Conn.read_body(conn) - + :logger.warning(Kernel.inspect(res)) case res do {:error, _} -> raise "failed to read request body: #{:error}" {_, data, _} -> - Poison.decode!(data, as: %RegisterRequest{}) - _ -> raise "failed to read request body. uexpected result: #{res}" + req = Poison.decode!(data, as: %Request{}) + validate_request(req) + req + _ -> raise "failed to read request body. unexpected result #{Kernel.inspect(res)}" + end + end + + def to_model(req = %Request{}) do + %User{ + login: req.login, + password: req.password + } + end + + defp validate_request(req = %Request{}) do + if String.length(req.login) < 3 do + raise InvalidArgumentException, %{message: "login must be 3 symbols at minimum", args: ["login"]} + else if String.length(req.password) < 8 do + raise InvalidArgumentException, %{message: "password must be 8 symbols at minimum", args: ["password"]} + end + end + end + + defimpl String.Chars, for: DrainCloudCoreWeb.AuthController.RegisterRequest do + def to_string(req) do + case Jason.encode(req) do + {:ok, str} -> str + {:error, msg} -> raise "failed to encode register request to string: #{msg}" + end end end end diff --git a/lib/draincloud_core_web/controllers/errors/errors.ex b/lib/draincloud_core_web/controllers/errors/errors.ex new file mode 100644 index 0000000..480901b --- /dev/null +++ b/lib/draincloud_core_web/controllers/errors/errors.ex @@ -0,0 +1,13 @@ +defmodule DrainCloudCoreWeb.Errors.InvalidArgumentException do + alias __MODULE__, as: InvalidArgumentException + defexception [:message, :args] + + @impl true + def exception(term) do + case term do + [] -> %InvalidArgumentException{} + {message, args} -> %InvalidArgumentException{message: message, args: args} + _ -> %InvalidArgumentException{message: "Error: " <> term} + end + end +end -- 2.45.2 From 312be3073356e7b2373eba2407f442ef02da69fb Mon Sep 17 00:00:00 2001 From: optclblast Date: Mon, 9 Sep 2024 01:19:41 +0300 Subject: [PATCH 03/11] mix format --- .../auth_controller/auth_controller.ex | 29 ++++++++++++++----- .../migrations/20240908091209_add_users.exs | 8 ++--- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex b/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex index 7909a67..d15d56d 100644 --- a/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex +++ b/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex @@ -10,7 +10,7 @@ defmodule DrainCloudCoreWeb.AuthController do req = Request.from_request(conn) Log.debug("new register request: #{req}") - model = Request.to_model req + model = Request.to_model(req) try do Repo.insert(model) @@ -23,23 +23,29 @@ defmodule DrainCloudCoreWeb.AuthController do end defmodule DrainCloudCoreWeb.AuthController.RegisterRequest do - @derive [Poison.Encoder,Jason.Encoder] + @derive [Poison.Encoder, Jason.Encoder] defstruct login: "", password: "" alias __MODULE__, as: Request alias DrainCloudCore.Auth.Users, as: User alias DrainCloudCoreWeb.Errors.InvalidArgumentException, as: InvalidArgumentException + def from_request(conn) do res = Plug.Conn.read_body(conn) :logger.warning(Kernel.inspect(res)) + case res do - {:error, _} -> raise "failed to read request body: #{:error}" + {:error, _} -> + raise "failed to read request body: #{:error}" + {_, data, _} -> req = Poison.decode!(data, as: %Request{}) validate_request(req) req - _ -> raise "failed to read request body. unexpected result #{Kernel.inspect(res)}" + + _ -> + raise "failed to read request body. unexpected result #{Kernel.inspect(res)}" end end @@ -52,12 +58,19 @@ defmodule DrainCloudCoreWeb.AuthController.RegisterRequest do defp validate_request(req = %Request{}) do if String.length(req.login) < 3 do - raise InvalidArgumentException, %{message: "login must be 3 symbols at minimum", args: ["login"]} - else if String.length(req.password) < 8 do - raise InvalidArgumentException, %{message: "password must be 8 symbols at minimum", args: ["password"]} + raise InvalidArgumentException, %{ + message: "login must be 3 symbols at minimum", + args: ["login"] + } + else + if String.length(req.password) < 8 do + raise InvalidArgumentException, %{ + message: "password must be 8 symbols at minimum", + args: ["password"] + } + end end end - end defimpl String.Chars, for: DrainCloudCoreWeb.AuthController.RegisterRequest do def to_string(req) do diff --git a/priv/repo/migrations/20240908091209_add_users.exs b/priv/repo/migrations/20240908091209_add_users.exs index 11df9b1..cd4a94b 100644 --- a/priv/repo/migrations/20240908091209_add_users.exs +++ b/priv/repo/migrations/20240908091209_add_users.exs @@ -3,11 +3,11 @@ defmodule DrainCloudCore.Repo.Migrations.AddUsers do def change do create table(:users) do - add :login, :string, [size: 120] + add :login, :string, size: 120 add :password, :string - add :created_at, :utc_datetime, [null: false, default: fragment("CURRENT_TIMESTAMP")] - add :updated_at, :utc_datetime, [null: false, default: fragment("CURRENT_TIMESTAMP")] - add :deleted_at, :utc_datetime, [null: true, default: nil] + add :created_at, :utc_datetime, null: false, default: fragment("CURRENT_TIMESTAMP") + add :updated_at, :utc_datetime, null: false, default: fragment("CURRENT_TIMESTAMP") + add :deleted_at, :utc_datetime, null: true, default: nil end create unique_index(:users, :login) -- 2.45.2 From 032ea859fb3f1e203a6f4c763180eb1a3efc25d1 Mon Sep 17 00:00:00 2001 From: optclblast Date: Wed, 11 Sep 2024 00:25:50 +0300 Subject: [PATCH 04/11] request parsing fix --- calls.api | 11 ---- .../auth_controller/auth_controller.ex | 60 +++++++++++-------- .../controllers/errors/errors.ex | 6 +- 3 files changed, 41 insertions(+), 36 deletions(-) delete mode 100644 calls.api diff --git a/calls.api b/calls.api deleted file mode 100644 index 1b34a2d..0000000 --- a/calls.api +++ /dev/null @@ -1,11 +0,0 @@ -{ - "body": { - "content": "", - "file": false, - "fileSize": false - }, - "headers": {}, - "method": "GET", - "title": "New HTTP Request", - "url": "" -} \ No newline at end of file diff --git a/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex b/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex index d15d56d..ca7c9a4 100644 --- a/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex +++ b/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex @@ -8,6 +8,7 @@ defmodule DrainCloudCoreWeb.AuthController do def register(conn = %Plug.Conn{}, _params) do req = Request.from_request(conn) + Log.debug("new register request: #{req}") model = Request.to_model(req) @@ -31,22 +32,10 @@ defmodule DrainCloudCoreWeb.AuthController.RegisterRequest do alias DrainCloudCore.Auth.Users, as: User alias DrainCloudCoreWeb.Errors.InvalidArgumentException, as: InvalidArgumentException - def from_request(conn) do - res = Plug.Conn.read_body(conn) - :logger.warning(Kernel.inspect(res)) + def from_request(conn = %Plug.Conn{}) do + :logger.debug("[from_request] incoming request: #{Kernel.inspect(conn.params)}") - case res do - {:error, _} -> - raise "failed to read request body: #{:error}" - - {_, data, _} -> - req = Poison.decode!(data, as: %Request{}) - validate_request(req) - req - - _ -> - raise "failed to read request body. unexpected result #{Kernel.inspect(res)}" - end + validate_and_build(conn.params) end def to_model(req = %Request{}) do @@ -56,22 +45,45 @@ defmodule DrainCloudCoreWeb.AuthController.RegisterRequest do } end - defp validate_request(req = %Request{}) do - if String.length(req.login) < 3 do + defp validate_and_build(req) do + validate(req) + |> build + end + + defp validate(req) do + validate_login(req) + |> validate_password + end + + defp validate_login(req) do + if String.length(Map.get(req, "login")) >= 3 do + req + else raise InvalidArgumentException, %{ message: "login must be 3 symbols at minimum", args: ["login"] } - else - if String.length(req.password) < 8 do - raise InvalidArgumentException, %{ - message: "password must be 8 symbols at minimum", - args: ["password"] - } - end end end + defp validate_password(req) do + if String.length(Map.get(req, "password")) >= 8 do + req + else + raise InvalidArgumentException, %{ + message: "password must be 8 symbols at minimum", + args: ["password"] + } + end + end + + defp build(req) do + %Request{ + login: Map.get(req, "login"), + password: Map.get(req, "password") + } + end + defimpl String.Chars, for: DrainCloudCoreWeb.AuthController.RegisterRequest do def to_string(req) do case Jason.encode(req) do diff --git a/lib/draincloud_core_web/controllers/errors/errors.ex b/lib/draincloud_core_web/controllers/errors/errors.ex index 480901b..7fd488a 100644 --- a/lib/draincloud_core_web/controllers/errors/errors.ex +++ b/lib/draincloud_core_web/controllers/errors/errors.ex @@ -2,11 +2,15 @@ defmodule DrainCloudCoreWeb.Errors.InvalidArgumentException do alias __MODULE__, as: InvalidArgumentException defexception [:message, :args] + @impl true + def exception(%{message: message, args: args}) do + %InvalidArgumentException{message: message, args: args} + end + @impl true def exception(term) do case term do [] -> %InvalidArgumentException{} - {message, args} -> %InvalidArgumentException{message: message, args: args} _ -> %InvalidArgumentException{message: "Error: " <> term} end end -- 2.45.2 From 1c3862471285ef366079e9ff3305f5658838136a Mon Sep 17 00:00:00 2001 From: optclblast Date: Sun, 15 Sep 2024 23:56:12 +0300 Subject: [PATCH 05/11] some lazy changes --- lib/draincloud_core/{ => repo}/repo.ex | 0 lib/draincloud_core/repo/user_repo.ex | 8 ++ .../auth_controller/auth_controller.ex | 79 ++----------------- .../auth_controller/login_request.ex | 71 +++++++++++++++++ .../auth_controller/register_request.ex | 71 +++++++++++++++++ 5 files changed, 158 insertions(+), 71 deletions(-) rename lib/draincloud_core/{ => repo}/repo.ex (100%) create mode 100644 lib/draincloud_core/repo/user_repo.ex create mode 100644 lib/draincloud_core_web/controllers/auth_controller/login_request.ex create mode 100644 lib/draincloud_core_web/controllers/auth_controller/register_request.ex diff --git a/lib/draincloud_core/repo.ex b/lib/draincloud_core/repo/repo.ex similarity index 100% rename from lib/draincloud_core/repo.ex rename to lib/draincloud_core/repo/repo.ex diff --git a/lib/draincloud_core/repo/user_repo.ex b/lib/draincloud_core/repo/user_repo.ex new file mode 100644 index 0000000..63687a3 --- /dev/null +++ b/lib/draincloud_core/repo/user_repo.ex @@ -0,0 +1,8 @@ +defmodule DrainCloudCore.UsersRepo do + alias DrainCloudCore.Repo, as: Repo + import Ecto.Query + + def password_by_login(login) do + Repo.all(from u in :users, where: u.login = login, select: u.password, limit: 1) + end +end diff --git a/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex b/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex index ca7c9a4..5979750 100644 --- a/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex +++ b/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex @@ -1,17 +1,18 @@ defmodule DrainCloudCoreWeb.AuthController do use DrainCloudCoreWeb, :controller - alias DrainCloudCoreWeb.AuthController.RegisterRequest, as: Request + alias DrainCloudCoreWeb.AuthController.RegisterRequest, as: RegisterRequest + alias DrainCloudCoreWeb.AuthController.LoginRequest, as: LoginRequest alias :logger, as: Log alias DrainCloudCore.Repo, as: Repo - def register(conn = %Plug.Conn{}, _params) do - req = Request.from_request(conn) + def register(conn, _params) do + req = RegisterRequest.from_request(conn) Log.debug("new register request: #{req}") - model = Request.to_model(req) + model = RegisterRequest.to_model(req) try do Repo.insert(model) @@ -21,75 +22,11 @@ defmodule DrainCloudCoreWeb.AuthController do json(conn, req) end -end -defmodule DrainCloudCoreWeb.AuthController.RegisterRequest do - @derive [Poison.Encoder, Jason.Encoder] + def login(conn, _params) do + req = LoginRequest.from_request(conn) - defstruct login: "", password: "" + Log.debug("new login request: #{req}") - alias __MODULE__, as: Request - alias DrainCloudCore.Auth.Users, as: User - alias DrainCloudCoreWeb.Errors.InvalidArgumentException, as: InvalidArgumentException - - def from_request(conn = %Plug.Conn{}) do - :logger.debug("[from_request] incoming request: #{Kernel.inspect(conn.params)}") - - validate_and_build(conn.params) - end - - def to_model(req = %Request{}) do - %User{ - login: req.login, - password: req.password - } - end - - defp validate_and_build(req) do - validate(req) - |> build - end - - defp validate(req) do - validate_login(req) - |> validate_password - end - - defp validate_login(req) do - if String.length(Map.get(req, "login")) >= 3 do - req - else - raise InvalidArgumentException, %{ - message: "login must be 3 symbols at minimum", - args: ["login"] - } - end - end - - defp validate_password(req) do - if String.length(Map.get(req, "password")) >= 8 do - req - else - raise InvalidArgumentException, %{ - message: "password must be 8 symbols at minimum", - args: ["password"] - } - end - end - - defp build(req) do - %Request{ - login: Map.get(req, "login"), - password: Map.get(req, "password") - } - end - - defimpl String.Chars, for: DrainCloudCoreWeb.AuthController.RegisterRequest do - def to_string(req) do - case Jason.encode(req) do - {:ok, str} -> str - {:error, msg} -> raise "failed to encode register request to string: #{msg}" - end - end end end diff --git a/lib/draincloud_core_web/controllers/auth_controller/login_request.ex b/lib/draincloud_core_web/controllers/auth_controller/login_request.ex new file mode 100644 index 0000000..32d9b56 --- /dev/null +++ b/lib/draincloud_core_web/controllers/auth_controller/login_request.ex @@ -0,0 +1,71 @@ +defmodule DraincloudCoreWeb.AuthController.LoginRequest do + @derive [Poison.Encoder, Jason.Encoder] + + defstruct login: "", password: "" + + alias __MODULE__, as: Request + alias DrainCloudCore.Auth.Users, as: User + alias DrainCloudCoreWeb.Errors.InvalidArgumentException, as: InvalidArgumentException + + def from_request(conn = %Plug.Conn{}) do + # TODO remove Kernel.inspect calls + :logger.debug("[from_request] incoming request: #{Kernel.inspect(conn.params)}") + + validate_and_build(conn.params) + end + + def to_model(req = %Request{}) do + %User{ + login: req.login, + password: req.password + } + end + + defp validate_and_build(req) do + validate(req) + |> build + end + + defp validate(req) do + validate_login(req) + |> validate_password + end + + defp validate_login(req) do + if String.length(Map.get(req, "login")) >= 3 do + req + else + raise InvalidArgumentException, %{ + message: "login must be 3 symbols at minimum", + args: ["login"] + } + end + end + + defp validate_password(req) do + if String.length(Map.get(req, "password")) >= 8 do + req + else + raise InvalidArgumentException, %{ + message: "password must be 8 symbols at minimum", + args: ["password"] + } + end + end + + defp build(req) do + %Request{ + login: Map.get(req, "login"), + password: Map.get(req, "password") + } + end + + defimpl String.Chars, for: DrainCloudCoreWeb.AuthController.LoginRequest do + def to_string(req) do + case Jason.encode(req) do + {:ok, str} -> str + {:error, msg} -> raise "failed to encode login request to string: #{msg}" + end + end + end +end diff --git a/lib/draincloud_core_web/controllers/auth_controller/register_request.ex b/lib/draincloud_core_web/controllers/auth_controller/register_request.ex new file mode 100644 index 0000000..8392288 --- /dev/null +++ b/lib/draincloud_core_web/controllers/auth_controller/register_request.ex @@ -0,0 +1,71 @@ +defmodule DrainCloudCoreWeb.AuthController.RegisterRequest do + @derive [Poison.Encoder, Jason.Encoder] + + defstruct login: "", password: "" + + alias __MODULE__, as: Request + alias DrainCloudCore.Auth.Users, as: User + alias DrainCloudCoreWeb.Errors.InvalidArgumentException, as: InvalidArgumentException + + def from_request(conn = %Plug.Conn{}) do + # TODO remove Kernel.inspect calls + :logger.debug("[from_request] incoming request: #{Kernel.inspect(conn.params)}") + + validate_and_build(conn.params) + end + + def to_model(req = %Request{}) do + %User{ + login: req.login, + password: req.password + } + end + + defp validate_and_build(req) do + validate(req) + |> build + end + + defp validate(req) do + validate_login(req) + |> validate_password + end + + defp validate_login(req) do + if String.length(Map.get(req, "login")) >= 3 do + req + else + raise InvalidArgumentException, %{ + message: "login must be 3 symbols at minimum", + args: ["login"] + } + end + end + + defp validate_password(req) do + if String.length(Map.get(req, "password")) >= 8 do + req + else + raise InvalidArgumentException, %{ + message: "password must be 8 symbols at minimum", + args: ["password"] + } + end + end + + defp build(req) do + %Request{ + login: Map.get(req, "login"), + password: Map.get(req, "password") + } + end + + defimpl String.Chars, for: DrainCloudCoreWeb.AuthController.RegisterRequest do + def to_string(req) do + case Jason.encode(req) do + {:ok, str} -> str + {:error, msg} -> raise "failed to encode register request to string: #{msg}" + end + end + end +end -- 2.45.2 From 2dbaf1de10a478cd7ff391f37eaffd5c8ae27a50 Mon Sep 17 00:00:00 2001 From: optclblast Date: Mon, 16 Sep 2024 22:48:04 +0300 Subject: [PATCH 06/11] tmp --- lib/draincloud_core/repo/user_repo.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/draincloud_core/repo/user_repo.ex b/lib/draincloud_core/repo/user_repo.ex index 63687a3..d7e3147 100644 --- a/lib/draincloud_core/repo/user_repo.ex +++ b/lib/draincloud_core/repo/user_repo.ex @@ -3,6 +3,7 @@ defmodule DrainCloudCore.UsersRepo do import Ecto.Query def password_by_login(login) do - Repo.all(from u in :users, where: u.login = login, select: u.password, limit: 1) + query = from u in :users, where: u.login = login, select: u.password, limit: 1 + Repo.all(query) end end -- 2.45.2 From bd99555cd89948d35d5e9f03058fb429c54d8aa8 Mon Sep 17 00:00:00 2001 From: optclblast Date: Wed, 18 Sep 2024 00:13:39 +0300 Subject: [PATCH 07/11] almost done with auth. initialized sessions stuff --- lib/draincloud_core/auth/auth.ex | 6 +++- lib/draincloud_core/auth/sessions.ex | 21 +++++++++++ lib/draincloud_core/auth/sessions_store.ex | 21 +++++++++++ lib/draincloud_core/auth/users.ex | 11 ++++++ lib/draincloud_core/repo/user_repo.ex | 9 ----- .../auth_controller/auth_controller.ex | 36 ++++++++++--------- .../auth_controller/login_request.ex | 4 +-- .../auth_controller/register_request.ex | 8 ++--- .../controllers/errors/errors.ex | 11 ++++++ lib/draincloud_core_web/error_handler.ex | 10 ++++++ lib/draincloud_core_web/router.ex | 11 ++++++ .../migrations/20240917204624_sessions.exs | 15 ++++++++ 12 files changed, 131 insertions(+), 32 deletions(-) create mode 100644 lib/draincloud_core/auth/sessions.ex create mode 100644 lib/draincloud_core/auth/sessions_store.ex delete mode 100644 lib/draincloud_core/repo/user_repo.ex create mode 100644 lib/draincloud_core_web/error_handler.ex create mode 100644 priv/repo/migrations/20240917204624_sessions.exs diff --git a/lib/draincloud_core/auth/auth.ex b/lib/draincloud_core/auth/auth.ex index abf9db2..f963afa 100644 --- a/lib/draincloud_core/auth/auth.ex +++ b/lib/draincloud_core/auth/auth.ex @@ -1,6 +1,10 @@ defmodule DraincloudCore.Auth do def is_logon(_token) do # TODO here - true + false + end + + def auth_cookies(conn = %Plug.Conn{}, user = %DrainCloudCore.Auth.Users{}) do + end end diff --git a/lib/draincloud_core/auth/sessions.ex b/lib/draincloud_core/auth/sessions.ex new file mode 100644 index 0000000..0c65998 --- /dev/null +++ b/lib/draincloud_core/auth/sessions.ex @@ -0,0 +1,21 @@ +defmodule DrainCloudCore.Auth.SessionsRepo do + use Ecto.Schema + import Ecto.Changeset + import Ecto.Query + + schema "sessions" do + field :token, :string + field :user_id, :id + field :user_agent, :string + field :created_at, :utc_datetime + field :expires_at, :utc_datetime + end + + def changeset(session, params \\ %{}) do + session + |> cast(params, [:id, :token, :user_id, :user_agent, :created_at, :expires_at]) + |> validate_required([:id, :token, :user_id, :user_agent, :created_at, :expires_at]) + end + + +end diff --git a/lib/draincloud_core/auth/sessions_store.ex b/lib/draincloud_core/auth/sessions_store.ex new file mode 100644 index 0000000..fdffe7c --- /dev/null +++ b/lib/draincloud_core/auth/sessions_store.ex @@ -0,0 +1,21 @@ +defmodule DrainCloudCore.Auth.SessionsStore do + @behaviour Plug.Session.Store + + alias DrainCloudCore.Repo, as: Repo + + def init(_opts), do: :ok + + def put(conn, sid, any, opts) do + + end + + def get(conn, cookie, opts) do + + end + + def delete(conn, sid, opts) do + + end + + +end diff --git a/lib/draincloud_core/auth/users.ex b/lib/draincloud_core/auth/users.ex index de1d1d3..5e243cb 100644 --- a/lib/draincloud_core/auth/users.ex +++ b/lib/draincloud_core/auth/users.ex @@ -1,6 +1,9 @@ defmodule DrainCloudCore.Auth.Users do use Ecto.Schema import Ecto.Changeset + import Ecto.Query + + alias DrainCloudCore.Repo, as: Repo schema "users" do field :login, :string @@ -15,4 +18,12 @@ defmodule DrainCloudCore.Auth.Users do |> cast(params, [:id, :login, :password, :updated_at, :deleted_at]) |> validate_required([:id]) end + + def add_user(user) do + Repo.insert(user) + end + + def password_by_login(login) do + Repo.all(from u in "users", where: u.login == ^login, select: u.password, limit: 1) + end end diff --git a/lib/draincloud_core/repo/user_repo.ex b/lib/draincloud_core/repo/user_repo.ex deleted file mode 100644 index d7e3147..0000000 --- a/lib/draincloud_core/repo/user_repo.ex +++ /dev/null @@ -1,9 +0,0 @@ -defmodule DrainCloudCore.UsersRepo do - alias DrainCloudCore.Repo, as: Repo - import Ecto.Query - - def password_by_login(login) do - query = from u in :users, where: u.login = login, select: u.password, limit: 1 - Repo.all(query) - end -end diff --git a/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex b/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex index 5979750..4411127 100644 --- a/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex +++ b/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex @@ -1,32 +1,36 @@ defmodule DrainCloudCoreWeb.AuthController do use DrainCloudCoreWeb, :controller + import Plug.Conn + alias DrainCloudCoreWeb.AuthController.RegisterRequest, as: RegisterRequest alias DrainCloudCoreWeb.AuthController.LoginRequest, as: LoginRequest alias :logger, as: Log - - alias DrainCloudCore.Repo, as: Repo + alias DrainCloudCore.Auth.Users , as: Repo def register(conn, _params) do - req = RegisterRequest.from_request(conn) - - Log.debug("new register request: #{req}") - - model = RegisterRequest.to_model(req) - try do - Repo.insert(model) + RegisterRequest.from_request(conn) + |> RegisterRequest.to_model + |> Repo.add_user + # TODO send cookies and tokens + send_resp(conn, 200, Jason.encode! %{ok: true}) rescue - e in RuntimeError -> Log.error("failed to insert new user: #{e}") + e in RuntimeError -> + Log.error("failed to insert new user: #{e}") + raise e end - - json(conn, req) end def login(conn, _params) do - req = LoginRequest.from_request(conn) - - Log.debug("new login request: #{req}") - + try do + LoginRequest.from_request(conn) + # TODO send cookies and tokens + send_resp(conn, 200, Jason.encode! %{ok: true}) + rescue + e in RuntimeError -> + Log.error("failed to insert new user: #{e}") + raise e + end end end diff --git a/lib/draincloud_core_web/controllers/auth_controller/login_request.ex b/lib/draincloud_core_web/controllers/auth_controller/login_request.ex index 32d9b56..90ed84a 100644 --- a/lib/draincloud_core_web/controllers/auth_controller/login_request.ex +++ b/lib/draincloud_core_web/controllers/auth_controller/login_request.ex @@ -56,11 +56,11 @@ defmodule DraincloudCoreWeb.AuthController.LoginRequest do defp build(req) do %Request{ login: Map.get(req, "login"), - password: Map.get(req, "password") + password: Map.get(req, "password") # TODO hash password } end - defimpl String.Chars, for: DrainCloudCoreWeb.AuthController.LoginRequest do + defimpl String.Chars, for: __MODULE__ do def to_string(req) do case Jason.encode(req) do {:ok, str} -> str diff --git a/lib/draincloud_core_web/controllers/auth_controller/register_request.ex b/lib/draincloud_core_web/controllers/auth_controller/register_request.ex index 8392288..ea8d168 100644 --- a/lib/draincloud_core_web/controllers/auth_controller/register_request.ex +++ b/lib/draincloud_core_web/controllers/auth_controller/register_request.ex @@ -43,11 +43,11 @@ defmodule DrainCloudCoreWeb.AuthController.RegisterRequest do end defp validate_password(req) do - if String.length(Map.get(req, "password")) >= 8 do + if String.length(Map.get(req, "password")) >= 4 do req else raise InvalidArgumentException, %{ - message: "password must be 8 symbols at minimum", + message: "password must be 4 symbols at minimum", args: ["password"] } end @@ -56,11 +56,11 @@ defmodule DrainCloudCoreWeb.AuthController.RegisterRequest do defp build(req) do %Request{ login: Map.get(req, "login"), - password: Map.get(req, "password") + password: Map.get(req, "password") # TODO hash password } end - defimpl String.Chars, for: DrainCloudCoreWeb.AuthController.RegisterRequest do + defimpl String.Chars, for: __MODULE__ do def to_string(req) do case Jason.encode(req) do {:ok, str} -> str diff --git a/lib/draincloud_core_web/controllers/errors/errors.ex b/lib/draincloud_core_web/controllers/errors/errors.ex index 7fd488a..626a7a3 100644 --- a/lib/draincloud_core_web/controllers/errors/errors.ex +++ b/lib/draincloud_core_web/controllers/errors/errors.ex @@ -1,4 +1,6 @@ defmodule DrainCloudCoreWeb.Errors.InvalidArgumentException do + @derive [Jason.Encoder] + alias __MODULE__, as: InvalidArgumentException defexception [:message, :args] @@ -14,4 +16,13 @@ defmodule DrainCloudCoreWeb.Errors.InvalidArgumentException do _ -> %InvalidArgumentException{message: "Error: " <> term} end end + + defimpl String.Chars, for: __MODULE__ do + def to_string(err) do + case Jason.encode(err) do + {:ok, str} -> str + {:error, msg} -> raise "failed to encode register request to string: #{msg}" + end + end + end end diff --git a/lib/draincloud_core_web/error_handler.ex b/lib/draincloud_core_web/error_handler.ex new file mode 100644 index 0000000..f47ee71 --- /dev/null +++ b/lib/draincloud_core_web/error_handler.ex @@ -0,0 +1,10 @@ +defmodule DrainCloudCoreWeb.ErrorHandler do + alias DrainCloudCoreWeb.Errors.InvalidArgumentException, as: InvalidArgumentException + def handle_reason(reason = %InvalidArgumentException{}), do: Jason.encode!(reason) + + def handle_reason(reason) do + :logger.error(inspect(reason)) + + Jason.encode!(%{error: "Oops! Something went wrong!"}) + end +end diff --git a/lib/draincloud_core_web/router.ex b/lib/draincloud_core_web/router.ex index b787062..2481daa 100644 --- a/lib/draincloud_core_web/router.ex +++ b/lib/draincloud_core_web/router.ex @@ -1,5 +1,10 @@ defmodule DrainCloudCoreWeb.Router do use DrainCloudCoreWeb, :router + use Plug.ErrorHandler + import Plug.Conn + + alias :logger, as: Log + alias DrainCloudCoreWeb.ErrorHandler, as: ErrorHandler pipeline :browser do plug :accepts, ["html"] @@ -20,6 +25,12 @@ defmodule DrainCloudCoreWeb.Router do post "/register", AuthController, :register end + @impl Plug.ErrorHandler + def handle_errors(conn, %{kind: _kind, reason: reason, stack: _stack}) do + + send_resp(conn, 500, ErrorHandler.handle_reason(reason)) + end + # Enable LiveDashboard in development if Application.compile_env(:draincloud_core, :dev_routes) do # If you want to use the LiveDashboard in production, you should put diff --git a/priv/repo/migrations/20240917204624_sessions.exs b/priv/repo/migrations/20240917204624_sessions.exs new file mode 100644 index 0000000..626af6a --- /dev/null +++ b/priv/repo/migrations/20240917204624_sessions.exs @@ -0,0 +1,15 @@ +defmodule DrainCloudCore.Repo.Migrations.Sessions do + use Ecto.Migration + + def change do + create table(:sessions) do + add :token, :string + add :user_id, references("users", on_delete: :nothing) + add :user_agent, :string + add :created_at, :utc_datetime + add :expires_at, :utc_datetime + end + + create unique_index(:sessions, :token) + end +end -- 2.45.2 From ba0402c7fefffc056a058a7da1831f10dd472602 Mon Sep 17 00:00:00 2001 From: optclblast Date: Wed, 18 Sep 2024 00:19:33 +0300 Subject: [PATCH 08/11] workflow added --- .gitea/workflows/elixir.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .gitea/workflows/elixir.yml diff --git a/.gitea/workflows/elixir.yml b/.gitea/workflows/elixir.yml new file mode 100644 index 0000000..f6f14a5 --- /dev/null +++ b/.gitea/workflows/elixir.yml @@ -0,0 +1,32 @@ +name: Base CI + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +permissions: + contents: read + +jobs: + build: + name: Build and test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Elixir + uses: erlef/setup-beam@61e01a43a562a89bfc54c7f9a378ff67b03e4a21 # v1.16.0 + with: + elixir-version: '1.14.0' # [Required] Define the Elixir version + otp-version: '25.0' # [Required] Define the Erlang/OTP version + - name: Restore dependencies cache + uses: actions/cache@v3 + with: + path: deps + key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }} + restore-keys: ${{ runner.os }}-mix- + - name: Install dependencies + run: mix deps.get + - name: Run tests + run: mix test -- 2.45.2 From 098cca693575ad905882b5f34a758357461dfde3 Mon Sep 17 00:00:00 2001 From: optclblast Date: Wed, 18 Sep 2024 00:20:16 +0300 Subject: [PATCH 09/11] workflow added for gh --- .github/workflows/elixir.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/elixir.yml diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml new file mode 100644 index 0000000..f6f14a5 --- /dev/null +++ b/.github/workflows/elixir.yml @@ -0,0 +1,32 @@ +name: Base CI + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +permissions: + contents: read + +jobs: + build: + name: Build and test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Elixir + uses: erlef/setup-beam@61e01a43a562a89bfc54c7f9a378ff67b03e4a21 # v1.16.0 + with: + elixir-version: '1.14.0' # [Required] Define the Elixir version + otp-version: '25.0' # [Required] Define the Erlang/OTP version + - name: Restore dependencies cache + uses: actions/cache@v3 + with: + path: deps + key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }} + restore-keys: ${{ runner.os }}-mix- + - name: Install dependencies + run: mix deps.get + - name: Run tests + run: mix test -- 2.45.2 From 34429ce640e3d4d4b42b2a852db6195ee626c20e Mon Sep 17 00:00:00 2001 From: optclblast Date: Wed, 18 Sep 2024 00:46:33 +0300 Subject: [PATCH 10/11] tmp --- lib/draincloud_core/auth/sessions_store.ex | 2 ++ .../controllers/auth_controller/auth_controller.ex | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/draincloud_core/auth/sessions_store.ex b/lib/draincloud_core/auth/sessions_store.ex index fdffe7c..9818ffd 100644 --- a/lib/draincloud_core/auth/sessions_store.ex +++ b/lib/draincloud_core/auth/sessions_store.ex @@ -17,5 +17,7 @@ defmodule DrainCloudCore.Auth.SessionsStore do end + def initialize_session(conn, user) do + end end diff --git a/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex b/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex index 4411127..930b5fb 100644 --- a/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex +++ b/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex @@ -9,6 +9,16 @@ defmodule DrainCloudCoreWeb.AuthController do alias DrainCloudCore.Auth.Users , as: Repo def register(conn, _params) do + Log.debug( + Enum.find_value(conn.req_headers, "", fn x -> + case x do + {"user-agent", agent} -> agent + _ -> nil + end + end) + |> inspect + ) + try do RegisterRequest.from_request(conn) |> RegisterRequest.to_model -- 2.45.2 From 90b0ef81ef7f250a9dbe1d7774e54135a1664a8a Mon Sep 17 00:00:00 2001 From: optclblast Date: Thu, 19 Sep 2024 00:09:09 +0300 Subject: [PATCH 11/11] tmp --- lib/draincloud_core/auth/sessions.ex | 2 +- lib/draincloud_core/auth/sessions_store.ex | 24 ++++++++++++++++++- .../auth_controller/auth_controller.ex | 3 +-- .../auth_controller/login_request.ex | 3 --- lib/draincloud_core_web/endpoint.ex | 4 ---- lib/draincloud_core_web/gettext.ex | 21 ---------------- lib/draincloud_core_web/router.ex | 7 ------ 7 files changed, 25 insertions(+), 39 deletions(-) diff --git a/lib/draincloud_core/auth/sessions.ex b/lib/draincloud_core/auth/sessions.ex index 0c65998..827f4ae 100644 --- a/lib/draincloud_core/auth/sessions.ex +++ b/lib/draincloud_core/auth/sessions.ex @@ -1,4 +1,4 @@ -defmodule DrainCloudCore.Auth.SessionsRepo do +defmodule DrainCloudCore.Auth.Session do use Ecto.Schema import Ecto.Changeset import Ecto.Query diff --git a/lib/draincloud_core/auth/sessions_store.ex b/lib/draincloud_core/auth/sessions_store.ex index 9818ffd..cdc89ad 100644 --- a/lib/draincloud_core/auth/sessions_store.ex +++ b/lib/draincloud_core/auth/sessions_store.ex @@ -1,6 +1,9 @@ defmodule DrainCloudCore.Auth.SessionsStore do @behaviour Plug.Session.Store + @token_len 64 + + alias DrainCloudCore.Auth.SessionsRepo alias DrainCloudCore.Repo, as: Repo def init(_opts), do: :ok @@ -17,7 +20,26 @@ defmodule DrainCloudCore.Auth.SessionsStore do end - def initialize_session(conn, user) do + def new_session(conn, user) do + %DrainCloudCore.Auth.Session { + user_id: user.id, + token: new_token(@token_len), + user_agent: user_agent(conn), + created_at: DateTime.utc_now(), + expires_at: DateTime.add(DateTime.utc_now(), 7*24, :hour) + } + end + defp user_agent(conn) do + Enum.find_value(conn.req_headers, "", fn x -> + case x do + {"user-agent", agent} -> agent + _ -> nil + end + end) + end + + defp new_token(length) do + :crypto.strong_rand_bytes(length) |> Base.url_encode64 |> binary_part(0, length) end end diff --git a/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex b/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex index 930b5fb..77a6331 100644 --- a/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex +++ b/lib/draincloud_core_web/controllers/auth_controller/auth_controller.ex @@ -23,11 +23,10 @@ defmodule DrainCloudCoreWeb.AuthController do RegisterRequest.from_request(conn) |> RegisterRequest.to_model |> Repo.add_user - # TODO send cookies and tokens send_resp(conn, 200, Jason.encode! %{ok: true}) rescue e in RuntimeError -> - Log.error("failed to insert new user: #{e}") + Log.error("failed to create new user: #{e}") raise e end end diff --git a/lib/draincloud_core_web/controllers/auth_controller/login_request.ex b/lib/draincloud_core_web/controllers/auth_controller/login_request.ex index 90ed84a..c1368d0 100644 --- a/lib/draincloud_core_web/controllers/auth_controller/login_request.ex +++ b/lib/draincloud_core_web/controllers/auth_controller/login_request.ex @@ -8,9 +8,6 @@ defmodule DraincloudCoreWeb.AuthController.LoginRequest do alias DrainCloudCoreWeb.Errors.InvalidArgumentException, as: InvalidArgumentException def from_request(conn = %Plug.Conn{}) do - # TODO remove Kernel.inspect calls - :logger.debug("[from_request] incoming request: #{Kernel.inspect(conn.params)}") - validate_and_build(conn.params) end diff --git a/lib/draincloud_core_web/endpoint.ex b/lib/draincloud_core_web/endpoint.ex index 2348684..4aa1f25 100644 --- a/lib/draincloud_core_web/endpoint.ex +++ b/lib/draincloud_core_web/endpoint.ex @@ -15,10 +15,6 @@ defmodule DrainCloudCoreWeb.Endpoint do websocket: [connect_info: [session: @session_options]], longpoll: [connect_info: [session: @session_options]] - # 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: :draincloud_core, diff --git a/lib/draincloud_core_web/gettext.ex b/lib/draincloud_core_web/gettext.ex index 5a13399..49a9038 100644 --- a/lib/draincloud_core_web/gettext.ex +++ b/lib/draincloud_core_web/gettext.ex @@ -1,24 +1,3 @@ defmodule DrainCloudCoreWeb.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 DrainCloudCoreWeb.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: :draincloud_core end diff --git a/lib/draincloud_core_web/router.ex b/lib/draincloud_core_web/router.ex index 2481daa..f141bf2 100644 --- a/lib/draincloud_core_web/router.ex +++ b/lib/draincloud_core_web/router.ex @@ -3,7 +3,6 @@ defmodule DrainCloudCoreWeb.Router do use Plug.ErrorHandler import Plug.Conn - alias :logger, as: Log alias DrainCloudCoreWeb.ErrorHandler, as: ErrorHandler pipeline :browser do @@ -31,13 +30,7 @@ defmodule DrainCloudCoreWeb.Router do send_resp(conn, 500, ErrorHandler.handle_reason(reason)) end - # Enable LiveDashboard in development if Application.compile_env(:draincloud_core, :dev_routes) do - # If you want to use the LiveDashboard in production, you should put - # it behind authentication and allow only admins to access it. - # If your application does not have an admins-only section yet, - # you can use Plug.BasicAuth to set up some basic authentication - # as long as you are also using SSL (which you should anyway). import Phoenix.LiveDashboard.Router scope "/dev" do -- 2.45.2