From ab75f741f76fddd49e3000a6648e0b66cdee534d Mon Sep 17 00:00:00 2001 From: yujonglee Date: Sat, 22 Jun 2024 09:49:11 +0900 Subject: [PATCH] Init Ash resources (#1) * init * migration * fix test * style auth page --- core/.formatter.exs | 10 +- core/assets/tailwind.config.js | 3 +- core/config/config.exs | 9 + core/lib/canary/accounts/account.ex | 41 +++ core/lib/canary/accounts/account_user.ex | 19 ++ core/lib/canary/accounts/accounts.ex | 10 + .../canary/accounts/changes/init_account.ex | 17 ++ core/lib/canary/accounts/secrets.ex | 10 + core/lib/canary/accounts/token.ex | 11 + core/lib/canary/accounts/user.ex | 50 ++++ core/lib/canary/application.ex | 3 +- core/lib/canary/clients/clients.ex | 7 + .../clients/{discord_bot.ex => discord.ex} | 2 +- core/lib/canary/clients/website.ex | 40 +++ core/lib/canary/repo.ex | 8 +- core/lib/canary/sources/document.ex | 27 ++ core/lib/canary/sources/snapshot.ex | 24 ++ core/lib/canary/sources/sources.ex | 9 + core/lib/canary/sources/website.ex | 38 +++ core/lib/canary_web.ex | 2 +- core/lib/canary_web/auth_overrides.ex | 10 + .../canary_web/controllers/auth_controller.ex | 28 ++ core/lib/canary_web/controllers/auth_html.ex | 5 + .../controllers/auth_html/failure.html.heex | 1 + .../controllers/page_html/home.html.heex | 254 +++--------------- core/lib/canary_web/live_user_auth.ex | 28 ++ core/lib/canary_web/router.ex | 27 +- core/lib/postgrex_types.ex | 5 + core/mix.exs | 6 +- core/mix.lock | 29 ++ .../20240622003409_install_3_extensions.exs | 107 ++++++++ .../migrations/20240622003411_init_ash.exs | 165 ++++++++++++ .../repo/account_users/20240622003411.json | 77 ++++++ .../repo/accounts/20240622003411.json | 49 ++++ .../repo/client_websites/20240622003411.json | 78 ++++++ .../resource_snapshots/repo/extensions.json | 8 + .../repo/source_documents/20240622003411.json | 78 ++++++ .../repo/source_snapshots/20240622003411.json | 49 ++++ .../repo/source_websites/20240622003411.json | 68 +++++ .../repo/tokens/20240622003411.json | 89 ++++++ .../repo/users/20240622003411.json | 64 +++++ .../controllers/page_controller_test.exs | 2 +- 42 files changed, 1339 insertions(+), 228 deletions(-) create mode 100644 core/lib/canary/accounts/account.ex create mode 100644 core/lib/canary/accounts/account_user.ex create mode 100644 core/lib/canary/accounts/accounts.ex create mode 100644 core/lib/canary/accounts/changes/init_account.ex create mode 100644 core/lib/canary/accounts/secrets.ex create mode 100644 core/lib/canary/accounts/token.ex create mode 100644 core/lib/canary/accounts/user.ex create mode 100644 core/lib/canary/clients/clients.ex rename core/lib/canary/clients/{discord_bot.ex => discord.ex} (98%) create mode 100644 core/lib/canary/clients/website.ex create mode 100644 core/lib/canary/sources/document.ex create mode 100644 core/lib/canary/sources/snapshot.ex create mode 100644 core/lib/canary/sources/sources.ex create mode 100644 core/lib/canary/sources/website.ex create mode 100644 core/lib/canary_web/auth_overrides.ex create mode 100644 core/lib/canary_web/controllers/auth_controller.ex create mode 100644 core/lib/canary_web/controllers/auth_html.ex create mode 100644 core/lib/canary_web/controllers/auth_html/failure.html.heex create mode 100644 core/lib/canary_web/live_user_auth.ex create mode 100644 core/lib/postgrex_types.ex create mode 100644 core/priv/repo/migrations/20240622003409_install_3_extensions.exs create mode 100644 core/priv/repo/migrations/20240622003411_init_ash.exs create mode 100644 core/priv/resource_snapshots/repo/account_users/20240622003411.json create mode 100644 core/priv/resource_snapshots/repo/accounts/20240622003411.json create mode 100644 core/priv/resource_snapshots/repo/client_websites/20240622003411.json create mode 100644 core/priv/resource_snapshots/repo/extensions.json create mode 100644 core/priv/resource_snapshots/repo/source_documents/20240622003411.json create mode 100644 core/priv/resource_snapshots/repo/source_snapshots/20240622003411.json create mode 100644 core/priv/resource_snapshots/repo/source_websites/20240622003411.json create mode 100644 core/priv/resource_snapshots/repo/tokens/20240622003411.json create mode 100644 core/priv/resource_snapshots/repo/users/20240622003411.json diff --git a/core/.formatter.exs b/core/.formatter.exs index ef8840ce..7f031d05 100644 --- a/core/.formatter.exs +++ b/core/.formatter.exs @@ -1,5 +1,13 @@ [ - import_deps: [:ecto, :ecto_sql, :phoenix], + import_deps: [ + :ecto, + :ecto_sql, + :phoenix, + :ash, + :ash_phoenix, + :ash_postgres, + :ash_authentication + ], subdirectories: ["priv/*/migrations"], plugins: [Phoenix.LiveView.HTMLFormatter], inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}", "priv/*/seeds.exs"] diff --git a/core/assets/tailwind.config.js b/core/assets/tailwind.config.js index 9f204df4..035cd30f 100644 --- a/core/assets/tailwind.config.js +++ b/core/assets/tailwind.config.js @@ -9,7 +9,8 @@ module.exports = { content: [ "./js/**/*.js", "../lib/canary_web.ex", - "../lib/canary_web/**/*.*ex" + "../lib/canary_web/**/*.*ex", + "../deps/ash_authentication_phoenix/**/*.*ex", ], theme: { extend: { diff --git a/core/config/config.exs b/core/config/config.exs index 207550c7..7dd93779 100644 --- a/core/config/config.exs +++ b/core/config/config.exs @@ -66,6 +66,15 @@ config :canary, Oban, queues: [default: 10], repo: Canary.Repo +config :canary, Canary.Repo, types: Canary.PostgrexTypes + +config :canary, + ash_domains: [ + Canary.Accounts, + Canary.Sources, + Canary.Clients + ] + # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. import_config "#{config_env()}.exs" diff --git a/core/lib/canary/accounts/account.ex b/core/lib/canary/accounts/account.ex new file mode 100644 index 00000000..6db461bd --- /dev/null +++ b/core/lib/canary/accounts/account.ex @@ -0,0 +1,41 @@ +defmodule Canary.Accounts.Account do + use Ash.Resource, + domain: Canary.Accounts, + data_layer: AshPostgres.DataLayer + + attributes do + uuid_primary_key :id + + attribute :user_id, :uuid do + allow_nil? false + end + + attribute :name, :string do + allow_nil? false + end + end + + relationships do + many_to_many :users, Canary.Accounts.User do + through Canary.Accounts.AccountUser + end + + has_many :source_websites, Canary.Sources.Website + has_many :client_websites, Canary.Clients.Website + end + + actions do + create :create do + accept [:user_id, :name] + end + + update :update do + accept [:name] + end + end + + postgres do + table "accounts" + repo Canary.Repo + end +end diff --git a/core/lib/canary/accounts/account_user.ex b/core/lib/canary/accounts/account_user.ex new file mode 100644 index 00000000..00649dbc --- /dev/null +++ b/core/lib/canary/accounts/account_user.ex @@ -0,0 +1,19 @@ +defmodule Canary.Accounts.AccountUser do + use Ash.Resource, + domain: Canary.Accounts, + data_layer: AshPostgres.DataLayer + + relationships do + belongs_to :user, Canary.Accounts.User, primary_key?: true, allow_nil?: false + belongs_to :account, Canary.Accounts.Account, primary_key?: true, allow_nil?: false + end + + actions do + defaults [:read, :destroy, create: :*, update: :*] + end + + postgres do + table "account_users" + repo Canary.Repo + end +end diff --git a/core/lib/canary/accounts/accounts.ex b/core/lib/canary/accounts/accounts.ex new file mode 100644 index 00000000..a779dcbc --- /dev/null +++ b/core/lib/canary/accounts/accounts.ex @@ -0,0 +1,10 @@ +defmodule Canary.Accounts do + use Ash.Domain + + resources do + resource Canary.Accounts.User + resource Canary.Accounts.Token + resource Canary.Accounts.Account + resource Canary.Accounts.AccountUser + end +end diff --git a/core/lib/canary/accounts/changes/init_account.ex b/core/lib/canary/accounts/changes/init_account.ex new file mode 100644 index 00000000..56ce1008 --- /dev/null +++ b/core/lib/canary/accounts/changes/init_account.ex @@ -0,0 +1,17 @@ +defmodule Canary.Accounts.Changes.InitAccount do + use Ash.Resource.Change + + @default_account_name "Default" + + @impl true + def change(changeset, _, _) do + Ash.Changeset.after_action(changeset, fn _, user -> + case Canary.Accounts.Account + |> Ash.Changeset.for_create(:create, %{user_id: user.id, name: @default_account_name}) + |> Ash.create() do + {:ok, _} -> {:ok, user} + error -> error + end + end) + end +end diff --git a/core/lib/canary/accounts/secrets.ex b/core/lib/canary/accounts/secrets.ex new file mode 100644 index 00000000..e51ef248 --- /dev/null +++ b/core/lib/canary/accounts/secrets.ex @@ -0,0 +1,10 @@ +defmodule Canary.Accounts.Secrets do + use AshAuthentication.Secret + + def secret_for([:authentication, :tokens, :signing_secret], Canary.Accounts.User, _) do + case Application.fetch_env(:canary, CanaryWeb.Endpoint) do + {:ok, endpoint_config} -> Keyword.fetch(endpoint_config, :secret_key_base) + :error -> :error + end + end +end diff --git a/core/lib/canary/accounts/token.ex b/core/lib/canary/accounts/token.ex new file mode 100644 index 00000000..3a2e6503 --- /dev/null +++ b/core/lib/canary/accounts/token.ex @@ -0,0 +1,11 @@ +defmodule Canary.Accounts.Token do + use Ash.Resource, + domain: Canary.Accounts, + data_layer: AshPostgres.DataLayer, + extensions: [AshAuthentication.TokenResource] + + postgres do + table "tokens" + repo Canary.Repo + end +end diff --git a/core/lib/canary/accounts/user.ex b/core/lib/canary/accounts/user.ex new file mode 100644 index 00000000..652d5d53 --- /dev/null +++ b/core/lib/canary/accounts/user.ex @@ -0,0 +1,50 @@ +defmodule Canary.Accounts.User do + use Ash.Resource, + domain: Canary.Accounts, + data_layer: AshPostgres.DataLayer, + extensions: [AshAuthentication] + + attributes do + uuid_primary_key :id + + attribute :email, :ci_string do + allow_nil? false + public? true + end + + attribute :hashed_password, :string, allow_nil?: false, sensitive?: true + end + + relationships do + many_to_many :accounts, Canary.Accounts.Account do + through Canary.Accounts.AccountUser + end + end + + changes do + change Canary.Accounts.Changes.InitAccount, on: [:create] + end + + identities do + identity :unique_email, [:email] + end + + authentication do + strategies do + password :password do + identity_field :email + end + end + + tokens do + enabled? true + token_resource Canary.Accounts.Token + signing_secret Canary.Accounts.Secrets + end + end + + postgres do + table "users" + repo Canary.Repo + end +end diff --git a/core/lib/canary/application.ex b/core/lib/canary/application.ex index acd6eb22..24d5f29b 100644 --- a/core/lib/canary/application.ex +++ b/core/lib/canary/application.ex @@ -10,6 +10,7 @@ defmodule Canary.Application do children = discord() ++ [ + {AshAuthentication.Supervisor, otp_app: :canary}, CanaryWeb.Telemetry, Canary.Repo, {Oban, Application.fetch_env!(:canary, Oban)}, @@ -39,7 +40,7 @@ defmodule Canary.Application do defp discord() do if Application.get_env(:nostrum, :token) do - [Nostrum.Application, Canary.Clients.DiscordBot] + [Nostrum.Application, Canary.Clients.Discord] else [] end diff --git a/core/lib/canary/clients/clients.ex b/core/lib/canary/clients/clients.ex new file mode 100644 index 00000000..e76e9d75 --- /dev/null +++ b/core/lib/canary/clients/clients.ex @@ -0,0 +1,7 @@ +defmodule Canary.Clients do + use Ash.Domain + + resources do + resource Canary.Clients.Website + end +end diff --git a/core/lib/canary/clients/discord_bot.ex b/core/lib/canary/clients/discord.ex similarity index 98% rename from core/lib/canary/clients/discord_bot.ex rename to core/lib/canary/clients/discord.ex index c7caecf0..66530923 100644 --- a/core/lib/canary/clients/discord_bot.ex +++ b/core/lib/canary/clients/discord.ex @@ -1,4 +1,4 @@ -defmodule Canary.Clients.DiscordBot do +defmodule Canary.Clients.Discord do use Nostrum.Consumer alias Nostrum.Api diff --git a/core/lib/canary/clients/website.ex b/core/lib/canary/clients/website.ex new file mode 100644 index 00000000..43bd1bff --- /dev/null +++ b/core/lib/canary/clients/website.ex @@ -0,0 +1,40 @@ +defmodule Canary.Clients.Website do + use Ash.Resource, + domain: Canary.Clients, + data_layer: AshPostgres.DataLayer + + attributes do + uuid_primary_key :id + + attribute :account_id, :uuid do + allow_nil? false + end + + attribute :base_url, :string do + allow_nil? false + end + + attribute :public_key, :string do + allow_nil? false + default &Ash.UUID.generate/0 + end + end + + actions do + defaults [:read, :destroy] + + create :create do + accept [:base_url, :account_id] + change set_attribute(:public_key, Ash.UUID.generate()) + end + end + + relationships do + belongs_to :account, Canary.Accounts.Account + end + + postgres do + table "client_websites" + repo Canary.Repo + end +end diff --git a/core/lib/canary/repo.ex b/core/lib/canary/repo.ex index ef3cf931..7eb6efb3 100644 --- a/core/lib/canary/repo.ex +++ b/core/lib/canary/repo.ex @@ -1,5 +1,7 @@ defmodule Canary.Repo do - use Ecto.Repo, - otp_app: :canary, - adapter: Ecto.Adapters.Postgres + use AshPostgres.Repo, otp_app: :canary + + def installed_extensions do + ["uuid-ossp", "citext", "ash-functions"] + end end diff --git a/core/lib/canary/sources/document.ex b/core/lib/canary/sources/document.ex new file mode 100644 index 00000000..0d838008 --- /dev/null +++ b/core/lib/canary/sources/document.ex @@ -0,0 +1,27 @@ +defmodule Canary.Sources.Document do + use Ash.Resource, + domain: Canary.Sources, + data_layer: AshPostgres.DataLayer + + attributes do + integer_primary_key :id + + attribute :content, :string + attribute :embedding, :vector + end + + relationships do + belongs_to :snapshot, Canary.Sources.Snapshot + end + + actions do + create :create do + accept [:content, :embedding] + end + end + + postgres do + table "source_documents" + repo Canary.Repo + end +end diff --git a/core/lib/canary/sources/snapshot.ex b/core/lib/canary/sources/snapshot.ex new file mode 100644 index 00000000..0de0e198 --- /dev/null +++ b/core/lib/canary/sources/snapshot.ex @@ -0,0 +1,24 @@ +defmodule Canary.Sources.Snapshot do + use Ash.Resource, + domain: Canary.Sources, + data_layer: AshPostgres.DataLayer + + attributes do + uuid_primary_key :id + + attribute :source_id, :uuid do + allow_nil? false + end + + create_timestamp :created_at + end + + relationships do + has_many :documents, Canary.Sources.Document + end + + postgres do + table "source_snapshots" + repo Canary.Repo + end +end diff --git a/core/lib/canary/sources/sources.ex b/core/lib/canary/sources/sources.ex new file mode 100644 index 00000000..65527de3 --- /dev/null +++ b/core/lib/canary/sources/sources.ex @@ -0,0 +1,9 @@ +defmodule Canary.Sources do + use Ash.Domain + + resources do + resource Canary.Sources.Snapshot + resource Canary.Sources.Document + resource Canary.Sources.Website + end +end diff --git a/core/lib/canary/sources/website.ex b/core/lib/canary/sources/website.ex new file mode 100644 index 00000000..59aec95a --- /dev/null +++ b/core/lib/canary/sources/website.ex @@ -0,0 +1,38 @@ +defmodule Canary.Sources.Website do + use Ash.Resource, + domain: Canary.Sources, + data_layer: AshPostgres.DataLayer + + attributes do + uuid_primary_key :id + + attribute :account_id, :uuid do + allow_nil? false + end + + attribute :base_url, :string do + allow_nil? false + end + end + + actions do + defaults [:destroy] + + create :create do + accept [:base_url, :account_id] + end + end + + relationships do + belongs_to :account, Canary.Accounts.Account + + has_many :snapshots, Canary.Sources.Snapshot do + destination_attribute :source_id + end + end + + postgres do + table "source_websites" + repo Canary.Repo + end +end diff --git a/core/lib/canary_web.ex b/core/lib/canary_web.ex index f35aa6a0..236973c9 100644 --- a/core/lib/canary_web.ex +++ b/core/lib/canary_web.ex @@ -21,7 +21,7 @@ defmodule CanaryWeb do def router do quote do - use Phoenix.Router, helpers: false + use Phoenix.Router, helpers: true # Import common connection and controller functions to use in pipelines import Plug.Conn diff --git a/core/lib/canary_web/auth_overrides.ex b/core/lib/canary_web/auth_overrides.ex new file mode 100644 index 00000000..801d7f4c --- /dev/null +++ b/core/lib/canary_web/auth_overrides.ex @@ -0,0 +1,10 @@ +defmodule CanaryWeb.AuthOverrides do + use AshAuthentication.Phoenix.Overrides + + override AshAuthentication.Phoenix.Components.Banner do + set(:text, "🐤 Canary") + set(:text_class, "text-2xl font-bold text-black dark:text-white") + set(:image_url, "") + set(:dark_image_url, "") + end +end diff --git a/core/lib/canary_web/controllers/auth_controller.ex b/core/lib/canary_web/controllers/auth_controller.ex new file mode 100644 index 00000000..16a53ed1 --- /dev/null +++ b/core/lib/canary_web/controllers/auth_controller.ex @@ -0,0 +1,28 @@ +defmodule CanaryWeb.AuthController do + use CanaryWeb, :controller + use AshAuthentication.Phoenix.Controller + + def success(conn, _activity, user, _token) do + return_to = get_session(conn, :return_to) || ~p"/" + + conn + |> delete_session(:return_to) + |> store_in_session(user) + |> assign(:current_user, user) + |> redirect(to: return_to) + end + + def failure(conn, _activity, _reason) do + conn + |> put_flash(:error, "Incorrect email or password") + |> redirect(to: ~p"/sign-in") + end + + def sign_out(conn, _params) do + return_to = get_session(conn, :return_to) || ~p"/" + + conn + |> clear_session() + |> redirect(to: return_to) + end +end diff --git a/core/lib/canary_web/controllers/auth_html.ex b/core/lib/canary_web/controllers/auth_html.ex new file mode 100644 index 00000000..d56e1d16 --- /dev/null +++ b/core/lib/canary_web/controllers/auth_html.ex @@ -0,0 +1,5 @@ +defmodule CanaryWeb.AuthHTML do + use CanaryWeb, :html + + embed_templates "auth_html/*" +end diff --git a/core/lib/canary_web/controllers/auth_html/failure.html.heex b/core/lib/canary_web/controllers/auth_html/failure.html.heex new file mode 100644 index 00000000..f227f55f --- /dev/null +++ b/core/lib/canary_web/controllers/auth_html/failure.html.heex @@ -0,0 +1 @@ +

Authentication Error

diff --git a/core/lib/canary_web/controllers/page_html/home.html.heex b/core/lib/canary_web/controllers/page_html/home.html.heex index dc1820b1..7304b2c2 100644 --- a/core/lib/canary_web/controllers/page_html/home.html.heex +++ b/core/lib/canary_web/controllers/page_html/home.html.heex @@ -1,222 +1,52 @@ -<.flash_group flash={@flash} /> - -
-
- -

- Phoenix Framework - - v<%= Application.spec(:phoenix, :vsn) %> - -

-

- Peace of mind from prototype to production. -

-

- Build rich, interactive web applications quickly, with less code and fewer moving parts. Join our growing community of developers using Phoenix to craft APIs, HTML5 apps and more, for fun or at scale. -

-
-
- + + +
+
+
+

+ Demo +

+
+
+
+
+
+
+
+
+
diff --git a/core/lib/canary_web/live_user_auth.ex b/core/lib/canary_web/live_user_auth.ex new file mode 100644 index 00000000..99d264fc --- /dev/null +++ b/core/lib/canary_web/live_user_auth.ex @@ -0,0 +1,28 @@ +defmodule CanaryWeb.LiveUserAuth do + import Phoenix.Component + use CanaryWeb, :verified_routes + + def on_mount(:live_user_optional, _params, _session, socket) do + if socket.assigns[:current_user] do + {:cont, socket} + else + {:cont, assign(socket, :current_user, nil)} + end + end + + def on_mount(:live_user_required, _params, _session, socket) do + if socket.assigns[:current_user] do + {:cont, socket} + else + {:halt, Phoenix.LiveView.redirect(socket, to: ~p"/sign-in")} + end + end + + def on_mount(:live_no_user, _params, _session, socket) do + if socket.assigns[:current_user] do + {:halt, Phoenix.LiveView.redirect(socket, to: ~p"/")} + else + {:cont, assign(socket, :current_user, nil)} + end + end +end diff --git a/core/lib/canary_web/router.ex b/core/lib/canary_web/router.ex index e5133ce5..7ea0f200 100644 --- a/core/lib/canary_web/router.ex +++ b/core/lib/canary_web/router.ex @@ -1,5 +1,6 @@ defmodule CanaryWeb.Router do use CanaryWeb, :router + use AshAuthentication.Phoenix.Router pipeline :browser do plug :accepts, ["html"] @@ -8,23 +9,37 @@ defmodule CanaryWeb.Router do plug :put_root_layout, html: {CanaryWeb.Layouts, :root} plug :protect_from_forgery plug :put_secure_browser_headers + plug :load_from_session end pipeline :api do plug :accepts, ["json"] + plug :load_from_bearer end scope "/", CanaryWeb do pipe_through :browser - get "/", PageController, :home - live "/native", NativeLive + sign_in_route( + register_path: "/register", + overrides: [CanaryWeb.AuthOverrides, AshAuthentication.Phoenix.Overrides.Default] + ) + + sign_out_route(AuthController) + auth_routes_for(Canary.Accounts.User, to: AuthController) + reset_route([]) end - # Other scopes may use custom stacks. - # scope "/api", CanaryWeb do - # pipe_through :api - # end + scope "/", CanaryWeb do + pipe_through :browser + + get "/", PageController, :home + + ash_authentication_live_session :native, + on_mount: {CanaryWeb.LiveUserAuth, :live_user_optional} do + live "/native", NativeLive, :index + end + end # Enable Swoosh mailbox preview in development if Application.compile_env(:canary, :dev_routes) do diff --git a/core/lib/postgrex_types.ex b/core/lib/postgrex_types.ex new file mode 100644 index 00000000..c26d4231 --- /dev/null +++ b/core/lib/postgrex_types.ex @@ -0,0 +1,5 @@ +Postgrex.Types.define( + Canary.PostgrexTypes, + [AshPostgres.Extensions.Vector] ++ Ecto.Adapters.Postgres.extensions(), + [] +) diff --git a/core/mix.exs b/core/mix.exs index c6ff0a1b..c7bfd56b 100644 --- a/core/mix.exs +++ b/core/mix.exs @@ -60,7 +60,11 @@ defmodule Canary.MixProject do {:oban, "~> 2.17"}, {:rustler, "~> 0.32.1"}, {:nostrum, "~> 0.9.1", runtime: false}, - {:gun, "~> 2.0", runtime: true} + {:gun, "~> 2.0", runtime: true}, + {:ash, "~> 3.0"}, + {:ash_authentication, "~> 4.0"}, + {:ash_authentication_phoenix, "~> 2.0"}, + {:ash_postgres, "~> 2.0"} ] end diff --git a/core/mix.lock b/core/mix.lock index 47f43086..39344ff2 100644 --- a/core/mix.lock +++ b/core/mix.lock @@ -1,9 +1,19 @@ %{ + "ash": {:hex, :ash, "3.0.15", "1cea8ca799dc8281d09e316a189fddfb27a2a29a0b0e5af369aa83d6f731ca75", [:mix], [{:comparable, "~> 1.0", [hex: :comparable, repo: "hexpm", optional: false]}, {:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7", [hex: :ecto, repo: "hexpm", optional: false]}, {:ets, "~> 0.8", [hex: :ets, repo: "hexpm", optional: false]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: false]}, {:picosat_elixir, "~> 0.2", [hex: :picosat_elixir, repo: "hexpm", optional: true]}, {:plug, ">= 0.0.0", [hex: :plug, repo: "hexpm", optional: true]}, {:reactor, ">= 0.8.1 and < 1.0.0-0", [hex: :reactor, repo: "hexpm", optional: false]}, {:simple_sat, ">= 0.1.1 and < 1.0.0-0", [hex: :simple_sat, repo: "hexpm", optional: true]}, {:spark, ">= 2.1.18 and < 3.0.0-0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:stream_data, "~> 1.0", [hex: :stream_data, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.1", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "97abfed57f2bf29c3889c51f0dfa23b382a1361a9d70e7d82d7e59a2be6bdc73"}, + "ash_authentication": {:hex, :ash_authentication, "4.0.1", "27e5fcda1022897a02903441a049ba9e5f655e51a757039d946f5bce1de0447c", [:mix], [{:ash, "~> 3.0", [hex: :ash, repo: "hexpm", optional: false]}, {:ash_postgres, "~> 2.0", [hex: :ash_postgres, repo: "hexpm", optional: true]}, {:assent, ">= 0.2.8 and < 1.0.0-0", [hex: :assent, repo: "hexpm", optional: false]}, {:bcrypt_elixir, "~> 3.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: false]}, {:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:finch, "~> 0.18.0", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:joken, "~> 2.5", [hex: :joken, repo: "hexpm", optional: false]}, {:plug, "~> 1.13", [hex: :plug, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}], "hexpm", "e204585c8eed2d46a12e7031da48a169c513d5074ba43da90be0a92f7e1e0413"}, + "ash_authentication_phoenix": {:hex, :ash_authentication_phoenix, "2.0.0", "1d2dd0abc9b9e008ea4423e902eb24825dbf4b9d1329bd079d7064ecfc45d319", [:mix], [{:ash, "~> 3.0", [hex: :ash, repo: "hexpm", optional: false]}, {:ash_authentication, "~> 4.0", [hex: :ash_authentication, repo: "hexpm", optional: false]}, {:ash_phoenix, "~> 2.0", [hex: :ash_phoenix, repo: "hexpm", optional: false]}, {:bcrypt_elixir, "~> 3.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_html_helpers, "~> 1.0", [hex: :phoenix_html_helpers, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:slugify, "~> 1.3", [hex: :slugify, repo: "hexpm", optional: false]}], "hexpm", "6a7c24d57ef6f7a4456d5ba139c8221df6a7ed81f15707a23fc33ad369e43a36"}, + "ash_phoenix": {:hex, :ash_phoenix, "2.0.4", "0d18a3371879b875865180aaabc1697a35a6dcb9ebd2f346456208214bd02c9e", [:mix], [{:ash, "~> 3.0", [hex: :ash, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.5.6 or ~> 1.6", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.20.3 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "f3ea5309b42cdcaafc0ca713757cd4bb4819e02aeacc5195a040a955e861767d"}, + "ash_postgres": {:hex, :ash_postgres, "2.0.12", "0cd30b5eab6ef6fc77d1f29c23bd8b9ad62e676f8aa14bf9194d3cf87e10adf2", [:mix], [{:ash, ">= 3.0.15 and < 4.0.0-0", [hex: :ash, repo: "hexpm", optional: false]}, {:ash_sql, ">= 0.2.6 and < 1.0.0-0", [hex: :ash_sql, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.9", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "a6536a641bcb3dc0ff5b351c35b9334e5586170037f88c0035f532dcba872700"}, + "ash_sql": {:hex, :ash_sql, "0.2.6", "097a191b138af6bd5104ae0e166db5deb443fe3a4616b349fffe98120382765d", [:mix], [{:ash, "~> 3.0", [hex: :ash, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.9", [hex: :ecto_sql, repo: "hexpm", optional: false]}], "hexpm", "076abb07d7762537880a12699b756c7c86c1a4e98fcd0dc8c8059de93f7e9265"}, + "assent": {:hex, :assent, "0.2.10", "27e544c3428996c8ad744d473b3ceae86e4eb7db6bc7432676420e67e9148dd7", [:mix], [{:certifi, ">= 0.0.0", [hex: :certifi, repo: "hexpm", optional: true]}, {:finch, "~> 0.15", [hex: :finch, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: true]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:req, "~> 0.4", [hex: :req, repo: "hexpm", optional: true]}, {:ssl_verify_fun, ">= 0.0.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: true]}], "hexpm", "8483bf9621e994795a70a4ad8fda725abfb6a9675d63a9bfd4217c76d4a2d82a"}, "bandit": {:hex, :bandit, "1.5.5", "df28f1c41f745401fe9e85a6882033f5f3442ab6d30c8a2948554062a4ab56e0", [:mix], [{:hpax, "~> 0.2.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", "f21579a29ea4bc08440343b2b5f16f7cddf2fea5725d31b72cf973ec729079e1"}, + "bcrypt_elixir": {:hex, :bcrypt_elixir, "3.1.0", "0b110a9a6c619b19a7f73fa3004aa11d6e719a67e672d1633dc36b6b2290a0f7", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "2ad2acb5a8bc049e8d5aa267802631912bb80d5f4110a178ae7999e69dca1bf7"}, "castle": {:hex, :castle, "0.3.0", "47b1a550b2348a6d7e60e43ded1df19dca601ed21ef6f267c3dbb1b3a301fbf5", [:mix], [{:forecastle, "~> 0.1.0", [hex: :forecastle, repo: "hexpm", optional: false]}], "hexpm", "dbdc1c171520c4591101938a3d342dec70d36b7f5b102a5c138098581e35fcef"}, "castore": {:hex, :castore, "1.0.7", "b651241514e5f6956028147fe6637f7ac13802537e895a724f90bf3e36ddd1dd", [:mix], [], "hexpm", "da7785a4b0d2a021cd1292a60875a784b6caef71e76bf4917bdee1f390455cf5"}, "certifi": {:hex, :certifi, "2.13.0", "e52be248590050b2dd33b0bb274b56678f9068e67805dca8aa8b1ccdb016bbf6", [:rebar3], [], "hexpm", "8f3d9533a0f06070afdfd5d596b32e21c6580667a492891851b0e2737bc507a1"}, "chacha20": {:hex, :chacha20, "1.0.4", "0359d8f9a32269271044c1b471d5cf69660c362a7c61a98f73a05ef0b5d9eb9e", [:mix], [], "hexpm", "2027f5d321ae9903f1f0da7f51b0635ad6b8819bc7fe397837930a2011bc2349"}, + "comeonin": {:hex, :comeonin, "5.4.0", "246a56ca3f41d404380fc6465650ddaa532c7f98be4bda1b4656b3a37cc13abe", [:mix], [], "hexpm", "796393a9e50d01999d56b7b8420ab0481a7538d0caf80919da493b4a6e51faf1"}, + "comparable": {:hex, :comparable, "1.0.0", "bb669e91cedd14ae9937053e5bcbc3c52bb2f22422611f43b6e38367d94a495f", [:mix], [{:typable, "~> 0.1", [hex: :typable, repo: "hexpm", optional: false]}], "hexpm", "277c11eeb1cd726e7cd41c6c199e7e52fa16ee6830b45ad4cdc62e51f62eb60c"}, "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"}, "curve25519": {:hex, :curve25519, "1.0.5", "f801179424e4012049fcfcfcda74ac04f65d0ffceeb80e7ef1d3352deb09f5bb", [:mix], [], "hexpm", "0fba3ad55bf1154d4d5fc3ae5fb91b912b77b13f0def6ccb3a5d58168ff4192d"}, "db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"}, @@ -12,19 +22,26 @@ "ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [: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", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"}, "ecto_sql": {:hex, :ecto_sql, "3.11.3", "4eb7348ff8101fbc4e6bbc5a4404a24fecbe73a3372d16569526b0cf34ebc195", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16 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", "e5f36e3d736b99c7fee3e631333b8394ade4bafe9d96d35669fca2d81c2be928"}, "ed25519": {:hex, :ed25519, "1.4.1", "479fb83c3e31987c9cad780e6aeb8f2015fb5a482618cdf2a825c9aff809afc4", [:mix], [], "hexpm", "0dacb84f3faa3d8148e81019ca35f9d8dcee13232c32c9db5c2fb8ff48c80ec7"}, + "elixir_make": {:hex, :elixir_make, "0.8.4", "4960a03ce79081dee8fe119d80ad372c4e7badb84c493cc75983f9d3bc8bde0f", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "6e7f1d619b5f61dfabd0a20aa268e575572b542ac31723293a4c1a567d5ef040"}, "equivalex": {:hex, :equivalex, "1.0.3", "170d9a82ae066e0020dfe1cf7811381669565922eb3359f6c91d7e9a1124ff74", [:mix], [], "hexpm", "46fa311adb855117d36e461b9c0ad2598f72110ad17ad73d7533c78020e045fc"}, "esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"}, + "ets": {:hex, :ets, "0.9.0", "79c6a6c205436780486f72d84230c6cba2f8a9920456750ddd1e47389107d5fd", [:mix], [], "hexpm", "2861fdfb04bcaeff370f1a5904eec864f0a56dcfebe5921ea9aadf2a481c822b"}, "expo": {:hex, :expo, "0.5.2", "beba786aab8e3c5431813d7a44b828e7b922bfa431d6bfbada0904535342efe2", [:mix], [], "hexpm", "8c9bfa06ca017c9cb4020fabe980bc7fdb1aaec059fd004c2ab3bff03b1c599c"}, "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, "finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"}, "floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"}, "forecastle": {:hex, :forecastle, "0.1.2", "f8dab08962c7a33010ebd39182513129f17b8814aa16fa453ddd536040882daf", [:mix], [], "hexpm", "8efaeb2e7d0fa24c605605e42562e2dbb0ffd11dc1dd99ef77d78884536ce501"}, "gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"}, + "glob_ex": {:hex, :glob_ex, "0.1.7", "eae6b6377147fb712ac45b360e6dbba00346689a87f996672fe07e97d70597b1", [:mix], [], "hexpm", "decc1c21c0c73df3c9c994412716345c1692477b9470e337f628a7e08da0da6a"}, "gun": {:hex, :gun, "2.1.0", "b4e4cbbf3026d21981c447e9e7ca856766046eff693720ba43114d7f5de36e87", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "52fc7fc246bfc3b00e01aea1c2854c70a366348574ab50c57dfe796d24a0101d"}, "heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized", depth: 1]}, "hpax": {:hex, :hpax, "0.2.0", "5a58219adcb75977b2edce5eb22051de9362f08236220c9e859a47111c194ff5", [:mix], [], "hexpm", "bea06558cdae85bed075e6c036993d43cd54d447f76d8190a8db0dc5893fa2f1"}, + "igniter": {:hex, :igniter, "0.2.0", "a163b308954878c5dd16d8e61e295dc2ff9562761a23c2a1bb154dd0f204f2a0", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:req, "~> 0.4", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, "~> 0.9", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.3", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "012ed8a8c0d3e6f3bd3585925e87421e67f924b64ce5045920dae9ee9aca2707"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, + "joken": {:hex, :joken, "2.6.1", "2ca3d8d7f83bf7196296a3d9b2ecda421a404634bfc618159981a960020480a1", [:mix], [{:jose, "~> 1.11.9", [hex: :jose, repo: "hexpm", optional: false]}], "hexpm", "ab26122c400b3d254ce7d86ed066d6afad27e70416df947cdcb01e13a7382e68"}, + "jose": {:hex, :jose, "1.11.10", "a903f5227417bd2a08c8a00a0cbcc458118be84480955e8d251297a425723f83", [:mix, :rebar3], [], "hexpm", "0d6cd36ff8ba174db29148fc112b5842186b68a90ce9fc2b3ec3afe76593e614"}, "kcl": {:hex, :kcl, "1.4.2", "8b73a55a14899dc172fcb05a13a754ac171c8165c14f65043382d567922f44ab", [:mix], [{:curve25519, ">= 1.0.4", [hex: :curve25519, repo: "hexpm", optional: false]}, {:ed25519, "~> 1.3", [hex: :ed25519, repo: "hexpm", optional: false]}, {:poly1305, "~> 1.0", [hex: :poly1305, repo: "hexpm", optional: false]}, {:salsa20, "~> 1.0", [hex: :salsa20, repo: "hexpm", optional: false]}], "hexpm", "9f083dd3844d902df6834b258564a82b21a15eb9f6acdc98e8df0c10feeabf05"}, + "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"}, "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, "mint": {:hex, :mint, "1.6.1", "065e8a5bc9bbd46a41099dfea3e0656436c5cbcb6e741c80bd2bad5cd872446f", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "4fc518dcc191d02f433393a72a7ba3f6f94b101d094cb6bf532ea54c89423780"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, @@ -34,16 +51,27 @@ "phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.6.1", "96798325fab2fed5a824ca204e877b81f9afd2e480f581e81f7b4b64a5a477f2", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.17", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "0ae544ff99f3c482b0807c5cec2c8289e810ecacabc04959d82c3337f4703391"}, "phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"}, + "phoenix_html_helpers": {:hex, :phoenix_html_helpers, "1.0.1", "7eed85c52eff80a179391036931791ee5d2f713d76a81d0d2c6ebafe1e11e5ec", [:mix], [{:phoenix_html, "~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "cffd2385d1fa4f78b04432df69ab8da63dc5cf63e07b713a4dcf36a3740e3090"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.5.3", "f2161c207fda0e4fb55165f650f7f8db23f02b29e3bff00ff7ef161d6ac1f09d", [:mix], [{:file_system, "~> 0.3 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "b4ec9cd73cb01ff1bd1cac92e045d13e7030330b74164297d1aee3907b54803c"}, "phoenix_live_view": {:hex, :phoenix_live_view, "0.20.17", "f396bbdaf4ba227b82251eb75ac0afa6b3da5e509bc0d030206374237dfc9450", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a61d741ffb78c85fdbca0de084da6a48f8ceb5261a79165b5a0b59e5f65ce98b"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, + "phoenix_view": {:hex, :phoenix_view, "2.0.4", "b45c9d9cf15b3a1af5fb555c674b525391b6a1fe975f040fb4d913397b31abf4", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "4e992022ce14f31fe57335db27a28154afcc94e9983266835bb3040243eb620b"}, "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"}, "poly1305": {:hex, :poly1305, "1.0.4", "7cdc8961a0a6e00a764835918cdb8ade868044026df8ef5d718708ea6cc06611", [:mix], [{:chacha20, "~> 1.0", [hex: :chacha20, repo: "hexpm", optional: false]}, {:equivalex, "~> 1.0", [hex: :equivalex, repo: "hexpm", optional: false]}], "hexpm", "e14e684661a5195e149b3139db4a1693579d4659d65bba115a307529c47dbc3b"}, "postgrex": {:hex, :postgrex, "0.18.0", "f34664101eaca11ff24481ed4c378492fed2ff416cd9b06c399e90f321867d7e", [: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", "a042989ba1bc1cca7383ebb9e461398e3f89f868c92ce6671feb7ef132a252d1"}, + "reactor": {:hex, :reactor, "0.8.4", "344d02ba4a0010763851f4e4aa0ff190ebe7e392e3c27c6cd143dde077b986e7", [:mix], [{:libgraph, "~> 0.16", [hex: :libgraph, repo: "hexpm", optional: false]}, {:spark, "~> 2.0", [hex: :spark, repo: "hexpm", optional: false]}, {:splode, "~> 0.2", [hex: :splode, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.2", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "49c1fd3c786603cec8140ce941c41c7ea72cc4411860ccdee9876c4ca2204f81"}, + "req": {:hex, :req, "0.5.0", "6d8a77c25cfc03e06a439fb12ffb51beade53e3fe0e2c5e362899a18b50298b3", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "dda04878c1396eebbfdec6db6f3d4ca609e5c8846b7ee88cc56eb9891406f7a3"}, + "rewrite": {:hex, :rewrite, "0.10.5", "6afadeae0b9d843b27ac6225e88e165884875e0aed333ef4ad3bf36f9c101bed", [:mix], [{:glob_ex, "~> 0.1", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.0", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "51cc347a4269ad3a1e7a2c4122dbac9198302b082f5615964358b4635ebf3d4f"}, "rustler": {:hex, :rustler, "0.32.1", "f4cf5a39f9e85d182c0a3f75fa15b5d0add6542ab0bf9ceac6b4023109ebd3fc", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:toml, "~> 0.6", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "b96be75526784f86f6587f051bc8d6f4eaff23d6e0f88dbcfe4d5871f52946f7"}, "salsa20": {:hex, :salsa20, "1.0.4", "404cbea1fa8e68a41bcc834c0a2571ac175580fec01cc38cc70c0fb9ffc87e9b", [:mix], [], "hexpm", "745ddcd8cfa563ddb0fd61e7ce48d5146279a2cf7834e1da8441b369fdc58ac6"}, + "slugify": {:hex, :slugify, "1.3.1", "0d3b8b7e5c1eeaa960e44dce94382bee34a39b3ea239293e457a9c5b47cc6fd3", [:mix], [], "hexpm", "cb090bbeb056b312da3125e681d98933a360a70d327820e4b7f91645c4d8be76"}, + "sourceror": {:hex, :sourceror, "1.3.0", "70ab9e8bf6df085a1effba4b49ad621b7153b065f69ef6cdb82e6088f2026029", [:mix], [], "hexpm", "1794c3ceeca4eb3f9437261721e4d9cbf846d7c64c7aee4f64062b18d5ce1eac"}, + "spark": {:hex, :spark, "2.2.4", "077363750eec4d80ffd4b20075676d17fce8bf82af1aa6aa51d2a539685b8d83", [:mix], [{:igniter, "~> 0.2", [hex: :igniter, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.2", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "fd92bdd4508852bcd445c463d0536d0f130ed828d90401d17a061bcdeca4372a"}, + "spitfire": {:hex, :spitfire, "0.1.3", "7ea0f544005dfbe48e615ed90250c9a271bfe126914012023fd5e4b6b82b7ec7", [:mix], [], "hexpm", "d53b5107bcff526a05c5bb54c95e77b36834550affd5830c9f58760e8c543657"}, + "splode": {:hex, :splode, "0.2.4", "71046334c39605095ca4bed5d008372e56454060997da14f9868534c17b84b53", [:mix], [], "hexpm", "ca3b95f0d8d4b482b5357954fec857abd0fa3ea509d623334c1328e7382044c2"}, + "stream_data": {:hex, :stream_data, "1.1.1", "fd515ca95619cca83ba08b20f5e814aaf1e5ebff114659dc9731f966c9226246", [:mix], [], "hexpm", "45d0cd46bd06738463fd53f22b70042dbb58c384bb99ef4e7576e7bb7d3b8c8c"}, "swoosh": {:hex, :swoosh, "1.16.9", "20c6a32ea49136a4c19f538e27739bb5070558c0fa76b8a95f4d5d5ca7d319a1", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.0", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "878b1a7a6c10ebbf725a3349363f48f79c5e3d792eb621643b0d276a38acc0a6"}, "tailwind": {:hex, :tailwind, "0.2.3", "277f08145d407de49650d0a4685dc062174bdd1ae7731c5f1da86163a24dfcdb", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "8e45e7a34a676a7747d04f7913a96c770c85e6be810a1d7f91e713d3a3655b5d"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, @@ -51,6 +79,7 @@ "telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"}, "thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"}, "toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"}, + "typable": {:hex, :typable, "0.3.0", "0431e121d124cd26f312123e313d2689b9a5322b15add65d424c07779eaa3ca1", [:mix], [], "hexpm", "880a0797752da1a4c508ac48f94711e04c86156f498065a83d160eef945858f8"}, "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, "websock_adapter": {:hex, :websock_adapter, "0.5.6", "0437fe56e093fd4ac422de33bf8fc89f7bc1416a3f2d732d8b2c8fd54792fe60", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "e04378d26b0af627817ae84c92083b7e97aca3121196679b73c73b99d0d133ea"}, } diff --git a/core/priv/repo/migrations/20240622003409_install_3_extensions.exs b/core/priv/repo/migrations/20240622003409_install_3_extensions.exs new file mode 100644 index 00000000..e7964772 --- /dev/null +++ b/core/priv/repo/migrations/20240622003409_install_3_extensions.exs @@ -0,0 +1,107 @@ +defmodule Canary.Repo.Migrations.Install3Extensions20240622003408 do + @moduledoc """ + Installs any extensions that are mentioned in the repo's `installed_extensions/0` callback + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + execute("CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"") + execute("CREATE EXTENSION IF NOT EXISTS \"citext\"") + + execute(""" + CREATE OR REPLACE FUNCTION ash_elixir_or(left BOOLEAN, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) + AS $$ SELECT COALESCE(NULLIF($1, FALSE), $2) $$ + LANGUAGE SQL + IMMUTABLE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_elixir_or(left ANYCOMPATIBLE, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) + AS $$ SELECT COALESCE($1, $2) $$ + LANGUAGE SQL + IMMUTABLE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_elixir_and(left BOOLEAN, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) AS $$ + SELECT CASE + WHEN $1 IS TRUE THEN $2 + ELSE $1 + END $$ + LANGUAGE SQL + IMMUTABLE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_elixir_and(left ANYCOMPATIBLE, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) AS $$ + SELECT CASE + WHEN $1 IS NOT NULL THEN $2 + ELSE $1 + END $$ + LANGUAGE SQL + IMMUTABLE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_trim_whitespace(arr text[]) + RETURNS text[] AS $$ + DECLARE + start_index INT = 1; + end_index INT = array_length(arr, 1); + BEGIN + WHILE start_index <= end_index AND arr[start_index] = '' LOOP + start_index := start_index + 1; + END LOOP; + + WHILE end_index >= start_index AND arr[end_index] = '' LOOP + end_index := end_index - 1; + END LOOP; + + IF start_index > end_index THEN + RETURN ARRAY[]::text[]; + ELSE + RETURN arr[start_index : end_index]; + END IF; + END; $$ + LANGUAGE plpgsql + IMMUTABLE; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_raise_error(json_data jsonb) + RETURNS BOOLEAN AS $$ + BEGIN + -- Raise an error with the provided JSON data. + -- The JSON object is converted to text for inclusion in the error message. + RAISE EXCEPTION 'ash_error: %', json_data::text; + RETURN NULL; + END; + $$ LANGUAGE plpgsql; + """) + + execute(""" + CREATE OR REPLACE FUNCTION ash_raise_error(json_data jsonb, type_signal ANYCOMPATIBLE) + RETURNS ANYCOMPATIBLE AS $$ + BEGIN + -- Raise an error with the provided JSON data. + -- The JSON object is converted to text for inclusion in the error message. + RAISE EXCEPTION 'ash_error: %', json_data::text; + RETURN NULL; + END; + $$ LANGUAGE plpgsql; + """) + end + + def down do + # Uncomment this if you actually want to uninstall the extensions + # when this migration is rolled back: + # execute("DROP EXTENSION IF EXISTS \"uuid-ossp\"") + # execute("DROP EXTENSION IF EXISTS \"citext\"") + execute( + "DROP FUNCTION IF EXISTS ash_raise_error(jsonb), ash_raise_error(jsonb, ANYCOMPATIBLE), ash_elixir_and(BOOLEAN, ANYCOMPATIBLE), ash_elixir_and(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(BOOLEAN, ANYCOMPATIBLE), ash_trim_whitespace(text[])" + ) + end +end diff --git a/core/priv/repo/migrations/20240622003411_init_ash.exs b/core/priv/repo/migrations/20240622003411_init_ash.exs new file mode 100644 index 00000000..5ab8ac4e --- /dev/null +++ b/core/priv/repo/migrations/20240622003411_init_ash.exs @@ -0,0 +1,165 @@ +defmodule Canary.Repo.Migrations.InitAsh do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + create table(:users, primary_key: false) do + add :id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true + add :email, :citext, null: false + add :hashed_password, :text, null: false + end + + create unique_index(:users, [:email], name: "users_unique_email_index") + + create table(:tokens, primary_key: false) do + add :updated_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + + add :created_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + + add :extra_data, :map + add :purpose, :text, null: false + add :expires_at, :utc_datetime, null: false + add :subject, :text, null: false + add :jti, :text, null: false, primary_key: true + end + + create table(:source_websites, primary_key: false) do + add :id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true + add :account_id, :uuid, null: false + add :base_url, :text, null: false + end + + create table(:source_snapshots, primary_key: false) do + add :id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true + add :source_id, :uuid, null: false + + add :created_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + end + + create table(:source_documents, primary_key: false) do + add :id, :bigserial, null: false, primary_key: true + add :content, :text + add :embedding, :vector + + add :snapshot_id, + references(:source_snapshots, + column: :id, + name: "source_documents_snapshot_id_fkey", + type: :uuid, + prefix: "public" + ) + end + + create table(:client_websites, primary_key: false) do + add :id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true + add :account_id, :uuid, null: false + add :base_url, :text, null: false + add :public_key, :text, null: false, default: fragment("gen_random_uuid()") + end + + create table(:accounts, primary_key: false) do + add :id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true + end + + alter table(:source_websites) do + modify :account_id, + references(:accounts, + column: :id, + name: "source_websites_account_id_fkey", + type: :uuid, + prefix: "public" + ) + end + + alter table(:client_websites) do + modify :account_id, + references(:accounts, + column: :id, + name: "client_websites_account_id_fkey", + type: :uuid, + prefix: "public" + ) + end + + alter table(:accounts) do + add :user_id, :uuid, null: false + add :name, :text, null: false + end + + create table(:account_users, primary_key: false) do + add :user_id, + references(:users, + column: :id, + name: "account_users_user_id_fkey", + type: :uuid, + prefix: "public" + ), + primary_key: true, + null: false + + add :account_id, + references(:accounts, + column: :id, + name: "account_users_account_id_fkey", + type: :uuid, + prefix: "public" + ), + primary_key: true, + null: false + end + end + + def down do + drop constraint(:account_users, "account_users_user_id_fkey") + + drop constraint(:account_users, "account_users_account_id_fkey") + + drop table(:account_users) + + alter table(:accounts) do + remove :name + remove :user_id + end + + drop constraint(:client_websites, "client_websites_account_id_fkey") + + alter table(:client_websites) do + modify :account_id, :uuid + end + + drop constraint(:source_websites, "source_websites_account_id_fkey") + + alter table(:source_websites) do + modify :account_id, :uuid + end + + drop table(:accounts) + + drop table(:client_websites) + + drop constraint(:source_documents, "source_documents_snapshot_id_fkey") + + drop table(:source_documents) + + drop table(:source_snapshots) + + drop table(:source_websites) + + drop table(:tokens) + + drop_if_exists unique_index(:users, [:email], name: "users_unique_email_index") + + drop table(:users) + end +end diff --git a/core/priv/resource_snapshots/repo/account_users/20240622003411.json b/core/priv/resource_snapshots/repo/account_users/20240622003411.json new file mode 100644 index 00000000..55c6c9e5 --- /dev/null +++ b/core/priv/resource_snapshots/repo/account_users/20240622003411.json @@ -0,0 +1,77 @@ +{ + "attributes": [ + { + "default": "nil", + "size": null, + "type": "uuid", + "source": "user_id", + "references": { + "name": "account_users_user_id_fkey", + "table": "users", + "destination_attribute": "id", + "primary_key?": true, + "schema": "public", + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "on_delete": null, + "on_update": null, + "deferrable": false, + "match_with": null, + "match_type": null, + "index?": false, + "destination_attribute_default": null, + "destination_attribute_generated": null + }, + "allow_nil?": false, + "primary_key?": true, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "uuid", + "source": "account_id", + "references": { + "name": "account_users_account_id_fkey", + "table": "accounts", + "destination_attribute": "id", + "primary_key?": true, + "schema": "public", + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "on_delete": null, + "on_update": null, + "deferrable": false, + "match_with": null, + "match_type": null, + "index?": false, + "destination_attribute_default": null, + "destination_attribute_generated": null + }, + "allow_nil?": false, + "primary_key?": true, + "generated?": false + } + ], + "table": "account_users", + "hash": "8C7C071F2D634C3EDA43F48706068AE6AF793DCA586810ACAC646B1C704684C1", + "repo": "Elixir.Canary.Repo", + "identities": [], + "schema": null, + "check_constraints": [], + "custom_indexes": [], + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "base_filter": null, + "custom_statements": [], + "has_create_action": true +} \ No newline at end of file diff --git a/core/priv/resource_snapshots/repo/accounts/20240622003411.json b/core/priv/resource_snapshots/repo/accounts/20240622003411.json new file mode 100644 index 00000000..4d48c6df --- /dev/null +++ b/core/priv/resource_snapshots/repo/accounts/20240622003411.json @@ -0,0 +1,49 @@ +{ + "attributes": [ + { + "default": "fragment(\"gen_random_uuid()\")", + "size": null, + "type": "uuid", + "source": "id", + "references": null, + "allow_nil?": false, + "primary_key?": true, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "uuid", + "source": "user_id", + "references": null, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "text", + "source": "name", + "references": null, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + } + ], + "table": "accounts", + "hash": "BD5B3DA8E76B8EEB9F6C64F36FFAE42C95D2E11491F0A684735E5BD2B105F391", + "repo": "Elixir.Canary.Repo", + "identities": [], + "schema": null, + "check_constraints": [], + "custom_indexes": [], + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "base_filter": null, + "custom_statements": [], + "has_create_action": true +} \ No newline at end of file diff --git a/core/priv/resource_snapshots/repo/client_websites/20240622003411.json b/core/priv/resource_snapshots/repo/client_websites/20240622003411.json new file mode 100644 index 00000000..5cb0dc7a --- /dev/null +++ b/core/priv/resource_snapshots/repo/client_websites/20240622003411.json @@ -0,0 +1,78 @@ +{ + "attributes": [ + { + "default": "fragment(\"gen_random_uuid()\")", + "size": null, + "type": "uuid", + "source": "id", + "references": null, + "allow_nil?": false, + "primary_key?": true, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "uuid", + "source": "account_id", + "references": { + "name": "client_websites_account_id_fkey", + "table": "accounts", + "destination_attribute": "id", + "primary_key?": true, + "schema": "public", + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "on_delete": null, + "on_update": null, + "deferrable": false, + "match_with": null, + "match_type": null, + "index?": false, + "destination_attribute_default": null, + "destination_attribute_generated": null + }, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "text", + "source": "base_url", + "references": null, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + }, + { + "default": "fragment(\"gen_random_uuid()\")", + "size": null, + "type": "text", + "source": "public_key", + "references": null, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + } + ], + "table": "client_websites", + "hash": "8332509792F55790570E7E016542D2187D3F524FFF6BE8F7E5DB292DBFCCE813", + "repo": "Elixir.Canary.Repo", + "identities": [], + "schema": null, + "check_constraints": [], + "custom_indexes": [], + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "base_filter": null, + "custom_statements": [], + "has_create_action": true +} \ No newline at end of file diff --git a/core/priv/resource_snapshots/repo/extensions.json b/core/priv/resource_snapshots/repo/extensions.json new file mode 100644 index 00000000..3123bbc2 --- /dev/null +++ b/core/priv/resource_snapshots/repo/extensions.json @@ -0,0 +1,8 @@ +{ + "installed": [ + "uuid-ossp", + "citext", + "ash-functions" + ], + "ash_functions_version": 3 +} \ No newline at end of file diff --git a/core/priv/resource_snapshots/repo/source_documents/20240622003411.json b/core/priv/resource_snapshots/repo/source_documents/20240622003411.json new file mode 100644 index 00000000..abf4e280 --- /dev/null +++ b/core/priv/resource_snapshots/repo/source_documents/20240622003411.json @@ -0,0 +1,78 @@ +{ + "attributes": [ + { + "default": "nil", + "size": null, + "type": "bigint", + "source": "id", + "references": null, + "allow_nil?": false, + "primary_key?": true, + "generated?": true + }, + { + "default": "nil", + "size": null, + "type": "text", + "source": "content", + "references": null, + "allow_nil?": true, + "primary_key?": false, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "vector", + "source": "embedding", + "references": null, + "allow_nil?": true, + "primary_key?": false, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "uuid", + "source": "snapshot_id", + "references": { + "name": "source_documents_snapshot_id_fkey", + "table": "source_snapshots", + "destination_attribute": "id", + "primary_key?": true, + "schema": "public", + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "on_delete": null, + "on_update": null, + "deferrable": false, + "match_with": null, + "match_type": null, + "index?": false, + "destination_attribute_default": null, + "destination_attribute_generated": null + }, + "allow_nil?": true, + "primary_key?": false, + "generated?": false + } + ], + "table": "source_documents", + "hash": "B8CEDE0157AF39735778EC702CF045AABB797EDC06094E5EB2EFAC4B9A585DE5", + "repo": "Elixir.Canary.Repo", + "identities": [], + "schema": null, + "check_constraints": [], + "custom_indexes": [], + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "base_filter": null, + "custom_statements": [], + "has_create_action": true +} \ No newline at end of file diff --git a/core/priv/resource_snapshots/repo/source_snapshots/20240622003411.json b/core/priv/resource_snapshots/repo/source_snapshots/20240622003411.json new file mode 100644 index 00000000..70f375d2 --- /dev/null +++ b/core/priv/resource_snapshots/repo/source_snapshots/20240622003411.json @@ -0,0 +1,49 @@ +{ + "attributes": [ + { + "default": "fragment(\"gen_random_uuid()\")", + "size": null, + "type": "uuid", + "source": "id", + "references": null, + "allow_nil?": false, + "primary_key?": true, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "uuid", + "source": "source_id", + "references": null, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + }, + { + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "size": null, + "type": "utc_datetime_usec", + "source": "created_at", + "references": null, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + } + ], + "table": "source_snapshots", + "hash": "2B6AA28369F3232CB1A43BE484E36AFC3A315C5DBD5CC78C2C62C59DC2E1174F", + "repo": "Elixir.Canary.Repo", + "identities": [], + "schema": null, + "check_constraints": [], + "custom_indexes": [], + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "base_filter": null, + "custom_statements": [], + "has_create_action": false +} \ No newline at end of file diff --git a/core/priv/resource_snapshots/repo/source_websites/20240622003411.json b/core/priv/resource_snapshots/repo/source_websites/20240622003411.json new file mode 100644 index 00000000..7d6694a2 --- /dev/null +++ b/core/priv/resource_snapshots/repo/source_websites/20240622003411.json @@ -0,0 +1,68 @@ +{ + "attributes": [ + { + "default": "fragment(\"gen_random_uuid()\")", + "size": null, + "type": "uuid", + "source": "id", + "references": null, + "allow_nil?": false, + "primary_key?": true, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "uuid", + "source": "account_id", + "references": { + "name": "source_websites_account_id_fkey", + "table": "accounts", + "destination_attribute": "id", + "primary_key?": true, + "schema": "public", + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "on_delete": null, + "on_update": null, + "deferrable": false, + "match_with": null, + "match_type": null, + "index?": false, + "destination_attribute_default": null, + "destination_attribute_generated": null + }, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "text", + "source": "base_url", + "references": null, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + } + ], + "table": "source_websites", + "hash": "59E075FE98042B9D504DD8F0F3359EB1E362882D3FA3C698A6BECC9532369A5D", + "repo": "Elixir.Canary.Repo", + "identities": [], + "schema": null, + "check_constraints": [], + "custom_indexes": [], + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "base_filter": null, + "custom_statements": [], + "has_create_action": true +} \ No newline at end of file diff --git a/core/priv/resource_snapshots/repo/tokens/20240622003411.json b/core/priv/resource_snapshots/repo/tokens/20240622003411.json new file mode 100644 index 00000000..5e0e14d5 --- /dev/null +++ b/core/priv/resource_snapshots/repo/tokens/20240622003411.json @@ -0,0 +1,89 @@ +{ + "attributes": [ + { + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "size": null, + "type": "utc_datetime_usec", + "source": "updated_at", + "references": null, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + }, + { + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "size": null, + "type": "utc_datetime_usec", + "source": "created_at", + "references": null, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "map", + "source": "extra_data", + "references": null, + "allow_nil?": true, + "primary_key?": false, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "text", + "source": "purpose", + "references": null, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "utc_datetime", + "source": "expires_at", + "references": null, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "text", + "source": "subject", + "references": null, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "text", + "source": "jti", + "references": null, + "allow_nil?": false, + "primary_key?": true, + "generated?": false + } + ], + "table": "tokens", + "hash": "1CA2AB7345A410491D592E69231B2D2F9B12377FE02F945D468028F1444C3744", + "repo": "Elixir.Canary.Repo", + "identities": [], + "schema": null, + "check_constraints": [], + "custom_indexes": [], + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "base_filter": null, + "custom_statements": [], + "has_create_action": true +} \ No newline at end of file diff --git a/core/priv/resource_snapshots/repo/users/20240622003411.json b/core/priv/resource_snapshots/repo/users/20240622003411.json new file mode 100644 index 00000000..569fc2e2 --- /dev/null +++ b/core/priv/resource_snapshots/repo/users/20240622003411.json @@ -0,0 +1,64 @@ +{ + "attributes": [ + { + "default": "fragment(\"gen_random_uuid()\")", + "size": null, + "type": "uuid", + "source": "id", + "references": null, + "allow_nil?": false, + "primary_key?": true, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "citext", + "source": "email", + "references": null, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + }, + { + "default": "nil", + "size": null, + "type": "text", + "source": "hashed_password", + "references": null, + "allow_nil?": false, + "primary_key?": false, + "generated?": false + } + ], + "table": "users", + "hash": "2B407E081645AF1CE0F2C379D332FF9E5EF2FCA13706A94375318794ECF0C5B6", + "repo": "Elixir.Canary.Repo", + "identities": [ + { + "name": "unique_email", + "keys": [ + { + "type": "atom", + "value": "email" + } + ], + "where": null, + "base_filter": null, + "all_tenants?": false, + "nils_distinct?": true, + "index_name": "users_unique_email_index" + } + ], + "schema": null, + "check_constraints": [], + "custom_indexes": [], + "multitenancy": { + "global": null, + "attribute": null, + "strategy": null + }, + "base_filter": null, + "custom_statements": [], + "has_create_action": true +} \ No newline at end of file diff --git a/core/test/canary_web/controllers/page_controller_test.exs b/core/test/canary_web/controllers/page_controller_test.exs index 67cb2242..a417c186 100644 --- a/core/test/canary_web/controllers/page_controller_test.exs +++ b/core/test/canary_web/controllers/page_controller_test.exs @@ -3,6 +3,6 @@ defmodule CanaryWeb.PageControllerTest do test "GET /", %{conn: conn} do conn = get(conn, ~p"/") - assert html_response(conn, 200) =~ "Peace of mind from prototype to production" + assert html_response(conn, 200) =~ "Canary" end end