Class: Actor
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- Actor
- Defined in:
- app/models/actor.rb
Overview
An Actor is a social entity. This includes individuals, but also groups, departments, organizations even nations or states.
Actors are the nodes of a social network. Two actors are linked by a Tie. The type of a tie is a Relation. Each actor can define and customize their relations.
Actor subtypes
An actor subtype is called a Subject. SocialStream provides 2 actor subtypes, User and Group, but the application developer can define as many actor subtypes as required. Actors subtypes are added to config/initializers/social_stream.rb
Class Method Summary collapse
- .find_by_webfinger!(link) ⇒ Object
-
.normalize(a) ⇒ Object
Get actor from object, if possible.
-
.normalize_id(a) ⇒ Object
Get actor’s id from an object, if possible.
Instance Method Summary collapse
- #activity_relations(subject, options = {}) ⇒ Object
-
#activity_relations?(*args) ⇒ Boolean
Are there any activity_relations present?.
- #avatar! ⇒ Object
-
#can_comment?(activity) ⇒ Boolean
Is this Actor allowed to create a comment on activity?.
-
#comment_relations(activity) ⇒ Object
Are there any relations that allow this actor to create a comment on activity?.
-
#contact_actors(options = {}) ⇒ Object
All the actors this one has relation with.
- #contact_subjects(options = {}) ⇒ Object
-
#contact_to(subject) ⇒ Object
Return a contact to subject.
-
#contact_to!(subject) ⇒ Object
Return a contact to subject.
-
#liked_by(subject) ⇒ Object
:nodoc:.
-
#liked_by?(subject) ⇒ Boolean
Does subject like this Actor?.
-
#likes ⇒ Object
The ‘like’ qualifications emmited to this actor.
- #logo ⇒ Object
-
#mailboxer_email ⇒ Object
Returns the email used for Mailboxer.
-
#new_like(subject) ⇒ Object
Build a new activity where subject like this.
-
#pending_contacts ⇒ Object
Build a new Contact from each that has not inverse.
-
#relation_custom(name) ⇒ Object
A given relation defined and managed by this actor.
- #relation_customs ⇒ Object
-
#relation_public ⇒ Object
The Relation::Public for this Actor.
-
#represented_by?(subject) ⇒ Boolean
Can this actor be represented by subject.
-
#should_email?(object) ⇒ Boolean
Returning whether an email should be sent for this object (Message or Notification).
-
#subject ⇒ Object
The subject instance for this actor.
-
#suggestion(options = {}) ⇒ Contact
By now, it returns a tie suggesting a relation from SuggestedRelations to another subject without any current relation.
-
#suggestions(n) ⇒ Object
Make n suggestions TODO: make more.
-
#ties_to(subject) ⇒ Object
Set of ties sent by this actor received by subject.
- #ties_to?(a) ⇒ Boolean
-
#to_param ⇒ Object
Use slug as parameter.
-
#wall(type, options = {}) ⇒ Object
The set of activities in the wall of this Actor.
Class Method Details
.find_by_webfinger!(link) ⇒ Object
131 132 133 134 135 |
# File 'app/models/actor.rb', line 131 def find_by_webfinger!(link) link =~ /(acct:)?(.*)@/ find_by_slug! $2 end |
.normalize(a) ⇒ Object
Get actor from object, if possible
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'app/models/actor.rb', line 114 def normalize(a) case a when Actor a when Integer Actor.find a when Array a.map{ |e| Actor.normalize(e) } else begin a.actor rescue raise "Unable to normalize actor #{ a.inspect }" end end end |
.normalize_id(a) ⇒ Object
Get actor’s id from an object, if possible
103 104 105 106 107 108 109 110 111 112 |
# File 'app/models/actor.rb', line 103 def normalize_id(a) case a when Integer a when Array a.map{ |e| normalize_id(e) } else Actor.normalize(a).id end end |
Instance Method Details
#activity_relations(subject, options = {}) ⇒ Object
309 310 311 312 313 |
# File 'app/models/actor.rb', line 309 def activity_relations(subject, = {}) return relations if Actor.normalize(subject) == self Array.new end |
#activity_relations?(*args) ⇒ Boolean
Are there any activity_relations present?
316 317 318 |
# File 'app/models/actor.rb', line 316 def activity_relations?(*args) activity_relations(*args).any? end |
#avatar! ⇒ Object
394 395 396 |
# File 'app/models/actor.rb', line 394 def avatar! avatars.active.first || avatars.build end |
#can_comment?(activity) ⇒ Boolean
Is this Actor allowed to create a comment on activity?
We are allowing comments from everyone signed in by now
323 324 325 326 327 |
# File 'app/models/actor.rb', line 323 def can_comment?(activity) return true comment_relations(activity).any? end |
#comment_relations(activity) ⇒ Object
Are there any relations that allow this actor to create a comment on activity?
330 331 332 333 |
# File 'app/models/actor.rb', line 330 def comment_relations(activity) activity.relations.select{ |r| r.is_a?(Relation::Public) } | Relation.allow(self, 'create', 'activity', :in => activity.relations) end |
#contact_actors(options = {}) ⇒ Object
All the actors this one has relation with
Options:
-
type: Filter by the class of the contacts.
-
direction: sent or received
-
relations: Restrict the relations of considered ties. Defaults to relations of custom type
-
include_self: False by default, don’t include this actor as subject even they have ties with themselves.
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'app/models/actor.rb', line 181 def contact_actors( = {}) subject_types = Array([:type] || self.class.subtypes) subject_classes = subject_types.map{ |s| s.to_s.classify } as = Actor.select("DISTINCT actors.*"). where('actors.subject_type' => subject_classes). includes(subject_types) case [:direction] when :sent as = as.joins(:received_ties => :relation).merge(Contact.sent_by(self)) when :received as = as.joins(:sent_ties => :relation).merge(Contact.received_by(self)) else raise "contact actors in both directions are not supported yet" end if [:include_self].blank? as = as.where("actors.id != ?", self.id) end if [:relations].present? as = as.merge(Tie.([:relations])) else as = as.merge(Relation.where(:type => 'Relation::Custom')) end as end |
#contact_subjects(options = {}) ⇒ Object
218 219 220 221 222 223 224 225 226 |
# File 'app/models/actor.rb', line 218 def contact_subjects( = {}) as = contact_actors() if block_given? as = yield(as) end as.map(&:subject) end |
#contact_to(subject) ⇒ Object
Return a contact to subject.
229 230 231 |
# File 'app/models/actor.rb', line 229 def contact_to(subject) sent_contacts.received_by(subject).first end |
#contact_to!(subject) ⇒ Object
Return a contact to subject. Create it if it does not exist
234 235 236 237 |
# File 'app/models/actor.rb', line 234 def contact_to!(subject) contact_to(subject) || sent_contacts.create!(:receiver_id => Actor.normalize_id(subject)) end |
#liked_by(subject) ⇒ Object
:nodoc:
404 405 406 |
# File 'app/models/actor.rb', line 404 def liked_by(subject) #:nodoc: likes.joins(:contact).merge(Contact.sent_by(subject)) end |
#liked_by?(subject) ⇒ Boolean
Does subject like this Actor?
409 410 411 |
# File 'app/models/actor.rb', line 409 def liked_by?(subject) liked_by(subject).present? end |
#likes ⇒ Object
The ‘like’ qualifications emmited to this actor
399 400 401 402 |
# File 'app/models/actor.rb', line 399 def likes Activity.joins(:activity_verb).where('activity_verbs.name' => "like"). joins(:activity_objects).where('activity_objects.id' => activity_object_id) end |
#logo ⇒ Object
390 391 392 |
# File 'app/models/actor.rb', line 390 def logo avatar!.logo end |
#mailboxer_email ⇒ Object
Returns the email used for Mailboxer
139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'app/models/actor.rb', line 139 def mailboxer_email return email if email.present? if (group = self.subject).is_a? Group relation = group.relation_customs.sort.first receivers = group.contact_actors(:direction => :sent, :relations => relation) emails = Array.new receivers.each do |receiver| emails << receiver.email end return emails end end |
#new_like(subject) ⇒ Object
Build a new activity where subject like this
414 415 416 417 418 419 420 421 422 |
# File 'app/models/actor.rb', line 414 def new_like(subject) a = Activity.new :verb => "like", :contact => subject.contact_to!(self), :relation_ids => Array(subject.relation_public.id) a.activity_objects << activity_object a end |
#pending_contacts ⇒ Object
Build a new Contact from each that has not inverse
336 337 338 339 340 341 |
# File 'app/models/actor.rb', line 336 def pending_contacts received_contacts.not_reflexive.pending.all.map do |c| c.inverse || c.receiver.contact_to!(c.sender) end end |
#relation_custom(name) ⇒ Object
A given relation defined and managed by this actor
164 165 166 |
# File 'app/models/actor.rb', line 164 def relation_custom(name) relation_customs.find_by_name(name) end |
#relation_customs ⇒ Object
159 160 161 |
# File 'app/models/actor.rb', line 159 def relation_customs relations.where(:type => 'Relation::Custom') end |
#relation_public ⇒ Object
The Relation::Public for this Actor
169 170 171 |
# File 'app/models/actor.rb', line 169 def relation_public Relation::Public.of(self) end |
#represented_by?(subject) ⇒ Boolean
Can this actor be represented by subject. Does she has permissions for it?
293 294 295 296 297 298 299 300 301 302 |
# File 'app/models/actor.rb', line 293 def represented_by?(subject) return false if subject.blank? self.class.normalize(subject) == self || sent_ties. merge(Contact.received_by(subject)). joins(:relation => :permissions). merge(Permission.represent). any? end |
#should_email?(object) ⇒ Boolean
Returning whether an email should be sent for this object (Message or Notification). Required by Mailboxer gem.
426 427 428 |
# File 'app/models/actor.rb', line 426 def should_email?(object) return notify_by_email end |
#subject ⇒ Object
The subject instance for this actor
153 154 155 156 |
# File 'app/models/actor.rb', line 153 def subject subtype_instance || activity_object.try(:object) end |
#suggestion(options = {}) ⇒ Contact
By now, it returns a tie suggesting a relation from SuggestedRelations to another subject without any current relation
- Options
-
type: the class of the recommended subject
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'app/models/actor.rb', line 255 def suggestion( = {}) candidates_types = ( [:type].present? ? Array([:type]) : self.class.subtypes ) candidates_classes = candidates_types.map{ |t| t.to_s.classify.constantize } # Candidates are all the instance of "type" minus all the subjects # that are receiving any tie from this actor candidates = candidates_classes.inject([]) do |cs, klass| cs += klass.all - contact_subjects(:type => klass.to_s.underscore, :direction => :sent, :relations => relations.to_a) cs -= Array(subject) if subject.is_a?(klass) cs end candidate = candidates[rand(candidates.size)] return nil unless candidate.present? contact_to!(candidate) end |
#suggestions(n) ⇒ Object
Make n suggestions TODO: make more
244 245 246 |
# File 'app/models/actor.rb', line 244 def suggestions(n) n.times.map{ |m| suggestion } end |
#ties_to(subject) ⇒ Object
Set of ties sent by this actor received by subject
279 280 281 |
# File 'app/models/actor.rb', line 279 def ties_to(subject) sent_ties.merge(Contact.received_by(subject)) end |
#ties_to?(a) ⇒ Boolean
283 284 285 |
# File 'app/models/actor.rb', line 283 def ties_to?(subject) ties_to(subject).present? end |
#to_param ⇒ Object
Use slug as parameter
431 432 433 |
# File 'app/models/actor.rb', line 431 def to_param slug end |
#wall(type, options = {}) ⇒ Object
The set of activities in the wall of this Actor.
There are two types of walls:
- home
-
includes all the activities from this Actor and their followed actors
See {Permission } for more information on the following support - profile
-
The set of activities in the wall profile of this Actor, it includes only the activities from the ties of this actor that can be read by the subject
Options:
- :for
-
the subject that is accessing the wall
- :relation
-
show only activities that are attached at this relation level. For example, the wall for members of the group.
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 |
# File 'app/models/actor.rb', line 356 def wall(type, = {}) args = {} args[:type] = type args[:owner] = self # Preserve this options [ :for, :object_type ].each do |opt| args[opt] = [opt] end if type == :home args[:followed] = Actor.followed_by(self).map(&:id) end # TODO: this is not scalling for sure. We must use a fact table in the future args[:relation_ids] = case type when :home # The relations from followings that can be read Relation.allow(self, 'read', 'activity').map(&:id) when :profile # FIXME: options[:relation] # # The relations that can be read by options[:for] [:for].present? ? Relation.allow([:for], 'read', 'activity').map(&:id) : [] else raise "Unknown type of wall: #{ type }" end Activity.wall args end |