social_stream 0.0.2 → 0.0.3

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.
data/Gemfile CHANGED
@@ -10,6 +10,7 @@ end
10
10
 
11
11
  gem 'atd-ancestry', :require => 'ancestry'
12
12
  gem 'devise'
13
+ gem 'inherited_resources'
13
14
  gem 'cancan'
14
15
 
15
16
  gem "rspec-rails", ">= 2.0.0.beta"
@@ -54,7 +54,11 @@ GEM
54
54
  factory_girl (1.3.2)
55
55
  ffi (0.6.3)
56
56
  rake (>= 0.8.7)
57
+ has_scope (0.5.0)
57
58
  i18n (0.4.1)
59
+ inherited_resources (1.1.2)
60
+ has_scope (~> 0.5.0)
61
+ responders (~> 0.6.0)
58
62
  json_pure (1.4.6)
59
63
  linecache (0.43)
60
64
  mail (2.2.7)
@@ -83,16 +87,17 @@ GEM
83
87
  rake (>= 0.8.4)
84
88
  thor (~> 0.14.0)
85
89
  rake (0.8.7)
86
- rspec (2.0.0)
87
- rspec-core (= 2.0.0)
88
- rspec-expectations (= 2.0.0)
89
- rspec-mocks (= 2.0.0)
90
- rspec-core (2.0.0)
91
- rspec-expectations (2.0.0)
90
+ responders (0.6.2)
91
+ rspec (2.0.1)
92
+ rspec-core (~> 2.0.1)
93
+ rspec-expectations (~> 2.0.1)
94
+ rspec-mocks (~> 2.0.1)
95
+ rspec-core (2.0.1)
96
+ rspec-expectations (2.0.1)
92
97
  diff-lcs (>= 1.1.2)
93
- rspec-mocks (2.0.0)
94
- rspec-core (= 2.0.0)
95
- rspec-expectations (= 2.0.0)
98
+ rspec-mocks (2.0.1)
99
+ rspec-core (~> 2.0.1)
100
+ rspec-expectations (~> 2.0.1)
96
101
  rspec-rails (2.0.1)
97
102
  rspec (~> 2.0.0)
98
103
  ruby-debug (0.10.3)
@@ -123,6 +128,7 @@ DEPENDENCIES
123
128
  capybara (>= 0.3.9)
124
129
  devise
125
130
  factory_girl
131
+ inherited_resources
126
132
  rails (= 3.0.0)
127
133
  rspec-rails (>= 2.0.0.beta)
128
134
  ruby-debug (>= 0.10.3)
data/Rakefile CHANGED
@@ -32,6 +32,7 @@ spec = Gem::Specification.new do |s|
32
32
  s.files = FileList["[A-Z]*", "{app,config,lib}/**/*"]
33
33
  s.add_dependency('atd-ancestry', '~> 1.3.0')
34
34
  s.add_dependency('devise', '~> 1.1.3')
35
+ s.add_dependency('inherited_resources', '~> 1.1.2')
35
36
  end
36
37
 
37
38
  Rake::GemPackageTask.new(spec) do |pkg|
