simplify post file thumbnails

This commit is contained in:
Dylan Knutson
2025-03-04 01:58:23 +00:00
parent 0040bc45a2
commit f845d06267
20 changed files with 490 additions and 2042 deletions

View File

@@ -125,6 +125,7 @@ gem "ripcord"
gem "ruby-prof"
gem "ruby-prof-speedscope"
gem "ruby-vips"
gem "dhash-vips"
gem "table_print"
gem "zstd-ruby"
gem "rouge"

View File

@@ -155,6 +155,8 @@ GEM
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
dhash-vips (0.2.3.0)
ruby-vips (~> 2.0, != 2.1.1, != 2.1.0)
diff-lcs (1.5.1)
diffy (3.4.3)
discard (1.4.0)
@@ -572,6 +574,7 @@ DEPENDENCIES
db-query-matchers (~> 0.14)
debug (~> 1.10)
devise (~> 4.9)
dhash-vips
diffy
discard
disco

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -34,6 +34,7 @@ module Domain::DomainsHelper
gumroad.com
hipolink.me
inkbunny.net
itch.io
instagram.com
ko-fi.com
livejournal.com
@@ -80,6 +81,7 @@ module Domain::DomainsHelper
"subscribestar.com" => "subscribestar.png",
"subscribestar.adult" => "subscribestar.png",
"gumroad.com" => "gumroad.png",
"itch.io" => "itch-io.png",
"t.me" => "telegram.png",
"tumblr.com" => "tumblr.png",
"twitter.com" => "x-twitter.png",

View File

@@ -1,28 +0,0 @@
# typed: strict
class Domain::PerceptualHash < ReduxApplicationRecord
include AttrJsonRecordAliases
self.table_name = "domain_perceptual_hashes"
belongs_to :thumbnail,
foreign_key: :thumbnail_id,
class_name: "::Domain::PostFileThumbnail"
validates :algorithm, presence: true
validates :hash_value, presence: true
# Ensure uniqueness of algorithm and hash_version per thumbnail
validates :algorithm, uniqueness: { scope: %i[thumbnail_id] }
# Supported perceptual hash algorithms
ALGORITHMS =
T.let(
{
phash: "phash", # Perceptual hash
dhash: "dhash", # Difference hash
ahash: "ahash", # Average hash
whash: "whash", # Wavelet hash
colorhash: "colorhash", # Color histogram hash
},
T::Hash[Symbol, String],
)
end

View File

@@ -10,11 +10,11 @@ class Domain::PostFile < ReduxApplicationRecord
optional: true,
foreign_key: :blob_sha256
has_many :thumbnails,
class_name: "::Domain::PostFileThumbnail",
foreign_key: :post_file_id,
dependent: :destroy,
inverse_of: :post_file
has_one :fingerprint,
class_name: "::Domain::PostFileFingerprint",
foreign_key: :post_file_id,
dependent: :destroy,
inverse_of: :post_file
attr_json :state, :string
attr_json :url_str, :string

View File

@@ -0,0 +1,38 @@
# typed: strict
class Domain::PostFileFingerprint < ReduxApplicationRecord
include AttrJsonRecordAliases
self.table_name = "domain_post_file_fingerprints"
belongs_to :post_file,
foreign_key: :post_file_id,
class_name: "::Domain::PostFile",
inverse_of: :fingerprint
validates :hash_value, presence: true
VALID_CONTENT_TYPES =
T.let(
[
%r{image/jpeg},
%r{image/jpg},
%r{image/png},
%r{image/gif},
%r{image/webp},
],
T::Array[Regexp],
)
before_validation do |fingerprint|
next false if fingerprint.hash_value.present?
next false unless (path = post_file&.blob&.absolute_file_path)
next false unless File.exist?(path)
next false unless blob = post_file&.blob
next false unless content_type = blob.content_type
unless VALID_CONTENT_TYPES.any? { |type| content_type.match?(type) }
next false
end
fingerprint = DHashVips::IDHash.fingerprint(path)
self.hash_value = fingerprint.to_s(2).rjust(256, "0")
end
end

View File

@@ -1,102 +0,0 @@
# typed: strict
class Domain::PostFileThumbnail < ReduxApplicationRecord
include AttrJsonRecordAliases
self.table_name = "domain_post_file_thumbnails"
belongs_to :post_file,
foreign_key: :post_file_id,
class_name: "::Domain::PostFile",
inverse_of: :thumbnails
has_many :perceptual_hashes,
class_name: "::Domain::PerceptualHash",
foreign_key: :thumbnail_id,
dependent: :destroy
validates :thumbnail_type,
presence: true,
uniqueness: {
scope: :post_file_id,
},
inclusion: {
in: Domain::ThumbnailType.values.map(&:name),
}
TMP_DIR = T.let(File.join(BlobFile::ROOT_DIR, "tmp-files"), String)
THUMBNAIL_ROOT_DIR =
T.let(File.join(BlobFile::ROOT_DIR, "post_file_thumbnails"), String)
THUMBNAIL_CONTENT_TYPES =
T.let(
[
%r{image/jpeg},
%r{image/jpg},
%r{image/png},
%r{image/gif},
%r{image/webp},
],
T::Array[Regexp],
)
sig { returns(T.nilable(String)) }
def absolute_file_path
return nil unless thumbnail_type = self.thumbnail_type
return nil unless post_file_id = self.post_file&.id
return nil unless sha256 = self.post_file&.blob_sha256
sha256_hex = HexUtil.bin2hex(sha256)
path_segments = [
THUMBNAIL_ROOT_DIR,
thumbnail_type,
*BlobFile.path_segments([2, 2, 1], sha256_hex),
]
path_segments[-1] = "#{path_segments[-1]}.jpeg"
path_segments.join("/")
end
sig do
params(
post_file: Domain::PostFile,
thumbnail_type: Domain::ThumbnailType,
).returns(T.nilable(Domain::PostFileThumbnail))
end
def self.find_or_create_from_post_file(post_file, thumbnail_type)
if t = find_by(post_file: post_file, thumbnail_type: thumbnail_type.name)
return t
end
return nil unless post_file.state_ok?
return nil unless log_entry = post_file.log_entry
unless THUMBNAIL_CONTENT_TYPES.any? { |regex|
regex.match?(log_entry.content_type)
}
return nil
end
file_path = post_file.blob&.absolute_file_path
return nil unless file_path
thumbnail =
Domain::PostFileThumbnail.new(
post_file: post_file,
thumbnail_type: thumbnail_type.name,
)
thumbnail_path = thumbnail.absolute_file_path.to_s
unless File.exist?(thumbnail_path)
FileUtils.mkdir_p(File.dirname(thumbnail_path))
tmp_file_path = File.join(TMP_DIR, "thumbnail-#{SecureRandom.uuid}.jpeg")
image_data =
Vips::Image.thumbnail(
file_path,
thumbnail_type.width,
height: thumbnail_type.height,
size: :force,
)
image_data.jpegsave(tmp_file_path, Q: thumbnail_type.quality, strip: true)
FileUtils.mv(tmp_file_path, thumbnail_path)
end
thumbnail.save!
thumbnail
end
end

View File

@@ -34,7 +34,7 @@ class Domain::ThumbnailType < T::Enum
when Large
512
when PHash
64
32
end
end

View File

@@ -1,14 +1,16 @@
class CreateDomainPostFileThumbnails < ActiveRecord::Migration[7.0]
def change
create_table :domain_post_file_thumbnails do |t|
create_table :domain_post_file_fingerprints do |t|
t.references :post_file,
null: false,
foreign_key: {
to_table: :domain_post_files,
},
index: true
t.string :thumbnail_type, null: false, index: true
t.bit :hash_value, limit: 256
t.timestamps
t.index :hash_value, using: :hnsw, opclass: :bit_hamming_ops
end
end
end

