social_stream 0.4.3 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. data/app/controllers/api_controller.rb +1 -1
  2. data/app/controllers/contacts_controller.rb +1 -1
  3. data/app/controllers/conversations_controller.rb +5 -5
  4. data/app/controllers/groups_controller.rb +1 -0
  5. data/app/controllers/likes_controller.rb +17 -5
  6. data/app/controllers/messages_controller.rb +3 -1
  7. data/app/controllers/profiles_controller.rb +4 -0
  8. data/app/controllers/representations_controller.rb +12 -1
  9. data/app/controllers/tags_controller.rb +15 -0
  10. data/app/controllers/users_controller.rb +3 -0
  11. data/app/helpers/activities_helper.rb +13 -6
  12. data/app/models/activity.rb +53 -52
  13. data/app/models/activity_object.rb +2 -0
  14. data/app/models/actor.rb +85 -19
  15. data/app/models/avatar.rb +2 -1
  16. data/app/models/like.rb +28 -13
  17. data/app/models/permission.rb +7 -7
  18. data/app/models/profile.rb +1 -1
  19. data/app/models/relation/custom.rb +111 -0
  20. data/app/models/relation/public.rb +42 -0
  21. data/app/models/relation.rb +1 -89
  22. data/app/models/sphere.rb +7 -0
  23. data/app/models/tie.rb +65 -52
  24. data/app/models/tie_activity.rb +38 -0
  25. data/app/views/activities/_new.html.erb +4 -4
  26. data/app/views/activities/_options.html.erb +2 -2
  27. data/app/views/actors/_actor.html.erb +0 -0
  28. data/app/views/avatars/index.html.erb +5 -2
  29. data/app/views/comments/_new.html.erb +2 -2
  30. data/app/views/contacts/index.html.erb +5 -1
  31. data/app/views/conversations/edit.html.erb +4 -0
  32. data/app/views/conversations/index.html.erb +5 -1
  33. data/app/views/conversations/show.html.erb +4 -0
  34. data/app/views/frontpage/index.html.erb +4 -0
  35. data/app/views/groups/_sidebar_index.html.erb +7 -42
  36. data/app/views/groups/index.html.erb +3 -0
  37. data/app/views/groups/new.html.erb +3 -0
  38. data/app/views/groups/show.html.erb +7 -0
  39. data/app/views/layouts/_account.html.erb +16 -0
  40. data/app/views/layouts/_footer.html.erb +1 -1
  41. data/app/views/layouts/_header.erb +7 -22
  42. data/app/views/layouts/_representation.html.erb +25 -12
  43. data/app/views/layouts/application.html.erb +6 -3
  44. data/app/views/layouts/frontpage.html.erb +1 -1
  45. data/app/views/likes/create.js.erb +1 -1
  46. data/app/views/likes/destroy.js.erb +1 -1
  47. data/app/views/messages/new.html.erb +7 -5
  48. data/app/views/profiles/_profile.html.erb +20 -0
  49. data/app/views/profiles/edit.html.erb +42 -0
  50. data/app/views/profiles/show.html.erb +4 -0
  51. data/app/views/profiles/update.js.erb +5 -0
  52. data/app/views/subjects/_toolbar_profile_menu_tie_options.html.erb +3 -1
  53. data/app/views/ties/_new.html.erb +1 -1
  54. data/app/views/users/index.html.erb +4 -0
  55. data/app/views/users/show.html.erb +5 -0
  56. data/config/locales/en.yml +54 -1
  57. data/config/routes.rb +3 -1
  58. data/lib/generators/social_stream/install_generator.rb +2 -1
  59. data/lib/generators/social_stream/templates/migration.rb +23 -27
  60. data/lib/generators/social_stream/templates/public/images/btn/error.png +0 -0
  61. data/lib/generators/social_stream/templates/public/images/btn/info.png +0 -0
  62. data/lib/generators/social_stream/templates/public/images/btn/like.png +0 -0
  63. data/lib/generators/social_stream/templates/public/images/btn/nolike.png +0 -0
  64. data/lib/generators/social_stream/templates/public/images/btn/success.png +0 -0
  65. data/lib/generators/social_stream/templates/public/images/btn/warning.png +0 -0
  66. data/lib/generators/social_stream/templates/public/javascripts/ajax.paginate.js +12 -19
  67. data/lib/generators/social_stream/templates/public/javascripts/jquery.validate.js +1 -1
  68. data/lib/generators/social_stream/templates/public/javascripts/main.js +20 -10
  69. data/lib/generators/social_stream/templates/public/stylesheets/default/base.css +21 -4
  70. data/lib/generators/social_stream/templates/public/stylesheets/default/header.css +8 -3
  71. data/lib/generators/social_stream/templates/relations.yml +7 -13
  72. data/lib/social_stream/ability.rb +39 -20
  73. data/lib/social_stream/controllers/helpers.rb +6 -0
  74. data/lib/social_stream/models/object.rb +8 -4
  75. data/lib/social_stream/models/subject.rb +6 -0
  76. data/lib/social_stream/rails.rb +6 -3
  77. data/lib/social_stream/version.rb +1 -1
  78. data/lib/tasks/db/populate.rake +11 -1
  79. data/social_stream.gemspec +7 -8
  80. data/spec/controllers/comments_controller_spec.rb +6 -2
  81. data/spec/controllers/posts_controller_spec.rb +93 -5
  82. data/spec/controllers/profiles_controller_spec.rb +58 -1
  83. data/spec/controllers/representations_controller_spec.rb +51 -0
  84. data/spec/controllers/users_controller_spec.rb +28 -0
  85. data/spec/dummy/config/relations.yml +7 -13
  86. data/spec/dummy/db/schema.rb +2 -13
  87. data/spec/factories/tie.rb +1 -1
  88. data/spec/models/activity_spec.rb +28 -67
  89. data/spec/models/profile_spec.rb +38 -0
  90. data/spec/models/tie_activity_spec.rb +88 -31
  91. data/spec/models/tie_spec.rb +20 -14
  92. data/spec/support/db.rb +8 -10
  93. data/spec/support/migrations.rb +24 -0
  94. metadata +74 -59
