social_stream 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
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