social_stream-base 0.17.3 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/app/assets/images/flags/pt.png +0 -0
  2. data/app/assets/javascripts/social_stream.toolbar.js +41 -0
  3. data/app/assets/stylesheets/settings.css +1 -0
  4. data/app/controllers/activity_actions_controller.rb +44 -0
  5. data/app/controllers/followers_controller.rb +39 -0
  6. data/app/helpers/activities_helper.rb +10 -10
  7. data/app/helpers/activity_actions_helper.rb +35 -0
  8. data/app/helpers/contacts_helper.rb +1 -1
  9. data/app/helpers/followers_helper.rb +5 -0
  10. data/app/helpers/toolbar_helper.rb +55 -68
  11. data/app/models/activity_action.rb +28 -0
  12. data/app/models/activity_object.rb +11 -2
  13. data/app/models/actor.rb +23 -33
  14. data/app/models/contact.rb +32 -43
  15. data/app/models/group.rb +2 -6
  16. data/app/models/relation.rb +1 -1
  17. data/app/models/relation/follow.rb +14 -0
  18. data/app/models/tie.rb +30 -30
  19. data/app/models/user.rb +8 -0
  20. data/app/views/activities/_options.html.erb +0 -1
  21. data/app/views/activity_actions/_follow_form.html.erb +10 -0
  22. data/app/views/activity_actions/_follow_sentence.html.erb +3 -0
  23. data/app/views/activity_actions/_update_form.js.erb +2 -0
  24. data/app/views/activity_actions/create.js.erb +1 -0
  25. data/app/views/activity_actions/update.js.erb +1 -0
  26. data/app/views/avatars/index.html.erb +1 -1
  27. data/app/views/cheesecake/index.html.erb +1 -1
  28. data/app/views/contacts/{_link.html.erb → _link_custom.html.erb} +0 -0
  29. data/app/views/contacts/_link_follow.html.erb +12 -0
  30. data/app/views/contacts/edit.html.erb +1 -1
  31. data/app/views/contacts/index.html.erb +1 -1
  32. data/app/views/contacts/index.js.erb +1 -1
  33. data/app/views/contacts/new.html.erb +1 -1
  34. data/app/views/conversations/index.html.erb +1 -1
  35. data/app/views/conversations/index.js.erb +1 -1
  36. data/app/views/conversations/show.html.erb +1 -1
  37. data/app/views/conversations/show.js.erb +1 -1
  38. data/app/views/devise/registrations/edit.html.erb +1 -1
  39. data/app/views/followers/destroy.js.erb +1 -0
  40. data/app/views/followers/index.html.erb +5 -0
  41. data/app/views/followers/update.js.erb +1 -0
  42. data/app/views/groups/_show.html.erb +1 -1
  43. data/app/views/groups/new.html.erb +1 -1
  44. data/app/views/layouts/_header_dropdown_menu.html.erb +5 -3
  45. data/app/views/messages/new.html.erb +1 -1
  46. data/app/views/messages/new.js.erb +1 -1
  47. data/app/views/objects/_show.html.erb +1 -1
  48. data/app/views/profiles/edit.html.erb +1 -1
  49. data/app/views/profiles/show.html.erb +1 -1
  50. data/app/views/relation/customs/index.html.erb +1 -1
  51. data/app/views/settings/index.html.erb +1 -1
  52. data/app/views/settings/index.js.erb +1 -0
  53. data/app/views/ties/index.html.erb +1 -1
  54. data/app/views/toolbar/_logo.html.erb +0 -7
  55. data/app/views/users/_show.html.erb +1 -1
  56. data/config/locales/en.yml +16 -6
  57. data/config/locales/es.yml +15 -6
  58. data/config/locales/pt.yml +507 -0
  59. data/config/locales/rails.pt.yml +192 -0
  60. data/config/routes.rb +20 -7
  61. data/db/migrate/20120316093946_create_activity_actions.rb +15 -0
  62. data/db/migrate/20120316113728_activity_action_follow.rb +23 -0
  63. data/lib/generators/social_stream/base/install_generator.rb +0 -4
  64. data/lib/generators/social_stream/base/templates/initializer.rb +7 -0
  65. data/lib/inherited_resources/social_stream.rb +18 -0
  66. data/lib/rails/social_stream.rb +23 -0
  67. data/lib/social_stream-base.rb +7 -3
  68. data/lib/social_stream/base/dependencies.rb +3 -2
  69. data/lib/social_stream/base/engine.rb +6 -6
  70. data/lib/social_stream/base/version.rb +1 -1
  71. data/lib/social_stream/models/channeled.rb +8 -0
  72. data/lib/social_stream/models/object.rb +1 -3
  73. data/lib/social_stream/models/subtype.rb +31 -25
  74. data/lib/social_stream/models/supertype.rb +54 -19
  75. data/lib/social_stream/views/toolbar/base.rb +143 -0
  76. data/lib/tasks/db/populate.rake +1 -1
  77. data/social_stream-base.gemspec +1 -3
  78. data/spec/dummy/config/initializers/social_stream.rb +7 -0
  79. data/spec/models/activity_action_spec.rb +26 -0
  80. data/spec/models/tie_spec.rb +2 -2
  81. metadata +91 -84
  82. data/app/assets/javascripts/toolbar.js +0 -22
  83. data/app/views/layouts/_settings.html.erb +0 -18
  84. data/app/views/toolbar/_home.html.erb +0 -15
  85. data/app/views/toolbar/_messages.html.erb +0 -15
  86. data/app/views/toolbar/_profile.html.erb +0 -28
  87. data/lib/generators/social_stream/base/templates/navigation.rb +0 -4
  88. data/lib/social_stream/toolbar_config/base.rb +0 -94
