social_stream-base 0.19.2 → 0.20.0

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 (50) hide show
  1. data/app/assets/javascripts/social_stream.follow.js +23 -0
  2. data/app/assets/javascripts/social_stream.wall.js.erb +3 -3
  3. data/app/controllers/search_controller.rb +30 -16
  4. data/app/helpers/location_helper.rb +1 -44
  5. data/app/helpers/search_helper.rb +7 -7
  6. data/app/models/activity.rb +0 -21
  7. data/app/models/activity_action.rb +8 -0
  8. data/app/models/activity_object.rb +55 -25
  9. data/app/models/activity_object_audience.rb +8 -0
  10. data/app/models/actor.rb +9 -0
  11. data/app/models/comment.rb +1 -3
  12. data/app/models/group.rb +3 -0
  13. data/app/models/post.rb +1 -3
  14. data/app/models/relation.rb +5 -0
  15. data/app/models/relation/follow.rb +6 -7
  16. data/app/models/relation/public.rb +5 -0
  17. data/app/models/relation/single.rb +11 -1
  18. data/app/views/activities/_new.html.erb +1 -1
  19. data/app/views/contacts/_link_follow.html.erb +8 -4
  20. data/app/views/followers/update.js.erb +2 -0
  21. data/app/views/layouts/_search.html.erb +2 -2
  22. data/app/views/search/_extended_search.html.erb +17 -17
  23. data/app/views/search/_form.html.erb +4 -4
  24. data/app/views/search/_header_search.html.erb +2 -2
  25. data/app/views/search/index.html.erb +1 -1
  26. data/app/views/search/index.js.erb +4 -4
  27. data/db/migrate/20120403175913_create_activity_object_audiences.rb +34 -0
  28. data/db/migrate/20120411132550_add_visit_count_to_activity_object.rb +9 -0
  29. data/db/migrate/20120411151413_relation_public_permissions.rb +8 -0
  30. data/lib/generators/social_stream/base/templates/initializer.rb +3 -0
  31. data/lib/social_stream-base.rb +2 -1
  32. data/lib/social_stream/ability/base.rb +14 -8
  33. data/lib/social_stream/base/dependencies.rb +1 -0
  34. data/lib/social_stream/base/thinking-sphinx.rb +18 -0
  35. data/lib/social_stream/base/version.rb +1 -1
  36. data/lib/social_stream/controllers/objects.rb +6 -0
  37. data/lib/social_stream/test_helpers/controllers.rb +1 -1
  38. data/lib/social_stream/views/location.rb +48 -0
  39. data/lib/tasks/db/populate.rake +1 -1
  40. data/lib/thinking-sphinx/social_stream.rb +3 -0
  41. data/spec/controllers/groups_controller_spec.rb +6 -6
  42. data/spec/controllers/posts_controller_spec.rb +6 -6
  43. data/spec/controllers/users_controller_spec.rb +4 -4
  44. data/spec/dummy/config/initializers/social_stream.rb +3 -0
  45. data/spec/factories/activity.rb +24 -1
  46. data/spec/factories/post.rb +1 -1
  47. data/spec/models/activity_authorization_spec.rb +1 -1
  48. data/spec/models/post_spec.rb +0 -4
  49. data/spec/models/relation_follow_spec.rb +8 -0
  50. metadata +73 -64
@@ -0,0 +1,23 @@
1
+ SocialStream.Follow = (function(SS, $, undefined){
2
+ var initButtons = function(){
3
+ $(".following-button").mouseenter(function(){
4
+ $(this).hide();
5
+ $(this).siblings(".unfollow-button").show();
6
+ });
7
+
8
+ $(".unfollow-button").mouseleave(function(){
9
+ $(this).hide();
10
+ $(this).siblings(".following-button").show();
11
+ });
12
+
13
+ $(".unfollow-button").hide();
14
+ }
15
+
16
+ $(function(){
17
+ SocialStream.Follow.initButtons();
18
+ });
19
+
20
+ return {
21
+ initButtons: initButtons
22
+ };
23
+ })(SocialStream, jQuery);
@@ -91,7 +91,7 @@ SocialStream.Wall = (function(SS, $, undefined){
91
91
  });