@@ -0,0 +1,2 @@
1
+ class ActivitiesController < ApplicationController
2
+ end
@@ -0,0 +1,9 @@
1
+ class PostsController < InheritedResources::Base
2
+ respond_to :html, :xml, :js
3
+
4
+ def destroy
5
+ @post_activity = resource.post_activity
6
+
7
+ destroy!
8
+ end
9
+ end
@@ -0,0 +1,73 @@
1
+ class TiesController < ApplicationController
2
+ before_filter :actor!
3
+
4
+ # GET /ties
5
+ # GET /ties.xml
6
+ def index
7
+ @ties = actor.sent_ties.all
8
+
9
+ respond_to do |format|
10
+ format.html # index.html.erb
11
+ format.xml { render :xml => @ties }
12
+ end
13
+ end
14
+
15
+ # GET /ties/1
16
+ # GET /ties/1.xml
17
+ def show
18
+ @tie = actor.sent_ties.find(params[:id])
19
+
20
+ respond_to do |format|
21
+ format.html # show.html.erb
22
+ format.xml { render :xml => @tie }
23
+ end
24
+ end
25
+
26
+ # GET /ties/new
27
+ # GET /ties/new.xml
28
+ def new
29
+ @tie = actor!.sent_ties.build(params[:tie])
30
+
31
+ respond_to do |format|
32
+ format.html {render :layout => false }
33
+ #format.xml { render :xml => @tie }
34
+ format.js {render :partial => "ties/new"}
35
+ end
36
+ end
37
+
38
+ # POST /ties
39
+ # POST /ties.xml
40
+ def create
41
+ @tie = Tie.new(params[:tie])
42
+
43
+ respond_to do |format|
44
+ if @tie.save
45
+ format.html { redirect_to(@tie, :notice => 'Tie was successfully created.') }
46
+ format.xml { render :xml => @tie, :status => :created, :location => @tie }
47
+ format.js
48
+ else
49
+ format.html { render :partial => "new" }
50
+ format.xml { render :xml => @tie.errors, :status => :unprocessable_entity }
51
+ format.js
52
+ end
53
+ end
54
+ end
55
+
56
+ # DELETE /ties/1
57
+ # DELETE /ties/1.xml
58
+ def destroy
59
+ @tie = Tie.find(params[:id])
60
+ @tie.destroy
61
+
62
+ respond_to do |format|
63
+ format.html { redirect_to(ties_url) }
64
+ format.xml { head :ok }
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def actor!
71
+ current_user
72
+ end
73
+ end
@@ -0,0 +1,18 @@
1
+ module TiesHelper
2
+ def suggestion_brief(subject)
3
+ "18 contacts in common"
4
+ end
5
+
6
+ def suggestion_link(subject, relations)
7
+ relation = relations[subject.class.to_s.underscore.to_sym] # relation = relations[:user]
8
+
9
+ raise "Relation not provided for #{ subject.class.to_s.underscore }" if relation.blank?
10
+
11
+ link_to t("tie.suggestion.#{ relation }.new"),
12
+ new_tie_path("tie[sender_id]" => current_user.actor.id,
13
+ "tie[receiver_id]" => subject.actor.id,
14
+ "tie[relation_name]" => relation),
15
+ :class => 'boxy',
16
+ :title => t("tie.suggestion.#{ relation }.confirm_new", :name => subject.name)
17
+ end
18
+ end
@@ -6,9 +6,13 @@ class ActivityVerb < ActiveRecord::Base
6
6
 
7
7
  has_many :activities
8
8
 
9
+ scope :verb_name, lambda{ |n|
10
+ where(:name => n)
11
+ }
12
+
9
13
  class << self
10
14
  def [] name
11
- find_by_name(name)
15
+ verb_name(name).first
12
16
  end
13
17
  end
14
18
  end
@@ -23,22 +23,57 @@ class Actor < ActiveRecord::Base
23
23
  Tie.sent_or_received_by(self)
24
24
  end
25
25
 
26
- # All the subject actors of class type that have at least one tie
27
- # with this actor
26
+ # All the subject actors of class subject_type that send at least one tie
27
+ # to this actor
28
28
  #
29
29
  # Options::
30
30
  # * relations: Restrict the relations of considered ties
31
- def contacts(type, options = {})
32
- type_class = type.to_s.classify.constantize
31
+ # * include_self: False by default, don't include this actor as subject even they
32
+ # have ties with themselves.
33
+ def sender_subjects(subject_type, options = {})
34
+ # FIXME: DRY!
35
+ subject_class = subject_type.to_s.classify.constantize
33
36
 
