diff --git a/lib/polar/globals.ex b/lib/polar/globals.ex index fb58ca3..eb9a7cd 100644 --- a/lib/polar/globals.ex +++ b/lib/polar/globals.ex @@ -1,2 +1,25 @@ defmodule Polar.Globals do + alias Polar.Repo + alias Polar.Globals.Basic + alias Polar.Globals.Setting + + @defaults %{ + "basic" => Basic + } + + def get(key) do + Setting + |> Repo.get_by(key: key) + |> case do + nil -> + module = Map.fetch!(@defaults, key) + + struct(module, %{}) + + %Setting{value: value} -> + module = Map.fetch!(@defaults, key) + + module.parse!(value) + end + end end diff --git a/lib/polar/globals/basic.ex b/lib/polar/globals/basic.ex new file mode 100644 index 0000000..5001c99 --- /dev/null +++ b/lib/polar/globals/basic.ex @@ -0,0 +1,24 @@ +defmodule Polar.Globals.Basic do + use Ecto.Schema + import Ecto.Changeset + + @primary_key false + + embedded_schema do + field :enable_registration, :boolean, default: true + field :versions_per_product, :integer, default: 1 + end + + def changeset(basic, attrs \\ %{}) do + basic + |> cast(attrs, [:enable_registration, :versions_per_product]) + |> validate_required([:enable_registration, :versions_per_product]) + |> validate_number(:versions_per_product, less_than_or_equal_to: 3) + end + + def parse(value) do + %__MODULE__{} + |> changeset(value) + |> apply_action!(:insert) + end +end diff --git a/lib/polar/globals/setting.ex b/lib/polar/globals/setting.ex index 1e8eeaf..d885dde 100644 --- a/lib/polar/globals/setting.ex +++ b/lib/polar/globals/setting.ex @@ -14,5 +14,6 @@ defmodule Polar.Globals.Setting do setting |> cast(attrs, [:key, :value]) |> validate_required([:key, :value]) + |> validate_inclusion(:key, ["basic"]) end end diff --git a/lib/polar/streams/version/manager.ex b/lib/polar/streams/version/manager.ex index bc333b7..6a12796 100644 --- a/lib/polar/streams/version/manager.ex +++ b/lib/polar/streams/version/manager.ex @@ -1,10 +1,37 @@ defmodule Polar.Streams.Version.Manager do alias Polar.Repo + alias Polar.Globals alias Polar.Streams.Version + import Ecto.Query, only: [from: 2] + def create(product, attrs) do %Version{product_id: product.id} |> Version.changeset(attrs) |> Repo.insert() + |> case do + {:ok, version} = result -> + bot = Polar.Accounts.Automation.get_bot!() + + basic_setting = Globals.get("basic") + + from( + v in Version, + where: + v.product_id == ^version.product_id and + v.current_state == ^"active", + offset: ^basic_setting.versions_per_product, + order_by: [desc: :inserted_at] + ) + |> Repo.all() + |> Enum.each(fn v -> + Eventful.Transit.perform(v, bot, "deactivate") + end) + + result + + error -> + error + end end end diff --git a/test/polar/streams/item/manager_test.exs b/test/polar/streams/item/manager_test.exs index 8b8e189..7b0eddc 100644 --- a/test/polar/streams/item/manager_test.exs +++ b/test/polar/streams/item/manager_test.exs @@ -12,6 +12,10 @@ defmodule Polar.Streams.Item.ManagerTest do setup do user = user_fixture() + password = Accounts.generate_automation_password() + + _bot = bot_fixture(%{password: password}) + {:ok, space} = Accounts.create_space(user, %{name: "test-item-increment"}) {:ok, credential} = diff --git a/test/polar/streams/product/manager_test.exs b/test/polar/streams/product/manager_test.exs index 475c14d..da1d6a9 100644 --- a/test/polar/streams/product/manager_test.exs +++ b/test/polar/streams/product/manager_test.exs @@ -1,11 +1,21 @@ defmodule Polar.Streams.Product.ManagerTest do use Polar.DataCase, async: true + alias Polar.Accounts alias Polar.Streams alias Polar.Streams.Product + import Polar.AccountsFixtures import Polar.StreamsFixtures + setup do + password = Accounts.generate_automation_password() + + _bot = bot_fixture(%{password: password}) + + :ok + end + describe "filter" do setup do {:ok, %Product{} = without_active_versions} = diff --git a/test/polar/streams/version/manager_test.exs b/test/polar/streams/version/manager_test.exs index 882b09c..849b49f 100644 --- a/test/polar/streams/version/manager_test.exs +++ b/test/polar/streams/version/manager_test.exs @@ -2,8 +2,15 @@ defmodule Polar.Streams.Version.ManagerTest do use Polar.DataCase, async: true alias Polar.Streams + alias Polar.Accounts + + import Polar.AccountsFixtures setup do + password = Accounts.generate_automation_password() + + _bot = bot_fixture(%{password: password}) + {:ok, product} = Streams.create_product(%{ aliases: ["alpine/3.19", "alpine/3.19/default"], @@ -24,7 +31,7 @@ defmodule Polar.Streams.Version.ManagerTest do test "can successfully create new version", %{product: product} do assert {:ok, _version} = Streams.create_version(product, %{ - serial: "20240209_13:00", + serial: "20240209-2", items: [ %{ name: "lxd.tar.gz", @@ -51,4 +58,75 @@ defmodule Polar.Streams.Version.ManagerTest do }) end end + + describe "deactivate old version on create" do + setup %{product: product} do + {:ok, version} = + Streams.create_version(product, %{ + serial: "20240209-2", + items: [ + %{ + name: "lxd.tar.gz", + file_type: "lxd.tar.gz", + hash: "35363f3d086271ed5402d61ab18ec03987bed51758c00079b8c9d372ff6d62dd", + size: 876, + is_metadata: true, + path: "images/alpine/edge/amd64/default/20240209_13:00/incus.tar.xz", + combined_hashes: [ + %{ + name: "combined_squashfs_sha256", + hash: "a9f02be498bf52b7bac7b5b1cfceb115878d257ad86a359a969e61fbd4bfe0bf" + } + ] + }, + %{ + name: "root.squashfs", + file_type: "squashfs", + hash: "47cc4070da1bf17d8364c390…3603f4ed7e9e46582e690d2", + size: 2_982_800, + path: "images/alpine/edge/amd64/default/20240209_13:00/rootfs.tar.xz" + } + ] + }) + + %{existing_version: version} + end + + test "creating a new version deactivates old versions", %{ + product: product, + existing_version: existing_version + } do + assert {:ok, _version} = + Streams.create_version(product, %{ + serial: "20240209-3", + items: [ + %{ + name: "lxd.tar.gz", + file_type: "lxd.tar.gz", + hash: "35363f3d086271ed5402d61ab18ec03987bed51758c00079b8c9d372ff6d62aa", + size: 876, + is_metadata: true, + path: "images/alpine/edge/amd64/default/20240209_13:00/incus.tar.xz", + combined_hashes: [ + %{ + name: "combined_squashfs_sha256", + hash: "a9f02be498bf52b7bac7b5b1cfceb115878d257ad86a359a969e61fbd4bfe0aa" + } + ] + }, + %{ + name: "root.squashfs", + file_type: "squashfs", + hash: "47cc4070da1bf17d8364c390…3603f4ed7e9e46582e690aa", + size: 2_982_800, + path: "images/alpine/edge/amd64/default/20240209_13:00/rootfs.tar.xz" + } + ] + }) + + existing_version = Repo.reload(existing_version) + + assert existing_version.current_state == "inactive" + end + end end diff --git a/test/polar/streams/version/transitions_test.exs b/test/polar/streams/version/transitions_test.exs index 2577bca..e973675 100644 --- a/test/polar/streams/version/transitions_test.exs +++ b/test/polar/streams/version/transitions_test.exs @@ -1,6 +1,7 @@ defmodule Polar.Streams.Version.TransitionsTest do use Polar.DataCase, async: true + alias Polar.Accounts alias Polar.Streams import Polar.AccountsFixtures @@ -8,6 +9,10 @@ defmodule Polar.Streams.Version.TransitionsTest do setup do user = user_fixture() + password = Accounts.generate_automation_password() + + _bot = bot_fixture(%{password: password}) + {:ok, product} = Streams.create_product(%{ aliases: ["alpine/3.19", "alpine/3.19/default"], diff --git a/test/polar_web/controllers/stream_controller_test.exs b/test/polar_web/controllers/stream_controller_test.exs index 0fffe85..d141fb3 100644 --- a/test/polar_web/controllers/stream_controller_test.exs +++ b/test/polar_web/controllers/stream_controller_test.exs @@ -10,6 +10,10 @@ defmodule PolarWeb.StreamControllerTest do setup do user = user_fixture() + password = Accounts.generate_automation_password() + + _bot = bot_fixture(%{password: password}) + {:ok, space} = Accounts.create_space(user, %{name: "some-test-123"}) {:ok, credential} = diff --git a/test/polar_web/live/root_live_test.exs b/test/polar_web/live/root_live_test.exs index cab257d..b8e16f9 100644 --- a/test/polar_web/live/root_live_test.exs +++ b/test/polar_web/live/root_live_test.exs @@ -11,6 +11,10 @@ defmodule PolarWeb.RootLiveTest do setup do user = user_fixture() + password = Accounts.generate_automation_password() + + _bot = bot_fixture(%{password: password}) + {:ok, space} = Accounts.create_space(user, %{name: "some-test-123"}) {:ok, credential} =