@@ -26,7 +26,7 @@ class ApiController < ApplicationController
26
26
  end
27
27
 
28
28
  @page = params[:page]
29
- @activities = @user.wall(:home).paginate(:page => params[:page], :per_page => 10)
29
+ @activities = @user.wall(:profile).paginate(:page => params[:page], :per_page => 10)
30
30
  respond_to do |format|
31
31
  format.atom
32
32
  end
@@ -8,7 +8,7 @@ class ContactsController < ApplicationController
8
8
  q.alphabetic.
9
9
  letter(params[:letter]).
10
10
  search(params[:search]).
11
- merge(Tie.original.related_by(current_subject.relations.find_by_id(params[:relation])))
11
+ merge(Tie.related_by(current_subject.relations.find_by_id(params[:relation])))
12
12
  }
13
13
 
14
14
  respond_to do |format|
@@ -15,9 +15,9 @@ class ConversationsController < ApplicationController
15
15
 
16
16
  def show
17
17
  if @box.eql? 'trash'
18
- @receipts = @conversation.receipts(@actor).trash
18
+ @receipts = @mailbox.receipts_for(@conversation).trash
19
19
  else
20
- @receipts = @conversation.receipts(@actor).not_trash
20
+ @receipts = @mailbox.receipts_for(@conversation).not_trash
21
21
  end
22
22
  render :action => :show
23
23
  @receipts.mark_as_read
@@ -41,14 +41,14 @@ class ConversationsController < ApplicationController
41
41
  end
42
42
 
43
43
  if params[:reply_all].present?
44
- last_receipt = @conversation.receipts(@actor).last
44
+ last_receipt = @mailbox.receipts_for(@conversation).last
45
45
  @receipt = @actor.reply_to_all(last_receipt, params[:body])
46
46
  end
47
47
 
48
48
  if @box.eql? 'trash'
49
- @receipts = @conversation.receipts(@actor).trash
49
+ @receipts = @mailbox.receipts_for(@conversation).trash
50
50
  else