Binary file
@@ -0,0 +1,41 @@
1
+ SocialStream.Toolbar = (function(SS, $, undefined){
2
+ var init = function(options){
3
+ $('.toolbar_menu ul li ul').hide();
4
+ $('.toolbar_menu li a').click(function() {
5
+ $(this).next().slideToggle('normal');
6
+ });
7
+
8
+ Menu.init(options);
9
+ }
10
+
11
+ var Menu = (function(SS, $, undefined){
12
+ var init = function(options){
13
+ //Logo menu for current subject
14
+ //Full Caption Sliding (Hidden to Visible)
15
+ $('.logo_grid.logo_full').hover( function() {
16
+ $(".logo_menu", this).stop().animate({top:'101px'},{queue:false,duration:160});
17
+ }, function() {
18
+ $(".logo_menu", this).stop().animate({top:'1119px'},{queue:false,duration:160});
19
+ });
20
+
21
+ if (options != undefined && options['option'] != undefined && options['option'].length) {
22
+ expand(options['option']);
23
+ }
24
+ }
25
+
26
+ var expand = function(id) {
27
+ $('#toolbar_menu-' + id).next().show();
28
+ }
29
+
30
+ return {
31
+ init: init,
32
+ expand: expand
33
+ }
34
+ })(SS, $)
35
+
36
+ return {
37
+ init: init,
38
+ expandMenu: Menu.expand
39
+ }
40
+
41
+ })(SocialStream, jQuery);
@@ -14,6 +14,7 @@ select#language option {
14
14
  select#language option[value=browser] { padding-left: 0; }
15
15
  select#language option[value=en] { background-image: url(flags/en.png); }
16
16
  select#language option[value=es] { background-image: url(flags/es.png); }
17
+ select#language option[value=pt] { background-image: url(flags/pt.png); }
17
18
  #api_token {
18
19
  font-weight: bold;
19
20
  font-style: italic;
