Domain::FaFavIdAndDate for tracking when fa favs are made
This commit is contained in:
@@ -135,6 +135,36 @@ class Domain::Fa::Job::FavsJob < Domain::Fa::Job::Base
|
||||
page_parser = Domain::Fa::Parser::Page.from_log_entry(response.log_entry)
|
||||
return ScanPageResult::Stop.new unless page_parser.probably_listings_page?
|
||||
|
||||
first_faved = page_parser.submissions_parsed[0]
|
||||
if first_faved.present?
|
||||
Domain::FaFavIdAndDate.upsert(
|
||||
{
|
||||
user_id: user.id,
|
||||
post_fa_id: first_faved.id,
|
||||
fav_fa_id: first_faved.fav_id,
|
||||
date: page_parser.most_recent_faved_at_time,
|
||||
},
|
||||
unique_by: %i[user_id post_fa_id],
|
||||
)
|
||||
end
|
||||
|
||||
fa_fav_id_date_data =
|
||||
(page_parser.submissions_parsed[1..] || []).filter_map do |sub_data|
|
||||
user_id = user.id
|
||||
fav_fa_id = sub_data.fav_id
|
||||
post_fa_id = sub_data.id
|
||||
next if fav_fa_id.nil? || post_fa_id.nil? || user_id.nil?
|
||||
{ user_id:, fav_fa_id:, post_fa_id: }
|
||||
end
|
||||
|
||||
if fa_fav_id_date_data.any?
|
||||
Domain::FaFavIdAndDate.upsert_all(
|
||||
fa_fav_id_date_data,
|
||||
unique_by: %i[user_id post_fa_id],
|
||||
update_only: [:fav_fa_id],
|
||||
)
|
||||
end
|
||||
|
||||
listing_page_stats =
|
||||
update_and_enqueue_posts_from_listings_page(
|
||||
ListingPageType::FavsPage.new(page_number: @page_id, user:),
|
||||
|
||||
@@ -141,6 +141,22 @@ class Domain::Fa::Job::UserPageJob < Domain::Fa::Job::Base
|
||||
recent_faved_posts =
|
||||
Domain::Post::FaPost.where(fa_id: recent_faved_fa_ids).to_a
|
||||
|
||||
# upsert faved IDs into the database
|
||||
Domain::FaFavIdAndDate.upsert_all(
|
||||
user_page
|
||||
.submissions_json_data
|
||||
.filter { |sub_data| recent_faved_fa_ids.include?(sub_data.fa_id) }
|
||||
.map do |fav_data|
|
||||
{
|
||||
user_id: user.id,
|
||||
post_fa_id: fav_data.fa_id,
|
||||
date: fav_data.faved_at,
|
||||
}
|
||||
end,
|
||||
unique_by: %i[user_id post_fa_id],
|
||||
update_only: [:date],
|
||||
)
|
||||
|
||||
# create missing posts in the favorites section
|
||||
(recent_faved_fa_ids - recent_faved_posts.map(&:fa_id)).each do |fa_id|
|
||||
post = Domain::Post::FaPost.find_or_create_by(fa_id:)
|
||||
|
||||
@@ -18,6 +18,7 @@ class Domain::Fa::Parser::ListedSubmissionParserHelper
|
||||
@title = T.let(nil, T.nilable(String))
|
||||
@view_path = T.let(nil, T.nilable(String))
|
||||
@thumb_path = T.let(nil, T.nilable(String))
|
||||
@fav_id = T.let(nil, T.nilable(Integer))
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(Integer)) }
|
||||
@@ -79,4 +80,12 @@ class Domain::Fa::Parser::ListedSubmissionParserHelper
|
||||
@elem.css("b u a img").first["src"]
|
||||
end
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(Integer)) }
|
||||
def fav_id
|
||||
@fav_id ||=
|
||||
begin
|
||||
@elem.attr("data-fav-id")&.to_i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -122,7 +122,7 @@ class Domain::Fa::Parser::Page < Domain::Fa::Parser::Base
|
||||
ActiveSupport::TimeZone.new("America/New_York")
|
||||
else
|
||||
# server default?
|
||||
ActiveSupport::TimeZone.new("America/Los_Angeles")
|
||||
raise("unknown logged in user #{logged_in_user}")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class Domain::Fa::Parser::UserPageHelper < Domain::Fa::Parser::Base
|
||||
@num_comments_given = T.let(nil, T.nilable(Integer))
|
||||
@num_journals = T.let(nil, T.nilable(Integer))
|
||||
@num_favorites = T.let(nil, T.nilable(Integer))
|
||||
@recent_favs = T.let(nil, T.nilable(T::Array[Integer]))
|
||||
@recent_fav_fa_ids = T.let(nil, T.nilable(T::Array[Integer]))
|
||||
@recent_gallery_fa_ids = T.let(nil, T.nilable(T::Array[Integer]))
|
||||
@recent_watchers = T.let(nil, T.nilable(T::Array[RecentUser]))
|
||||
@recent_watching = T.let(nil, T.nilable(T::Array[RecentUser]))
|
||||
@@ -36,7 +36,7 @@ class Domain::Fa::Parser::UserPageHelper < Domain::Fa::Parser::Base
|
||||
@main_about = T.let(nil, T.nilable(Nokogiri::XML::Element))
|
||||
@num_watched_by = T.let(nil, T.nilable(Integer))
|
||||
@num_watching = T.let(nil, T.nilable(Integer))
|
||||
@favorites_json_data = T.let(nil, T.nilable(T::Array[FavoritesData]))
|
||||
@submissions_json_data = T.let(nil, T.nilable(T::Array[SubmissionData]))
|
||||
@march_2025_update =
|
||||
T.let(elem.css(".js-displayName").first.present?, T::Boolean)
|
||||
|
||||
@@ -248,7 +248,7 @@ class Domain::Fa::Parser::UserPageHelper < Domain::Fa::Parser::Base
|
||||
|
||||
sig { returns(T::Array[Integer]) }
|
||||
def recent_fav_fa_ids
|
||||
@recent_favs ||=
|
||||
@recent_fav_fa_ids ||=
|
||||
case @page_version
|
||||
when VERSION_2
|
||||
@elem
|
||||
@@ -265,27 +265,7 @@ class Domain::Fa::Parser::UserPageHelper < Domain::Fa::Parser::Base
|
||||
end
|
||||
end
|
||||
|
||||
class RecentFav < T::Struct
|
||||
include T::Struct::ActsAsComparable
|
||||
|
||||
const :fa_id, Integer
|
||||
const :title, String
|
||||
const :creator, Domain::User::FaUser
|
||||
const :faved_at, Time
|
||||
end
|
||||
|
||||
sig { returns(T::Array[RecentFav]) }
|
||||
def recent_favs
|
||||
@recent_favs ||=
|
||||
case @page_version
|
||||
when VERSION_2
|
||||
@elem.css("#gallery-latest-favorites").first.css("figure a")
|
||||
else
|
||||
unimplemented_version!
|
||||
end
|
||||
end
|
||||
|
||||
class FavoritesData < T::ImmutableStruct
|
||||
class SubmissionData < T::ImmutableStruct
|
||||
include T::Struct::ActsAsComparable
|
||||
|
||||
const :fa_id, Integer
|
||||
@@ -293,14 +273,13 @@ class Domain::Fa::Parser::UserPageHelper < Domain::Fa::Parser::Base
|
||||
const :user_full_name, String
|
||||
const :url_name, String
|
||||
const :date_full, String
|
||||
const :date_fuzzy, String
|
||||
const :icon_rating, String
|
||||
const :faved_at, Time
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(T::Array[FavoritesData])) }
|
||||
def favorites_json_data
|
||||
@favorites_json_data ||=
|
||||
sig { returns(T::Array[SubmissionData]) }
|
||||
def submissions_json_data
|
||||
@submissions_json_data ||=
|
||||
case @page_version
|
||||
when VERSION_2
|
||||
json =
|
||||
@@ -308,11 +287,7 @@ class Domain::Fa::Parser::UserPageHelper < Domain::Fa::Parser::Base
|
||||
if (e = @elem.css("#js-submissionData").first)
|
||||
e.inner_html&.to_s
|
||||
else
|
||||
@elem
|
||||
.inner_html
|
||||
.match(/const submission_data = (.*);$/)
|
||||
&.[](1)
|
||||
&.to_s
|
||||
@elem.inner_html.match(/submission_data = (.*);$/)&.[](1)&.to_s
|
||||
end,
|
||||
T.nilable(String),
|
||||
)
|
||||
@@ -320,15 +295,21 @@ class Domain::Fa::Parser::UserPageHelper < Domain::Fa::Parser::Base
|
||||
JSON
|
||||
.parse(json)
|
||||
.map do |fa_id, data|
|
||||
date_full = data["date_full"]
|
||||
date_full =
|
||||
data["date_full"] ||
|
||||
begin
|
||||
html_date = data["html_date"]
|
||||
parsed = html_date && Nokogiri::XML.parse(html_date)
|
||||
parsed&.css("span")&.attr("title")&.to_s ||
|
||||
raise("invalid html date: #{data}")
|
||||
end
|
||||
faved_at = @page.logged_in_user_tz.parse(date_full)
|
||||
FavoritesData.new(
|
||||
SubmissionData.new(
|
||||
fa_id: fa_id.to_i,
|
||||
title: data["title"],
|
||||
user_full_name: data["username"],
|
||||
url_name: data["lower"],
|
||||
date_full:,
|
||||
date_fuzzy: data["date_fuzzy"],
|
||||
icon_rating: data["icon_rating"],
|
||||
faved_at:,
|
||||
)
|
||||
|
||||
16
app/models/domain/fa_fav_id_and_date.rb
Normal file
16
app/models/domain/fa_fav_id_and_date.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
# typed: strict
|
||||
class Domain::FaFavIdAndDate < ReduxApplicationRecord
|
||||
self.table_name = "domain_fa_fav_id_and_dates"
|
||||
|
||||
scope :complete, -> { where.not(date: nil).where.not(fav_fa_id: nil) }
|
||||
|
||||
belongs_to :user,
|
||||
class_name: "Domain::User::FaUser",
|
||||
inverse_of: :favs_and_dates
|
||||
belongs_to :post,
|
||||
class_name: "Domain::Post::FaPost",
|
||||
foreign_key: :post_fa_id,
|
||||
primary_key: :fa_id,
|
||||
optional: true
|
||||
validates :post_fa_id, presence: true
|
||||
end
|
||||
@@ -21,7 +21,7 @@ class Domain::PostGroup::SofurryFolder < Domain::PostGroup
|
||||
|
||||
sig { override.returns(T.nilable(String)) }
|
||||
def external_url_for_view
|
||||
if (type = self.media_type) && (sofurry_id = self.sofurry_id) &&
|
||||
if (type = self.media_types.first) && (sofurry_id = self.sofurry_id) &&
|
||||
(owner_id = self.owner&.sofurry_id)
|
||||
"https://www.sofurry.com/browse/folder/#{type}?by=#{owner_id}&folder=#{sofurry_id}"
|
||||
end
|
||||
|
||||
@@ -44,6 +44,11 @@ class Domain::User::FaUser < Domain::User
|
||||
class_name: "::HttpLogEntry",
|
||||
optional: true
|
||||
|
||||
has_many :favs_and_dates,
|
||||
class_name: "Domain::FaFavIdAndDate",
|
||||
foreign_key: :user_id,
|
||||
inverse_of: :user
|
||||
|
||||
enum :state,
|
||||
{ ok: "ok", account_disabled: "account_disabled", error: "error" },
|
||||
prefix: :state
|
||||
|
||||
16
db/migrate/20250709235107_create_fa_fav_id_and_dates.rb
Normal file
16
db/migrate/20250709235107_create_fa_fav_id_and_dates.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
class CreateFaFavIdAndDates < ActiveRecord::Migration[7.2]
|
||||
def change
|
||||
mirai_tablespace!
|
||||
|
||||
create_table :domain_fa_fav_id_and_dates do |t|
|
||||
t.references :user, null: false, foreign_key: { to_table: :domain_users }
|
||||
t.integer :post_fa_id
|
||||
t.integer :fav_fa_id
|
||||
t.datetime :date
|
||||
t.timestamps
|
||||
|
||||
t.index %i[user_id post_fa_id], unique: true
|
||||
t.index %i[fav_fa_id]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2174,6 +2174,40 @@ CREATE SEQUENCE public.domain_e621_users_id_seq
|
||||
ALTER SEQUENCE public.domain_e621_users_id_seq OWNED BY public.domain_e621_users.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: domain_fa_fav_id_and_dates; Type: TABLE; Schema: public; Owner: -; Tablespace: mirai
|
||||
--
|
||||
|
||||
CREATE TABLE public.domain_fa_fav_id_and_dates (
|
||||
id bigint NOT NULL,
|
||||
user_id bigint NOT NULL,
|
||||
post_fa_id integer,
|
||||
fav_fa_id integer,
|
||||
date timestamp(6) without time zone,
|
||||
created_at timestamp(6) without time zone NOT NULL,
|
||||
updated_at timestamp(6) without time zone NOT NULL
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: domain_fa_fav_id_and_dates_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.domain_fa_fav_id_and_dates_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: domain_fa_fav_id_and_dates_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.domain_fa_fav_id_and_dates_id_seq OWNED BY public.domain_fa_fav_id_and_dates.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: domain_fa_favs; Type: TABLE; Schema: public; Owner: -; Tablespace: mirai
|
||||
--
|
||||
@@ -4614,6 +4648,13 @@ ALTER TABLE ONLY public.domain_e621_tags ALTER COLUMN id SET DEFAULT nextval('pu
|
||||
ALTER TABLE ONLY public.domain_e621_users ALTER COLUMN id SET DEFAULT nextval('public.domain_e621_users_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: domain_fa_fav_id_and_dates id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.domain_fa_fav_id_and_dates ALTER COLUMN id SET DEFAULT nextval('public.domain_fa_fav_id_and_dates_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: domain_fa_posts id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
@@ -5399,6 +5440,14 @@ ALTER TABLE ONLY public.domain_e621_users
|
||||
ADD CONSTRAINT domain_e621_users_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: domain_fa_fav_id_and_dates domain_fa_fav_id_and_dates_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: mirai
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.domain_fa_fav_id_and_dates
|
||||
ADD CONSTRAINT domain_fa_fav_id_and_dates_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: domain_fa_posts domain_fa_posts_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: mirai
|
||||
--
|
||||
@@ -6928,6 +6977,27 @@ CREATE INDEX index_domain_e621_users_on_json_attributes ON public.domain_e621_us
|
||||
|
||||
SET default_tablespace = mirai;
|
||||
|
||||
--
|
||||
-- Name: index_domain_fa_fav_id_and_dates_on_fav_fa_id; Type: INDEX; Schema: public; Owner: -; Tablespace: mirai
|
||||
--
|
||||
|
||||
CREATE INDEX index_domain_fa_fav_id_and_dates_on_fav_fa_id ON public.domain_fa_fav_id_and_dates USING btree (fav_fa_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_domain_fa_fav_id_and_dates_on_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: mirai
|
||||
--
|
||||
|
||||
CREATE INDEX index_domain_fa_fav_id_and_dates_on_user_id ON public.domain_fa_fav_id_and_dates USING btree (user_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_domain_fa_fav_id_and_dates_on_user_id_and_post_fa_id; Type: INDEX; Schema: public; Owner: -; Tablespace: mirai
|
||||
--
|
||||
|
||||
CREATE UNIQUE INDEX index_domain_fa_fav_id_and_dates_on_user_id_and_post_fa_id ON public.domain_fa_fav_id_and_dates USING btree (user_id, post_fa_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: index_domain_fa_favs_on_post_id; Type: INDEX; Schema: public; Owner: -; Tablespace: mirai
|
||||
--
|
||||
@@ -8765,6 +8835,14 @@ ALTER TABLE ONLY public.http_log_entries
|
||||
ADD CONSTRAINT fk_rails_42f35e9da0 FOREIGN KEY (response_headers_id) REFERENCES public.http_log_entry_headers(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: domain_fa_fav_id_and_dates fk_rails_4ad7be007e; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.domain_fa_fav_id_and_dates
|
||||
ADD CONSTRAINT fk_rails_4ad7be007e FOREIGN KEY (user_id) REFERENCES public.domain_users(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: domain_user_user_follows fk_rails_4b2ab65400; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
@@ -9060,6 +9138,7 @@ ALTER TABLE ONLY public.domain_twitter_tweets
|
||||
SET search_path TO "$user", public;
|
||||
|
||||
INSERT INTO "schema_migrations" (version) VALUES
|
||||
('20250709235107'),
|
||||
('20250628000003'),
|
||||
('20250628000002'),
|
||||
('20250626191434'),
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# typed: true
|
||||
|
||||
# DO NOT EDIT MANUALLY
|
||||
# This is an autogenerated file for dynamic methods in `Domain::Fa::EnqueueDueUserFavsScans`.
|
||||
# Please instead update this file by running `bin/tapioca dsl Domain::Fa::EnqueueDueUserFavsScans`.
|
||||
|
||||
|
||||
class Domain::Fa::EnqueueDueUserFavsScans
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
|
||||
class << self
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
end
|
||||
end
|
||||
@@ -1,16 +0,0 @@
|
||||
# typed: true
|
||||
|
||||
# DO NOT EDIT MANUALLY
|
||||
# This is an autogenerated file for dynamic methods in `Domain::Fa::EnqueueDueUserPageScans`.
|
||||
# Please instead update this file by running `bin/tapioca dsl Domain::Fa::EnqueueDueUserPageScans`.
|
||||
|
||||
|
||||
class Domain::Fa::EnqueueDueUserPageScans
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
|
||||
class << self
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
end
|
||||
end
|
||||
@@ -1,16 +0,0 @@
|
||||
# typed: true
|
||||
|
||||
# DO NOT EDIT MANUALLY
|
||||
# This is an autogenerated file for dynamic methods in `Domain::Fa::EnqueueUnscannedOkPosts`.
|
||||
# Please instead update this file by running `bin/tapioca dsl Domain::Fa::EnqueueUnscannedOkPosts`.
|
||||
|
||||
|
||||
class Domain::Fa::EnqueueUnscannedOkPosts
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
|
||||
class << self
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
end
|
||||
end
|
||||
1453
sorbet/rbi/dsl/domain/fa_fav_id_and_date.rbi
generated
Normal file
1453
sorbet/rbi/dsl/domain/fa_fav_id_and_date.rbi
generated
Normal file
File diff suppressed because it is too large
Load Diff
174
sorbet/rbi/dsl/domain/post_group/sofurry_folder.rbi
generated
174
sorbet/rbi/dsl/domain/post_group/sofurry_folder.rbi
generated
@@ -8,7 +8,6 @@
|
||||
class Domain::PostGroup::SofurryFolder
|
||||
include GeneratedAssociationMethods
|
||||
include GeneratedAttributeMethods
|
||||
include EnumMethodsModule
|
||||
extend CommonRelationMethods
|
||||
extend GeneratedRelationMethods
|
||||
|
||||
@@ -51,9 +50,6 @@ class Domain::PostGroup::SofurryFolder
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
|
||||
sig { returns(T::Hash[T.any(String, Symbol), Integer]) }
|
||||
def media_types; end
|
||||
|
||||
sig do
|
||||
params(
|
||||
attributes: T.untyped,
|
||||
@@ -457,38 +453,6 @@ class Domain::PostGroup::SofurryFolder
|
||||
def third_to_last!; end
|
||||
end
|
||||
|
||||
module EnumMethodsModule
|
||||
sig { void }
|
||||
def media_type_art!; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def media_type_art?; end
|
||||
|
||||
sig { void }
|
||||
def media_type_journals!; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def media_type_journals?; end
|
||||
|
||||
sig { void }
|
||||
def media_type_music!; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def media_type_music?; end
|
||||
|
||||
sig { void }
|
||||
def media_type_photos!; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def media_type_photos?; end
|
||||
|
||||
sig { void }
|
||||
def media_type_stories!; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def media_type_stories?; end
|
||||
end
|
||||
|
||||
module GeneratedAssociationMethods
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(::Domain::User::SofurryUser) }
|
||||
def build_owner(*args, &blk); end
|
||||
@@ -613,42 +577,12 @@ class Domain::PostGroup::SofurryFolder
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) }
|
||||
def lock(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) }
|
||||
def media_type_art(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) }
|
||||
def media_type_journals(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) }
|
||||
def media_type_music(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) }
|
||||
def media_type_photos(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) }
|
||||
def media_type_stories(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) }
|
||||
def merge(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) }
|
||||
def none(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) }
|
||||
def not_media_type_art(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) }
|
||||
def not_media_type_journals(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) }
|
||||
def not_media_type_music(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) }
|
||||
def not_media_type_photos(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) }
|
||||
def not_media_type_stories(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) }
|
||||
def null_relation?(*args, &blk); end
|
||||
|
||||
@@ -930,64 +864,50 @@ class Domain::PostGroup::SofurryFolder
|
||||
sig { void }
|
||||
def json_attributes_will_change!; end
|
||||
|
||||
sig { returns(T.nilable(::String)) }
|
||||
def media_type; end
|
||||
sig { returns(T.untyped) }
|
||||
def media_types; end
|
||||
|
||||
sig do
|
||||
params(
|
||||
value: T.nilable(T.any(::String, ::Symbol, ::Integer))
|
||||
).returns(T.nilable(T.any(::String, ::Symbol, ::Integer)))
|
||||
end
|
||||
def media_type=(value); end
|
||||
sig { params(value: T.untyped).returns(T.untyped) }
|
||||
def media_types=(value); end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def media_type?; end
|
||||
|
||||
sig { returns(T.nilable(::String)) }
|
||||
def media_type_before_last_save; end
|
||||
def media_types?; end
|
||||
|
||||
sig { returns(T.untyped) }
|
||||
def media_type_before_type_cast; end
|
||||
def media_types_before_last_save; end
|
||||
|
||||
sig { returns(T.untyped) }
|
||||
def media_types_before_type_cast; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def media_type_came_from_user?; end
|
||||
def media_types_came_from_user?; end
|
||||
|
||||
sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) }
|
||||
def media_type_change; end
|
||||
sig { returns(T.nilable([T.untyped, T.untyped])) }
|
||||
def media_types_change; end
|
||||
|
||||
sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) }
|
||||
def media_type_change_to_be_saved; end
|
||||
sig { returns(T.nilable([T.untyped, T.untyped])) }
|
||||
def media_types_change_to_be_saved; end
|
||||
|
||||
sig do
|
||||
params(
|
||||
from: T.nilable(T.any(::String, ::Symbol, ::Integer)),
|
||||
to: T.nilable(T.any(::String, ::Symbol, ::Integer))
|
||||
).returns(T::Boolean)
|
||||
end
|
||||
def media_type_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
|
||||
sig { params(from: T.untyped, to: T.untyped).returns(T::Boolean) }
|
||||
def media_types_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
|
||||
|
||||
sig { returns(T.nilable(::String)) }
|
||||
def media_type_in_database; end
|
||||
sig { returns(T.untyped) }
|
||||
def media_types_in_database; end
|
||||
|
||||
sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) }
|
||||
def media_type_previous_change; end
|
||||
sig { returns(T.nilable([T.untyped, T.untyped])) }
|
||||
def media_types_previous_change; end
|
||||
|
||||
sig do
|
||||
params(
|
||||
from: T.nilable(T.any(::String, ::Symbol, ::Integer)),
|
||||
to: T.nilable(T.any(::String, ::Symbol, ::Integer))
|
||||
).returns(T::Boolean)
|
||||
end
|
||||
def media_type_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
|
||||
sig { params(from: T.untyped, to: T.untyped).returns(T::Boolean) }
|
||||
def media_types_previously_changed?(from: T.unsafe(nil), to: T.unsafe(nil)); end
|
||||
|
||||
sig { returns(T.nilable(::String)) }
|
||||
def media_type_previously_was; end
|
||||
sig { returns(T.untyped) }
|
||||
def media_types_previously_was; end
|
||||
|
||||
sig { returns(T.nilable(::String)) }
|
||||
def media_type_was; end
|
||||
sig { returns(T.untyped) }
|
||||
def media_types_was; end
|
||||
|
||||
sig { void }
|
||||
def media_type_will_change!; end
|
||||
def media_types_will_change!; end
|
||||
|
||||
sig { returns(T.nilable(::String)) }
|
||||
def name; end
|
||||
@@ -1092,7 +1012,7 @@ class Domain::PostGroup::SofurryFolder
|
||||
def restore_json_attributes!; end
|
||||
|
||||
sig { void }
|
||||
def restore_media_type!; end
|
||||
def restore_media_types!; end
|
||||
|
||||
sig { void }
|
||||
def restore_name!; end
|
||||
@@ -1136,11 +1056,11 @@ class Domain::PostGroup::SofurryFolder
|
||||
sig { returns(T::Boolean) }
|
||||
def saved_change_to_json_attributes?; end
|
||||
|
||||
sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) }
|
||||
def saved_change_to_media_type; end
|
||||
sig { returns(T.nilable([T.untyped, T.untyped])) }
|
||||
def saved_change_to_media_types; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def saved_change_to_media_type?; end
|
||||
def saved_change_to_media_types?; end
|
||||
|
||||
sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) }
|
||||
def saved_change_to_name; end
|
||||
@@ -1381,7 +1301,7 @@ class Domain::PostGroup::SofurryFolder
|
||||
def will_save_change_to_json_attributes?; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def will_save_change_to_media_type?; end
|
||||
def will_save_change_to_media_types?; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def will_save_change_to_name?; end
|
||||
@@ -1469,42 +1389,12 @@ class Domain::PostGroup::SofurryFolder
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) }
|
||||
def lock(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) }
|
||||
def media_type_art(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) }
|
||||
def media_type_journals(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) }
|
||||
def media_type_music(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) }
|
||||
def media_type_photos(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) }
|
||||
def media_type_stories(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) }
|
||||
def merge(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) }
|
||||
def none(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) }
|
||||
def not_media_type_art(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) }
|
||||
def not_media_type_journals(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) }
|
||||
def not_media_type_music(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) }
|
||||
def not_media_type_photos(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) }
|
||||
def not_media_type_stories(*args, &blk); end
|
||||
|
||||
sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) }
|
||||
def null_relation?(*args, &blk); end
|
||||
|
||||
|
||||
16
sorbet/rbi/dsl/enqueue_due_post_file_jobs.rbi
generated
16
sorbet/rbi/dsl/enqueue_due_post_file_jobs.rbi
generated
@@ -1,16 +0,0 @@
|
||||
# typed: true
|
||||
|
||||
# DO NOT EDIT MANUALLY
|
||||
# This is an autogenerated file for dynamic methods in `EnqueueDuePostFileJobs`.
|
||||
# Please instead update this file by running `bin/tapioca dsl EnqueueDuePostFileJobs`.
|
||||
|
||||
|
||||
class EnqueueDuePostFileJobs
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
|
||||
class << self
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
end
|
||||
end
|
||||
16
sorbet/rbi/dsl/tasks/enqueue_due_post_file_jobs_task.rbi
generated
Normal file
16
sorbet/rbi/dsl/tasks/enqueue_due_post_file_jobs_task.rbi
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
# typed: true
|
||||
|
||||
# DO NOT EDIT MANUALLY
|
||||
# This is an autogenerated file for dynamic methods in `Tasks::EnqueueDuePostFileJobsTask`.
|
||||
# Please instead update this file by running `bin/tapioca dsl Tasks::EnqueueDuePostFileJobsTask`.
|
||||
|
||||
|
||||
class Tasks::EnqueueDuePostFileJobsTask
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
|
||||
class << self
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
end
|
||||
end
|
||||
16
sorbet/rbi/dsl/tasks/fa/enqueue_due_user_favs_scans_task.rbi
generated
Normal file
16
sorbet/rbi/dsl/tasks/fa/enqueue_due_user_favs_scans_task.rbi
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
# typed: true
|
||||
|
||||
# DO NOT EDIT MANUALLY
|
||||
# This is an autogenerated file for dynamic methods in `Tasks::Fa::EnqueueDueUserFavsScansTask`.
|
||||
# Please instead update this file by running `bin/tapioca dsl Tasks::Fa::EnqueueDueUserFavsScansTask`.
|
||||
|
||||
|
||||
class Tasks::Fa::EnqueueDueUserFavsScansTask
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
|
||||
class << self
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
end
|
||||
end
|
||||
16
sorbet/rbi/dsl/tasks/fa/enqueue_due_user_page_scans_task.rbi
generated
Normal file
16
sorbet/rbi/dsl/tasks/fa/enqueue_due_user_page_scans_task.rbi
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
# typed: true
|
||||
|
||||
# DO NOT EDIT MANUALLY
|
||||
# This is an autogenerated file for dynamic methods in `Tasks::Fa::EnqueueDueUserPageScansTask`.
|
||||
# Please instead update this file by running `bin/tapioca dsl Tasks::Fa::EnqueueDueUserPageScansTask`.
|
||||
|
||||
|
||||
class Tasks::Fa::EnqueueDueUserPageScansTask
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
|
||||
class << self
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
end
|
||||
end
|
||||
16
sorbet/rbi/dsl/tasks/fa/enqueue_unscanned_ok_posts_task.rbi
generated
Normal file
16
sorbet/rbi/dsl/tasks/fa/enqueue_unscanned_ok_posts_task.rbi
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
# typed: true
|
||||
|
||||
# DO NOT EDIT MANUALLY
|
||||
# This is an autogenerated file for dynamic methods in `Tasks::Fa::EnqueueUnscannedOkPostsTask`.
|
||||
# Please instead update this file by running `bin/tapioca dsl Tasks::Fa::EnqueueUnscannedOkPostsTask`.
|
||||
|
||||
|
||||
class Tasks::Fa::EnqueueUnscannedOkPostsTask
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
|
||||
class << self
|
||||
sig { returns(ColorLogger) }
|
||||
def logger; end
|
||||
end
|
||||
end
|
||||
@@ -473,5 +473,38 @@ describe Domain::Fa::Job::FavsJob do
|
||||
|
||||
expect(user.faved_posts.count).to eq(85)
|
||||
end
|
||||
|
||||
it "records FaFavIdAndDate records" do
|
||||
# assume a record for 58923196 already exists with a date
|
||||
# but no fav_fa_id
|
||||
date_58923196 = Time.parse("May 11, 2023 10:54 AM")
|
||||
Domain::FaFavIdAndDate.create!(
|
||||
user:,
|
||||
post_fa_id: 58_923_196,
|
||||
date: date_58923196,
|
||||
)
|
||||
|
||||
perform_now({ url_name: "zzreg" })
|
||||
fa_fav_and_dates = Domain::FaFavIdAndDate.all
|
||||
expect(fa_fav_and_dates.count).to eq(85)
|
||||
expect(fa_fav_and_dates.map(&:user_id)).to all(eq(user.id))
|
||||
|
||||
# the first record should have a date
|
||||
sub_51810098 = fa_fav_and_dates.find { |f| f.post_fa_id == 51_810_098 }
|
||||
expect(sub_51810098.fav_fa_id).to eq(1_724_359_446)
|
||||
expect(sub_51810098.date).to eq(
|
||||
Time.parse("Dec 14, 2024 12:39 AM -08:00"),
|
||||
)
|
||||
|
||||
# non-first new records should not have a date populated
|
||||
sub_58724276 = fa_fav_and_dates.find { |f| f.post_fa_id == 58_724_276 }
|
||||
expect(sub_58724276.fav_fa_id).to eq(1_724_341_165)
|
||||
expect(sub_58724276.date).to be_nil
|
||||
|
||||
# existing record should have its fav_fa_id populated, and date should be unchanged
|
||||
sub_58923196 = fa_fav_and_dates.find { |f| f.post_fa_id == 58_923_196 }
|
||||
expect(sub_58923196.fav_fa_id).to eq(1_715_343_287)
|
||||
expect(sub_58923196.date).to eq(date_58923196)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -52,6 +52,31 @@ describe Domain::Fa::Job::UserPageJob do
|
||||
|
||||
let(:user) { Domain::User::FaUser.find_by(url_name: "meesh") }
|
||||
|
||||
let(:faved_post_fa_ids) do
|
||||
[
|
||||
51_671_587,
|
||||
51_660_483,
|
||||
51_656_085,
|
||||
51_656_135,
|
||||
51_633_080,
|
||||
51_633_041,
|
||||
51_535_939,
|
||||
51_631_696,
|
||||
51_634_520,
|
||||
51_632_374,
|
||||
51_631_377,
|
||||
51_631_461,
|
||||
51_624_859,
|
||||
51_618_150,
|
||||
51_621_410,
|
||||
51_618_586,
|
||||
51_617_113,
|
||||
51_613_740,
|
||||
51_600_523,
|
||||
51_594_821,
|
||||
]
|
||||
end
|
||||
|
||||
it "records the right stats" do
|
||||
perform_now({ url_name: "meesh" })
|
||||
expect(user).to_not be_nil
|
||||
@@ -72,6 +97,33 @@ describe Domain::Fa::Job::UserPageJob do
|
||||
)
|
||||
end
|
||||
|
||||
it "records FaFavIdAndDate records" do
|
||||
user = create(:domain_user_fa_user, url_name: "meesh")
|
||||
|
||||
# existing record that has a fav_fa_id but no date
|
||||
Domain::FaFavIdAndDate.create!(
|
||||
user:,
|
||||
post_fa_id: 51_617_113,
|
||||
fav_fa_id: 1_234_567_890,
|
||||
)
|
||||
|
||||
perform_now({ url_name: "meesh" })
|
||||
fa_fav_and_dates = Domain::FaFavIdAndDate.all
|
||||
expect(fa_fav_and_dates.count).to eq(20)
|
||||
expect(fa_fav_and_dates.map(&:post_fa_id)).to contain_exactly(
|
||||
*faved_post_fa_ids,
|
||||
)
|
||||
fav_51671587 = fa_fav_and_dates.find { |f| f.post_fa_id == 51_671_587 }
|
||||
expect(fav_51671587.user).to eq(user)
|
||||
expect(fav_51671587.date).to eq(Time.parse("Apr 6, 2023 04:28 PM -07:00"))
|
||||
expect(fav_51671587.fav_fa_id).to be_nil
|
||||
|
||||
fav_51617113 = fa_fav_and_dates.find { |f| f.post_fa_id == 51_617_113 }
|
||||
expect(fav_51617113.user).to eq(user)
|
||||
expect(fav_51617113.date).to eq(Time.parse("Apr 2, 2023 02:49 PM -07:00"))
|
||||
expect(fav_51617113.fav_fa_id).to eq(1_234_567_890)
|
||||
end
|
||||
|
||||
context "the user does not yet exist" do
|
||||
it "the user is created" do
|
||||
expect do perform_now({ url_name: "meesh" }) end.to change {
|
||||
@@ -836,6 +888,43 @@ describe Domain::Fa::Job::UserPageJob do
|
||||
]
|
||||
end
|
||||
|
||||
let(:faved_post_fa_ids) do
|
||||
[
|
||||
49_881,
|
||||
72_900,
|
||||
60_088,
|
||||
60_086,
|
||||
58_000,
|
||||
57_298,
|
||||
57_282,
|
||||
56_811,
|
||||
55_187,
|
||||
54_431,
|
||||
58_488,
|
||||
31_830,
|
||||
31_425,
|
||||
31_413,
|
||||
31_409,
|
||||
29_859,
|
||||
28_961,
|
||||
26_304,
|
||||
24_977,
|
||||
24_451,
|
||||
]
|
||||
end
|
||||
|
||||
it "creates FaFavIdAndDate records for new style of page" do
|
||||
perform_now({ url_name: "dilgear" })
|
||||
fa_fav_and_dates = Domain::FaFavIdAndDate.all
|
||||
expect(fa_fav_and_dates.count).to eq(20)
|
||||
expect(fa_fav_and_dates.map(&:post_fa_id)).to contain_exactly(
|
||||
*faved_post_fa_ids,
|
||||
)
|
||||
fav_26304 = fa_fav_and_dates.find { |f| f.post_fa_id == 26_304 }
|
||||
expect(fav_26304.date).to eq(Time.parse("Feb 17, 2006 07:09 AM -08:00"))
|
||||
expect(fav_26304.fav_fa_id).to be_nil
|
||||
end
|
||||
|
||||
context "user has not had a favs scan in the past" do
|
||||
it "enqueues a favs job" do
|
||||
perform_now({ url_name: "dilgear" })
|
||||
|
||||
@@ -696,14 +696,14 @@ describe Domain::Fa::Parser::Page do
|
||||
end
|
||||
|
||||
describe "parsing a user page" do
|
||||
describe "#favorites_json_data" do
|
||||
describe "#submissions_json_data" do
|
||||
it "works with a user page with old embedded json format" do
|
||||
parser =
|
||||
get_fa_parser("user_page/user_page_zzreg_one_scrap_submission.html")
|
||||
up = parser.user_page
|
||||
expect(up.favorites_json_data.length).to eq(20)
|
||||
expect(up.submissions_json_data.length).to eq(20)
|
||||
|
||||
fav0 = up.favorites_json_data.find { |f| f.fa_id == 59_785_748 }
|
||||
fav0 = up.submissions_json_data.find { |f| f.fa_id == 59_785_748 }
|
||||
expect(fav0).to be_present
|
||||
expect(fav0.fa_id).to eq(59_785_748)
|
||||
expect(fav0.user_full_name).to eq("-creeps")
|
||||
@@ -721,9 +721,9 @@ describe Domain::Fa::Parser::Page do
|
||||
"user_page/user_page_zzreg_new_submission_data_elem.html",
|
||||
)
|
||||
up = parser.user_page
|
||||
expect(up.favorites_json_data.length).to eq(20)
|
||||
expect(up.submissions_json_data.length).to eq(20)
|
||||
|
||||
fav0 = up.favorites_json_data.find { |f| f.fa_id == 60_272_845 }
|
||||
fav0 = up.submissions_json_data.find { |f| f.fa_id == 60_272_845 }
|
||||
expect(fav0).to be_present
|
||||
expect(fav0.fa_id).to eq(60_272_845)
|
||||
expect(fav0.user_full_name).to eq("MuskyDusky")
|
||||
@@ -734,7 +734,7 @@ describe Domain::Fa::Parser::Page do
|
||||
faved_at = Time.parse(date_full + " -07:00")
|
||||
expect(fav0.faved_at).to eq(faved_at)
|
||||
|
||||
fav19 = up.favorites_json_data.find { |f| f.fa_id == 59_860_095 }
|
||||
fav19 = up.submissions_json_data.find { |f| f.fa_id == 59_860_095 }
|
||||
expect(fav19.title).to eq("🔞Outdoor Cookie")
|
||||
expect(fav19.user_full_name).to eq("KeaveMind")
|
||||
expect(fav19.url_name).to eq("keavemind")
|
||||
|
||||
Reference in New Issue
Block a user