51
- @receipts = @conversation.receipts(@actor).not_trash
51
+ @receipts = @mailbox.receipts_for(@conversation).not_trash
52
52
  end
53
53
  render :action => :show
54
54
  @receipts.mark_as_read
@@ -7,6 +7,7 @@ class GroupsController < InheritedResources::Base
7
7
  @groups = Group.alphabetic.
8
8
  letter(params[:letter]).
9
9
  search(params[:search]).
10
+ tagged_with(params[:tag]).
10
11
  paginate(:per_page => 10, :page => params[:page])
11
12
 
12
13
  index! do |format|
@@ -1,10 +1,10 @@
1
1
  class LikesController < ApplicationController
2
- before_filter :authenticate_user!
2
+ before_filter :authenticate_user!, :indirect_object
3
3
 
4
4
  # POST /activities/1/like.js
5
5
  def create
6
- @like = Like.new(current_subject, params[:activity_id])
7
-
6
+ @like = Like.build(current_subject, @indirect_id)
7
+
8
8
  respond_to do |format|
9
9
  if @like.save
10
10
  format.js
@@ -16,8 +16,8 @@ class LikesController < ApplicationController
16
16
 
17
17
  # DELETE /activities/1/like.js
18
18
  def destroy
19
- @like = Like.find!(current_subject, params[:activity_id])
20
-
19
+ @like = Like.find!(current_subject, @indirect_id)
20
+
21
21
  respond_to do |format|
22
22
  if @like.destroy
23
23
  format.js
@@ -26,4 +26,16 @@ class LikesController < ApplicationController
26
26
  end
27
27
  end
28
28
  end
29
+
30
+ private
31
+
32
+ def indirect_object
33
+ if params[:activity_id].present?
34
+ @indirect_id = Activity.find(params[:activity_id])
35
+ elsif params[:user_id].present?
36
+ @indirect_id = User.find_by_slug!(params[:user_id])
37
+ elsif params[:group_id].present?
38
+ @indirect_id = Group.find_by_slug!(params[:group_id])
39
+ end
40
+ end
29
41
  end
@@ -1,5 +1,6 @@
1
1
  class MessagesController < ApplicationController
2
2
 
3
+ before_filter :authenticate_user!
3
4
  before_filter :get_mailbox, :get_box, :get_actor
4
5
 
5
6
  def index
@@ -46,6 +47,7 @@ class MessagesController < ApplicationController
46
47
  @receipt = @actor.send_message(@recipients, params[:body], params[:subject])
47
48
  if (@receipt.errors.blank?)
48
49
  @conversation = @receipt.conversation
50
+ flash[:success]="Your message was sent"
49
51
  redirect_to conversation_path(@conversation, :box => :sentbox)
50
52
  else
51
53
  render :action => :new
@@ -77,7 +79,7 @@ class MessagesController < ApplicationController
77
79
  def get_box
78
80
  if params[:box].blank? or !["inbox","sentbox","trash"].include?params[:box]
79
81
  @box = "inbox"
80
- return
82
+ return
81
83
  end
82
84
  @box = params[:box]
83
85
  end
@@ -1,5 +1,9 @@
1
1
  class ProfilesController < InheritedResources::Base
2
2
  belongs_to_subjects(:singleton => true)
3
+
4
+ load_and_authorize_resource :profile,
5
+ :through => SocialStream.subjects,
6
+ :singleton => true
3
7
 
4
8
  respond_to :html, :xml, :js
5
9
  end
@@ -1,8 +1,19 @@
1
1
  # Changes context for users to represent other subjects
2
2
  class RepresentationsController < ApplicationController
3
+ before_filter :load_representation
4
+
5
+ authorize_resource
6
+
3
7
  def create
4
- self.current_subject = Representation.new(params[:representation]).subject
8
+ self.current_subject = @representation.subject
5
9
 
6
10
  redirect_to(request.referer || home_path)
7
11
  end
12
+
13
+ private
14
+
15
+ # Build representation from params
16
+ def load_representation
17
+ @representation = Representation.new(params[:representation])
18
+ end
8
19
  end