@@ -0,0 +1,44 @@
1
+ class ActivityActionsController < ApplicationController
2
+ # Last tendencies in rails talk about filtering params in the controller,
3
+ # instead of using attr_protected
4
+ #
5
+ # We hope it will be shiped in Rails 4, so we write our custom method for now
6
+ before_filter :clean_params
7
+
8
+ before_filter :can_read_activity_object, :only => :create
9
+
10
+ respond_to :js
11
+
12
+ def create
13
+ @activity_action =
14
+ current_subject.
15
+ sent_actions.
16
+ find_or_create_by_activity_object_id @activity_object.id
17
+
18
+ @activity_action.update_attributes params[:activity_action]
19
+ end
20
+
21
+ def update
22
+ activity_action.update_attributes params[:activity_action]
23
+ end
24
+
25
+ private
26
+
27
+ def clean_params
28
+ return if params[:activity_action].blank?
29
+
30
+ params[:activity_action].delete(:actor_id)
31
+ params[:activity_action].delete(:activity_object_id) if params[:id].present?
32
+ end
33
+
34
+ def can_read_activity_object
35
+ @activity_object = ActivityObject.find(params[:activity_action][:activity_object_id])
36
+
37
+ authorize! :read, @activity_object.object
38
+ end
39
+
40
+ def activity_action
41
+ @activity_action ||=
42
+ current_subject.sent_actions.find params[:id]
43
+ end
44
+ end
@@ -0,0 +1,39 @@
1
+ class FollowersController < ApplicationController
2
+ before_filter :authenticate_user!, :except => :index
3
+
4
+ respond_to :html, :js
5
+
6
+ def index
7
+ @contacts =
8
+ if params[:following]
9
+ current_subject.sent_contacts
10
+ else
11
+ current_subject.received_contacts
12
+ end
13
+
14
+ respond_to do |format|
15
+ format.html { @contacts = @contacts.page(params[:page]).per(20) }
16
+ format.js { @contacts = @contacts.page(params[:page]).per(20) }
17
+ format.json { render :text => to_json(@contacts) }
18
+ end
19
+ end
20
+
21
+ def update
22
+ current_contact.relation_ids = Array.wrap(Relation::Follow.instance.id)
23
+
24
+ respond_to :js
25
+ end
26
+
27
+ def destroy
28
+ current_contact.relation_ids = Array.new
29
+
30
+ respond_to :js
31
+ end
32
+
33
+ private
34
+
35
+ def current_contact
36
+ @contact ||=
37
+ current_subject.sent_contacts.find params[:id]
38
+ end
39
+ end
@@ -35,22 +35,22 @@ module ActivitiesHelper
35
35
  :owner_id => Actor.normalize_id(receiver)
36
36
  end
37
37
 
38
- def like_sentence(activity)
39
- likers_shown = 3
40
- likers_count = activity.likes.count
41
- likers_other = likers_count - likers_shown
38
+ def like_sentence(activity, options = {})
39
+ options[:likers_shown] ||= 2
42
40
 
43
41
  # TODO: select likers from current_subject's contacts
44
42
  likers =
45
- activity.likes.first(likers_shown).
43
+ activity.likes.first(options[:likers_shown]).
46
44
  map{ |a| a.sender_subject }.
47
- map{ |l| link_to l.name, l }.
48
- join(", ")
45
+ map{ |l| link_to l.name, l }
46
+
47
+ likers_count = activity.likes.count
48
+ likers_other = likers_count - options[:likers_shown]
49
49
 
50
50
  if likers_other > 0
51
- t("activity.like_sentence.many", :likers => likers, :count => likers_other).html_safe
52
- else
53
- t("activity.like_sentence.few", :likers => likers, :count => likers_count).html_safe
51
+ likers.push t("activity_action.sentence.more", :count => likers_other)
54
52
  end
53
+
54
+ t("activity.like_sentence", :likers => likers.to_sentence, :count => likers_count).html_safe
55
55
  end
56
56
  end
@@ -0,0 +1,35 @@
1
+ module ActivityActionsHelper
2
+ def toggle_follow_action(activity_object)
3
+ action = activity_object.action_from(current_subject)
4
+ action ||= activity_object.received_actions.build :actor_id => current_subject.actor_id
5
+
6
+ action.follow ^= true
7
+
8
+ action
9
+ end
10
+
11
+ # Show the {SocialStream::Models::Subject Subjects} that follow
12
+ # the {ActivityObject object}
13
+ #
14
+ # TODO: DRY with ActivitiesHelper#like_sentence
15
+ def followers_sentence(object, options = {})
16
+ options[:followers_shown] ||= 2
17
+
18
+ followers_count = object.follower_count
19
+
20
+ return "" unless followers_count > 0
21
+
22
+ followers =
23
+ object.followers.
24
+ map{ |a| a.subject }.
25
+ map{ |l| link_to l.name, l }
26
+
27
+ followers_other = followers_count - options[:followers_shown]
28
+
29
+ if followers_other > 0
30
+ followers.push t("activity_action.sentence.more", :count => followers_other)
31
+ end
32
+
33
+ t("#{ object.object_type.underscore }.activity_action.sentence.follow", :followers => followers.to_sentence, :count => followers_count, :default => :"activity_action.sentence.follow").html_safe
34
+ end
35
+ end
@@ -7,7 +7,7 @@ module ContactsHelper
7
7
  if c.reflexive?
8
8
  t('subject.this_is_you')