92
92
  $("#masterSubmitButton").val(I18n.t('activity.sending') + '...').attr("disabled", true);
93
93
 
94
- // Add _relation_ids[] parameter from authorization selector
94
+ // Add relation_ids[] parameter from authorization selector
95
95
  $('.liveAdded').remove();
96
96
 
97
97
  var currentForm = $(this);
@@ -102,7 +102,7 @@ SocialStream.Wall = (function(SS, $, undefined){
102
102
  .addClass('liveAdded')
103
103
  .attr('type', 'hidden')
104
104
  .attr('name', currentForm
105
- .attr('id').split('_')[1]+'[_relation_ids][]')
105
+ .attr('id').split('_')[1]+'[relation_ids][]')
106
106
  .val($(this).attr('value')));
107
107
  });
108
108
  return true;
@@ -128,7 +128,7 @@ SocialStream.Wall = (function(SS, $, undefined){
128
128
  $(this).removeAttr("readonly").val("").blur();
129
129
  });
130
130
  //New comments
131
- $('.input_new_comments').each(function() {chosen.result_deselect(0)
131
+ $('.input_new_comments').each(function() {
132
132
  $(this).removeAttr("readonly").val("");
133
133
  });
134
134
  }
@@ -6,20 +6,35 @@ class SearchController < ApplicationController
6
6
  RESULTS_SEARCH_PER_PAGE=12
7
7
  MIN_QUERY=2
8
8
  def index
9
- if params[:search_query].blank? or too_short_query
10
- @search_result = []
11
- else
12
- if params[:mode].eql? "header_search"
13
- @search_result = search :quick
14
- render :partial => "header_search"
15
- return
9
+ @search_result =
10
+ if params[:q].blank? || too_short_query
11
+ []
12
+ elsif params[:mode].eql? "header_search"
13
+ search :quick
14
+ elsif params[:type].present?
15
+ focus_search
16
16
  else
17
- if params[:focus].present?
18
- @search_result = focus_search
19
- else
20
- @search_result = search :extended
21
- end
17
+ search :extended
22
18
  end
19
+
20
+ respond_to do |format|
21
+ format.html {
22
+ if params[:mode] == "header_search"
23
+ render :partial => "header_search"
24
+ end
25
+ }
26
+
27
+ format.json {
28
+ json_obj = (
29
+ params[:type].present? ?
30
+ { params[:type].pluralize => @search_result } :
31
+ @search_result
32
+ )
33
+
34
+ render :json => json_obj
35
+ }
36
+
37
+ format.js
23
38
  end
24
39
  end
25
40
 
@@ -43,7 +58,7 @@ class SearchController < ApplicationController
43
58
  end
44
59
 
45
60
  def focus_search
46
- @search_class_sym = params[:focus].singularize.to_sym unless params[:focus].blank?
61
+ @search_class_sym = params[:type].singularize.to_sym unless params[:type].blank?
47
62
  search_class = @search_class_sym.to_s.classify.constantize
48
63
  result = ThinkingSphinx.search(get_search_query, :classes => [search_class])
49
64
  result = authorization_filter result
@@ -51,13 +66,13 @@ class SearchController < ApplicationController
51
66
  end
52
67
 
53
68
  def too_short_query
54
- bare_query = strip_tags(params[:search_query]) unless bare_query.html_safe?
69
+ bare_query = strip_tags(params[:q]) unless bare_query.html_safe?
55
70
  return bare_query.strip.size < MIN_QUERY
56
71
  end
57
72
 
58
73
  def get_search_query
59
74
  search_query = ""
60
- param = strip_tags(params[:search_query]) || ""
75
+ param = strip_tags(params[:q]) || ""
61
76
  bare_query = param unless bare_query.html_safe?
62
77
  search_query_words = bare_query.strip.split
63
78
  search_query_words.each_index do |i|
@@ -70,7 +85,6 @@ class SearchController < ApplicationController
70
85
  def authorization_filter results
71
86
  filtered_results = Array.new
72
87
  results.each do |result|
73
- puts result
74
88
  if result.is_a? SocialStream::Models::Object
75
89
  filtered_results << result if can? :read, result
76
90
  else
@@ -1,46 +1,3 @@
1
1
  module LocationHelper
2
-
3
- # Renders the location stack for your view. You can add as many stack levels as you wish.
4
- #
5
- # Usage:
6
- # <%= location(level1,leve2,level3,level4,....) %>
7
- #
8
- # Output:
9
- # base > level1 > level2 > level3 > level 4
10
- #
11
- # Default configuration:
12
- # base => "You are here" ("location.base" on config/locales)
13
- # separator => ">" ("location.separator" on config/locales)
14
- #
15
- # Styles and HTML wrapping:
16
- # partial => location/_location.html.erb
17
- #
18
- # Example:
19
- # Render a location with two leves depth:
20
- #
21
- # <%= location(link_to(leve1.name, level1.url),link_to(leve2.name, level2.url)) %>
22
- #
23
- def location(*stack)
24
-
25
- location_body = render :partial => "location/location_body", :locals=>{:stack => stack}
26
-
27
- location_div = capture do
28
- render :partial => "location/location", :locals=>{:location_body => location_body}
29
- end
30
-
31
- case request.format
32
- when Mime::JS
33
- response = <<-EOJ
34
-
35
- $('#map_location').html("#{ escape_javascript(location_div) }");
36
- EOJ
37
-
38
- response.html_safe
39
- else
40
- content_for(:location) do
41
- location_div
42
- end
43
- end
44
-
45
- end
2
+ include SocialStream::Views::Location
46
3
  end
@@ -1,7 +1,7 @@
1
1
  module SearchHelper
2
2
  def too_short_query?
3
- return true if params[:search_query].blank?
4
- bare_query = strip_tags(params[:search_query]) unless bare_query.html_safe?
3
+ return true if params[:q].blank?
4
+ bare_query = strip_tags(params[:q]) unless bare_query.html_safe?
5
5
  return bare_query.strip.size < SearchController::MIN_QUERY
6
6
  end
7
7
 
@@ -26,15 +26,15 @@ module SearchHelper
26
26
 
27
27
  def get_search_query_words
28
28
  search_query = ""
29
- bare_query = strip_tags(params[:search_query]) unless bare_query.html_safe?
29
+ bare_query = strip_tags(params[:q]) unless bare_query.html_safe?
30
30
  return bare_query.strip.split
31
31
  end
32
32
 
33
33
  def search_class(type, model_sym)
34
34
  case type
35
35
  when :selected
36
- params[:focus].present? &&
37
- params[:focus].eql?(model_sym.to_s) &&
36
+ params[:type].present? &&
37
+ params[:type].eql?(model_sym.to_s) &&
38
38
  'selected' || ''
39
39
  when :disabled
40
40
  search_results?(model_sym) &&
@@ -61,8 +61,8 @@ module SearchHelper
61
61
 
62
62
  link_to_if results,
63
63
  content_tag(:span, t("#{ model_sym }.title.other"), span_options),
64
- search_path(:focus => model_sym,
65
- :search_query => params[:search_query]),
64
+ search_path(:type => model_sym,
65
+ :q => params[:q]),
66
66
  :remote => true
67
67
  end
68
68
  end
@@ -90,8 +90,6 @@ class Activity < ActiveRecord::Base
90
90
  order("created_at desc")
91
91
  }