@@ -0,0 +1,15 @@
1
+ class TagsController < ApplicationController
2
+ before_filter :authenticate_user!
3
+
4
+ def index
5
+ @tags = ActsAsTaggableOn::Tag.where('name like ?','%'+params[:tag]+'%').limit(10)
6
+ response = @tags.map{ |t| { 'key' => t.name, 'value' => t.name } }.to_json
7
+ if @tags.count == 0
8
+ response = "[{\"key\":\""+params[:tag]+"\" , \"value\":\""+params[:tag]+"\"}]"
9
+ end
10
+
11
+ respond_to do |format|
12
+ format.json { render :text => response}
13
+ end
14
+ end
15
+ end
@@ -1,10 +1,13 @@
1
1
  class UsersController < InheritedResources::Base
2
+ load_and_authorize_resource
3
+
2
4
  respond_to :html, :xml, :js
3
5
 
4
6
  def index
5
7
  @users = User.alphabetic.
6
8
  letter(params[:letter]).
7
9
  search(params[:search]).
10
+ tagged_with(params[:tag]).
8
11
  paginate(:per_page => 10, :page => params[:page])
9
12
 
10
13
  index! do |format|
@@ -1,14 +1,21 @@
1
1
  module ActivitiesHelper
2
-
2
+
3
3
  # Link to 'like' or 'unlike' depending on the like status of the activity to current_subject
4
4
  #
5
- # @param [Activity]
5
+ # @param [Object]
6
6
  # @return [String]
7
- def link_like(activity)
8
- if (activity.liked_by?(current_subject))
9
- link_to t('activity.unlike'), activity_like_path(activity), :method => :delete, :remote => true
7
+ def link_like(object)
8
+ if !user_signed_in?
9
+ link_to image_tag("btn/nolike.png", :class => "menu_icon")+
10
+ t('activity.like'),new_user_session_path
10
11
  else
11
- link_to t('activity.like'), activity_like_path(activity), :method => :post, :remote => true
12
+ if (object.liked_by?(current_subject))
13
+ link_to image_tag("btn/like.png", :class => "menu_icon")+
14
+ t('activity.unlike'), [object, :like], :method => :delete, :remote => true
15
+ else
16
+ link_to image_tag("btn/nolike.png", :class => "menu_icon")+
17
+ t('activity.like'), [object, :like], :method => :post, :remote => true
18
+ end
12
19
  end
13
20
  end
14
21
  end
@@ -10,12 +10,6 @@
10
10
  # There are two types of wall, :home and :profile. Check {Actor#wall} for more information
11
11
  #
12
12
  class Activity < ActiveRecord::Base
13
- # The direction of the sender and receiver subjects compared with the attached tie
14
- SUBJECT_DIRECTIONS = {
15
- :direct => %w(follow make-friend),
16
- :inverse => %w(like post update)
17
- }
18
-
19
13
  has_ancestry
20
14
 
21
15
  belongs_to :activity_verb
@@ -34,8 +28,8 @@ class Activity < ActiveRecord::Base
34
28
  has_many :activity_objects,
35
29
  :through => :activity_object_activities
36
30
 
37
- after_create :like_direct_object
38
-
31
+ after_create :send_notifications
32
+
39
33
  scope :wall, lambda { |type, ties|
40
34
  q = select("DISTINCT activities.*").
41
35
  roots.
@@ -51,9 +45,9 @@ class Activity < ActiveRecord::Base
51
45
  q
52
46
  }
53
47
 
54
- # After an activity is created, it is associated to ties
48
+ # After an activity is created, it is disseminated to follower ties
55
49
  attr_accessor :_tie
56
- after_create :assign_to_ties
50
+ after_create :disseminate_to_ties
57
51
 
58
52
  # The name of the verb of this activity
59
53
  def verb
@@ -70,7 +64,7 @@ class Activity < ActiveRecord::Base
70
64
  # This method provides the {Actor}. Use {#sender_subject} for the {SocialStream::Models::Subject Subject}
71
65
  # ({User}, {Group}, etc..)
