diff --git a/app/models/activity_pub/activity.rb b/app/models/activity_pub/activity.rb index ee555474..af005ff3 100644 --- a/app/models/activity_pub/activity.rb +++ b/app/models/activity_pub/activity.rb @@ -21,7 +21,7 @@ class ActivityPub validates :activity_pub_id, presence: true # Las actividades son únicas con respecto a su estado - validates :uri, presence: true, uniqueness: { scope: :activity_pub_id, message: 'estado duplicado' } + validates :uri, presence: true, url: true, uniqueness: { scope: :activity_pub_id, message: 'estado duplicado' } # Siempre en orden descendiente para saber el último estado default_scope -> { order(created_at: :desc) } diff --git a/app/models/activity_pub/activity/delete.rb b/app/models/activity_pub/activity/delete.rb index 5de20478..6a23a8b5 100644 --- a/app/models/activity_pub/activity/delete.rb +++ b/app/models/activity_pub/activity/delete.rb @@ -16,10 +16,16 @@ class ActivityPub ActivityPub.transaction do object = ActivityPub::Object.find_by(uri: ActivityPub.uri_from_object(content['object'])) - if object + if object.present? object.activity_pubs.find_each do |activity_pub| activity_pub.remove! if activity_pub.may_remove? end + + # Encontrar todas las acciones de moderación de le actore + # eliminade y moverlas a eliminar. + if object.actor_type? && object.actor.present? + ActorModeration.where(actor_id: object.actor.id).remove_all! + end end activity_pub.remove! if activity_pub.may_remove? diff --git a/app/models/activity_pub/actor.rb b/app/models/activity_pub/actor.rb index 919bc5e0..b03145e7 100644 --- a/app/models/activity_pub/actor.rb +++ b/app/models/activity_pub/actor.rb @@ -16,7 +16,7 @@ class ActivityPub has_many :remote_flags # Les actores son únicxs a toda la base de datos - validates :uri, presence: true, uniqueness: true + validates :uri, presence: true, url: true, uniqueness: true # Obtiene el nombre de la Actor como mención, solo si obtuvimos el # contenido de antemano. diff --git a/app/models/activity_pub/object.rb b/app/models/activity_pub/object.rb index 15b07bee..9061c4c5 100644 --- a/app/models/activity_pub/object.rb +++ b/app/models/activity_pub/object.rb @@ -6,7 +6,7 @@ class ActivityPub include ActivityPub::Concerns::JsonLdConcern # Los objetos son únicos a toda la base de datos - validates :uri, presence: true, uniqueness: true + validates :uri, presence: true, url: true, uniqueness: true has_many :activity_pubs, as: :object @@ -14,7 +14,20 @@ class ActivityPub # # @return [ActivityPub::Actor,nil] def actor - ActivityPub::Actor.find_by(uri: content['actor']) + ActivityPub::Actor.find_by(uri: actor_uri) + end + + # @return [String] + def actor_uri + content['attributedTo'] + end + + def actor_type? + false + end + + def object_type? + true end end end diff --git a/app/models/activity_pub/object/application.rb b/app/models/activity_pub/object/application.rb index 99ac935c..d26a7757 100644 --- a/app/models/activity_pub/object/application.rb +++ b/app/models/activity_pub/object/application.rb @@ -5,6 +5,8 @@ # Una aplicación o instancia class ActivityPub class Object - class Application < ActivityPub::Object; end + class Application < ActivityPub::Object + include Concerns::ActorTypeConcern + end end end diff --git a/app/models/activity_pub/object/audio.rb b/app/models/activity_pub/object/audio.rb new file mode 100644 index 00000000..48caea44 --- /dev/null +++ b/app/models/activity_pub/object/audio.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Audio = +# +# Representa artículos +class ActivityPub + class Object + class Audio < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/concerns/actor_type_concern.rb b/app/models/activity_pub/object/concerns/actor_type_concern.rb new file mode 100644 index 00000000..b2a643c7 --- /dev/null +++ b/app/models/activity_pub/object/concerns/actor_type_concern.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +class ActivityPub + class Object + module Concerns + module ActorTypeConcern + extend ActiveSupport::Concern + + included do + # La URI de le Actor en este caso es la misma id + # + # @return [String] + def actor_uri + uri + end + + # El objeto referencia a une Actor + # + # @see {https://www.w3.org/TR/activitystreams-vocabulary/#actor-types} + def actor_type? + true + end + + # El objeto es un objeto + # + # @see {https://www.w3.org/TR/activitystreams-vocabulary/#object-types} + def object_type? + false + end + end + end + end + end +end diff --git a/app/models/activity_pub/object/document.rb b/app/models/activity_pub/object/document.rb new file mode 100644 index 00000000..d7444514 --- /dev/null +++ b/app/models/activity_pub/object/document.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Document = +# +# Representa artículos +class ActivityPub + class Object + class Document < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/event.rb b/app/models/activity_pub/object/event.rb new file mode 100644 index 00000000..9fa1f6fc --- /dev/null +++ b/app/models/activity_pub/object/event.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Event = +# +# Representa artículos +class ActivityPub + class Object + class Event < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/group.rb b/app/models/activity_pub/object/group.rb new file mode 100644 index 00000000..08d11d0d --- /dev/null +++ b/app/models/activity_pub/object/group.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Group = +class ActivityPub + class Object + class Group < ActivityPub::Object + include Concerns::ActorTypeConcern + end + end +end diff --git a/app/models/activity_pub/object/image.rb b/app/models/activity_pub/object/image.rb new file mode 100644 index 00000000..9939a14b --- /dev/null +++ b/app/models/activity_pub/object/image.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Image = +# +# Representa artículos +class ActivityPub + class Object + class Image < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/organization.rb b/app/models/activity_pub/object/organization.rb index e3385232..e820c305 100644 --- a/app/models/activity_pub/object/organization.rb +++ b/app/models/activity_pub/object/organization.rb @@ -5,6 +5,8 @@ # Una organización class ActivityPub class Object - class Organization < ActivityPub::Object; end + class Organization < ActivityPub::Object + include Concerns::ActorTypeConcern + end end end diff --git a/app/models/activity_pub/object/page.rb b/app/models/activity_pub/object/page.rb new file mode 100644 index 00000000..f05503e2 --- /dev/null +++ b/app/models/activity_pub/object/page.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Page = +# +# Representa artículos +class ActivityPub + class Object + class Page < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/person.rb b/app/models/activity_pub/object/person.rb index a6a85d43..5bcab596 100644 --- a/app/models/activity_pub/object/person.rb +++ b/app/models/activity_pub/object/person.rb @@ -5,6 +5,8 @@ # Una persona, el perfil de une actore class ActivityPub class Object - class Person < ActivityPub::Object; end + class Person < ActivityPub::Object + include Concerns::ActorTypeConcern + end end end diff --git a/app/models/activity_pub/object/place.rb b/app/models/activity_pub/object/place.rb new file mode 100644 index 00000000..f04032ed --- /dev/null +++ b/app/models/activity_pub/object/place.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Place = +# +# Representa artículos +class ActivityPub + class Object + class Place < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/profile.rb b/app/models/activity_pub/object/profile.rb new file mode 100644 index 00000000..8f7183a2 --- /dev/null +++ b/app/models/activity_pub/object/profile.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Profile = +# +# Representa artículos +class ActivityPub + class Object + class Profile < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/relationship.rb b/app/models/activity_pub/object/relationship.rb new file mode 100644 index 00000000..ece995b4 --- /dev/null +++ b/app/models/activity_pub/object/relationship.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Relationship = +# +# Representa artículos +class ActivityPub + class Object + class Relationship < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/service.rb b/app/models/activity_pub/object/service.rb new file mode 100644 index 00000000..a276ea5b --- /dev/null +++ b/app/models/activity_pub/object/service.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Service = +class ActivityPub + class Object + class Service < ActivityPub::Object + include Concerns::ActorTypeConcern + end + end +end diff --git a/app/models/activity_pub/object/tombstone.rb b/app/models/activity_pub/object/tombstone.rb new file mode 100644 index 00000000..88f136b9 --- /dev/null +++ b/app/models/activity_pub/object/tombstone.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Tombstone = +# +# Representa artículos +class ActivityPub + class Object + class Tombstone < ActivityPub::Object; end + end +end diff --git a/app/models/activity_pub/object/video.rb b/app/models/activity_pub/object/video.rb new file mode 100644 index 00000000..fa4bbffb --- /dev/null +++ b/app/models/activity_pub/object/video.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# = Video = +# +# Representa artículos +class ActivityPub + class Object + class Video < ActivityPub::Object; end + end +end diff --git a/app/models/actor_moderation.rb b/app/models/actor_moderation.rb index e06ffbb1..01613f72 100644 --- a/app/models/actor_moderation.rb +++ b/app/models/actor_moderation.rb @@ -5,8 +5,8 @@ class ActorModeration < ApplicationRecord include AASM include AasmEventsConcern - IGNORED_EVENTS = [] - IGNORED_STATES = [] + IGNORED_EVENTS = %i[remove] + IGNORED_STATES = %i[removed] belongs_to :site belongs_to :remote_flag, optional: true, class_name: 'ActivityPub::RemoteFlag' @@ -23,11 +23,16 @@ class ActorModeration < ApplicationRecord self.update_all(aasm_state: 'paused', updated_at: Time.now) end + def self.remove_all! + self.update_all(aasm_state: 'removed', updated_at: Time.now) + end + aasm do state :paused, initial: true state :allowed state :blocked state :reported + state :removed event :pause do transitions from: %i[allowed blocked reported], to: :paused @@ -62,6 +67,12 @@ class ActorModeration < ApplicationRecord ActivityPub::RemoteFlagJob.perform_later(remote_flag: remote_flag) if remote_flag.waiting? end end + + # Si un perfil es eliminado remotamente, tenemos que dejar de + # mostrarlo y todas sus actividades. + event :remove do + transitions to: :removed + end end def pause_remotely! diff --git a/app/validators/url_validator.rb b/app/validators/url_validator.rb new file mode 100644 index 00000000..291f9288 --- /dev/null +++ b/app/validators/url_validator.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +# Valida URLs +# +# @see {https://storck.io/posts/better-http-url-validation-in-ruby-on-rails/} +class UrlValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + if value.blank? + record.errors.add(attribute, :url_missing) + return + end + + uri = URI.parse(value) + + record.errors.add(attribute, :scheme_missing) if uri.scheme.blank? + record.errors.add(attribute, :host_missing) if uri.host.blank? + record.errors.add(attribute, :path_missing) if uri.path.blank? + rescue URI::Error + record.errors.add(attribute, :invalid) + end +end diff --git a/app/views/components/_actor.haml b/app/views/components/_actor.haml index 3983d617..c58beae0 100644 --- a/app/views/components/_actor.haml +++ b/app/views/components/_actor.haml @@ -1,5 +1,7 @@ -# Componente Remote_Profile +- uri = text_plain(remote_profile['id']) + .py-2 %dl %dt= t('.profile_name') @@ -10,7 +12,7 @@ %dt= t('.profile_id') %dd - = link_to text_plain(remote_profile['id']) + = link_to uri, uri - if remote_profile['published'].present? %dt= t('.profile_published') diff --git a/db/migrate/20240307201510_remove_actor_moderations.rb b/db/migrate/20240307201510_remove_actor_moderations.rb new file mode 100644 index 00000000..92c6d23a --- /dev/null +++ b/db/migrate/20240307201510_remove_actor_moderations.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +# Mover todes les actores eliminades +class RemoveActorModerations < ActiveRecord::Migration[6.1] + def up + actor_ids = + ActivityPub.where(aasm_state: 'removed', object_type: 'ActivityPub::Object::Person').distinct.pluck(:actor_id) + + ActorModeration.where(id: actor_ids).remove_all! + end + + def down; end +end