View File

@@ -1,17 +0,0 @@
class CreateDomainPerceptualHashes < ActiveRecord::Migration[7.0]
def change
create_table :domain_perceptual_hashes do |t|
t.references :thumbnail,
null: false,
foreign_key: {
to_table: :domain_post_file_thumbnails,
},
index: true
t.string :algorithm, null: false, index: true
t.vector :hash_value
t.timestamps
end
# TODO - figure out right index type for hash_value
end
end

View File

@@ -2697,56 +2697,23 @@ ALTER SEQUENCE public.domain_inkbunny_users_id_seq OWNED BY public.domain_inkbun
--
-- Name: domain_perceptual_hashes; Type: TABLE; Schema: public; Owner: -
-- Name: domain_post_file_fingerprints; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.domain_perceptual_hashes (
id bigint NOT NULL,
thumbnail_id bigint NOT NULL,
algorithm character varying NOT NULL,
hash_value public.vector,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL
);
--
-- Name: domain_perceptual_hashes_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.domain_perceptual_hashes_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: domain_perceptual_hashes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.domain_perceptual_hashes_id_seq OWNED BY public.domain_perceptual_hashes.id;
--
-- Name: domain_post_file_thumbnails; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.domain_post_file_thumbnails (
CREATE TABLE public.domain_post_file_fingerprints (
id bigint NOT NULL,
post_file_id bigint NOT NULL,
thumbnail_type character varying NOT NULL,
hash_value bit(256),
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL
);
--
-- Name: domain_post_file_thumbnails_id_seq; Type: SEQUENCE; Schema: public; Owner: -
-- Name: domain_post_file_fingerprints_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.domain_post_file_thumbnails_id_seq
CREATE SEQUENCE public.domain_post_file_fingerprints_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
@@ -2755,10 +2722,10 @@ CREATE SEQUENCE public.domain_post_file_thumbnails_id_seq
--
-- Name: domain_post_file_thumbnails_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
-- Name: domain_post_file_fingerprints_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.domain_post_file_thumbnails_id_seq OWNED BY public.domain_post_file_thumbnails.id;
ALTER SEQUENCE public.domain_post_file_fingerprints_id_seq OWNED BY public.domain_post_file_fingerprints.id;
SET default_tablespace = mirai;
@@ -4654,17 +4621,10 @@ ALTER TABLE ONLY public.domain_inkbunny_users ALTER COLUMN id SET DEFAULT nextva
--
-- Name: domain_perceptual_hashes id; Type: DEFAULT; Schema: public; Owner: -
-- Name: domain_post_file_fingerprints id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.domain_perceptual_hashes ALTER COLUMN id SET DEFAULT nextval('public.domain_perceptual_hashes_id_seq'::regclass);
--
-- Name: domain_post_file_thumbnails id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.domain_post_file_thumbnails ALTER COLUMN id SET DEFAULT nextval('public.domain_post_file_thumbnails_id_seq'::regclass);
ALTER TABLE ONLY public.domain_post_file_fingerprints ALTER COLUMN id SET DEFAULT nextval('public.domain_post_file_fingerprints_id_seq'::regclass);
--
@@ -5450,19 +5410,11 @@ ALTER TABLE ONLY public.domain_inkbunny_users
--
-- Name: domain_perceptual_hashes domain_perceptual_hashes_pkey; Type: CONSTRAINT; Schema: public; Owner: -
-- Name: domain_post_file_fingerprints domain_post_file_fingerprints_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.domain_perceptual_hashes
ADD CONSTRAINT domain_perceptual_hashes_pkey PRIMARY KEY (id);
--
-- Name: domain_post_file_thumbnails domain_post_file_thumbnails_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.domain_post_file_thumbnails
ADD CONSTRAINT domain_post_file_thumbnails_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.domain_post_file_fingerprints
ADD CONSTRAINT domain_post_file_fingerprints_pkey PRIMARY KEY (id);
SET default_tablespace = mirai;
@@ -7067,31 +7019,17 @@ CREATE INDEX index_domain_inkbunny_users_on_shallow_update_log_entry_id ON publi
--
-- Name: index_domain_perceptual_hashes_on_algorithm; Type: INDEX; Schema: public; Owner: -
-- Name: index_domain_post_file_fingerprints_on_hash_value; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_domain_perceptual_hashes_on_algorithm ON public.domain_perceptual_hashes USING btree (algorithm);
CREATE INDEX index_domain_post_file_fingerprints_on_hash_value ON public.domain_post_file_fingerprints USING hnsw (hash_value public.bit_hamming_ops);
--
-- Name: index_domain_perceptual_hashes_on_thumbnail_id; Type: INDEX; Schema: public; Owner: -
-- Name: index_domain_post_file_fingerprints_on_post_file_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_domain_perceptual_hashes_on_thumbnail_id ON public.domain_perceptual_hashes USING btree (thumbnail_id);
--
-- Name: index_domain_post_file_thumbnails_on_post_file_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_domain_post_file_thumbnails_on_post_file_id ON public.domain_post_file_thumbnails USING btree (post_file_id);
--
-- Name: index_domain_post_file_thumbnails_on_thumbnail_type; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_domain_post_file_thumbnails_on_thumbnail_type ON public.domain_post_file_thumbnails USING btree (thumbnail_type);
CREATE INDEX index_domain_post_file_fingerprints_on_post_file_id ON public.domain_post_file_fingerprints USING btree (post_file_id);
SET default_tablespace = mirai;
@@ -8557,14 +8495,6 @@ ALTER TABLE ONLY public.domain_fa_follows
ADD CONSTRAINT fk_rails_175679b7a2 FOREIGN KEY (followed_id) REFERENCES public.domain_fa_users(id);
--
-- Name: domain_perceptual_hashes fk_rails_1ae1a89060; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.domain_perceptual_hashes
ADD CONSTRAINT fk_rails_1ae1a89060 FOREIGN KEY (thumbnail_id) REFERENCES public.domain_post_file_thumbnails(id);
--
-- Name: domain_post_group_joins fk_rails_22154fb920; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -8597,6 +8527,14 @@ ALTER TABLE ONLY public.domain_fa_user_avatars
ADD CONSTRAINT fk_rails_2a03f31297 FOREIGN KEY (log_entry_id) REFERENCES public.http_log_entries(id);
--
-- Name: domain_post_file_fingerprints fk_rails_2f27fdde74; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.domain_post_file_fingerprints
ADD CONSTRAINT fk_rails_2f27fdde74 FOREIGN KEY (post_file_id) REFERENCES public.domain_post_files(id);
--
-- Name: domain_inkbunny_files fk_rails_31a33e433e; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -8853,14 +8791,6 @@ ALTER TABLE ONLY public.domain_e621_taggings
ADD CONSTRAINT fk_rails_da3a488297 FOREIGN KEY (post_id) REFERENCES public.domain_e621_posts(id);
--
-- Name: domain_post_file_thumbnails fk_rails_dde88b4af5; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.domain_post_file_thumbnails
ADD CONSTRAINT fk_rails_dde88b4af5 FOREIGN KEY (post_file_id) REFERENCES public.domain_post_files(id);
--
-- Name: domain_inkbunny_follows fk_rails_dffb743e89; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@@ -8925,7 +8855,6 @@ SET search_path TO "$user", public;
INSERT INTO "schema_migrations" (version) VALUES
('20250302074924'),
('20250301000002'),
('20250301000001'),
('20250226003653'),
('20250222035939'),

22
rake/fingerprint.rake Normal file
View File

@@ -0,0 +1,22 @@
namespace :fingerprint do
desc "Create missing fingerprints"
task create_missing: :environment do
# create thumbnails that do not exist
relation = Domain::PostFile.where.missing(:fingerprint).includes(:blob)
pb = ProgressBar.create(total: relation.count)
relation.find_each do |post_file|
post_file.create_fingerprint
pb.progress = [pb.progress + 1, pb.total].min
end
end
task for_ids: :environment do
ids = ENV["IDS"].split(",")
pb = ProgressBar.create(total: ids.size)
ids.each do |id|
model = DomainController.find_model_from_param(Domain::Post, id)
model.files.each { |file| file.create_fingerprint }
pb.progress = [pb.progress + 1, pb.total].min
end
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -468,6 +468,9 @@ class Domain::PostFile
sig { params(args: T.untyped, blk: T.untyped).returns(::BlobFile) }
def build_blob(*args, &blk); end
sig { params(args: T.untyped, blk: T.untyped).returns(::Domain::PostFileFingerprint) }
def build_fingerprint(*args, &blk); end
sig { params(args: T.untyped, blk: T.untyped).returns(::HttpLogEntry) }
def build_log_entry(*args, &blk); end
@@ -480,6 +483,12 @@ class Domain::PostFile
sig { params(args: T.untyped, blk: T.untyped).returns(::BlobFile) }
def create_blob!(*args, &blk); end
sig { params(args: T.untyped, blk: T.untyped).returns(::Domain::PostFileFingerprint) }
def create_fingerprint(*args, &blk); end
sig { params(args: T.untyped, blk: T.untyped).returns(::Domain::PostFileFingerprint) }
def create_fingerprint!(*args, &blk); end
sig { params(args: T.untyped, blk: T.untyped).returns(::HttpLogEntry) }
def create_log_entry(*args, &blk); end
@@ -492,6 +501,12 @@ class Domain::PostFile
sig { params(args: T.untyped, blk: T.untyped).returns(::Domain::Post) }
def create_post!(*args, &blk); end
sig { returns(T.nilable(::Domain::PostFileFingerprint)) }
def fingerprint; end
sig { params(value: T.nilable(::Domain::PostFileFingerprint)).void }
def fingerprint=(value); end
sig { returns(T.nilable(::HttpLogEntry)) }
def log_entry; end
@@ -519,6 +534,9 @@ class Domain::PostFile
sig { returns(T.nilable(::BlobFile)) }
def reload_blob; end
sig { returns(T.nilable(::Domain::PostFileFingerprint)) }
def reload_fingerprint; end
sig { returns(T.nilable(::HttpLogEntry)) }
def reload_log_entry; end
@@ -528,25 +546,14 @@ class Domain::PostFile
sig { void }
def reset_blob; end
sig { void }
def reset_fingerprint; end
sig { void }
def reset_log_entry; end
sig { void }
def reset_post; end
sig { returns(T::Array[T.untyped]) }
def thumbnail_ids; end
sig { params(ids: T::Array[T.untyped]).returns(T::Array[T.untyped]) }
def thumbnail_ids=(ids); end
# This method is created by ActiveRecord on the `Domain::PostFile` class because it declared `has_many :thumbnails`.
# 🔗 [Rails guide for `has_many` association](https://guides.rubyonrails.org/association_basics.html#the-has-many-association)
sig { returns(::Domain::PostFileThumbnail::PrivateCollectionProxy) }
def thumbnails; end
sig { params(value: T::Enumerable[::Domain::PostFileThumbnail]).void }
def thumbnails=(value); end
end
module GeneratedAssociationRelationMethods

View File

@@ -463,6 +463,9 @@ class Domain::PostFile::InkbunnyPostFile
sig { params(args: T.untyped, blk: T.untyped).returns(::BlobFile) }
def build_blob(*args, &blk); end
sig { params(args: T.untyped, blk: T.untyped).returns(::Domain::PostFileFingerprint) }
def build_fingerprint(*args, &blk); end
sig { params(args: T.untyped, blk: T.untyped).returns(::HttpLogEntry) }
def build_log_entry(*args, &blk); end
@@ -475,6 +478,12 @@ class Domain::PostFile::InkbunnyPostFile
sig { params(args: T.untyped, blk: T.untyped).returns(::BlobFile) }
def create_blob!(*args, &blk); end
sig { params(args: T.untyped, blk: T.untyped).returns(::Domain::PostFileFingerprint) }
def create_fingerprint(*args, &blk); end
sig { params(args: T.untyped, blk: T.untyped).returns(::Domain::PostFileFingerprint) }
def create_fingerprint!(*args, &blk); end
sig { params(args: T.untyped, blk: T.untyped).returns(::HttpLogEntry) }
def create_log_entry(*args, &blk); end
@@ -487,6 +496,12 @@ class Domain::PostFile::InkbunnyPostFile
sig { params(args: T.untyped, blk: T.untyped).returns(::Domain::Post) }
def create_post!(*args, &blk); end
sig { returns(T.nilable(::Domain::PostFileFingerprint)) }
def fingerprint; end
sig { params(value: T.nilable(::Domain::PostFileFingerprint)).void }
def fingerprint=(value); end
sig { returns(T.nilable(::HttpLogEntry)) }
def log_entry; end
@@ -502,6 +517,9 @@ class Domain::PostFile::InkbunnyPostFile
sig { returns(T.nilable(::BlobFile)) }
def reload_blob; end
sig { returns(T.nilable(::Domain::PostFileFingerprint)) }
def reload_fingerprint; end
sig { returns(T.nilable(::HttpLogEntry)) }
def reload_log_entry; end
@@ -511,25 +529,14 @@ class Domain::PostFile::InkbunnyPostFile
sig { void }
def reset_blob; end
sig { void }
def reset_fingerprint; end
sig { void }
def reset_log_entry; end
sig { void }
def reset_post; end
sig { returns(T::Array[T.untyped]) }
def thumbnail_ids; end
sig { params(ids: T::Array[T.untyped]).returns(T::Array[T.untyped]) }
def thumbnail_ids=(ids); end
# This method is created by ActiveRecord on the `Domain::PostFile` class because it declared `has_many :thumbnails`.
# 🔗 [Rails guide for `has_many` association](https://guides.rubyonrails.org/association_basics.html#the-has-many-association)
sig { returns(::Domain::PostFileThumbnail::PrivateCollectionProxy) }
def thumbnails; end
sig { params(value: T::Enumerable[::Domain::PostFileThumbnail]).void }
def thumbnails=(value); end
end
module GeneratedAssociationRelationMethods

View File

@@ -1,11 +1,11 @@
# typed: true
# DO NOT EDIT MANUALLY
# This is an autogenerated file for dynamic methods in `Domain::PostFileThumbnail`.
# Please instead update this file by running `bin/tapioca dsl Domain::PostFileThumbnail`.
# This is an autogenerated file for dynamic methods in `Domain::PostFileFingerprint`.
# Please instead update this file by running `bin/tapioca dsl Domain::PostFileFingerprint`.
class Domain::PostFileThumbnail
class Domain::PostFileFingerprint
include GeneratedAssociationMethods
include GeneratedAttributeMethods
extend CommonRelationMethods
@@ -47,8 +47,8 @@ class Domain::PostFileThumbnail
sig do
params(
attributes: T.untyped,
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(::Domain::PostFileThumbnail)
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(::Domain::PostFileFingerprint)
end
def new(attributes = nil, &block); end
end
@@ -56,7 +56,7 @@ class Domain::PostFileThumbnail
module CommonRelationMethods
sig do
params(
block: T.nilable(T.proc.params(record: ::Domain::PostFileThumbnail).returns(T.untyped))
block: T.nilable(T.proc.params(record: ::Domain::PostFileFingerprint).returns(T.untyped))
).returns(T::Boolean)
end
def any?(&block); end
@@ -66,20 +66,20 @@ class Domain::PostFileThumbnail
sig do
params(
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(::Domain::PostFileThumbnail)
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(::Domain::PostFileFingerprint)
end
sig do
params(
attributes: T::Array[T.untyped],
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(T::Array[::Domain::PostFileThumbnail])
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(T::Array[::Domain::PostFileFingerprint])
end
sig do
params(
attributes: T.untyped,
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(::Domain::PostFileThumbnail)
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(::Domain::PostFileFingerprint)
end
def build(attributes = nil, &block); end
@@ -90,111 +90,111 @@ class Domain::PostFileThumbnail
sig do
params(
column_name: NilClass,
block: T.proc.params(object: ::Domain::PostFileThumbnail).void
block: T.proc.params(object: ::Domain::PostFileFingerprint).void
).returns(Integer)
end
def count(column_name = nil, &block); end
sig do
params(
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(::Domain::PostFileThumbnail)
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(::Domain::PostFileFingerprint)
end
sig do
params(
attributes: T::Array[T.untyped],
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(T::Array[::Domain::PostFileThumbnail])
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(T::Array[::Domain::PostFileFingerprint])
end
sig do
params(
attributes: T.untyped,
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(::Domain::PostFileThumbnail)
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(::Domain::PostFileFingerprint)
end
def create(attributes = nil, &block); end
sig do
params(
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(::Domain::PostFileThumbnail)
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(::Domain::PostFileFingerprint)
end
sig do
params(
attributes: T::Array[T.untyped],
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(T::Array[::Domain::PostFileThumbnail])
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(T::Array[::Domain::PostFileFingerprint])
end
sig do
params(
attributes: T.untyped,
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(::Domain::PostFileThumbnail)
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(::Domain::PostFileFingerprint)
end
def create!(attributes = nil, &block); end
sig do
params(
attributes: T::Array[T.untyped],
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(T::Array[::Domain::PostFileThumbnail])
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(T::Array[::Domain::PostFileFingerprint])
end
sig do
params(
attributes: T.untyped,
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(::Domain::PostFileThumbnail)
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(::Domain::PostFileFingerprint)
end
def create_or_find_by(attributes, &block); end
sig do
params(
attributes: T::Array[T.untyped],
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(T::Array[::Domain::PostFileThumbnail])
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(T::Array[::Domain::PostFileFingerprint])
end
sig do
params(
attributes: T.untyped,
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(::Domain::PostFileThumbnail)
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(::Domain::PostFileFingerprint)
end
def create_or_find_by!(attributes, &block); end
sig { returns(T::Array[::Domain::PostFileThumbnail]) }
sig { returns(T::Array[::Domain::PostFileFingerprint]) }
def destroy_all; end
sig { params(conditions: T.untyped).returns(T::Boolean) }
def exists?(conditions = :none); end
sig { returns(T.nilable(::Domain::PostFileThumbnail)) }
sig { returns(T.nilable(::Domain::PostFileFingerprint)) }
def fifth; end
sig { returns(::Domain::PostFileThumbnail) }
sig { returns(::Domain::PostFileFingerprint) }
def fifth!; end
sig do
params(
args: T.any(String, Symbol, ::ActiveSupport::Multibyte::Chars, T::Boolean, BigDecimal, Numeric, ::ActiveRecord::Type::Binary::Data, ::ActiveRecord::Type::Time::Value, Date, Time, ::ActiveSupport::Duration, T::Class[T.anything])
).returns(::Domain::PostFileThumbnail)
).returns(::Domain::PostFileFingerprint)
end
sig do
params(
args: T::Array[T.any(String, Symbol, ::ActiveSupport::Multibyte::Chars, T::Boolean, BigDecimal, Numeric, ::ActiveRecord::Type::Binary::Data, ::ActiveRecord::Type::Time::Value, Date, Time, ::ActiveSupport::Duration, T::Class[T.anything])]
).returns(T::Enumerable[::Domain::PostFileThumbnail])
).returns(T::Enumerable[::Domain::PostFileFingerprint])
end
sig do
params(
args: NilClass,
block: T.proc.params(object: ::Domain::PostFileThumbnail).void
).returns(T.nilable(::Domain::PostFileThumbnail))
block: T.proc.params(object: ::Domain::PostFileFingerprint).void
).returns(T.nilable(::Domain::PostFileFingerprint))
end
def find(args = nil, &block); end
sig { params(args: T.untyped).returns(T.nilable(::Domain::PostFileThumbnail)) }
sig { params(args: T.untyped).returns(T.nilable(::Domain::PostFileFingerprint)) }
def find_by(*args); end
sig { params(args: T.untyped).returns(::Domain::PostFileThumbnail) }
sig { params(args: T.untyped).returns(::Domain::PostFileFingerprint) }
def find_by!(*args); end
sig do
@@ -204,7 +204,7 @@ class Domain::PostFileThumbnail
batch_size: Integer,
error_on_ignore: T.untyped,
order: Symbol,
block: T.proc.params(object: ::Domain::PostFileThumbnail).void
block: T.proc.params(object: ::Domain::PostFileFingerprint).void
).void
end
sig do
@@ -214,7 +214,7 @@ class Domain::PostFileThumbnail
batch_size: Integer,
error_on_ignore: T.untyped,
order: Symbol
).returns(T::Enumerator[::Domain::PostFileThumbnail])
).returns(T::Enumerator[::Domain::PostFileFingerprint])
end
def find_each(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc, &block); end
@@ -225,7 +225,7 @@ class Domain::PostFileThumbnail
batch_size: Integer,
error_on_ignore: T.untyped,
order: Symbol,
block: T.proc.params(object: T::Array[::Domain::PostFileThumbnail]).void
block: T.proc.params(object: T::Array[::Domain::PostFileFingerprint]).void
).void
end
sig do
@@ -235,78 +235,78 @@ class Domain::PostFileThumbnail
batch_size: Integer,
error_on_ignore: T.untyped,
order: Symbol
).returns(T::Enumerator[T::Enumerator[::Domain::PostFileThumbnail]])
).returns(T::Enumerator[T::Enumerator[::Domain::PostFileFingerprint]])
end
def find_in_batches(start: nil, finish: nil, batch_size: 1000, error_on_ignore: nil, order: :asc, &block); end
sig do
params(
attributes: T::Array[T.untyped],
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(T::Array[::Domain::PostFileThumbnail])
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(T::Array[::Domain::PostFileFingerprint])
end
sig do
params(
attributes: T.untyped,
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(::Domain::PostFileThumbnail)
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(::Domain::PostFileFingerprint)
end
def find_or_create_by(attributes, &block); end
sig do
params(
attributes: T::Array[T.untyped],
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(T::Array[::Domain::PostFileThumbnail])
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(T::Array[::Domain::PostFileFingerprint])
end
sig do
params(
attributes: T.untyped,
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(::Domain::PostFileThumbnail)
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(::Domain::PostFileFingerprint)
end
def find_or_create_by!(attributes, &block); end
sig do
params(
attributes: T::Array[T.untyped],
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(T::Array[::Domain::PostFileThumbnail])
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(T::Array[::Domain::PostFileFingerprint])
end
sig do
params(
attributes: T.untyped,
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(::Domain::PostFileThumbnail)
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(::Domain::PostFileFingerprint)
end
def find_or_initialize_by(attributes, &block); end
sig { params(signed_id: T.untyped, purpose: T.untyped).returns(T.nilable(::Domain::PostFileThumbnail)) }
sig { params(signed_id: T.untyped, purpose: T.untyped).returns(T.nilable(::Domain::PostFileFingerprint)) }
def find_signed(signed_id, purpose: nil); end
sig { params(signed_id: T.untyped, purpose: T.untyped).returns(::Domain::PostFileThumbnail) }
sig { params(signed_id: T.untyped, purpose: T.untyped).returns(::Domain::PostFileFingerprint) }
def find_signed!(signed_id, purpose: nil); end
sig { params(arg: T.untyped, args: T.untyped).returns(::Domain::PostFileThumbnail) }
sig { params(arg: T.untyped, args: T.untyped).returns(::Domain::PostFileFingerprint) }
def find_sole_by(arg, *args); end
sig { returns(T.nilable(::Domain::PostFileThumbnail)) }
sig { params(limit: Integer).returns(T::Array[::Domain::PostFileThumbnail]) }
sig { returns(T.nilable(::Domain::PostFileFingerprint)) }
sig { params(limit: Integer).returns(T::Array[::Domain::PostFileFingerprint]) }
def first(limit = nil); end
sig { returns(::Domain::PostFileThumbnail) }
sig { returns(::Domain::PostFileFingerprint) }
def first!; end
sig { returns(T.nilable(::Domain::PostFileThumbnail)) }
sig { returns(T.nilable(::Domain::PostFileFingerprint)) }
def forty_two; end
sig { returns(::Domain::PostFileThumbnail) }
sig { returns(::Domain::PostFileFingerprint) }
def forty_two!; end
sig { returns(T.nilable(::Domain::PostFileThumbnail)) }
sig { returns(T.nilable(::Domain::PostFileFingerprint)) }
def fourth; end
sig { returns(::Domain::PostFileThumbnail) }
sig { returns(::Domain::PostFileFingerprint) }
def fourth!; end
sig { returns(Array) }
@@ -340,16 +340,16 @@ class Domain::PostFileThumbnail
sig { params(record: T.untyped).returns(T::Boolean) }
def include?(record); end
sig { returns(T.nilable(::Domain::PostFileThumbnail)) }
sig { params(limit: Integer).returns(T::Array[::Domain::PostFileThumbnail]) }
sig { returns(T.nilable(::Domain::PostFileFingerprint)) }
sig { params(limit: Integer).returns(T::Array[::Domain::PostFileFingerprint]) }
def last(limit = nil); end
sig { returns(::Domain::PostFileThumbnail) }
sig { returns(::Domain::PostFileFingerprint) }
def last!; end
sig do
params(
block: T.nilable(T.proc.params(record: ::Domain::PostFileThumbnail).returns(T.untyped))
block: T.nilable(T.proc.params(record: ::Domain::PostFileFingerprint).returns(T.untyped))
).returns(T::Boolean)
end
def many?(&block); end
@@ -365,33 +365,33 @@ class Domain::PostFileThumbnail
sig do
params(
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(::Domain::PostFileThumbnail)
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(::Domain::PostFileFingerprint)
end
sig do
params(
attributes: T::Array[T.untyped],
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(T::Array[::Domain::PostFileThumbnail])
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(T::Array[::Domain::PostFileFingerprint])
end
sig do
params(
attributes: T.untyped,
block: T.nilable(T.proc.params(object: ::Domain::PostFileThumbnail).void)
).returns(::Domain::PostFileThumbnail)
block: T.nilable(T.proc.params(object: ::Domain::PostFileFingerprint).void)
).returns(::Domain::PostFileFingerprint)
end
def new(attributes = nil, &block); end
sig do
params(
block: T.nilable(T.proc.params(record: ::Domain::PostFileThumbnail).returns(T.untyped))
block: T.nilable(T.proc.params(record: ::Domain::PostFileFingerprint).returns(T.untyped))
).returns(T::Boolean)
end
def none?(&block); end
sig do
params(
block: T.nilable(T.proc.params(record: ::Domain::PostFileThumbnail).returns(T.untyped))
block: T.nilable(T.proc.params(record: ::Domain::PostFileFingerprint).returns(T.untyped))
).returns(T::Boolean)
end
def one?(&block); end
@@ -402,19 +402,19 @@ class Domain::PostFileThumbnail
sig { params(column_names: T.untyped).returns(T.untyped) }
def pluck(*column_names); end
sig { returns(T.nilable(::Domain::PostFileThumbnail)) }
sig { returns(T.nilable(::Domain::PostFileFingerprint)) }
def second; end
sig { returns(::Domain::PostFileThumbnail) }
sig { returns(::Domain::PostFileFingerprint) }
def second!; end
sig { returns(T.nilable(::Domain::PostFileThumbnail)) }
sig { returns(T.nilable(::Domain::PostFileFingerprint)) }
def second_to_last; end
sig { returns(::Domain::PostFileThumbnail) }
sig { returns(::Domain::PostFileFingerprint) }
def second_to_last!; end
sig { returns(::Domain::PostFileThumbnail) }
sig { returns(::Domain::PostFileFingerprint) }
def sole; end
sig { params(initial_value_or_column: T.untyped).returns(T.any(Integer, Float, BigDecimal)) }
@@ -422,28 +422,28 @@ class Domain::PostFileThumbnail
type_parameters(:U)
.params(
initial_value_or_column: T.nilable(T.type_parameter(:U)),
block: T.proc.params(object: ::Domain::PostFileThumbnail).returns(T.type_parameter(:U))
block: T.proc.params(object: ::Domain::PostFileFingerprint).returns(T.type_parameter(:U))
).returns(T.type_parameter(:U))
end
def sum(initial_value_or_column = nil, &block); end
sig { returns(T.nilable(::Domain::PostFileThumbnail)) }
sig { params(limit: Integer).returns(T::Array[::Domain::PostFileThumbnail]) }
sig { returns(T.nilable(::Domain::PostFileFingerprint)) }
sig { params(limit: Integer).returns(T::Array[::Domain::PostFileFingerprint]) }
def take(limit = nil); end
sig { returns(::Domain::PostFileThumbnail) }
sig { returns(::Domain::PostFileFingerprint) }
def take!; end
sig { returns(T.nilable(::Domain::PostFileThumbnail)) }
sig { returns(T.nilable(::Domain::PostFileFingerprint)) }
def third; end
sig { returns(::Domain::PostFileThumbnail) }
sig { returns(::Domain::PostFileFingerprint) }
def third!; end
sig { returns(T.nilable(::Domain::PostFileThumbnail)) }
sig { returns(T.nilable(::Domain::PostFileFingerprint)) }
def third_to_last; end
sig { returns(::Domain::PostFileThumbnail) }
sig { returns(::Domain::PostFileFingerprint) }
def third_to_last!; end
end
@@ -457,20 +457,6 @@ class Domain::PostFileThumbnail
sig { params(args: T.untyped, blk: T.untyped).returns(::Domain::PostFile) }
def create_post_file!(*args, &blk); end
sig { returns(T::Array[T.untyped]) }
def perceptual_hash_ids; end
sig { params(ids: T::Array[T.untyped]).returns(T::Array[T.untyped]) }
def perceptual_hash_ids=(ids); end
# This method is created by ActiveRecord on the `Domain::PostFileThumbnail` class because it declared `has_many :perceptual_hashes`.
# 🔗 [Rails guide for `has_many` association](https://guides.rubyonrails.org/association_basics.html#the-has-many-association)
sig { returns(::Domain::PerceptualHash::PrivateCollectionProxy) }
def perceptual_hashes; end
sig { params(value: T::Enumerable[::Domain::PerceptualHash]).void }
def perceptual_hashes=(value); end
sig { returns(T.nilable(::Domain::PostFile)) }
def post_file; end
@@ -709,6 +695,51 @@ class Domain::PostFileThumbnail
sig { void }
def created_at_will_change!; end
sig { returns(T.nilable(::String)) }
def hash_value; end
sig { params(value: T.nilable(::String)).returns(T.nilable(::String)) }
def hash_value=(value); end
sig { returns(T::Boolean) }
def hash_value?; end
sig { returns(T.nilable(::String)) }
def hash_value_before_last_save; end
sig { returns(T.untyped) }
def hash_value_before_type_cast; end
sig { returns(T::Boolean) }
def hash_value_came_from_user?; end
sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) }
def hash_value_change; end
sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) }
def hash_value_change_to_be_saved; end
sig { params(from: T.nilable(::String), to: T.nilable(::String)).returns(T::Boolean) }
def hash_value_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::String)) }
def hash_value_in_database; end
sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) }
def hash_value_previous_change; end
sig { params(from: T.nilable(::String), to: T.nilable(::String)).returns(T::Boolean) }
def hash_value_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::String)) }
def hash_value_previously_was; end
sig { returns(T.nilable(::String)) }
def hash_value_was; end
sig { void }
def hash_value_will_change!; end
sig { returns(T.nilable(::Integer)) }
def id; end
@@ -847,6 +878,9 @@ class Domain::PostFileThumbnail
sig { void }
def restore_created_at!; end
sig { void }
def restore_hash_value!; end
sig { void }
def restore_id!; end
@@ -856,9 +890,6 @@ class Domain::PostFileThumbnail
sig { void }
def restore_post_file_id!; end
sig { void }
def restore_thumbnail_type!; end
sig { void }
def restore_updated_at!; end
@@ -868,6 +899,12 @@ class Domain::PostFileThumbnail
sig { returns(T::Boolean) }
def saved_change_to_created_at?; end
sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) }
def saved_change_to_hash_value; end
sig { returns(T::Boolean) }
def saved_change_to_hash_value?; end
sig { returns(T.nilable([T.nilable(::Integer), T.nilable(::Integer)])) }
def saved_change_to_id; end
@@ -886,63 +923,12 @@ class Domain::PostFileThumbnail
sig { returns(T::Boolean) }
def saved_change_to_post_file_id?; end
sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) }
def saved_change_to_thumbnail_type; end
sig { returns(T::Boolean) }
def saved_change_to_thumbnail_type?; end
sig { returns(T.nilable([T.nilable(::ActiveSupport::TimeWithZone), T.nilable(::ActiveSupport::TimeWithZone)])) }
def saved_change_to_updated_at; end
sig { returns(T::Boolean) }
def saved_change_to_updated_at?; end
sig { returns(T.nilable(::String)) }
def thumbnail_type; end
sig { params(value: T.nilable(::String)).returns(T.nilable(::String)) }
def thumbnail_type=(value); end
sig { returns(T::Boolean) }
def thumbnail_type?; end
sig { returns(T.nilable(::String)) }
def thumbnail_type_before_last_save; end
sig { returns(T.untyped) }
def thumbnail_type_before_type_cast; end
sig { returns(T::Boolean) }
def thumbnail_type_came_from_user?; end
sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) }
def thumbnail_type_change; end
sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) }
def thumbnail_type_change_to_be_saved; end
sig { params(from: T.nilable(::String), to: T.nilable(::String)).returns(T::Boolean) }
def thumbnail_type_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::String)) }
def thumbnail_type_in_database; end
sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) }
def thumbnail_type_previous_change; end
sig { params(from: T.nilable(::String), to: T.nilable(::String)).returns(T::Boolean) }
def thumbnail_type_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
sig { returns(T.nilable(::String)) }
def thumbnail_type_previously_was; end
sig { returns(T.nilable(::String)) }
def thumbnail_type_was; end
sig { void }
def thumbnail_type_will_change!; end
sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) }
def updated_at; end
@@ -1001,6 +987,9 @@ class Domain::PostFileThumbnail
sig { returns(T::Boolean) }
def will_save_change_to_created_at?; end
sig { returns(T::Boolean) }
def will_save_change_to_hash_value?; end
sig { returns(T::Boolean) }
def will_save_change_to_id?; end
@@ -1010,9 +999,6 @@ class Domain::PostFileThumbnail
sig { returns(T::Boolean) }
def will_save_change_to_post_file_id?; end
sig { returns(T::Boolean) }
def will_save_change_to_thumbnail_type?; end
sig { returns(T::Boolean) }
def will_save_change_to_updated_at?; end
end
@@ -1182,17 +1168,17 @@ class Domain::PostFileThumbnail
include CommonRelationMethods
include GeneratedAssociationRelationMethods
Elem = type_member { { fixed: ::Domain::PostFileThumbnail } }
Elem = type_member { { fixed: ::Domain::PostFileFingerprint } }
sig { returns(T::Array[::Domain::PostFileThumbnail]) }
sig { returns(T::Array[::Domain::PostFileFingerprint]) }
def to_a; end
sig { returns(T::Array[::Domain::PostFileThumbnail]) }
sig { returns(T::Array[::Domain::PostFileFingerprint]) }
def to_ary; end
end
class PrivateAssociationRelationGroupChain < PrivateAssociationRelation
Elem = type_member { { fixed: ::Domain::PostFileThumbnail } }
Elem = type_member { { fixed: ::Domain::PostFileFingerprint } }
sig { params(column_name: T.any(String, Symbol)).returns(T::Hash[T.untyped, T.any(Integer, Float, BigDecimal)]) }
def average(column_name); end
@@ -1227,7 +1213,7 @@ class Domain::PostFileThumbnail
end
class PrivateAssociationRelationWhereChain
Elem = type_member { { fixed: ::Domain::PostFileThumbnail } }
Elem = type_member { { fixed: ::Domain::PostFileFingerprint } }
sig { params(args: T.untyped).returns(PrivateAssociationRelation) }
def associated(*args); end
@@ -1243,18 +1229,18 @@ class Domain::PostFileThumbnail
include CommonRelationMethods
include GeneratedAssociationRelationMethods
Elem = type_member { { fixed: ::Domain::PostFileThumbnail } }
Elem = type_member { { fixed: ::Domain::PostFileFingerprint } }
sig do
params(
records: T.any(::Domain::PostFileThumbnail, T::Enumerable[T.any(::Domain::PostFileThumbnail, T::Enumerable[::Domain::PostFileThumbnail])])
records: T.any(::Domain::PostFileFingerprint, T::Enumerable[T.any(::Domain::PostFileFingerprint, T::Enumerable[::Domain::PostFileFingerprint])])
).returns(PrivateCollectionProxy)
end
def <<(*records); end
sig do
params(
records: T.any(::Domain::PostFileThumbnail, T::Enumerable[T.any(::Domain::PostFileThumbnail, T::Enumerable[::Domain::PostFileThumbnail])])
records: T.any(::Domain::PostFileFingerprint, T::Enumerable[T.any(::Domain::PostFileFingerprint, T::Enumerable[::Domain::PostFileFingerprint])])
).returns(PrivateCollectionProxy)
end
def append(*records); end
@@ -1264,45 +1250,45 @@ class Domain::PostFileThumbnail
sig do
params(
records: T.any(::Domain::PostFileThumbnail, T::Enumerable[T.any(::Domain::PostFileThumbnail, T::Enumerable[::Domain::PostFileThumbnail])])
records: T.any(::Domain::PostFileFingerprint, T::Enumerable[T.any(::Domain::PostFileFingerprint, T::Enumerable[::Domain::PostFileFingerprint])])
).returns(PrivateCollectionProxy)
end
def concat(*records); end
sig { returns(T::Array[::Domain::PostFileThumbnail]) }
sig { returns(T::Array[::Domain::PostFileFingerprint]) }
def load_target; end
sig do
params(
records: T.any(::Domain::PostFileThumbnail, T::Enumerable[T.any(::Domain::PostFileThumbnail, T::Enumerable[::Domain::PostFileThumbnail])])
records: T.any(::Domain::PostFileFingerprint, T::Enumerable[T.any(::Domain::PostFileFingerprint, T::Enumerable[::Domain::PostFileFingerprint])])
).returns(PrivateCollectionProxy)
end
def prepend(*records); end
sig do
params(
records: T.any(::Domain::PostFileThumbnail, T::Enumerable[T.any(::Domain::PostFileThumbnail, T::Enumerable[::Domain::PostFileThumbnail])])
records: T.any(::Domain::PostFileFingerprint, T::Enumerable[T.any(::Domain::PostFileFingerprint, T::Enumerable[::Domain::PostFileFingerprint])])
).returns(PrivateCollectionProxy)
end
def push(*records); end
sig do
params(
other_array: T.any(::Domain::PostFileThumbnail, T::Enumerable[T.any(::Domain::PostFileThumbnail, T::Enumerable[::Domain::PostFileThumbnail])])
).returns(T::Array[::Domain::PostFileThumbnail])
other_array: T.any(::Domain::PostFileFingerprint, T::Enumerable[T.any(::Domain::PostFileFingerprint, T::Enumerable[::Domain::PostFileFingerprint])])
).returns(T::Array[::Domain::PostFileFingerprint])
end
def replace(other_array); end
sig { returns(PrivateAssociationRelation) }
def scope; end
sig { returns(T::Array[::Domain::PostFileThumbnail]) }
sig { returns(T::Array[::Domain::PostFileFingerprint]) }
def target; end
sig { returns(T::Array[::Domain::PostFileThumbnail]) }
sig { returns(T::Array[::Domain::PostFileFingerprint]) }
def to_a; end
sig { returns(T::Array[::Domain::PostFileThumbnail]) }
sig { returns(T::Array[::Domain::PostFileFingerprint]) }
def to_ary; end
end
@@ -1310,17 +1296,17 @@ class Domain::PostFileThumbnail
include CommonRelationMethods
include GeneratedRelationMethods
Elem = type_member { { fixed: ::Domain::PostFileThumbnail } }
Elem = type_member { { fixed: ::Domain::PostFileFingerprint } }
sig { returns(T::Array[::Domain::PostFileThumbnail]) }
sig { returns(T::Array[::Domain::PostFileFingerprint]) }
def to_a; end
sig { returns(T::Array[::Domain::PostFileThumbnail]) }
sig { returns(T::Array[::Domain::PostFileFingerprint]) }
def to_ary; end
end
class PrivateRelationGroupChain < PrivateRelation
Elem = type_member { { fixed: ::Domain::PostFileThumbnail } }
Elem = type_member { { fixed: ::Domain::PostFileFingerprint } }
sig { params(column_name: T.any(String, Symbol)).returns(T::Hash[T.untyped, T.any(Integer, Float, BigDecimal)]) }
def average(column_name); end
@@ -1355,7 +1341,7 @@ class Domain::PostFileThumbnail
end
class PrivateRelationWhereChain
Elem = type_member { { fixed: ::Domain::PostFileThumbnail } }
Elem = type_member { { fixed: ::Domain::PostFileFingerprint } }
sig { params(args: T.untyped).returns(PrivateRelation) }
def associated(*args); end