72
66
  def sender
73
- direct? ? tie.sender : tie.receiver
67
+ tie.sender
74
68
  end
75
69
 
76
70
  # The {SocialStream::Models::Subject Subject} author of this activity
@@ -78,7 +72,7 @@ class Activity < ActiveRecord::Base
78
72
  # This method provides the {SocialStream::Models::Subject Subject} ({User}, {Group}, etc...).
79
73
  # Use {#sender} for the {Actor}.
80
74
  def sender_subject
81
- direct? ? tie.sender_subject : tie.receiver_subject
75
+ tie.sender_subject
82
76
  end
83
77
 
84
78
  # The wall where the activity is shown belongs to receiver
@@ -86,7 +80,7 @@ class Activity < ActiveRecord::Base
86
80
  # This method provides the {Actor}. Use {#receiver_subject} for the {SocialStream::Models::Subject Subject}
87
81
  # ({User}, {Group}, etc..)
88
82
  def receiver
89
- direct? ? tie.receiver : tie.sender
83
+ tie.receiver
90
84
  end
91
85
 
92
86
  # The wall where the activity is shown belongs to the receiver
@@ -94,7 +88,7 @@ class Activity < ActiveRecord::Base
94
88
  # This method provides the {SocialStream::Models::Subject Subject} ({User}, {Group}, etc...).
95
89
  # Use {#receiver} for the {Actor}.
96
90
  def receiver_subject
97
- direct? ? tie.receiver_subject : tie.sender_subject
91
+ tie.receiver_subject
98
92
  end
99
93
 
100
94
  # The comments about this activity
@@ -108,7 +102,7 @@ class Activity < ActiveRecord::Base
108
102
  end
109
103
 
110
104
  def liked_by(user) #:nodoc:
111
- likes.joins(:ties).where('tie_activities.original' => true).merge(Tie.received_by(user))
105
+ likes.joins(:ties).where('tie_activities.original' => true).merge(Tie.sent_by(user))
112
106
  end
113
107
 
114
108
  # Does user like this activity?
@@ -118,9 +112,14 @@ class Activity < ActiveRecord::Base
118
112
 
119
113
  # Build a new children activity where subject like this
120
114
  def new_like(subject)
121
- children.new :verb => "like",
122
- :_tie => subject.sent_ties(:receiver => receiver,
123
- :relation => relation).first
115
+ a = children.new :verb => "like",
116
+ :_tie => subject.sent_ties(:receiver => receiver).first
117
+
118
+ if direct_activity_object.present?
119
+ a.activity_objects << direct_activity_object
120
+ end
121
+
122
+ a
124
123
  end
125
124
 
126
125
  # The first activity object of this activity
@@ -136,7 +135,7 @@ class Activity < ActiveRecord::Base
136
135
  # The title for this activity in the stream
137
136
  def title view
138
137
  case verb
139
- when "follow", "make-friend"
138
+ when "follow", "make-friend", "like"
140
139
  I18n.t "activity.verb.#{ verb }.#{ tie.receiver.subject_type }.title",
141
140
  :subject => view.link_name(sender_subject),
142
141
  :contact => view.link_name(receiver_subject)
@@ -144,47 +143,49 @@ class Activity < ActiveRecord::Base
144
143
  view.link_name sender_subject
145
144
  end.html_safe
146
145
  end
