social_stream 0.0.2 → 0.0.3

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