From aa6e85071656e910d51497814341e3440fbafd1d Mon Sep 17 00:00:00 2001 From: luckydonald Date: Fri, 1 May 2026 23:13:09 +0200 Subject: [PATCH] Expose image subscriptions similar to hides (#527). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is based on the changes for `hides` in ba904786de8f34ce8729759a68622779584840bd (know as eef9ec612fc19bd39bdb09e0a354f5a8d4590db8 after rebase). Changes made: 1. Migration (`priv/repo/migrations/20260501234567_add_subscriptions_count_to_images.exs`) — adds `subscriptions_count integer not null default 0` to images and backfills it from `image_subscriptions`. 2. `lib/philomena/images/image.ex` — added `field :subscriptions_count, :integer, default: 0`. 3. `lib/philomena/subscriptions.ex` — added `defoverridable create_subscription: 2, delete_subscription: 2` at the end of the `quote` block so callers can override with `super/2`. 4. `lib/philomena/images.ex` — added `create_subscription/2` and `delete_subscription/2` overrides that call `super` then increment/decrement `subscriptions_count` atomically via `Repo.update_all(inc: ...)`. 5. `lib/philomena/images/search_index.ex` — added `subscriptions: %{type: "integer"}` to the mapping and `subscriptions: image.subscriptions_count` to `as_json/1`. 6. `lib/philomena/images/query.ex` — added `subscriptions` to `int_fields` in `anonymous_fields/0`. 7. `lib/philomena_web/image_sorter.ex` — added `subscriptions` to `@allowed_fields`. 8. `lib/philomena_web/templates/search/_form.html.slime` — added `"Sort by subscriptions": :subscriptions` after the `hides` entry. 9. `lib/philomena_web/views/api/json/image_view.ex` — added `subscriptions: image.subscriptions_count` to the image JSON response. --- lib/philomena/images.ex | 20 +++++++++++++++++++ lib/philomena/images/image.ex | 1 + lib/philomena/images/query.ex | 2 +- lib/philomena/images/search_index.ex | 4 +++- lib/philomena/subscriptions.ex | 2 ++ lib/philomena_web/image_sorter.ex | 1 + .../templates/search/_form.html.slime | 1 + .../views/api/json/image_view.ex | 1 + ...4567_add_subscriptions_count_to_images.exs | 16 +++++++++++++++ 9 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 priv/repo/migrations/20260501234567_add_subscriptions_count_to_images.exs diff --git a/lib/philomena/images.ex b/lib/philomena/images.ex index 7623de0d1..ebd84b73b 100644 --- a/lib/philomena/images.ex +++ b/lib/philomena/images.ex @@ -43,6 +43,26 @@ defmodule Philomena.Images do on_delete: :clear_image_notification, id_name: :image_id + def create_subscription(object, user) do + result = super(object, user) + + if match?({:ok, _}, result) do + Image |> where(id: ^object.id) |> Repo.update_all(inc: [subscriptions_count: 1]) + end + + result + end + + def delete_subscription(object, user) do + result = super(object, user) + + if match?({:ok, _}, result) do + Image |> where(id: ^object.id) |> Repo.update_all(inc: [subscriptions_count: -1]) + end + + result + end + @doc """ Gets a single image. diff --git a/lib/philomena/images/image.ex b/lib/philomena/images/image.ex index f9e2aa7ce..f67a60dd4 100644 --- a/lib/philomena/images/image.ex +++ b/lib/philomena/images/image.ex @@ -83,6 +83,7 @@ defmodule Philomena.Images.Image do field :hidden_image_key, :string field :scratchpad, :string field :hides_count, :integer, default: 0 + field :subscriptions_count, :integer, default: 0 field :approved, :boolean field :removed_tags, {:array, :any}, default: [], virtual: true diff --git a/lib/philomena/images/query.ex b/lib/philomena/images/query.ex index 5650ed4a0..87f2b32d2 100644 --- a/lib/philomena/images/query.ex +++ b/lib/philomena/images/query.ex @@ -110,7 +110,7 @@ defmodule Philomena.Images.Query do defp anonymous_fields do [ int_fields: - ~W(id width height score upvotes downvotes hides faves pixels size orig_size comment_count source_count tag_count) ++ + ~W(id width height score upvotes downvotes hides subscriptions faves pixels size orig_size comment_count source_count tag_count) ++ tag_count_fields(), numeric_fields: ~W(uploader_id faved_by_id duplicate_id), float_fields: ~W(aspect_ratio wilson_score duration), diff --git a/lib/philomena/images/search_index.ex b/lib/philomena/images/search_index.ex index 54e9603f3..add64f540 100644 --- a/lib/philomena/images/search_index.ex +++ b/lib/philomena/images/search_index.ex @@ -89,7 +89,8 @@ defmodule Philomena.Images.SearchIndex do content_official_tag_count: %{type: "integer"}, spoiler_tag_count: %{type: "integer"}, scratchpad: %{type: "text", analyzer: "snowball"}, - hides: %{type: "integer"} + hides: %{type: "integer"}, + subscriptions: %{type: "integer"} } } } @@ -104,6 +105,7 @@ defmodule Philomena.Images.SearchIndex do score: image.score, faves: image.faves_count, hides: image.hides_count, + subscriptions: image.subscriptions_count, comment_count: image.comments_count, width: image.image_width, height: image.image_height, diff --git a/lib/philomena/subscriptions.ex b/lib/philomena/subscriptions.ex index d0688107a..a9959cb7d 100644 --- a/lib/philomena/subscriptions.ex +++ b/lib/philomena/subscriptions.ex @@ -140,6 +140,8 @@ defmodule Philomena.Subscriptions do def maybe_subscribe_on(multi, change_name, user, field) do Philomena.Subscriptions.maybe_subscribe_on(multi, __MODULE__, change_name, user, field) end + + defoverridable create_subscription: 2, delete_subscription: 2 end end diff --git a/lib/philomena_web/image_sorter.ex b/lib/philomena_web/image_sorter.ex index c05db5122..233699d6b 100644 --- a/lib/philomena_web/image_sorter.ex +++ b/lib/philomena_web/image_sorter.ex @@ -17,6 +17,7 @@ defmodule PhilomenaWeb.ImageSorter do size duration hides + subscriptions ) def parse_sort(params, query) do diff --git a/lib/philomena_web/templates/search/_form.html.slime b/lib/philomena_web/templates/search/_form.html.slime index 0a10093fa..c2c28857a 100644 --- a/lib/philomena_web/templates/search/_form.html.slime +++ b/lib/philomena_web/templates/search/_form.html.slime @@ -156,6 +156,7 @@ h1 Search "Sort by score": :score, "Sort by Wilson score": :wilson_score, "Sort by hides": :hides, + "Sort by subscriptions": :subscriptions, "Sort by relevance": :_score, "Sort by width": :width, "Sort by height": :height, diff --git a/lib/philomena_web/views/api/json/image_view.ex b/lib/philomena_web/views/api/json/image_view.ex index 4646af232..57e7d6a1d 100644 --- a/lib/philomena_web/views/api/json/image_view.ex +++ b/lib/philomena_web/views/api/json/image_view.ex @@ -79,6 +79,7 @@ defmodule PhilomenaWeb.Api.Json.ImageView do downvotes: image.downvotes_count, faves: image.faves_count, hides: image.hides_count, + subscriptions: image.subscriptions_count, comment_count: image.comments_count, tag_count: length(image.tags), description: image.description, diff --git a/priv/repo/migrations/20260501234567_add_subscriptions_count_to_images.exs b/priv/repo/migrations/20260501234567_add_subscriptions_count_to_images.exs new file mode 100644 index 000000000..4ad2663cd --- /dev/null +++ b/priv/repo/migrations/20260501234567_add_subscriptions_count_to_images.exs @@ -0,0 +1,16 @@ +defmodule Philomena.Repo.Migrations.AddSubscriptionsCountToImages do + use Ecto.Migration + + def change do + alter table(:images) do + add :subscriptions_count, :integer, default: 0, null: false + end + + execute(""" + UPDATE images + SET subscriptions_count = ( + SELECT COUNT(*) FROM image_subscriptions WHERE image_id = images.id + ) + """) + end +end