126
sorbet/rbi/gems/cloudflare-rails@6.2.0.rbi generated Normal file
View File

@@ -0,0 +1,126 @@
# typed: true
# DO NOT EDIT MANUALLY
# This is an autogenerated file for types exported from the `cloudflare-rails` gem.
# Please instead update this file by running `bin/tapioca gem cloudflare-rails`.
# source://cloudflare-rails//lib/cloudflare_rails.rb#8
module CloudflareRails; end
# patch rack::request::helpers to use our cloudflare ips - this way request.ip is
# correct inside of rack and rails
#
# source://cloudflare-rails//lib/cloudflare_rails/check_trusted_proxies.rb#6
module CloudflareRails::CheckTrustedProxies
# @return [Boolean]
#
# source://cloudflare-rails//lib/cloudflare_rails/check_trusted_proxies.rb#18
def cloudflare?; end
# @return [Boolean]
#
# source://cloudflare-rails//lib/cloudflare_rails/check_trusted_proxies.rb#7
def cloudflare_ip?(ip); end
# @return [Boolean]
#
# source://cloudflare-rails//lib/cloudflare_rails/check_trusted_proxies.rb#14
def trusted_proxy?(ip); end
end
# source://cloudflare-rails//lib/cloudflare_rails/fallback_ips.rb#4
module CloudflareRails::FallbackIps; end
# convert our body into a list of IpAddrs
#
# source://cloudflare-rails//lib/cloudflare_rails/fallback_ips.rb#25
CloudflareRails::FallbackIps::IPS_V4 = T.let(T.unsafe(nil), Array)
# fetched from https://www.cloudflare.com/ips-v4/ on 2023-12-10
#
# source://cloudflare-rails//lib/cloudflare_rails/fallback_ips.rb#6
CloudflareRails::FallbackIps::IPS_V4_BODY = T.let(T.unsafe(nil), String)
# convert our body into a list of IpAddrs
#
# source://cloudflare-rails//lib/cloudflare_rails/fallback_ips.rb#39
CloudflareRails::FallbackIps::IPS_V6 = T.let(T.unsafe(nil), Array)
# from https://www.cloudflare.com/ips-v6/ on 2023-12-10
#
# source://cloudflare-rails//lib/cloudflare_rails/fallback_ips.rb#28
CloudflareRails::FallbackIps::IPS_V6_BODY = T.let(T.unsafe(nil), String)
# source://cloudflare-rails//lib/cloudflare_rails/importer.rb#7
class CloudflareRails::Importer
class << self
# source://cloudflare-rails//lib/cloudflare_rails/importer.rb#60
def cloudflare_ips(refresh: T.unsafe(nil)); end
# @raise [ResponseError]
#
# source://cloudflare-rails//lib/cloudflare_rails/importer.rb#37
def fetch(url); end
# source://cloudflare-rails//lib/cloudflare_rails/importer.rb#54
def fetch_with_cache(type); end
# source://cloudflare-rails//lib/cloudflare_rails/importer.rb#33
def ips_v4; end
# source://cloudflare-rails//lib/cloudflare_rails/importer.rb#29
def ips_v6; end
end
end
# source://cloudflare-rails//lib/cloudflare_rails/importer.rb#24
CloudflareRails::Importer::BASE_URL = T.let(T.unsafe(nil), String)
# source://cloudflare-rails//lib/cloudflare_rails/importer.rb#25
CloudflareRails::Importer::IPS_V4_URL = T.let(T.unsafe(nil), String)
# source://cloudflare-rails//lib/cloudflare_rails/importer.rb#26
CloudflareRails::Importer::IPS_V6_URL = T.let(T.unsafe(nil), String)
# Exceptions contain the Net::HTTP
# response object accessible via the {#response} method.
#
# source://cloudflare-rails//lib/cloudflare_rails/importer.rb#10
class CloudflareRails::Importer::ResponseError < ::StandardError
# Instantiate an instance of ResponseError with a Net::HTTPResponse object
#
# @param [Net::HTTPResponse]
# @return [ResponseError] a new instance of ResponseError
#
# source://cloudflare-rails//lib/cloudflare_rails/importer.rb#18
def initialize(response); end
# Returns the response of the last request
# Net::HTTPOK
#
# @return [Net::HTTPResponse] A subclass of Net::HTTPResponse, e.g.
#
# source://cloudflare-rails//lib/cloudflare_rails/importer.rb#14
def response; end
end
# source://cloudflare-rails//lib/cloudflare_rails/railtie.rb#6
class CloudflareRails::Railtie < ::Rails::Railtie; end
# setup defaults before we configure our app.
#
# source://cloudflare-rails//lib/cloudflare_rails/railtie.rb#8
CloudflareRails::Railtie::DEFAULTS = T.let(T.unsafe(nil), Hash)
# patch ActionDispatch::RemoteIP to use our cloudflare ips - this way
# request.remote_ip is correct inside of rails
#
# source://cloudflare-rails//lib/cloudflare_rails/remote_ip_proxies.rb#6
module CloudflareRails::RemoteIpProxies
# source://cloudflare-rails//lib/cloudflare_rails/remote_ip_proxies.rb#7
def proxies; end
end
# source://cloudflare-rails//lib/cloudflare_rails/version.rb#4
CloudflareRails::VERSION = T.let(T.unsafe(nil), String)

