social_stream-base 0.19.2 → 0.20.0

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