146
+
147
+ def notificable?
148
+ return true if is_root?
149
+ return true if ['post','update'].include? root.verb
150
+ #return false if ['follow','like','make_friend'].include? root.verb #Not necessary
151
+ return false
152
+ end
153
+
154
+ def notify
155
+ return nil if !notificable?
156
+ #Avaible verbs: follow, like, make-friend, post, update
157
+ case verb
158
+ when 'like'
159
+ #Like a SUBJECT
160
+
161
+ #Like an OBJECT
162
+
163
+ when 'follow','make_friend'
164
+ #Follow or Make friend with a SUBJECT
165
+ receipts = _tie.receiver.notify(I18n.t("activity.verb." + verb + "." + _tie.receiver_subject.class.to_s + ".notification.subject", :name => _tie.sender.name),
166
+ I18n.t("activity.verb." + verb + "." + _tie.receiver_subject.class.to_s + ".notification.body", :name => _tie.sender.name))
167
+ when 'post','update'
168
+ #Post or udapte an OBJECT
169
+ if _tie.sender!=_tie.receiver
170
+ receipts = _tie.receiver.notify(I18n.t("activity.verb." + verb + "." + _tie.receiver_subject.class.to_s + ".notification.subject", :name => _tie.sender.name, :direct_object => direct_object.class.to_s),
171
+ I18n.t("activity.verb." + verb + "." + _tie.receiver_subject.class.to_s + ".notification.body", :name => _tie.sender.name, :direct_object => direct_object.class.to_s))
172
+ end
173
+ end
174
+ end
147
175
 
148
176
  private
149
177
 
150
178
  # Assign to ties of followers
151
- def assign_to_ties
152
- original = tie_activities.create!(:tie => _tie)
153
-
154
- # All the ties following the activities attached to this tie, allowed to read
155
- # this activity
156
- Tie.following([_tie.sender_id, _tie.receiver_id]).each do |t|
157
- if _tie.allows?(t.sender_id, 'read', 'activity')
158
- tie_activities.create!(:tie => t,
159
- :original => false)
160
- end
161
- end
179
+ def disseminate_to_ties
180
+ # Create the original sender tie_activity
181
+ tie_activities.create!(:tie => _tie)
162
182
  end
163
183
 
164
- # Link like activities with parent direct object
165
- def like_direct_object
166
- return unless verb == "like"
167
-
168
- return if parent.direct_object.blank?
169
-
170
- activity_objects << parent.direct_activity_object
171
- end
172
184
 
173
185
  private
174
186
 
175
- # The {#sender} and the {#receiver} of the {Activity} depends on its {ActivityVerb}
176
- #
177
- # Contact activities such as make-friend or follow are direct. They have the same sender
178
- # and receiver as their tie. On the other hand, post activities are inverse. The sender of
179
- # the activity is the receiver of the tie and the receiver of the activity is the sender of
180
- # the tie
181
- def direct?
182
- if SUBJECT_DIRECTIONS[:direct].include?(verb)
183
- true
184
- elsif SUBJECT_DIRECTIONS[:inverse].include?(verb)
185
- false
186
- else
187
- raise "Unknown direction for verb #{ verb }"
188
- end
187
+ #Send notifications to actors based on proximity, interest and permissions
188
+ def send_notifications
189
+ notify
189
190
  end
190
191
  end
@@ -12,6 +12,8 @@ class ActivityObject < ActiveRecord::Base
12
12
  @subtypes_name = :object
13
13
  include SocialStream::Models::Supertype
14
14
 
15
+ acts_as_taggable
16
+
15
17
  has_many :activity_object_activities, :dependent => :destroy
16
18
  has_many :activities, :through => :activity_object_activities
17
19
  has_one :actor
data/app/models/actor.rb CHANGED
@@ -14,16 +14,19 @@ class Actor < ActiveRecord::Base
14
14
  @subtypes_name = :subject
15
15
  include SocialStream::Models::Supertype
16
16
 
17
+ delegate :tag_list, :tag_list=, :tagged_with, :tag_counts, :to => :activity_object
18
+
17
19
  validates_presence_of :name, :subject_type
18
20
 
19
21
  acts_as_messageable
22
+
20
23
  acts_as_url :name, :url_attribute => :slug
21
24
 
22
25
  has_one :profile, :dependent => :destroy
23
26
 
24
27
  has_many :avatars,
25
- :validate => true,
26
- :autosave => true
28
+ :validate => true,
29
+ :autosave => true
27
30
 
28
31
  has_many :sent_ties,
29
32
  :class_name => "Tie",
@@ -43,6 +46,10 @@ class Actor < ActiveRecord::Base
43
46
  :through => :sent_ties,
44
47
  :uniq => true
45
48
 
49
+ has_many :spheres
50
+
51
+ has_many :relations, :through => :spheres
52
+
46
53
  scope :alphabetic, order('actors.name')