34
- cs = type_class.
35
- select("DISTINCT #{ type_class.quoted_table_name }.*").
37
+ cs = subject_class.
38
+ select("DISTINCT #{ subject_class.quoted_table_name }.*").
39
+ with_sent_ties &
40
+ Tie.received_by(self)
41
+
42
+ if options[:include_self].blank?
43
+ cs = cs.where("#{ self.class.quoted_table_name }.id != ?", self.id)
44
+ end
45
+
46
+ if options[:relations].present?
47
+ cs &=
48
+ Tie.related_by(Tie.Relation(options[:relations], :mode => [ subject_class, self.subject.class ]))
49
+ end
50
+
51
+ cs
52
+ end
53
+
54
+ # All the subject actors of class subject_type that receive at least one tie
55
+ # from this actor
56
+ #
57
+ # Options::
58
+ # * relations: Restrict the relations of considered ties
59
+ # * include_self: False by default, don't include this actor as subject even they
60
+ # have ties with themselves.
61
+ def receiver_subjects(subject_type, options = {})
62
+ # FIXME: DRY!
63
+ subject_class = subject_type.to_s.classify.constantize
64
+
65
+ cs = subject_class.
66
+ select("DISTINCT #{ subject_class.quoted_table_name }.*").
36
67
  with_received_ties &
37
68
  Tie.sent_by(self)
38
69
 
70
+ if options[:include_self].blank?
71
+ cs = cs.where("#{ self.class.quoted_table_name }.id != ?", self.id)
72
+ end
73
+
39
74
  if options[:relations].present?
40
75
  cs &=
41
- Tie.related_by(Tie.Relation(options[:relations], :mode => [ subject.class, type_class ]))
76
+ Tie.related_by(Tie.Relation(options[:relations], :mode => [ subject.class, subject_class ]))
42
77
  end
43
78
 
44
79
  cs
@@ -46,9 +81,18 @@ class Actor < ActiveRecord::Base
46
81
 
47
82
  # This is an scaffold for a recomendations engine
48
83
  #
49
- # By now, it returns another actor without any current relation
50
- def suggestion(type = subject.class)
51
- candidates = type.to_s.classify.constantize.all - contacts(type)
84
+ # By now, it returns another subject without any current relation
85
+ #
86
+ # Options::
87
+ # * type: the class of the recommended subject
88
+ def suggestion(options = {})
89
+ type = options[:type]
90
+
91
+ type = type.present? ?
92
+ type.to_s.classify.constantize :
93
+ random_receiving_subject_type
94
+
95
+ candidates = type.all - receiver_subjects(type)
52
96
 
53
97
  candidates[rand(candidates.size)]
54
98
  end
@@ -58,5 +102,12 @@ class Actor < ActiveRecord::Base
58
102
  def wall
59
103
  Activity.wall ties
60
104
  end
105
+
106
+ private
107
+
108
+ def random_receiving_subject_type
109
+ type_candidates = subject.class.receiving_subject_classes
110
+ type_candidates[rand(type_candidates.size)]
111
+ end
61
112
  end
62
113
 
@@ -0,0 +1,3 @@
1
+ class Post < ActiveRecord::Base
2
+ validates_presence_of :text
3
+ end
@@ -43,6 +43,8 @@ class Tie < ActiveRecord::Base
43
43
 
44
44
  has_many :activities
45
45
 
46
+ scope :recent, order("#{ quoted_table_name }.created_at DESC")
47
+
46
48
  scope :sent_by, lambda { |a|
47
49
  where(:sender_id => Actor_id(a))
48
50
  }
@@ -50,3 +50,5 @@ $(".to_comment").livequery("blur", function(){
50
50
  $(this).parents(".activity_content").find(".input_new_comments").blur();
51
51
  return false;
52
52
  });
