From df0b1a4632023b95fe62e16c46806051b90a4824 Mon Sep 17 00:00:00 2001
From: KMY <tt@kmycode.net>
Date: Tue, 22 Aug 2023 13:33:20 +0900
Subject: [PATCH] Fix antenna fabricator tests and move duplicate check to db

---
 app/models/antenna_account.rb                   |  7 ++-----
 app/models/antenna_domain.rb                    |  7 ++-----
 app/models/antenna_tag.rb                       |  7 ++-----
 config/locales/ja.yml                           |  2 --
 ...822041804_add_antenna_elements_uniqueness.rb | 17 +++++++++++++++++
 db/schema.rb                                    |  5 ++++-
 spec/fabricators/antenna_account_fabricator.rb  |  2 ++
 spec/fabricators/circle_account_fabricator.rb   |  6 +++++-
 8 files changed, 34 insertions(+), 19 deletions(-)
 create mode 100644 db/migrate/20230822041804_add_antenna_elements_uniqueness.rb

diff --git a/app/models/antenna_account.rb b/app/models/antenna_account.rb
index 29da021425..b4cab184e7 100644
--- a/app/models/antenna_account.rb
+++ b/app/models/antenna_account.rb
@@ -15,14 +15,11 @@ class AntennaAccount < ApplicationRecord
   belongs_to :antenna
   belongs_to :account
 
-  validate :duplicate_account
   validate :limit_per_antenna
 
-  private
+  validates :account_id, uniqueness: { scope: :antenna_id }
 
-  def duplicate_account
-    raise Mastodon::ValidationError, I18n.t('antennas.errors.duplicate_account') if AntennaAccount.exists?(antenna_id: antenna_id, account_id: account_id, exclude: exclude)
-  end
+  private
 
   def limit_per_antenna
     raise Mastodon::ValidationError, I18n.t('antennas.errors.limit.accounts') if AntennaAccount.where(antenna_id: antenna_id).count >= Antenna::ACCOUNTS_PER_ANTENNA_LIMIT
diff --git a/app/models/antenna_domain.rb b/app/models/antenna_domain.rb
index 09e481ad9f..f4b80e2e9f 100644
--- a/app/models/antenna_domain.rb
+++ b/app/models/antenna_domain.rb
@@ -14,14 +14,11 @@
 class AntennaDomain < ApplicationRecord
   belongs_to :antenna
 
-  validate :duplicate_domain
   validate :limit_per_antenna
 
-  private
+  validates :name, uniqueness: { scope: :antenna_id }
 
-  def duplicate_domain
-    raise Mastodon::ValidationError, I18n.t('antennas.errors.duplicate_domain') if AntennaDomain.exists?(antenna_id: antenna_id, name: name, exclude: exclude)
-  end
+  private
 
   def limit_per_antenna
     raise Mastodon::ValidationError, I18n.t('antennas.errors.limit.domains') if AntennaDomain.where(antenna_id: antenna_id).count >= Antenna::DOMAINS_PER_ANTENNA_LIMIT
diff --git a/app/models/antenna_tag.rb b/app/models/antenna_tag.rb
index 0fbdbc0932..6abf5c0312 100644
--- a/app/models/antenna_tag.rb
+++ b/app/models/antenna_tag.rb
@@ -15,14 +15,11 @@ class AntennaTag < ApplicationRecord
   belongs_to :antenna
   belongs_to :tag
 
-  validate :duplicate_tag
   validate :limit_per_antenna
 
-  private
+  validates :tag_id, uniqueness: { scope: :antenna_id }
 
-  def duplicate_tag
-    raise Mastodon::ValidationError, I18n.t('antennas.errors.duplicate_tag') if AntennaTag.exists?(antenna_id: antenna_id, tag_id: tag_id, exclude: exclude)
-  end
+  private
 
   def limit_per_antenna
     raise Mastodon::ValidationError, I18n.t('antennas.errors.limit.tags') if AntennaTag.where(antenna_id: antenna_id).count >= Antenna::TAGS_PER_ANTENNA_LIMIT
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index b0a6b717aa..1962d9af0d 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -1023,8 +1023,6 @@ ja:
       keyword: キーワード
       tag: ハッシュタグ
     errors:
