# frozen_string_literal: true require 'httparty' # Listas de bloqueo y sus URLs de descarga class ActivityPub class Fediblock < ApplicationRecord class Client include ::HTTParty # @param url [String] # @return [HTTParty::Response] def get(url) self.class.get(url, parser: csv_parser) end # Procesa el CSV # # @return [Proc] def csv_parser @csv_parser ||= begin require 'csv' proc do |body, _| CSV.parse(body, headers: true) end end end end class FediblockDownloadError < ::StandardError; end validates_presence_of :title, :url, :format validates_inclusion_of :format, in: %w[mastodon fediblock none] HOSTNAME_HEADERS = { 'mastodon' => '#domain', 'fediblock' => 'domain' }.freeze def client @client ||= Client.new end # Todas las instancias de este fediblock def instances ActivityPub::Instance.where(hostname: hostnames) end # Descarga la lista y crea las instancias con el estado necesario def process! response = client.get(download_url) raise FediblockDownloadError unless response.success? Fediblock.transaction do csv = response.parsed_response process_csv! csv update(hostnames: csv.map { |r| r[hostname_header] }) end end private def hostname_header HOSTNAME_HEADERS[format] end # Crea o encuentra instancias que ya existían y las bloquea # # @param csv [CSV::Table] def process_csv!(csv) csv.each do |row| ActivityPub::Instance.find_or_create_by(hostname: row[hostname_header]).tap do |i| i.block! if i.may_block? end end end end end