Class: Fedipub::Actor

Inherits:
ApplicationRecord show all
Includes:
Announceable, HandlesDeleteRequests, HasUuid, Likeable
Defined in:
app/models/fedipub/actor.rb

Overview

Model storing distant actors and links to local ones.

To make a model act as an actor, use the Fedipub::ActorEntity concern

See also:

Defined Under Namespace

Classes: TombstonedError

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Announceable

#announce!

Methods included from Likeable

#dislike!, #like!

Methods included from HasUuid

#to_param, #uuid

Class Method Details

.find_by_account(account) ⇒ Fedipub::Actor?

Searches for an actor from account URI

Parameters:

  • account (String)

    Account URI (username@host)

Returns:



180
181
182
183
184
185
186
187
188
189
190
191
# File 'app/models/fedipub/actor.rb', line 180

def ()
  parts = Fediverse::Webfinger. 

  if Fediverse::Webfinger.local_user? parts
    actor = find_local_by_username! parts[:username]
  else
    actor = find_by username: parts[:username], server: parts[:domain]
    actor ||= Fediverse::Webfinger.fetch_actor(parts[:username], parts[:domain])
  end

  actor
end

.find_by_federation_url(federated_url) ⇒ Object



193
194
195
196
197
198
199
200
201
# File 'app/models/fedipub/actor.rb', line 193

def find_by_federation_url(federated_url)
  local_route = Utils::Host.local_route federated_url
  return find_param(local_route[:id]) if local_route && local_route[:controller] == 'fedipub/server/actors' && local_route[:action] == 'show'

  actor = find_by federated_url: federated_url
  return actor if actor

  Fediverse::Webfinger.fetch_actor_url(federated_url)
end

.find_by_federation_url!(federated_url) ⇒ Object



203
204
205
206
207
208
# File 'app/models/fedipub/actor.rb', line 203

def find_by_federation_url!(federated_url)
  find_by_federation_url(federated_url).tap do |actor|
    raise Fedipub::Actor::TombstonedError if actor.tombstoned?
    raise ActiveRecord::RecordNotFound if actor.nil?
  end
end

.find_local_by_username(username) ⇒ Object



238
239
240
241
242
243
244
245
246
247
248
249
# File 'app/models/fedipub/actor.rb', line 238

def find_local_by_username(username)
  actor = nil
  Fedipub::Configuration.actor_types.each_value do |entity|
    break if actor.present?

    actor = entity[:class].find_by(entity[:username_field] => username)&.fedipub_actor
  end
  return actor if actor

  # Last hope: Search for tombstoned actors
  Fedipub::Actor.local.tombstoned.find_by username: username
end

.find_local_by_username!(username) ⇒ Object



251
252
253
254
255
# File 'app/models/fedipub/actor.rb', line 251

def find_local_by_username!(username)
  find_local_by_username(username).tap do |actor|
    raise ActiveRecord::RecordNotFound if actor.nil?
  end
end

.find_or_create_by_account(account) ⇒ Object



210
211
212
213
214
215
216
# File 'app/models/fedipub/actor.rb', line 210

def ()
  actor =  
  # Create/update distant actors
  actor.save! unless actor.local?

  actor
end

.find_or_create_by_federation_url(url) ⇒ Object



218
219
220
221
222
223
224
# File 'app/models/fedipub/actor.rb', line 218

def find_or_create_by_federation_url(url)
  actor = find_by_federation_url url
  # Create/update distant actors
  actor.save! unless actor.local?

  actor
end

.find_or_create_by_object(object) ⇒ Object