53
+
54
+ $(".boxy").boxy();
@@ -0,0 +1,3 @@
1
+ <%= div_for post, :class => 'content_size' do %>
2
+ <%= post.text %>
3
+ <% end %>
@@ -0,0 +1,5 @@
1
+ //set a new value to input field with javascript
2
+ $("#input_activities").val("<%= t('activity.input') %>");
3
+ //Display the new post
4
+ $("#wall").prepend("<%= escape_javascript(render @post.post_activity) %>");
5
+ $("#activities_share_btn").hide();
@@ -0,0 +1,2 @@
1
+ $("#<%= dom_id(@post_activity) %>").hide();
2
+
@@ -1,13 +1,13 @@
1
- <% if actor.ties.pending.any? %>
1
+ <% if current_user.received_ties.pending.any? %>
2
2
  <div class="middle_box">
3
3
  <div class="middle_box_header">
4
4
  <%= image_tag('notifications.png', :class => "middle_box_picture_icon") %>
5
5
  <div class="middle_box_text_header"><%= t 'tie.pending.other' %></div>
6
6
  <div class="title_righ">
7
- <a href="#"><%= t 'tie.pending.see_all' %></a>
7
+ <a href="#"><%= t 'tie.pending.all' %></a>
8
8
  </div>
9
9
  </div>
10
- <% actor.ties.pending.each do |tie| %>
10
+ <% current_user.received_ties.pending.each do |tie| %>
11
11
  <div class="middle_box_content">
12
12
  <div class="actor_logo">
13
13
  <%= link_to(image_tag(tie.sender_subject.logo, :size => "55x40"),
@@ -0,0 +1,20 @@
1
+ <% if (subject = current_user.suggestion).present? %>
2
+ <div id="suggestion_<%= dom_id(subject) %>" class="suggestion">
3
+ <div class="suggestion_actor_logo">
4
+ <%= link_to(image_tag(subject.logo, :size =>"30x30"), subject) %>
5
+ </div>
6
+ <div class="suggestion_content">
7
+ <div class="suggestion_name">
8
+ <%= link_to(subject.name, subject) %>
9
+ </div>
10
+ <div class="suggestion_brief">
11
+ <%= suggestion_brief(subject) %>
12
+ </div>
13
+ <div class="suggestion_link">
14
+ <%= suggestion_link(subject, :user => 'friend_request',
15
+ :space => 'follower') %>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ <% end %>
20
+
@@ -0,0 +1,12 @@
1
+ <div class="suggestions_header">
2
+ <%= image_tag('notifications.png', :class => "suggestion_icon") %>
3
+ <div class="suggestion_text_header">
4
+ <%=t('tie.suggestion.one') %>
5
+ </div>
6
+ </div>
7
+ <div class="suggestions">
8
+ <% 2.times do %>
9
+ <%= render :partial => 'ties/suggestion' %>
10
+ <% end %>
11
+ </div>
12
+
@@ -14,16 +14,25 @@ en:
14
14
  one: "Home"
15
15
  location:
16
16
  message: "You are here > %{location}"
17
+ message: "Message"
17
18
  tie:
18
19
  pending:
19
20
  other: Pending requests
20
- see_all: See all
21
+ all: "All"
22
+ suggestion:
23
+ one: Suggestion
24
+ other: Suggestions
25
+ friend_request:
26
+ new: "+ Add as friend"
27
+ confirm_new: "Do you want to add %{name} as friend?"
28
+ follower:
29
+ new: "+ Follow"
30
+ confirm_new: "Do you want to follow %{name}?"
31
+ all: All
21
32
  time:
22
33
  ago: "%{time} ago"
23
34
  days: Days
24
35
  delete:
25
36
  confirm: Delete %{element}}?
26
37
  socialstream: "SocialStream"
27
- ask:
28
- add_friend: "¿Add %{name} as friend?"
29
38
  all_rights_reserved: All rights reserved
@@ -8,10 +8,10 @@ SocialStream.setup do |config|
8
8
  # Others available are:
9
9
  # :token_authenticatable, :confirmable, :lockable, :timeoutable, :validatable
