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?.
-
#common_contacts_count(subject) ⇒ Object
Count the contacts in common between this Actor and subject.
-
#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.
- #ego_contact ⇒ Object
-
#egocentric_ties ⇒ Object
The ties sent by this actor, plus the second grade ties.
-
#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) ⇒ Object
Returning the email address of the model if an email should be sent for this object (Message or Notification).
-
#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.
- #pending_contacts? ⇒ Boolean
- #pending_contacts_count ⇒ Object
-
#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.
-
#relation_reject ⇒ Object
The Relation::Reject for this Actor.
-
#represented_by?(subject) ⇒ Boolean
Can this actor be represented by subject.
- #sent_active_contact_ids ⇒ Object
-
#subject ⇒ Object
The subject instance for this actor.
- #suggestions(size = 1) ⇒ Contact
-
#ties_to(subject) ⇒ Object
Set of ties sent by this actor received by subject.
-
#ties_to?(subject) ⇒ Boolean
Is there any Tie sent by this actor and received by subject.
-
#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
142 143 144 145 146 |
# File 'app/models/actor.rb', line 142 def find_by_webfinger!(link) link =~ /(acct:)?(.*)@/ find_by_slug! $2 end |
.normalize(a) ⇒ Object
Get actor from object, if possible
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'app/models/actor.rb', line 125 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
114 115 116 117 118 119 120 121 122 123 |
# File 'app/models/actor.rb', line 114 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
347 348 349 350 351 352 353 |
# File 'app/models/actor.rb', line 347 def activity_relations(subject, = {}) if Actor.normalize(subject) == self return relation_customs + Array.wrap(relation_public) else Array.new end end |
#activity_relations?(*args) ⇒ Boolean
Are there any activity_relations present?
356 357 358 |
# File 'app/models/actor.rb', line 356 def activity_relations?(*args) activity_relations(*args).any? end |
#avatar! ⇒ Object
447 448 449 |
# File 'app/models/actor.rb', line 447 def avatar! avatar || 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
363 364 365 366 367 |
# File 'app/models/actor.rb', line 363 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?
370 371 372 373 |
# File 'app/models/actor.rb', line 370 def comment_relations(activity) activity.relations.select{ |r| r.is_a?(Relation::Public) } | Relation.allow(self, 'create', 'activity', :in => activity.relations) end |
#common_contacts_count(subject) ⇒ Object
Count the contacts in common between this Actor and subject
392 393 394 |
# File 'app/models/actor.rb', line 392 def common_contacts_count(subject) (sent_active_contact_ids & subject.sent_active_contact_ids).size 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. In the case of both directions, only relations belonging to Actor are valid. It defaults to relations of custom and public types
-
include_self: False by default, don’t include this actor as subject even they have ties with themselves.
-
load_subjects: True by default, make the queries for eager loading of contacts
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
# File 'app/models/actor.rb', line 215 def contact_actors( = {}) subject_types = Array([:type] || self.class.subtypes) subject_classes = subject_types.map{ |s| s.to_s.classify } as = Actor.select('actors.*'). # PostgreSQL requires that all the columns must be included in the GROUP BY group((Actor.columns.map(&:name).map{ |c| "actors.#{ c }" } + [ "contacts.created_at" ]).join(", ")). where('actors.subject_type' => subject_classes) if [:load_subjects].nil? || [:load_subjects] as = as.includes(subject_types) end # Make another query for getting the actors in the other way if [:direction].blank? rcv_opts = .dup rcv_opts[:direction] = :received rcv_opts[:load_subjects] = false sender_ids = contact_actors(rcv_opts).map(&:id) as = as.where(:id => sender_ids) [:direction] = :sent end 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 "How do you get here?!" 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', 'Relation::Public'])) end as end |
#contact_subjects(options = {}) ⇒ Object
269 270 271 272 273 274 275 276 277 |
# File 'app/models/actor.rb', line 269 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.
280 281 282 |
# File 'app/models/actor.rb', line 280 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
285 286 287 288 |
# File 'app/models/actor.rb', line 285 def contact_to!(subject) contact_to(subject) || sent_contacts.create!(:receiver => Actor.normalize(subject)) end |
#ego_contact ⇒ Object
291 292 293 |
# File 'app/models/actor.rb', line 291 def ego_contact contact_to!(self) end |
#egocentric_ties ⇒ Object
The ties sent by this actor, plus the second grade ties
324 325 326 327 |
# File 'app/models/actor.rb', line 324 def egocentric_ties @egocentric_ties ||= load_egocentric_ties end |
#liked_by(subject) ⇒ Object
:nodoc:
457 458 459 |
# File 'app/models/actor.rb', line 457 def liked_by(subject) #:nodoc: likes.joins(:contact).merge(Contact.sent_by(subject)) end |
#liked_by?(subject) ⇒ Boolean
Does subject like this Actor?
462 463 464 |
# File 'app/models/actor.rb', line 462 def liked_by?(subject) liked_by(subject).present? end |
#likes ⇒ Object
The ‘like’ qualifications emmited to this actor
452 453 454 455 |
# File 'app/models/actor.rb', line 452 def likes Activity.joins(:activity_verb).where('activity_verbs.name' => "like"). joins(:activity_objects).where('activity_objects.id' => activity_object_id) end |
#logo ⇒ Object
443 444 445 |
# File 'app/models/actor.rb', line 443 def logo avatar!.logo end |
#mailboxer_email(object) ⇒ Object
Returning the email address of the model if an email should be sent for this object (Message or Notification). If the actor is a Group and has no email address, an array with the email of the highest rank members will be returned isntead.
If no mail has to be sent, return nil.
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'app/models/actor.rb', line 154 def mailboxer_email(object) #If actor has disabled the emails, return nil. return nil if !notify_by_email #If actor has enabled the emails and has email return "#{name} <#{email}>" if email.present? #If actor is a Group, has enabled emails but no mail we return the highest_rank ones. 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| receiver_emails = receiver.mailboxer_email(object) case receiver_emails when String emails << receiver_emails when Array receiver_emails.each do |receiver_email| emails << receiver_email end end end return emails end end |
#new_like(subject) ⇒ Object
Build a new activity where subject like this
467 468 469 470 471 472 473 474 475 |
# File 'app/models/actor.rb', line 467 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
384 385 386 387 388 389 |
# File 'app/models/actor.rb', line 384 def pending_contacts received_contacts.pending.includes(:inverse).all.map do |c| c.inverse || c.receiver.contact_to!(c.sender) end end |
#pending_contacts? ⇒ Boolean
379 380 381 |
# File 'app/models/actor.rb', line 379 def pending_contacts? pending_contacts_count > 0 end |
#pending_contacts_count ⇒ Object
375 376 377 |
# File 'app/models/actor.rb', line 375 def pending_contacts_count received_contacts.not_reflexive.pending.count end |
#relation_custom(name) ⇒ Object
A given relation defined and managed by this actor
190 191 192 |
# File 'app/models/actor.rb', line 190 def relation_custom(name) relation_customs.find_by_name(name) end |
#relation_customs ⇒ Object
185 186 187 |
# File 'app/models/actor.rb', line 185 def relation_customs relations.where(:type => 'Relation::Custom') end |
#relation_public ⇒ Object
The Relation::Public for this Actor
195 196 197 |
# File 'app/models/actor.rb', line 195 def relation_public Relation::Public.of(self) end |
#relation_reject ⇒ Object
The Relation::Reject for this Actor
200 201 202 |
# File 'app/models/actor.rb', line 200 def relation_reject Relation::Reject.of(self) end |
#represented_by?(subject) ⇒ Boolean
Can this actor be represented by subject. Does she has permissions for it?
331 332 333 334 335 336 337 338 339 340 |
# File 'app/models/actor.rb', line 331 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 |
#sent_active_contact_ids ⇒ Object
295 296 297 298 |
# File 'app/models/actor.rb', line 295 def sent_active_contact_ids @sent_active_contact_ids ||= load_sent_active_contact_ids end |
#subject ⇒ Object
The subject instance for this actor
180 181 182 |
# File 'app/models/actor.rb', line 180 def subject subtype_instance end |
#suggestions(size = 1) ⇒ Contact
303 304 305 306 307 308 309 310 311 |
# File 'app/models/actor.rb', line 303 def suggestions(size = 1) candidates = Actor.where(Actor.arel_table[:id].not_in(sent_active_contact_ids + [id])) size.times.map { candidates.delete_at rand(candidates.size) }.compact.map { |a| contact_to! a } end |
#ties_to(subject) ⇒ Object
Set of ties sent by this actor received by subject
314 315 316 |
# File 'app/models/actor.rb', line 314 def ties_to(subject) sent_ties.merge(Contact.received_by(subject)) end |
#ties_to?(subject) ⇒ Boolean
Is there any Tie sent by this actor and received by subject
319 320 321 |
# File 'app/models/actor.rb', line 319 def ties_to?(subject) ties_to(subject).present? end |
#to_param ⇒ Object
Use slug as parameter
478 479 480 |
# File 'app/models/actor.rb', line 478 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.
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
# File 'app/models/actor.rb', line 409 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 |