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
data/app/models/group.rb CHANGED
@@ -34,6 +34,8 @@ class Group < ActiveRecord::Base
34
34
 
35
35
  # Creates the ties from the founder to the group
36
36
  def create_ties_from_founder
37
+ =begin
38
+ # FIXME: need to define a proper relation for this case. Maybe a system defined relation
37
39
  author.sent_contacts.create! :receiver_id => actor_id,
38
40
  :relation_ids => _relation_ids
39
41
 
@@ -41,6 +43,7 @@ class Group < ActiveRecord::Base
41
43
  user_author.sent_contacts.create! :receiver_id => actor_id,
42
44
  :relation_ids => _relation_ids
43
45
  end
46
+ =end
44
47
  end
45
48
 
46
49
  # Creates the ties from the group to the participants
data/app/models/post.rb CHANGED
@@ -5,9 +5,7 @@ class Post < 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 title
@@ -67,6 +67,11 @@ class Relation < ActiveRecord::Base
67
67
  where(:type => positive_names)
68
68
  }
69
69
 
70
+ scope :allowing, lambda { |action, object|
71
+ joins(:permissions).
72
+ merge(Permission.where(:action => action).where(:object => object))
73
+ }
74
+
70
75
  before_create :initialize_sender_type
71
76
 
72
77
  class << self
@@ -4,11 +4,10 @@
4
4
  # Use this model setting <tt>config.relation_model = :follow</tt> in your
5
5
  # <tt>config/initializers/social_stream.rb</tt>
6
6
  class Relation::Follow < Relation::Single
7
- class << self
8
- def instance
9
- first ||
10
- create(:permissions => Array(Permission.find_or_create_by_action('follow')))
11
- end
12
- end
7
+ PERMISSIONS =
8
+ [
9
+ [ 'create', 'activity' ],
10
+ [ 'read', 'activity' ],
11
+ [ 'follow', nil ]
12
+ ]
13
13
  end
14
-
@@ -1,4 +1,9 @@
1
1
  class Relation::Public < Relation::Single
2
+ PERMISSIONS =
3
+ [
4
+ [ 'read', 'activity' ]
5
+ ]
6
+
2
7
  # A {Relation::Public public relation} is always the weakest
3
8
  def <=>(relation)
4
9
  1
@@ -4,11 +4,21 @@
4
4
  # these {Relation relations}.
5
5
  #
6
6
  class Relation::Single < Relation
7
+ PERMISSIONS = []
8
+
7
9
  class << self
8
10
  def instance
9
11
  @instance ||=
10
- first || create!
12
+ first ||
13
+ create!(:permissions => permissions)
14
+ end
15
+
16
+ def permissions
17
+ self::PERMISSIONS.map{ |p|
18
+ Permission.find_or_create_by_action_and_object p.first, p.last
19
+ }
11
20
  end
21
+
12
22
  end
13
23
 
14
24
  # The name of public relation
@@ -32,7 +32,7 @@
32
32
  }
33
33
  //For security with check "var default_security_width = '100px';" in activities.js.erb
34
34
  <% end %>
35
- <%= select_tag :_relation_ids, options_for_select(current_subject.activity_relations(receiver).sort.map{ |r| [ r.name, r.id ] }), :id => 'security', :multiple => true, :title => t("activity.privacy.myself.contacts.#{ receiver.class.to_s.underscore }") %>
35
+ <%= select_tag :relation_ids, options_for_select(current_subject.activity_relations(receiver).sort.map{ |r| [ r.name, r.id ] }), :id => 'security', :multiple => true, :title => t("activity.privacy.myself.contacts.#{ receiver.class.to_s.underscore }") %>
36
36
  <% else %>
37
37
  <div id="security_chzn" class="chzn-container chzn-container-multi">
38
38
  <ul class="chzn-choices">
@@ -1,9 +1,13 @@
1
1
  <div class="<%= follow_link_class contact %>">
2
2
  <% if contact.sent? %>
3
- <%= t 'contact.following' %>
4
- <%= form_tag follower_path(contact), :method => :delete, :remote => true do |f| %>
5
- <%= submit_tag t('contact.unfollow') %>
6
- <% end %>
3
+ <div class="following-button">
4
+ <%= t 'contact.following' %>
5
+ </div>
6
+ <div class="unfollow-button">
7
+ <%= form_tag follower_path(contact), :method => :delete, :remote => true do |f| %>
8
+ <%= submit_tag t('contact.unfollow') %>
9
+ <% end %>
10
+ </div>
7
11
  <% else %>
8
12
  <%= form_tag follower_path(contact), :method => :put, :remote => true do |f| %>
9
13
  <%= submit_tag t('contact.follow') %>
@@ -1 +1,3 @@
1
1
  $(".<%= follow_link_class @contact %>").html("<%= escape_javascript render(:partial => "contacts/link_follow", :locals => { :contact => @contact.reload } )%>");