10
10
  # config.devise_modules :database_authenticatable, :registerable,
11
- :recoverable, :rememberable, :trackable
11
+ # :recoverable, :rememberable, :trackable
12
12
 
13
13
  # Type of activities managed by actors
14
14
  # Remember you must add an "activity_object_id" foreign key column to your migration!
15
15
  #
16
- # config.activity_objects = []
16
+ # config.activity_objects = [ :post ]
17
17
  end
@@ -56,6 +56,15 @@ class CreateSocialStream < ActiveRecord::Migration
56
56
  t.datetime "updated_at"
57
57
  end
58
58
 
59
+ create_table "posts", :force => true do |t|
60
+ t.integer "activity_object_id"
61
+ t.datetime "created_at"
62
+ t.datetime "updated_at"
63
+ t.text "text"
64
+ end
65
+
66
+ add_index "posts", ["activity_object_id"], :name => "fk_post_object"
67
+
59
68
  create_table "relation_permissions", :force => true do |t|
60
69
  t.integer "relation_id"
61
70
  t.integer "permission_id"
@@ -101,6 +110,7 @@ class CreateSocialStream < ActiveRecord::Migration
101
110
  t.integer "relation_id"
102
111
  t.datetime "created_at"
103
112
  t.datetime "updated_at"
113
+ t.text "message"
104
114
  end
105
115
 
106
116
  add_index "ties", ["receiver_id"], :name => "fk_tie_receiver"
@@ -16,7 +16,7 @@ module SocialStream
16
16
  :rememberable, :trackable ]
17
17
 
18
18
  mattr_accessor :activity_objects
19
- @@activity_objects = []
19
+ @@activity_objects = [ :post ]
20
20
 
21
21
  class << self
22
22
  def setup
@@ -25,8 +25,18 @@ module SocialStream
25
25
  end
26
26
 
27
27
  module InstanceMethods
28
+ # All the activities with this object
28
29
  def activities
29
- activity_object_activities.includes(:activity).map(&:activity).uniq
30
+ Activity.
31
+ includes(:activity_objects => self.class.to_s.underscore).
32
+ where("#{ self.class.quoted_table_name }.id" => self.id)
33
+ end
34
+
35
+ # The activity in which this object was posted
36
+ #
37
+ # FIXME: Currently it only supports direct objects
38
+ def post_activity
39
+ (activities.includes(:activity_verb) & ActivityVerb.verb_name('post')).first
30
40
  end
31
41
 
32
42
  # Create corresponding ActivityObject including this class type
@@ -2,7 +2,7 @@ require 'active_support/concern'
2
2
 
3
3
  module SocialStream
4
4
  module Models
5
- # Additional features for models that are actors
5
+ # Additional features for models that are subtypes of actors
6
6
  module Actor
7
7
  extend ActiveSupport::Concern
8
8
 
@@ -16,10 +16,14 @@ module SocialStream
16
16
  :permalink, :permalink=,
17
17
  :disabled, :disabled=,
18
18
  :ties, :sent_ties, :received_ties,
19
- :contacts, :suggestion,
19
+ :sender_subjects, :receiver_subjects, :suggestion,
20
20
  :wall,
21
21
  :to => :actor!
22
22
 
23
+
24
+ scope :with_sent_ties, joins(:actor => :sent_ties)
25
+ scope :with_received_ties, joins(:actor => :received_ties)
26
+
23
27
  after_create :initialize_default_ties
24
28
  end
25
29
 
@@ -45,8 +49,12 @@ module SocialStream
45
49
  Relation.mode(to_s, to)
46
50
  end
47
51
 
48
- def with_received_ties
49
- joins(:actor => :received_ties)
52
+ # Actor subtypes that may receive a tie from an instance of this class
53
+ def receiving_subject_classes
54
+ Relation.select("DISTINCT #{ Relation.quoted_table_name }.receiver_type").
55
+ where(:sender_type => to_s).
56
+ map(&:receiver_type).
57
+ map(&:constantize)
50
58
  end