47
54
 
48
55
  scope :letter, lambda { |param|
@@ -56,6 +63,12 @@ class Actor < ActiveRecord::Base
56
63
  where('actors.name LIKE ?', "%#{ param }%")
57
64
  end
58
65
  }
66
+
67
+ scope :tagged_with, lambda { |param|
68
+ if param.present?
69
+ joins(:activity_object).merge(ActivityObject.tagged_with(param))
70
+ end
71
+ }
59
72
 
60
73
  scope :distinct_initials, select('DISTINCT SUBSTR(actors.name,1,1) as initial').order("initial ASC")
61
74
 
@@ -121,15 +134,15 @@ class Actor < ActiveRecord::Base
121
134
  Tie.sent_or_received_by(self)
122
135
  end
123
136
 
124
- # Relations defined and managed by this actor
125
- def relations
126
- Relation.includes(:ties).merge(Tie.sent_by(self))
127
- end
128
-
129
137
  # A given relation defined and managed by this actor
130
138
  def relation(name)
131
139
  relations.find_by_name(name)
132
140
  end
141
+
142
+ # The {Relation::Public} for this {Actor}
143
+ def relation_public
144
+ Relation::Public.of(self)
145
+ end
133
146
 
134
147
  # All the {Actor actors} this one has relation with
135
148
  #
@@ -229,18 +242,39 @@ class Actor < ActiveRecord::Base
229
242
 
230
243
  # Set of ties sent by this actor received by a
231
244
  def ties_to(a)
232
- sent_ties.received_by(a).original
245
+ sent_ties.received_by(a)
246
+ end
247
+
248
+ # Get the first of the ties created to a, or create a new one with the {Relation::Public}
249
+ def ties_to!(a)
250
+ ties_to(a).present? ?
251
+ ties_to(a) :
252
+ Array(sent_ties.create!(:receiver => a,
253
+ :relation => relation_public))
233
254
  end
234
255
 
235
256
  def ties_to?(a)
236
257
  ties_to(a).present?
237
258
  end
238
-
239
- # All the ties this actor has with subject that support permission
240
- def sent_ties_allowing(subject, action, objective)
259
+
260
+ # The sent {Tie ties} by this {Actor} that grant subject the permission to perform action on object
261
+ def allow(subject, action, object = nil)
241
262
  return [] if subject.blank?
242
-
243
- sent_ties.allowing(subject, action, objective)
263
+
264
+ sent_ties.allowing(subject, action, object)
265
+ end
266
+
267
+ # Does this {Actor} have any {Tie} to subject that grants her the permission of performing action on object
268
+ def allow?(subject, action, object = nil)
269
+ allow(subject, action, object).any?
270
+ end
271
+
272
+ # Can this actor be represented by subject. Does she has permissions for it?
273
+ def represented_by?(subject)
274
+ return false if subject.blank?
275
+
276
+ self.class.normalize(subject) == self ||
277
+ allow?(subject, 'represent')
244
278
  end
245
279
 
246
280
  # The ties that allow attaching an activity to them. This method is used for caching
@@ -248,10 +282,17 @@ class Actor < ActiveRecord::Base
248
282
  @active_ties ||= {}
249
283
  end
250
284
 
251
- # The ties that allow subject creating activities for this actor
252
- def active_ties_for(subject)
285
+ # This {Actor} #allow s subject to create activities and subject has at least one tie to subject
286
+ def activity_ties_for(subject)
253
287
  active_ties[subject] ||=
254
- sent_ties_allowing(subject, 'create', 'activity')
288
+ ( allow?(subject, 'create', 'activity') ?
289
+ subject.ties_to!(self) :
290
+ [] )
291
+ end
292
+
293
+ # Is there any {Tie} for subject to create an activity to this {Actor} ?
294
+ def activity_ties_for?(subject)
295
+ activity_ties_for(subject).any?
255
296
  end
256
297
 
257
298
  def pending_ties
@@ -278,8 +319,7 @@ class Actor < ActiveRecord::Base
278
319
  ts = ties