Find or create actor from a given actor hash or actor id (actor's URL)



227
228
229
230
231
232
233
234
235
236
# File 'app/models/fedipub/actor.rb', line 227

def find_or_create_by_object(object)
  case object
  when String
    find_or_create_by_federation_url object
  when Hash
    find_or_create_by_federation_url object['id']
  else
    raise "Unsupported object type for actor (#{object.class})"
  end
end

Instance Method Details

#acct_uriObject



118
119
120
# File 'app/models/fedipub/actor.rb', line 118

def acct_uri
  "acct:#{username}@#{server}"
end

#actor_typeObject



81
82
83
# File 'app/models/fedipub/actor.rb', line 81

def actor_type
  use_entity_attributes? ? entity_configuration[:actor_type] : attributes['actor_type']
end

#at_address(prefix: '@') ⇒ Object



110
111
112
# File 'app/models/fedipub/actor.rb', line 110

def at_address(prefix: '@')
  "#{prefix}#{username}@#{server}"
end

#distant?Boolean

Returns:

  • (Boolean)


57
58
59
# File 'app/models/fedipub/actor.rb', line 57

def distant?
  !local?
end

#entity_configurationObject



142
143
144
145
146
# File 'app/models/fedipub/actor.rb', line 142

def entity_configuration
  raise("Entity not configured for #{entity_type}. Did you use \"acts_as_fedipub_actor\"?") unless Fedipub.actor_entity? entity_type

  Fedipub.actor_entity entity_type
end

#federated_urlObject



61
62
63
# File 'app/models/fedipub/actor.rb', line 61

def federated_url
  use_entity_attributes? ? Fedipub::Engine.routes.url_helpers.server_actor_url(self) : attributes['federated_url'].presence
end

#followed_by?(actor) ⇒ Fedipub::Following, false

Checks if current actor is followed by the given actor

Returns:



135
136
137
138
139
140
# File 'app/models/fedipub/actor.rb', line 135

def followed_by?(actor)
  list = following_followers.where actor: actor
  return list.first if list.one?

  false
end

#followers_urlObject



93
94
95
# File 'app/models/fedipub/actor.rb', line 93

def followers_url
  use_entity_attributes? ? Fedipub::Engine.routes.url_helpers.followers_server_actor_url(self) : attributes['followers_url']
end

#followings_urlObject



97
98
99
# File 'app/models/fedipub/actor.rb', line 97

def followings_url
  use_entity_attributes? ? Fedipub::Engine.routes.url_helpers.following_server_actor_url(self) : attributes['followings_url']
end

#follows?(actor) ⇒ Fedipub::Following, false

Checks if a given actor follows the current actor

Returns:



125
126
127
128
129
130
# File 'app/models/fedipub/actor.rb', line 125

def follows?(actor)
  list = following_follows.where target_actor: actor
  return list.first if list.one?

  false
end

#inbox_urlObject



85
86
87
# File 'app/models/fedipub/actor.rb', line 85

def inbox_url
  use_entity_attributes? ? Fedipub::Engine.routes.url_helpers.server_actor_inbox_url(self) : attributes['inbox_url']
end

#key_idObject



268
269
270
# File 'app/models/fedipub/actor.rb', line 268

def key_id
  "#{federated_url}#main-key"
end

#nameObject



71
72
73
74
75
# File 'app/models/fedipub/actor.rb', line 71

def name
  value = (entity.send(entity_configuration[:name_field]).to_s if use_entity_attributes?)

  value || attributes['name'] || username
end

#outbox_urlObject



89
90
91
# File 'app/models/fedipub/actor.rb', line 89

def outbox_url
  use_entity_attributes? ? Fedipub::Engine.routes.url_helpers.server_actor_outbox_url(self) : attributes['outbox_url']
end

#private_keyObject



263
264
265
266
# File 'app/models/fedipub/actor.rb', line 263

def private_key
  ensure_key_pair_exists!
  self[:private_key]
end

#profile_urlObject



101
102
103
104
105
106
107
108
# File 'app/models/fedipub/actor.rb', line 101

def profile_url
  return attributes['profile_url'].presence unless use_entity_attributes?

  method = entity_configuration[:profile_url_method]
  return Fedipub::Engine.routes.url_helpers.server_actor_url self unless method

  Rails.application.routes.url_helpers.send method, [entity]
end

#public_keyObject



258
259
260
261
# File 'app/models/fedipub/actor.rb', line 258

def public_key
  ensure_key_pair_exists!
  self[:public_key]
end

#serverObject



77
78
79
# File 'app/models/fedipub/actor.rb', line 77

def server
  use_entity_attributes? ? Utils::Host.localhost : attributes['server']
end

#short_at_addressObject



114
115
116
# File 'app/models/fedipub/actor.rb', line 114

def short_at_address
  use_entity_attributes? ? "@#{username}" : at_address
end

#sync!Object

Synchronizes actor with distant data

Raises:

  • (ActiveRecord::RecordNotFound)

    when distant data was not found



151
152
153
154
155
156
157
158
159
160
161
# File 'app/models/fedipub/actor.rb', line 151

def sync!
  if local?
    Rails.logger.info 'Ignored attempt to sync a local actor'
    return false
  end

  response = Fediverse::Webfinger.fetch_actor_url(federated_url)
  new_attributes = response.attributes.except 'id', 'uuid', 'created_at', 'updated_at', 'local', 'entity_id', 'entity_type'

  update! new_attributes
end

#tombstone!Object



167
168
169
# File 'app/models/fedipub/actor.rb', line 167

def tombstone!
  Fedipub::Utils::Actor.tombstone! self
end

#tombstoned?Boolean

Returns:

  • (Boolean)


163
164
165
# File 'app/models/fedipub/actor.rb', line 163

def tombstoned?
  tombstoned_at.present?
end

#untombstone!Object



171
172
173
# File 'app/models/fedipub/actor.rb', line 171

def untombstone!
  Fedipub::Utils::Actor.untombstone! self
end

#usernameObject



65
66
67
68
69
# File 'app/models/fedipub/actor.rb', line 65

def username
  return attributes['username'] unless use_entity_attributes?

  entity.send(entity_configuration[:username_field]).to_s
end