50
sorbet/rbi/gems/dhash-vips@0.2.3.0.rbi generated Normal file
View File

@@ -0,0 +1,50 @@
# typed: true
# DO NOT EDIT MANUALLY
# This is an autogenerated file for types exported from the `dhash-vips` gem.
# Please instead update this file by running `bin/tapioca gem dhash-vips`.
# source://dhash-vips//lib/dhash-vips.rb#4
module DHashVips
class << self
# source://dhash-vips//lib/dhash-vips.rb#6
def bw(image); end
end
end
# source://dhash-vips//lib/dhash-vips.rb#10
module DHashVips::DHash
extend ::DHashVips::DHash
# source://dhash-vips//lib/dhash-vips.rb#25
def calculate(file, hash_size = T.unsafe(nil)); end
# source://dhash-vips//lib/dhash-vips.rb#13
def hamming(a, b); end
# source://dhash-vips//lib/dhash-vips.rb#17
def pixelate(input, hash_size); end
end
# source://dhash-vips//lib/dhash-vips.rb#32
module DHashVips::IDHash
class << self
# source://dhash-vips//lib/dhash-vips.rb#66
def distance(a, b); end
# source://dhash-vips//lib/dhash-vips.rb#34
def distance3(a, b); end
# source://dhash-vips//lib/dhash-vips.rb#34
def distance3_ruby(a, b); end
# source://dhash-vips//lib/dhash-vips.rb#99
def fingerprint(input, power = T.unsafe(nil)); end
private
# source://dhash-vips//lib/dhash-vips.rb#78
def median(array); end
end
end