279
320
 
280
321
  if type == :profile
281
- # FIXME: show public activities
282
- return [] if options[:for].blank?
322
+ return ties.public_relation if options[:for].blank?
283
323
 
284
324
  ts = ts.allowing(options[:for], 'read', 'activity')
285
325
  end
@@ -299,10 +339,36 @@ class Actor < ActiveRecord::Base
299
339
  avatars.active.first || avatars.build
300
340
  end
301
341
 
342
+ # The 'like' qualifications emmited to this actor
343
+ def likes
344
+ Activity.joins(:activity_verb).where('activity_verbs.name' => "like").
345
+ joins(:activity_objects).where('activity_objects.id' => activity_object_id)
346
+ end
347
+
348
+ def liked_by(subject) #:nodoc:
349
+ likes.joins(:ties).where('tie_activities.original' => true).merge(Tie.sent_by(subject))
350
+ end
351
+
352
+ # Does subject like this {Actor}?
353
+ def liked_by?(subject)
354
+ liked_by(subject).present?
355
+ end
356
+
357
+ # Build a new activity where subject like this
358
+ def new_like(subject)
359
+ a = Activity.new :verb => "like",
360
+ :_tie => subject.ties_to(self).first
361
+
362
+ a.activity_objects << activity_object
363
+
364
+ a
365
+ end
366
+
302
367
  private
303
368
 
304
369
  # After create callback
305
370
  def create_initial_relations
306
- Relation.defaults_for(self)
371
+ Relation::Custom.defaults_for(self)
372
+ Relation::Public.default_for(self)
307
373
  end
308
374
  end
data/app/models/avatar.rb CHANGED
@@ -2,7 +2,8 @@ require 'RMagick'
2
2
 
3
3
  class Avatar < ActiveRecord::Base
4
4
  has_attached_file :logo,
5
- :styles => { :tie => "30x30>",
5
+ :styles => { :representation => "20x20>",
6
+ :tie => "30x30>",
6
7
  :actor => '35x35>',
7
8
  :profile => '94x94' },
8
9
  :default_url => "/images/logos/:style/:subtype_class.png"
data/app/models/like.rb CHANGED
@@ -1,34 +1,49 @@
1
1
  # Convenience class for managing like activities
2
2
  class Like
3
- attr_reader :activity
3
+ attr_reader :object
4
4
 
5
5
  class << self
6
6
  # Find the children activity of activity_id liked by subject
7
- def find(subject, activity_id)
8
- find_activity(activity_id).liked_by(subject).first
7
+ def find(subject, object)
8
+ like = new(object.liked_by(subject).first)
9
+ # Cache object to make it available before it is destroyed
10
+ like.object
11
+ like
9
12
  end
10
13
 
11
14
  # Like #find but raises error if not found
12
- def find!(subject, activity_id)
13
- find(subject, activity_id) ||
15
+ def find!(subject, object)
16
+ find(subject, object) ||
14
17
  raise(ActiveRecord::RecordNotFound)
15
18
  end
16
19
 
17
- # Find the activity that is liked
18
- def find_activity(id)
19
- Activity.find(id) ||
20
- raise(ActiveRecord::RecordNotFound)
20
+ def build(subject, object)
21
+ new object.new_like(subject)
21
22
  end
22
23
  end
23
24
 
24
25
  # Initialize a new like activity
25
- def initialize(subject, activity_id)
26
- @subject = subject
27
- @activity = self.class.find_activity(activity_id)
28
- @like = @activity.new_like(@subject)
26
+ def initialize(activity)
27
+ @like = activity
29
28
  end
30
29
 
31
30
  def save
32
31
  @like.save
33
32
  end
33
+
34
+ # The object that is liked. It can be an activity
35
+ def object
36
+ @object ||=
37
+ if @like.is_root?
38
+ obj = @like.direct_object
39
+ obj = obj.subject if obj.is_a?(Actor)
40
+ obj
41
+ else
42
+ @like.parent
43
+ end
44
+ end
45
+
46
+ def destroy
47
+ @like.destroy
48
+ end
34
49
  end