92
92
 
93
- before_validation :fill_relations
94
-
95
93
  after_create :increment_like_count
96
94
  after_destroy :decrement_like_count, :delete_notifications
97
95
 
@@ -325,25 +323,6 @@ class Activity < ActiveRecord::Base
325
323
 
326
324
  private
327
325
 
328
- # Before validation callback
329
- #
330
- # Fill the relations when posting to other subject's wall
331
- def fill_relations
332
- return if relation_ids.present?
333
-
334
- self.relation_ids =
335
- # FIXME: repeated in ActivityObject#_relation_ids
336
- if SocialStream.relation_model == :custom
337
- if channel.reflexive?
338
- receiver.relation_customs.map(&:id)
339
- else
340
- receiver.relation_customs.allow(channel.author, 'create', 'activity').map(&:id)
341
- end
342
- else
343
- Array.wrap Relation::Public.instance.id
344
- end
345
- end
346
-
347
326
  #
348
327
  # Get the email subject for the activity's notification
349
328
  #
@@ -19,6 +19,14 @@ class ActivityAction < ActiveRecord::Base
19
19
  where(:activity_object_id => ActivityObject.normalize_id(activity_object))
20
20
  }
21
21
 
22
+ scope :authored_or_owned, where(arel_table[:author].eq(true).
23
+ or(arel_table[:user_author].eq(true)).
24
+ or(arel_table[:owner].eq(true)))
25
+
26
+ scope :authored_or_owned_by, lambda{ |subject|
27
+ authored_or_owned.sent_by(subject)
28
+ }
29
+
22
30
  before_create :follow_by_author_and_owner