2
+
3
+ SocialStream.Follow.initButtons();
@@ -1,6 +1,6 @@
1
1
  <div id="header_search">
2
2
  <form action="<%=search_path%>" method="get" id="header_search_form">
3
- <%= text_field_tag :search_query, nil,:autocomplete => :off, :id => :header_search_input %>
3
+ <%= text_field_tag :q, nil,:autocomplete => :off, :id => :header_search_input %>
4
4
  </form>
5
5
  <div id="header_search_display">
6
6
  <ul><li class="loading"><%= image_tag('loading.gif', :class => :loading) %></li></ul>
@@ -44,7 +44,7 @@ $(document).ready(function() {
44
44
  $("#header_search_display").html("<ul><li class=\"loading\"><%= escape_javascript(image_tag('loading.gif', :class => :loading)) %></li></ul>").show();
45
45
  $.ajax({
46
46
  type : "GET",
47
- url : "<%= search_url %>?search_query=" + searchstring + "&mode=header_search",
47
+ url : "<%= search_url %>?q=" + searchstring + "&mode=header_search",
48
48
  success : function(html) {
49
49
  if ($("#header_search_input").val()==searchstring){ //Only show if input value is still the same
50
50
  $("#header_search_display").html(html);
@@ -1,19 +1,19 @@
1
1
  <% if @search_result.empty? %>
2
- <div class="model_with_details">
3
- <%= I18n.t('search.nothing') %>
4
- </div>
2
+ <div class="model_with_details">
3
+ <%= I18n.t('search.nothing') %>
4
+ </div>
5
5
  <% else %>
6
- <% @search_result.each do |model|%>
7
- <% if @search_class_sym.nil? %>
8
- <div class="subject_search_results block left">
9
- <%= render_global_search_for model %>
10
- </div>
11
- <% else %>
12
- <div class="subject_search_results block left <%= model.class.name.downcase %>">
13
- <%= render_focus_search_for model %>
14
- </div>
15
- <% end %>
16
- <% end %>
17
- <br class="clearfloat">
18
- <%= paginate @search_result %>
19
- <% end %>
6
+ <% @search_result.each do |model|%>
7
+ <% if @search_class_sym.nil? %>
8
+ <div class="subject_search_results block left">
9
+ <%= render_global_search_for model %>
10
+ </div>
11
+ <% else %>
12
+ <div class="subject_search_results block left <%= model.class.name.downcase %>">
13
+ <%= render_focus_search_for model %>
14
+ </div>
15
+ <% end %>
16
+ <% end %>
17
+ <br class="clearfloat">
18
+ <%= paginate @search_result %>
19
+ <% end %>
@@ -1,20 +1,20 @@
1
1
  <%= form_tag search_path, :method => :get,
2
2
  :remote => true,
3
3
  :id => "search_form" do %>
4
- <%= hidden_field_tag :focus, params[:focus] %>
4
+ <%= hidden_field_tag :type, params[:type] %>
5
5
  <div class="block">
6
6
  <div class="error" id="too_short_error" <%= 'style=display:block;' if too_short_query? %>><%= t('search.at_least') %></div>
7
7
 
8
8
  <div class="form_row search_row">
9
- <%= text_field_tag :search_query, params[:search_query], :autocomplete => :off, :id => :global_search_input %>
9
+ <%= text_field_tag :q, params[:q], :autocomplete => :off, :id => :global_search_input %>
10
10
  </div>
11
11
 
12
12
  <div id="focus_options" class="form_row search_row">
13
13
  <ul class="menu_plain_list">
14
14
  <li><%= link_to content_tag(:span,
15
15
  t('search.show_all'),
16
- :class => "global #{ params[:focus].blank? && 'selected' }"),
17
- search_path(:search_query => params[:search_query]),
16
+ :class => "global #{ params[:type].blank? && 'selected' }"),
17
+ search_path(:q => params[:q]),
18
18
  :remote => true %></li>
19
19
  <% SocialStream.extended_search_models.each do |model_sym| %>
20
20
  <li>
@@ -10,7 +10,7 @@
10
10
  <%= link_to raw('<li class="more">' +
11
11
  t("search.global.first_result.#{ total == 1 ? 'one' : 'more' }", :count => total) +
12
12
  '<br>' +
13
- t('search.global.query', :query => truncate(h(params[:search_query]),:length => 20)) +
13
+ t('search.global.query', :query => truncate(h(params[:q]),:length => 20)) +
14
14
  '</li>'),
15
- search_path(:search_query => params[:search_query]) %>
15
+ search_path(:q => params[:q]) %>
16
16
  </ul>
@@ -1,5 +1,5 @@
1
1
  <% content_for :title do %>
2
- <%= t('search.name')%> <%= params[:search_query].present? ? ": #{params[:search_query]}" : ""%>
2
+ <%= t('search.name')%> <%= params[:q].present? ? ": #{params[:q]}" : ""%>
3
3
  <% end %>
4
4
 
5
5
  <% sidebar %>
@@ -3,13 +3,13 @@
3
3
 
4
4
  $('#focus_options ul li a span').removeClass('selected');
5
5
 
6
- <% if params[:focus].present? %>
7
- $('#focus_options ul li a span.<%= params[:focus].pluralize.downcase %>').addClass('selected');
6
+ <% if params[:type].present? %>
7
+ $('#focus_options ul li a span.<%= params[:type].pluralize.downcase %>').addClass('selected');
8
8
  <% else %>
9
9
  $('#focus_options ul li a span.global').addClass('selected');
10
10
  <% end %>
11
11
 
12
- $('title').text('<%= t('search.name')%> <%= escape_javascript(params[:search_query].present? ? ": #{params[:search_query]}" : "")%>');
12
+ $('title').text('<%= t('search.name')%> <%= escape_javascript(params[:q].present? ? ": #{params[:q]}" : "")%>');
13
13
 
14
14
  <% if too_short_query? %>
15
15
  $('#too_short_error').show();
@@ -19,4 +19,4 @@
19
19
 
20
20
  $('#global_search_input').removeClass("searching");
21
21
 
22
- setActivityPrivacyTooltips();
22
+ setActivityPrivacyTooltips();
@@ -0,0 +1,34 @@
1
+ # This migration comes from social_stream_base_engine (originally 20120403175913)
2
+ class CreateActivityObjectAudiences < ActiveRecord::Migration
3
+ def change
4
+ create_table :activity_object_audiences do |t|
5
+ t.references :activity_object
6
+ t.references :relation
7
+
8
+ t.timestamps
9
+ end
10
+
11
+ add_foreign_key :activity_object_audiences, :activity_objects, :name => 'activity_object_audiences_on_activity_object_id'
12
+ add_foreign_key :activity_object_audiences, :relations, :name => 'activity_object_audiences_on_relation_id'
13
+
14
+
15
+ ActivityObject.all.each do |ao|
16
+ post_activity = ao.post_activity
17
+ next if post_activity.blank?
18
+
19
+ ao.relation_ids = post_activity.relation_ids
20
+ end
21
+
22
+ ActivityObjectAudience.record_timestamps = false
23
+
24
+ ActivityObject.all.each do |ao|
25
+ ao.activity_object_audiences.each do |aud|
26
+ aud.created_at = aud.updated_at = ao.created_at
27
+ aud.save!
28
+ end
29
+ end
30
+
31
+ ActivityObjectAudience.record_timestamps = true
32
+ ActivityObject.reset_column_information
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ class AddVisitCountToActivityObject < ActiveRecord::Migration
2
+ def up
3
+ add_column :activity_objects, :visit_count, :integer, :default => 0
4
+ end
5
+
6
+ def down
7
+ remove_column :activity_objects, :visit_count
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ class RelationPublicPermissions < ActiveRecord::Migration
2
+ def up
3
+ Relation::Public.instance.permissions = Relation::Public.permissions if Relation::Public.instance.permissions.blank?
4
+ end
5
+
6
+ def down
7
+ end
8
+ end
@@ -41,3 +41,6 @@ SocialStream.setup do |config|
41
41
  # Cleditor controls. It is used in new message editor, for example
42
42
  # config.cleditor_controls = "bold italic underline strikethrough subscript superscript | size style | bullets | image link unlink"
43
43
  end
44
+
45
+ # You can customize toolbar, sidebar and location bar from here
46
+ # See https://github.com/ging/social_stream/wiki/How-to-customize-the-toolbar,-sidebar-and-location
@@ -35,7 +35,8 @@ module SocialStream
35
35
  end
36
36
 
37
37
  module Views
38
- autoload :List, 'social_stream/views/list'
38
+ autoload :List, 'social_stream/views/list'
39
+ autoload :Location, 'social_stream/views/location'
39
40
 
40
41
  module Settings
41
42
  autoload :Base, 'social_stream/views/settings/base'
@@ -13,20 +13,26 @@ module SocialStream
13
13
  (SocialStream.objects - [ :actor, :comment ]).map{ |obj|
14
14
  obj.to_s.classify.constantize
15
15
  }.each do |klass|
16
- can :create, klass do |k| # can :create, Post do |post|
17
- k.build_post_activity.allow?(subject, 'create')
16
+ can :create, klass do |object| # can :create, Post do |post|
17
+ object.author.present? &&
18
+ object.owner.present? &&
19
+ object.author == Actor.normalize(subject) &&
20
+ ( object.author == object.owner ||
21
+ object.owner.allow?(subject, 'create', 'activity') )
18
22
  end
19
23
 
20
- can :read, klass do |k| # can :read, Post do |post|
21
- k.post_activity.allow?(subject, 'read')
24
+ can :read, klass do |object| # can :read, Post do |post|
25
+ object.authored_or_owned_by?(subject) ||
26
+ object.relation_ids.include?(Relation::Public.instance.id) ||
27
+ subject.present? && (object.relation_ids & subject.received_relation_ids).any?
22
28
  end
23
29
 
24
- can :update, klass do |k| # can :update, Post do |post|
25
- [k.author_id, k.owner_id].include?(Actor.normalize_id(subject))
30
+ can :update, klass do |object| # can :update, Post do |post|
31
+ object.authored_or_owned_by?(subject)
26
32
  end
27
33
 
28
- can :destroy, klass do |k| # can :destroy, Post do |post|
29
- [k.author_id, k.owner_id].include?(Actor.normalize_id(subject))
34
+ can :destroy, klass do |object| # can :destroy, Post do |post|
35
+ object.authored_or_owned_by?(subject)
30
36
  end
31
37
  end
32
38
 
@@ -40,6 +40,7 @@ require 'resque/server'
40
40
  require 'modernizr-rails'
41
41
  # Sphinx search engine
42
42
  require 'thinking-sphinx'
43
+ require 'thinking-sphinx/social_stream'
43
44
  # Syntactically Awesome Stylesheets
44
45
  require 'sass-rails'
45
46
  # Autolink text blocks
@@ -0,0 +1,18 @@
1
+ module SocialStream
2
+ module Base
3
+ module ThinkingSphinx
4
+ module Index
5
+ module Builder
6
+ def activity_object_index
7
+ indexes activity_object.title, :as => :title
8
+ indexes activity_object.description, :as => :description
9
+ indexes activity_object.tags.name, :as => :tags
10
+
11
+ has created_at
12
+ has activity_object.author_action(:actor_id), :as => :author_id
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,5 @@
1
1
  module SocialStream
2
2
  module Base
3
- VERSION = "0.19.2".freeze
3
+ VERSION = "0.20.0".freeze
4
4
  end
5
5
  end
@@ -8,6 +8,8 @@ module SocialStream
8
8
 
9
9
  before_filter :set_author_ids, :only => [ :new, :create, :update ]
10
10
 
11
+ after_filter :increment_visit_count, :only => :show
12
+
11
13
  load_and_authorize_resource :except => :index
12
14
 
13
15
  respond_to :html, :js
@@ -27,6 +29,10 @@ module SocialStream
27
29
 
28
30
  protected
29
31
 
32
+ def increment_visit_count
33
+ resource.activity_object.increment!(:visit_count) if request.format == 'html'
34
+ end
35
+
30
36
  def set_author_ids
31
37
  resource_params.first[:author_id] = current_subject.try(:actor_id)
32
38
  resource_params.first[:user_author_id] = current_user.try(:actor_id)
@@ -34,7 +34,7 @@ module SocialStream
34
34
 
35
35
  def model_assigned_to contact, relation_ids
36
36
  model_attributes[:owner_id] = contact.receiver.id
37
- model_attributes[:_relation_ids] = Array(relation_ids).map(&:id)
37
+ model_attributes[:relation_ids] = Array(relation_ids).map(&:id)
38
38
  end
39
39
 
40
40
  shared_examples_for "Allow Creating" do
@@ -0,0 +1,48 @@
1
+ module SocialStream
2
+ module Views
3
+ module Location
4
+ # Renders the location stack for your view. You can add as many stack levels as you wish.
5
+ #
6
+ # Usage:
7
+ # <%= location(level1,leve2,level3,level4,....) %>
8
+ #
9
+ # Output:
10
+ # base > level1 > level2 > level3 > level 4
11
+ #
12
+ # Default configuration:
13
+ # base => "You are here" ("location.base" on config/locales)
14
+ # separator => ">" ("location.separator" on config/locales)
15
+ #
16
+ # Styles and HTML wrapping:
17
+ # partial => location/_location.html.erb
18
+ #
19
+ # Example:
20
+ # Render a location with two leves depth:
21
+ #
22
+ # <%= location(link_to(leve1.name, level1.url),link_to(leve2.name, level2.url)) %>
23
+ #
24
+ def location(*stack)
25
+
26
+ location_body = render :partial => "location/location_body", :locals=>{:stack => stack}
27
+
28
+ location_div = capture do
29
+ render :partial => "location/location", :locals=>{:location_body => location_body}
30
+ end
31
+
32
+ case request.format
33
+ when Mime::JS
34
+ response = <<-EOJ
35
+
36
+ $('#map_location').html("#{ escape_javascript(location_div) }");
37
+ EOJ
38
+
39
+ response.html_safe
40
+ else
41
+ content_for(:location) do
42
+ location_div
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end