9
9
  else
10
- render :partial => 'contacts/link', :locals => { :contact => c }
10
+ render :partial => "contacts/link_#{ SocialStream.relation_model }", :locals => { :contact => c }
11
11
  end
12
12
 
13
13
  end
@@ -0,0 +1,5 @@
1
+ module FollowersHelper
2
+ def follow_link_class(contact)
3
+ "follow-link-#{ dom_id contact }"
4
+ end
5
+ end
@@ -1,109 +1,96 @@
1
+ # The toolbar is the left-side bar in Social Stream's layout
2
+ #
1
3
  module ToolbarHelper
2
4
  # Configuration of toolbar items
3
- include SocialStream::ToolbarConfig
5
+ include SocialStream::Views::Toolbar
4
6
 
5
- # Define the toolbar content for your view. There are two typical cases, depending on the value of
6
- # options[:profile]
7
- # * If present, render the profile menu for the {SocialStream::Models::Subject subject}
8
- # * If blank, render the home menu
7
+ # This method define the toolbar content for your view. The toolbar is at the left
8
+ # side of the screen in vanilla SocialStream distribution.
9
9
  #
10
- # The menu option allows overwriting a menu slot with the content of the given block
10
+ # The {type} argument chooses diffent configurations. There are three build-in cases:
11
+ # * :home, render the home menu
12
+ # * :profile, render the profile menu for the {SocialStream::Models::Subject subject}
13
+ # this {type} needs a :subject {option} with the subject in the sidebar
14
+ # * :messages, render the messages menu
11
15
  #
12
- #
13
- # Autoexpanding a menu section on your view:
16
+ # Autoexpand a menu section on your view:
14
17
  #
15
18
  # Toolbar allows you to autoexpand certain menu section that may be of interest for your view.
16
19
  # For example, the messages menu when you are looking your inbox. This is done through :option element.
17
20
  #
18
- # To get it working, you should use the proper :option to be expanded, ":option => :messages" in the
19
- # mentioned example. This will try
20
- # Base toolbar items, automatically, to expand the section of the menu where its root
21
- # list link, the one expanding the section, has an id equal to "#messages_menu". If you use
21
+ # To get it working, you should use the proper :option to be expanded. For instance,
22
22
  # ":options => :contacts" it will try to expand "#contacts_menu".
23
23
  #
24
- # For now its working with :option => :messages, :contacts or :groups
25
- #
26
- #
27
24
  # Examples:
28
25
  #
29
26
  # Render the home toolbar:
30
27
  #
31
28
  # <% toolbar %>
32
29
  #
30
+ # or
31
+ #
32
+ # <% toolbar :home %>
33
+ #
33
34
  # Render the profile toolbar for a user:
34
35
  #
35
- # <% toolbar :profile => @user %>
36
+ # <% toolbar :profile, :subject => @user %>
36
37
  #
37
- # Render the home toolbar changing the messages menu option:
38
+ # Render the messages menu:
38
39
  #
39
- # <% toolbar :option => :messages %>
40
+ # <% toolbar :messages %>
40
41
  #
41
42
  # Render the profile toolbar for group changing the contacts menu option:
42
43
  #
43
- # <% toolbar :profile => @group, :option => :contacts %>
44
+ # <% toolbar :profile, :subject => @group, :option => :contacts %>
44
45
  #
45
- def toolbar(options = {}, &block)
46
- if options[:option] && block_given?
47
- menu_options[options[:option]] = capture(&block)
48
- end
49
-
50
- content = capture do
51
- if options[:profile]
52
- render :partial => 'toolbar/profile', :locals => { :subject => options[:profile] }
53
- elsif options[:option].present? and options[:option].to_s.eql? 'messages'
54
- render :partial => 'toolbar/messages'
55
- else
56
- render :partial => 'toolbar/home'
57
- end
58
- end
46
+ def toolbar(type = :home, options = {})
47
+ content = toolbar_items(type, options).inject(ActiveSupport::SafeBuffer.new){ |result, item|
48
+ result + item[:html]
49
+ }
59
50
 
60
51
  case request.format
61
52
  when Mime::JS
62
53
  response = <<-EOJ
63
-
64
- $('#toolbarContent').html("#{ escape_javascript(content) }");
65
- initMenu();
66
- expandSubMenu('#{ options[:option] }');
67
- EOJ
54
+ $('#toolbarContent').html("#{ escape_javascript(content) }");
55
+ SocialStream.Toolbar.init({ option: '#{ options[:option] }' });
56
+ EOJ
68
57
 