51
59
  end
52
60
  end
@@ -24,7 +24,7 @@ module SocialStream #:nodoc:
24
24
  s = s.to_s.classify.constantize
25
25
  s.__send__(:include, features) unless s.ancestors.include?(features)
26
26
  rescue
27
- puts "Warning: could not load #{ s }"
27
+ puts "Warning: could not load #{ s.to_s.classify }"
28
28
  end
29
29
  end
30
30
  end
@@ -1,6 +1,8 @@
1
1
  # Load Devise constant
2
2
  require 'ancestry'
3
3
  require 'devise'
4
+ require 'inherited_resources'
5
+
4
6
  require 'social_stream/rails/common'
5
7
  File.expand_path(__FILE__) =~ /#{ File.join('vendor', 'plugins') }/ ?
6
8
  require('social_stream/rails/railtie') :
@@ -20,6 +20,7 @@ module SocialStream
20
20
 
21
21
  # https://rails.lighthouseapp.com/projects/8994/tickets/1905-apphelpers-within-plugin-not-being-mixed-in
22
22
  ApplicationController.helper ActivitiesHelper
23
+ ApplicationController.helper TiesHelper
23
24
  end
24
25
 
25
26
  initializer "social_stream.inflections" do
@@ -1,3 +1,3 @@
1
1
  module SocialStream
2
- VERSION = "0.0.2".freeze
2
+ VERSION = "0.0.3".freeze
3
3
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: social_stream
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 2
10
- version: 0.0.2
9
+ - 3
10
+ version: 0.0.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Antonio Tapiador
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-10-19 00:00:00 +02:00
19
+ date: 2010-10-20 00:00:00 +02:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -51,6 +51,22 @@ dependencies:
51
51
  version: 1.1.3
52
52
  type: :runtime
53
53
  version_requirements: *id002
54
+ - !ruby/object:Gem::Dependency
55
+ name: inherited_resources
56
+ prerelease: false
57
+ requirement: &id003 !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ hash: 23
63
+ segments:
64
+ - 1
65
+ - 1
66
+ - 2
67
+ version: 1.1.2
68
+ type: :runtime
69
+ version_requirements: *id003
54
70
  description: Ruby on Rails plug-in supporting social networking features and activity streams.
55
71
  email:
56
72
  executables: []
@@ -65,10 +81,12 @@ files:
65
81
  - Rakefile
66
82
  - Gemfile
67
83
  - README.rdoc
84
+ - app/helpers/ties_helper.rb
68
85
  - app/helpers/activities_helper.rb
69
86
  - app/models/activity_object.rb
70
87
  - app/models/relation_permission.rb
71
88
  - app/models/tie.rb
89
+ - app/models/post.rb
72
90
  - app/models/user.rb
73
91
  - app/models/permission.rb
74
92
  - app/models/actor.rb
@@ -76,9 +94,17 @@ files:
76
94
  - app/models/activity.rb
77
95
  - app/models/relation.rb
78
96
  - app/models/activity_verb.rb
97
+ - app/controllers/ties_controller.rb
98
+ - app/controllers/activities_controller.rb
79
99
  - app/controllers/home_controller.rb
100
+ - app/controllers/posts_controller.rb
101
+ - app/views/ties/_suggestions.html.erb
102
+ - app/views/ties/_suggestion.html.erb
80
103
  - app/views/ties/_pending.html.erb
81
104
  - app/views/devise/registrations/new.html.erb
105
+ - app/views/posts/_post.html.erb
106
+ - app/views/posts/create.js.erb
107
+ - app/views/posts/destroy.js.erb
82
108
  - app/views/activities/_activity.html.erb
83
109
  - app/views/activities/_activity_options.html.erb
84
110
  - app/views/activities/_subactivity_options.html.erb