View File

@@ -1,171 +0,0 @@
# typed: false
require "rails_helper"
RSpec.describe Domain::PostFileThumbnail do
describe ".find_or_create_from_post_file" do
let(:post) { create(:domain_post_fa_post) }
let(:blob_file) do
fixture_path =
Rails.root.join(
"test/fixtures/files/images/thumb-036aaab6-content-container.jpeg",
)
create(
:blob_file,
contents: File.binread(fixture_path),
content_type: "image/jpeg",
)
end
let(:log_entry) do
create(:http_log_entry, content_type: "image/jpeg", response: blob_file)
end
let(:post_file) do
create(:domain_post_file, post: post, state: "ok", log_entry: log_entry)
end
before do
# Ensure directories exist
FileUtils.mkdir_p(Domain::PostFileThumbnail::TMP_DIR)
end
it "creates a thumbnail for a valid post file" do
thumbnail =
described_class.find_or_create_from_post_file(
post_file,
Domain::ThumbnailType::Small,
)
expect(thumbnail).to be_a(Domain::PostFileThumbnail)
expect(thumbnail.post_file).to eq(post_file)
expect(thumbnail.thumbnail_type).to eq("small")
# Verify the thumbnail file was created on disk
thumbnail_path = thumbnail.absolute_file_path
expect(thumbnail_path).not_to be_nil
expect(File.exist?(thumbnail_path)).to be true
end
it "returns existing thumbnail if one already exists" do
# Create a thumbnail first
existing =
described_class.find_or_create_from_post_file(
post_file,
Domain::ThumbnailType::Small,
)
expect(existing).not_to be_nil
# Try to find or create again
thumbnail =
described_class.find_or_create_from_post_file(
post_file,
Domain::ThumbnailType::Small,
)
# Should return the existing one without creating a new one
expect(thumbnail).to eq(existing)
end
it "returns nil for a post file that's not in 'ok' state" do
post_file.update!(state: "pending")
thumbnail =
described_class.find_or_create_from_post_file(
post_file,
Domain::ThumbnailType::Small,
)
expect(thumbnail).to be_nil
end
it "returns nil for a post file without a log entry" do
post_file.update!(log_entry: nil)
thumbnail =
described_class.find_or_create_from_post_file(
post_file,
Domain::ThumbnailType::Small,
)
expect(thumbnail).to be_nil
end
it "returns nil for a post file with an unsupported content type" do
# Create a new log entry with PDF content type since HttpLogEntry is immutable
pdf_blob =
create(
:blob_file,
content_type: "application/pdf",
contents: "fake pdf data",
)
pdf_log_entry =
create(
:http_log_entry,
content_type: "application/pdf",
response: pdf_blob,
)
pdf_post_file =
create(
:domain_post_file,
post: post,
state: "ok",
log_entry: pdf_log_entry,
)
thumbnail =
described_class.find_or_create_from_post_file(
pdf_post_file,
Domain::ThumbnailType::Small,
)
expect(thumbnail).to be_nil
end
it "returns nil if the post file has no blob" do
allow(post_file).to receive(:blob).and_return(nil)
thumbnail =
described_class.find_or_create_from_post_file(
post_file,
Domain::ThumbnailType::Small,
)
expect(thumbnail).to be_nil
end
end
describe "#absolute_file_path" do
let(:post) { create(:domain_post_fa_post) }
let(:blob_file) do
create(
:blob_file,
content_type: "image/jpeg",
contents: "fake image data",
)
end
let(:post_file) do
create(:domain_post_file, post: post, state: "ok", blob: blob_file)
end
let(:thumbnail) do
create(
:domain_post_file_thumbnail,
post_file: post_file,
thumbnail_type: "small",
)
end
it "constructs the correct file path" do
expect(thumbnail.absolute_file_path).to start_with(
Domain::PostFileThumbnail::THUMBNAIL_ROOT_DIR,
)
end
it "returns nil if thumbnail_type is nil" do
thumbnail.thumbnail_type = nil
expect(thumbnail.absolute_file_path).to be_nil
end
it "returns nil if post_file is nil" do
thumbnail.post_file = nil
expect(thumbnail.absolute_file_path).to be_nil
end
end
end