69
58
  response.html_safe
70
59
  else
71
- content_for(:toolbar) do
72
- content
73
- end
74
- content_for(:javascript) do
75
- <<-EOJ
76
- expandSubMenu('#{ options[:option] }');
77
- EOJ
78
- end
60
+ content_for(:toolbar) do
61
+ content
62
+ end
63
+
64
+ content_for(:javascript) do
65
+ <<-EOJ
66
+ SocialStream.Toolbar.init({ option: '#{ options[:option] }' });
67
+ EOJ
68
+ end
79
69
  end
80
70
  end
81
71
 
82
- # Cache menu options for toolbar
83
- #
84
- # @api private
85
- def menu_options #:nodoc:
86
- @menu_options ||= {}
87
- end
72
+ def toolbar_menu(type, options = {})
73
+ ActiveSupport::SafeBuffer.new.tap do |menu|
74
+ menu << '<div class="toolbar_menu">'.html_safe
88
75
 
89
- #Prints the home toolbar menu.
90
- def home_toolbar_menu
91
- render_items home_toolbar_items
92
- end
76
+ toolbar_menu_render(toolbar_menu_items(type, options), menu)
93
77
 
94
- #Prints the profile toolbar menu.
95
- def profile_toolbar_menu(subject=current_subject)
96
- render_items profile_toolbar_items(subject)
78
+ menu << '</div>'.html_safe
79
+ end
97
80
  end
98
81
 
99
- #Prints the messages toolbar menu.
100
- def messages_toolbar_menu
101
- render_items messages_toolbar_items
102
- end
103
-
104
- #Renders array of navigation items with simple_navigation
105
- def render_items(items)
106
- menu = render_navigation :items => items
107
- return raw menu
82
+ def toolbar_menu_render(items, menu)
83
+ menu << '<ul>'.html_safe
84
+ items.each do |item|
85
+ menu << '<li>'.html_safe
86
+
87
+ menu << item[:html]
88
+ if item[:items].present?
89
+ toolbar_menu_render(item[:items], menu)
90
+ end
91
+
92
+ menu << '</li>'.html_safe
93
+ end
94
+ menu << '</ul>'.html_safe
108
95
  end
109
96
  end
@@ -0,0 +1,28 @@
1
+ # This model includes all the actions performed by {Actor actors}
2
+ # on {ActivityObject activity objects}
3
+ #
4
+ class ActivityAction < ActiveRecord::Base
5
+ belongs_to :actor
6
+ belongs_to :activity_object
7
+
8
+ before_save :change_follower_count
9
+
10
+ scope :sent_by, lambda{ |actor|
11
+ where(:actor_id => Actor.normalize_id(actor))
12
+ }
13
+
14
+ scope :received_by, lambda{ |activity_object|
15
+ where(:activity_object_id => ActivityObject.normalize_id(activity_object))
16
+ }
17
+
18
+ private
19
+
20
+ # Updates the follower_count counter in the {ActivityObject}
21
+ def change_follower_count
22
+ return unless follow_changed?
23
+
24
+ follow? ?
25
+ activity_object.increment!(:follower_count) :
26
+ activity_object.decrement!(:follower_count)
27
+ end
28
+ end
@@ -20,6 +20,14 @@ class ActivityObject < ActiveRecord::Base
20
20
  has_many :activity_object_activities, :dependent => :destroy
21
21
  has_many :activities, :through => :activity_object_activities
22
22
 
23
+ has_many :received_actions,
24
+ :class_name => "ActivityAction",
25
+ :dependent => :destroy
26
+ has_many :followers,
27
+ :through => :received_actions,
28
+ :source => :actor,
29
+ :conditions => { 'activity_actions.follow' => true }
30
+
23
31
  has_many :activity_object_properties,
24
32
  :dependent => :destroy
25
33
  has_many :object_properties,
@@ -56,8 +64,9 @@ class ActivityObject < ActiveRecord::Base
56
64
  object_type == "Actor"
57
65
  end
58
66
 
59
- def object_holder_hash
60
-
67
+ # Return the {Action} model to an {Actor}
68
+ def action_from(actor)
69
+ received_actions.sent_by(actor).first
61
70
  end
62
71
 
63
72
  end