-      duplicate_domain: すでに同じドメインが登録されています
-      duplicate_keyword: すでに同じキーワードが登録されています
       empty_contexts: 絞り込み条件が1つも指定されていないため無効です(除外条件はカウントされません)
       invalid_list_owner: これはあなたのリストではありません
       limit:
diff --git a/db/migrate/20230822041804_add_antenna_elements_uniqueness.rb b/db/migrate/20230822041804_add_antenna_elements_uniqueness.rb
new file mode 100644
index 0000000000..6654180efd
--- /dev/null
+++ b/db/migrate/20230822041804_add_antenna_elements_uniqueness.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require Rails.root.join('lib', 'mastodon', 'migration_helpers')
+
+class AddAntennaElementsUniqueness < ActiveRecord::Migration[7.0]
+  include Mastodon::MigrationHelpers
+
+  disable_ddl_transaction!
+
+  def change
+    safety_assured do
+      add_index :antenna_accounts, [:antenna_id, :account_id], unique: true
+      add_index :antenna_domains, [:antenna_id, :name], unique: true
+      add_index :antenna_tags, [:antenna_id, :tag_id], unique: true
+    end
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 4b237dd9d1..144679c85c 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema[7.0].define(version: 2023_08_21_061713) do
+ActiveRecord::Schema[7.0].define(version: 2023_08_22_041804) do
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
 
@@ -262,6 +262,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_21_061713) do
     t.datetime "created_at", precision: nil, null: false
     t.datetime "updated_at", precision: nil, null: false
     t.index ["account_id"], name: "index_antenna_accounts_on_account_id"
+    t.index ["antenna_id", "account_id"], name: "index_antenna_accounts_on_antenna_id_and_account_id", unique: true
     t.index ["antenna_id"], name: "index_antenna_accounts_on_antenna_id"
     t.index ["exclude"], name: "index_antenna_accounts_on_exclude"
   end
@@ -272,6 +273,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_21_061713) do
     t.boolean "exclude", default: false, null: false
     t.datetime "created_at", precision: nil, null: false
     t.datetime "updated_at", precision: nil, null: false
+    t.index ["antenna_id", "name"], name: "index_antenna_domains_on_antenna_id_and_name", unique: true
     t.index ["antenna_id"], name: "index_antenna_domains_on_antenna_id"
     t.index ["exclude"], name: "index_antenna_domains_on_exclude"
     t.index ["name"], name: "index_antenna_domains_on_name"
@@ -283,6 +285,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_21_061713) do
     t.boolean "exclude", default: false, null: false
     t.datetime "created_at", precision: nil, null: false
     t.datetime "updated_at", precision: nil, null: false
+    t.index ["antenna_id", "tag_id"], name: "index_antenna_tags_on_antenna_id_and_tag_id", unique: true
     t.index ["antenna_id"], name: "index_antenna_tags_on_antenna_id"
     t.index ["exclude"], name: "index_antenna_tags_on_exclude"
     t.index ["tag_id"], name: "index_antenna_tags_on_tag_id"
diff --git a/spec/fabricators/antenna_account_fabricator.rb b/spec/fabricators/antenna_account_fabricator.rb
index 70d4067d20..43e27cfbaf 100644
--- a/spec/fabricators/antenna_account_fabricator.rb
+++ b/spec/fabricators/antenna_account_fabricator.rb
@@ -1,5 +1,7 @@
 # frozen_string_literal: true
 
 Fabricator(:antenna_account) do
+  antenna { Fabricate.build(:antenna) }
+  account { Fabricate.build(:account) }
   exclude false
 end
diff --git a/spec/fabricators/circle_account_fabricator.rb b/spec/fabricators/circle_account_fabricator.rb
index 2de537bc31..9850a49ce2 100644
--- a/spec/fabricators/circle_account_fabricator.rb
+++ b/spec/fabricators/circle_account_fabricator.rb
@@ -1,3 +1,7 @@
 # frozen_string_literal: true
 
-Fabricator(:circle_account)
+Fabricator(:circle_account) do
+  circle { Fabricate(:circle) }
+  account { Fabricate(:account) }
+  before_create { |circle_account, _| circle_account.account.follow!(circle_account.circle.account) }
+end