diff --git a/app/jobs/activity/creator_added_model_job.rb b/app/jobs/activity/creator_added_model_job.rb new file mode 100644 index 000000000..1bdda9d1c --- /dev/null +++ b/app/jobs/activity/creator_added_model_job.rb @@ -0,0 +1,16 @@ +class Activity::CreatorAddedModelJob < ApplicationJob + queue_as :activity + + def perform(model_id) + model = Model.find(model_id) + Comment.create!( + system: true, + commentable: model, + commenter: model.creator, + comment: I18n.t("jobs.activity.creator_added_model.comment", # rubocop:disable I18n/RailsI18n/DecorateStringFormattingUsingInterpolation + model_name: model.name, + url: model.actor.profile_url, + tags: model.tag_list.map { |t| "##{t}" }.join(" ")) + ) + end +end diff --git a/app/models/concerns/followable.rb b/app/models/concerns/followable.rb index 2dda13067..118ccf74a 100644 --- a/app/models/concerns/followable.rb +++ b/app/models/concerns/followable.rb @@ -6,8 +6,6 @@ module Followable included do delegate :following_followers, to: :actor - after_commit :post_creation_activity, on: :create - after_commit :post_update_activity, on: :update after_followed :auto_accept end @@ -22,30 +20,6 @@ def followed_by?(follower) private - def post_creation_activity - user = permitted_users.with_permission("own").first || SiteSettings.default_user - return if user.nil? - user.create_actor_if_missing - Federails::Activity.create!( - actor: user.actor, - action: "Create", - entity: actor, - created_at: created_at - ) - end - - def post_update_activity - return if actor&.activities_as_entity&.where(created_at: TIMEOUT.minutes.ago..)&.count&.> 0 - user = permitted_users.with_permission("own").first || SiteSettings.default_user - return if user.nil? - Federails::Activity.create!( - actor: user.actor, - action: "Update", - entity: actor, - created_at: updated_at - ) - end - def auto_accept actor.following_followers.where(status: "pending").find_each { |x| x.accept! } end diff --git a/app/models/model.rb b/app/models/model.rb index 893f410cb..efe8e6015 100644 --- a/app/models/model.rb +++ b/app/models/model.rb @@ -27,7 +27,9 @@ class Model < ApplicationRecord # In Rails 7.1 we will be able to do this instead: # normalizes :license, with: -> license { license.blank? ? nil : license } + after_create :post_creation_activity before_update :move_files, if: :need_to_move_files? + after_update :post_update_activity after_commit :check_integrity, on: :update validates :name, presence: true @@ -196,4 +198,16 @@ def move_files def check_integrity Scan::CheckModelIntegrityJob.set(wait: 5.seconds).perform_later(id) end + + def post_creation_activity + if creator.present? + Activity::CreatorAddedModelJob.set(wait: 5.seconds).perform_later(id) + end + end + + def post_update_activity + if creator_previously_changed? + Activity::CreatorAddedModelJob.set(wait: 5.seconds).perform_later(id) + end + end end diff --git a/config/locales/en.yml b/config/locales/en.yml index b63047077..7c96ad973 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -280,6 +280,14 @@ en: placeholder: What are you looking for? update_actor: updated by %{name} %{time} ago jobs: + activity: + creator_added_model: + comment: | + I've just added a new model: "%{model_name}". + + Find it at %{url} + + %{tags} analysis: analyse_model_file: detect_duplicates: Detecting duplicate files diff --git a/db/migrate/20241009122540_add_system_to_comments.rb b/db/migrate/20241009122540_add_system_to_comments.rb new file mode 100644 index 000000000..703e442ee --- /dev/null +++ b/db/migrate/20241009122540_add_system_to_comments.rb @@ -0,0 +1,5 @@ +class AddSystemToComments < ActiveRecord::Migration[7.1] + def change + add_column :comments, :system, :boolean, null: false, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 43a62b5aa..0ee747a64 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_10_07_182824) do +ActiveRecord::Schema[7.1].define(version: 2024_10_09_122540) do create_table "caber_relations", force: :cascade do |t| t.string "subject_type" t.integer "subject_id" @@ -50,6 +50,7 @@ t.text "comment" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.boolean "system", default: false, null: false t.index ["commentable_type", "commentable_id"], name: "index_comments_on_commentable" t.index ["commenter_type", "commenter_id"], name: "index_comments_on_commenter" t.index ["public_id"], name: "index_comments_on_public_id", unique: true diff --git a/spec/jobs/activity/creator_added_model_job_spec.rb b/spec/jobs/activity/creator_added_model_job_spec.rb new file mode 100644 index 000000000..fd988fede --- /dev/null +++ b/spec/jobs/activity/creator_added_model_job_spec.rb @@ -0,0 +1,48 @@ +require "rails_helper" + +RSpec.describe Activity::CreatorAddedModelJob do + let(:creator) { create(:creator) } + let(:model) { create(:model, creator: creator, tag_list: "tag1, tag2") } + + it "adds a comment" do + expect { described_class.new.perform(model.id) }.to change(Comment, :count).by(1) + end + + it "ends up queueing an ActivityPub publish job" do + expect { described_class.new.perform(model.id) }.to have_enqueued_job Federails::NotifyInboxJob + end + + context "with a comment" do + subject(:comment) { model.comments.first } + + before do + described_class.new.perform(model.id) + end + + it "sets creator as author" do + expect(comment.commenter).to eq creator + end + + it "sets model as the subject" do + expect(comment.commentable).to eq model + end + + it "marks comment as a system comment" do + expect(comment.system).to be true + end + + it "includes model name in text" do + expect(comment.comment).to include model.name + end + + it "includes tags in text as hashtags" do + model.tag_list.each do |tag| + expect(comment.comment).to include "##{tag}" + end + end + + it "includes URL in text" do + expect(comment.comment).to include "http://localhost:3214/models/#{model.public_id}" + end + end +end diff --git a/spec/models/concerns/followable_shared.rb b/spec/models/concerns/followable_shared.rb index 3aa1a8cae..bb09dea60 100644 --- a/spec/models/concerns/followable_shared.rb +++ b/spec/models/concerns/followable_shared.rb @@ -15,31 +15,4 @@ expect(target.followers.count).to eq 1 end end - - context "when being created" do - before do - create(:admin) - end - - it "posts an activity" do - expect { create(described_class.to_s.underscore.to_sym) }.to change(Federails::Activity, :count).by(1) - end - end - - context "when being updated" do - let!(:entity) { create(described_class.to_s.underscore.to_sym) } - - before do - create(:admin) - end - - it "posts an activity after update" do - expect { entity.update caption: "test" }.to change(Federails::Activity, :count).by(1) - end - - it "doesn't posts an activity after update if there's already been one recently" do - entity.update caption: "change" - expect { entity.update caption: "test" }.not_to change(Federails::Activity, :count) - end - end end diff --git a/spec/models/model_spec.rb b/spec/models/model_spec.rb index d3b2e32c9..e9712e7ef 100644 --- a/spec/models/model_spec.rb +++ b/spec/models/model_spec.rb @@ -385,4 +385,18 @@ expect(file).to have_received(:delete_from_disk_and_destroy).once end end + + context "when making changes" do + it "queues creator-specific model creation job when model is created if a creator is set" do + model = create(:model, creator: create(:creator)) + expect(Activity::CreatorAddedModelJob).to have_been_enqueued.with(model.id) + end + + it "queues creator-specific model creation job when model is updated if a creator has changed" do + model = create(:model) + ActiveJob::Base.queue_adapter.enqueued_jobs.clear + model.update(creator: create(:creator)) + expect(Activity::CreatorAddedModelJob).to have_been_enqueued.with(model.id) + end + end end