23
31
 
24
32
  private
@@ -9,7 +9,6 @@
9
9
  # Objects are added to +config/initializers/social_stream.rb+
10
10
  #
11
11
  class ActivityObject < ActiveRecord::Base
12
- attr_writer :_relation_ids
13
12
  attr_reader :_activity_parent_id
14
13
 
15
14
  # ActivityObject is a supertype of SocialStream.objects
@@ -17,6 +16,9 @@ class ActivityObject < ActiveRecord::Base
17
16
 
18
17
  acts_as_taggable
19
18
 
19
+ has_many :activity_object_audiences, :dependent => :destroy
20
+ has_many :relations, :through => :activity_object_audiences
21
+
20
22
  has_many :activity_object_activities, :dependent => :destroy
21
23
  has_many :activities, :through => :activity_object_activities
22
24
 
@@ -29,6 +31,11 @@ class ActivityObject < ActiveRecord::Base
29
31
  :source => :actor,
30
32
  :conditions => { 'activity_actions.follow' => true }
31
33
 
34
+ # Associations for indexing
35
+ has_many :author_action,
36
+ :class_name => "ActivityAction",
37
+ :conditions => { 'activity_actions.author' => true }
38
+
32
39
  has_many :activity_object_properties,
33
40
  :dependent => :destroy
34
41
  has_many :object_properties,
@@ -42,7 +49,10 @@ class ActivityObject < ActiveRecord::Base
42
49
  :through => :activity_object_holders,
43
50
  :source => :activity_object
44
51
 
52
+ before_validation :fill_relation_ids, :if => lambda { |obj| obj.object_type != "Actor" }
53
+
45
54
  validates_presence_of :object_type
55
+ validate :allowed_relations, :if => lambda { |obj| obj.object_type != "Actor" }
46
56
 
47
57
  # TODO: This is currently defined in lib/social_stream/models/object.rb
48
58
  #
@@ -110,6 +120,15 @@ class ActivityObject < ActiveRecord::Base
110
120
  class_eval code, __FILE__, __LINE__ - code.lines.count - 2
111
121
  end
112
122
 
123
+ # subject was the author, user author or owner of this {ActivityObject}?
124
+ def authored_or_owned_by?(subject)
125
+ return false if subject.blank?
126
+
127
+ received_actions.
128
+ merge(ActivityAction.authored_or_owned_by(subject)).
129
+ any?
130
+ end
131
+
113
132
  # Was the author represented when this {ActivityObject} was created?
114
133
  def represented_author?
115
134
  author_id != user_author_id
@@ -146,28 +165,7 @@ class ActivityObject < ActiveRecord::Base
146
165
  Activity.new :author => author,
147
166
  :user_author => user_author,
148
167
  :owner => owner,
149
- :relation_ids => Array(_relation_ids)
150
- end
151
-
152
- def _relation_ids
153
- @_relation_ids ||=
154
- if author.blank? || owner.blank?
155
- nil
156
- else
157
- # FIXME: repeated in Activity#fill_relations
158
- if SocialStream.relation_model == :custom
159
- if author == owner
160
- owner.relation_customs.map(&:id)
161
- else
162
- owner.
163
- relation_customs.
164
- allow(author, 'create', 'activity').
165
- map(&:id)
166
- end
167
- else
168
- Array.wrap Relation::Public.instance.id
169
- end
170
- end
168
+ :relation_ids => relation_ids
171
169
  end
172
170
 
173
171
  def _activity_parent
@@ -175,12 +173,44 @@ class ActivityObject < ActiveRecord::Base
175
173
  end
176
174
 
177
175
  def _activity_parent_id=(id)
178
- self._relation_ids = Activity.find(id).relation_ids
176
+ self.relation_ids = Activity.find(id).relation_ids
179
177
  @_activity_parent_id = id
180
178
  end
181
179
 
182
180
  private
183
181
 
182
+ def fill_relation_ids
183
+ return if relation_ids.present? || author.blank? || owner.blank?
184
+
185
+ @valid_relations = true
186
+
187
+ self.relation_ids =
188
+ if SocialStream.relation_model == :custom
189
+ owner.
190
+ relations.
191
+ allowing('read', 'activity').
192
+ map(&:id)
193
+ else
194
+ Array.wrap Relation::Public.instance.id
195
+ end
196
+ end
197
+
198
+ # validate method
199
+ #
200
+ # check relations are included in
201
+ def allowed_relations
202
+ return if @valid_relations
203
+
204
+ allowed_rels =
205
+ owner.relations.allowing('read', 'activity') +
206
+ Relation::Single.allowing('read', 'activity')
207
+
208
+ if (relation_ids - allowed_rels.map(&:id)).any?
209
+ errors.add(:relation_ids, "not allowed")
210
+ end
211
+ end
212
+
213
+
184
214
  def create_post_activity
185
215
  create_activity "post"
186
216
  end
@@ -194,7 +224,7 @@ class ActivityObject < ActiveRecord::Base
194
224
  :author_id => author_id,
195
225
  :user_author => user_author,
196
226
  :owner => owner,
197
- :relation_ids => _relation_ids,
227
+ :relation_ids => relation_ids,
198
228
  :parent_id => _activity_parent_id
199
229
 
200
230
  a.activity_objects << self
@@ -0,0 +1,8 @@
1
+ # Every {ActivityObject} ({Post}, {Comment}, etc.) is shared with one or more {Relation Relations}.
2
+ #
3
+ # Each {Relation} is equivalent to a set {Actor Actors}, which are the ones that have {Tie Ties}
4
+ # to that {Relation}, in other words, the contacts that were added to that {Relation}
5
+ class ActivityObjectAudience < ActiveRecord::Base
6
+ belongs_to :activity_object
7
+ belongs_to :relation
8
+ end
data/app/models/actor.rb CHANGED
@@ -57,6 +57,10 @@ class Actor < ActiveRecord::Base
57
57
  has_many :received_ties,
58
58
  :through => :received_contacts,
59
59
  :source => :ties
60
+
61
+ has_many :received_relations,
62
+ :through => :received_ties,
63
+ :source => :relation
60
64
 
61
65
  has_many :senders,
62
66
  :through => :received_contacts,
@@ -313,6 +317,11 @@ class Actor < ActiveRecord::Base
313
317
  map(&:id)
314
318
  end
315
319
 
320
+ # Does this {Actor} allow subject to perform action on object?
321
+ def allow?(subject, action, object)
322
+ ties_to(subject).with_permissions(action, object).any?
323
+ end
324
+
316
325
  # The {Channel} of this {Actor} to self (totally close!)
317
326
  def self_channel
318
327
  Channel.find_or_create_by_author_id_and_user_author_id_and_owner_id id, id, id
@@ -5,9 +5,7 @@ class Comment < ActiveRecord::Base
5
5
  validates_presence_of :text
6
6
 
7
7
  define_index do
8
- indexes activity_object.description
9
-
10
- has created_at
8
+ activity_object_index
11
9
  end
12
10
 
13
11
  def parent_post