social_stream 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/.gitignore +1 -0
  2. data/.yardopts +2 -0
  3. data/Gemfile +2 -3
  4. data/Gemfile.lock +20 -3
  5. data/README.rdoc +2 -3
  6. data/Rakefile +15 -18
  7. data/app/controllers/groups_controller.rb +9 -0
  8. data/app/controllers/likes_controller.rb +47 -0
  9. data/app/controllers/ties_controller.rb +2 -72
  10. data/app/helpers/activities_helper.rb +5 -1
  11. data/app/helpers/ties_helper.rb +21 -10
  12. data/app/models/actor.rb +53 -14
  13. data/app/models/group.rb +13 -0
  14. data/app/models/tie.rb +11 -2
  15. data/app/models/user.rb +6 -0
  16. data/app/views/activities/_activity.html.erb +2 -2
  17. data/app/views/activities/_child.html.erb +23 -0
  18. data/app/views/activities/_jquery.html.erb +0 -2
  19. data/app/views/activities/{_activity_options.html.erb → _options.html.erb} +1 -1
  20. data/app/views/activities/_root.html.erb +32 -0
  21. data/app/views/activity_objects/_activity_object.html.erb +1 -0
  22. data/app/views/groups/_group.html.erb +3 -0
  23. data/app/views/groups/show.html.erb +28 -0
  24. data/app/views/home/_groups.html.erb +14 -0
  25. data/app/views/home/index.html.erb +1 -0
  26. data/app/views/likes/create.js.erb +2 -0
  27. data/app/views/likes/destroy.js.erb +1 -0
  28. data/app/views/ties/_form.html.erb +6 -0
  29. data/app/views/ties/_new.html.erb +26 -0
  30. data/app/views/ties/_pending.html.erb +2 -14
  31. data/app/views/ties/_pendings.html.erb +16 -0
  32. data/app/views/ties/_suggestions.html.erb +7 -3
  33. data/app/views/ties/_tie.html.erb +21 -0
  34. data/app/views/ties/create.js.erb +21 -0
  35. data/app/views/ties/new.html.erb +1 -0
  36. data/app/views/ties/new.js.erb +2 -0
  37. data/config/locales/en.yml +32 -11
  38. data/config/routes.rb +14 -0
  39. data/init.rb +3 -0
  40. data/lib/generators/social_stream/install_generator.rb +8 -4
  41. data/lib/generators/social_stream/templates/initializer.rb +1 -1
  42. data/lib/generators/social_stream/templates/migration.rb +14 -1
  43. data/lib/generators/social_stream/templates/seeds.yml +30 -0
  44. data/lib/paperclip/ext.rb +6 -0
  45. data/lib/social_stream.rb +1 -1
  46. data/lib/social_stream/models/actor.rb +19 -4
  47. data/lib/social_stream/models/supertype.rb +2 -6
  48. data/lib/social_stream/rails.rb +9 -3
  49. data/lib/social_stream/version.rb +1 -1
  50. data/social_stream.gemspec +15 -0
  51. data/spec/dummy/Rakefile +7 -0
  52. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  53. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  54. data/spec/dummy/app/models/ability.rb +23 -0
  55. data/spec/dummy/app/models/post.rb +2 -0
  56. data/spec/dummy/app/models/user.rb +2 -0
  57. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  58. data/spec/dummy/config.ru +4 -0
  59. data/spec/dummy/config/application.rb +46 -0
  60. data/spec/dummy/config/boot.rb +10 -0
  61. data/spec/dummy/config/database.yml +22 -0
  62. data/spec/dummy/config/environment.rb +5 -0
  63. data/spec/dummy/config/environments/development.rb +26 -0
  64. data/spec/dummy/config/environments/production.rb +49 -0
  65. data/spec/dummy/config/environments/test.rb +35 -0
  66. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  67. data/spec/dummy/config/initializers/devise.rb +142 -0
  68. data/spec/dummy/config/initializers/inflections.rb +10 -0
  69. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  70. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  71. data/spec/dummy/config/initializers/session_store.rb +8 -0
  72. data/spec/dummy/config/initializers/social_stream.rb +5 -0
  73. data/spec/dummy/config/locales/en.yml +5 -0
  74. data/spec/dummy/config/routes.rb +58 -0
  75. data/spec/dummy/db/.gitignore +1 -0
  76. data/spec/dummy/db/migrate/.gitkeep +0 -0
  77. data/spec/dummy/db/schema.rb +116 -0
  78. data/spec/dummy/db/seeds.rb +9 -0
  79. data/spec/dummy/db/seeds/social_stream.yml +54 -0
  80. data/spec/dummy/log/.gitignore +1 -0
  81. data/spec/dummy/public/404.html +26 -0
  82. data/spec/dummy/public/422.html +26 -0
  83. data/spec/dummy/public/500.html +26 -0
  84. data/spec/dummy/public/favicon.ico +0 -0
  85. data/spec/dummy/public/javascripts/application.js +2 -0
  86. data/spec/dummy/public/javascripts/controls.js +965 -0
  87. data/spec/dummy/public/javascripts/dragdrop.js +974 -0
  88. data/spec/dummy/public/javascripts/effects.js +1123 -0
  89. data/spec/dummy/public/javascripts/prototype.js +6001 -0
  90. data/spec/dummy/public/javascripts/rails.js +175 -0
  91. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  92. data/spec/dummy/script/rails +6 -0
  93. data/spec/factories/activity.rb +10 -0
  94. data/spec/factories/actor.rb +4 -0
  95. data/spec/factories/group.rb +3 -0
  96. data/spec/factories/post.rb +3 -0
  97. data/spec/factories/tie.rb +38 -0
  98. data/spec/factories/user.rb +4 -0
  99. data/spec/integration/navigation_spec.rb +9 -0
  100. data/spec/models/activity_spec.rb +420 -0
  101. data/spec/models/actor_spec.rb +16 -0
  102. data/spec/models/post_spec.rb +33 -0
  103. data/spec/models/tie_spec.rb +30 -0
  104. data/spec/models/user_space.rb +10 -0
  105. data/spec/social_stream_spec.rb +7 -0
  106. data/spec/spec_helper.rb +45 -0
  107. data/spec/support/cancan.rb +1 -0
  108. data/spec/support/db.rb +4 -0
  109. metadata +155 -45
  110. data/app/views/activities/_root_activity.html.erb +0 -32
  111. data/app/views/activities/_subactivity.html.erb +0 -23
  112. data/app/views/ties/_suggestion.html.erb +0 -20
  113. data/lib/social_stream/rails/routes.rb +0 -19
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pkg/*gem
data/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ lib/**/*.rb
2
+ app/**/*.rb
data/Gemfile CHANGED
@@ -8,9 +8,8 @@ if RUBY_VERSION < '1.9'
8
8
  gem "ruby-debug", ">= 0.10.3"
9
9
  end
10
10
 
11
- gem 'atd-ancestry', :require => 'ancestry'
12
- gem 'devise'
13
- gem 'inherited_resources'
11
+ gemspec
12
+
14
13
  gem 'cancan'
15
14
 
16
15
  gem "rspec-rails", ">= 2.0.0.beta"
data/Gemfile.lock CHANGED
@@ -1,3 +1,13 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ social_stream (0.0.4)
5
+ atd-ancestry (~> 1.3.0)
6
+ devise (~> 1.1.3)
7
+ inherited_resources (~> 1.1.2)
8
+ paperclip (~> 2.3.4)
9
+ stringex (~> 1.2.0)
10
+
1
11
  GEM
2
12
  remote: http://rubygems.org/
3
13
  specs:
@@ -67,6 +77,9 @@ GEM
67
77
  treetop (>= 1.4.5)
68
78
  mime-types (1.16)
69
79
  nokogiri (1.4.3.1)
80
+ paperclip (2.3.5)
81
+ activerecord
82
+ activesupport
70
83
  polyglot (0.3.1)
71
84
  rack (1.2.1)
72
85
  rack-mount (0.6.13)
@@ -112,6 +125,7 @@ GEM
112
125
  json_pure
113
126
  rubyzip
114
127
  sqlite3-ruby (1.3.1)
128
+ stringex (1.2.0)
115
129
  thor (0.14.3)
116
130
  treetop (1.4.8)
117
131
  polyglot (>= 0.3.1)
@@ -123,13 +137,16 @@ PLATFORMS
123
137
  ruby
124
138
 
125
139
  DEPENDENCIES
126
- atd-ancestry
140
+ atd-ancestry (~> 1.3.0)
127
141
  cancan
128
142
  capybara (>= 0.3.9)
129
- devise
143
+ devise (~> 1.1.3)
130
144
  factory_girl
131
- inherited_resources
145
+ inherited_resources (~> 1.1.2)
146
+ paperclip (~> 2.3.4)
132
147
  rails (= 3.0.0)
133
148
  rspec-rails (>= 2.0.0.beta)
134
149
  ruby-debug (>= 0.10.3)
150
+ social_stream!
135
151
  sqlite3-ruby
152
+ stringex (~> 1.2.0)
data/README.rdoc CHANGED
@@ -37,9 +37,8 @@ Then, execute:
37
37
  This will generate the following:
38
38
  * A migration providing the database schema
39
39
  * An initializer configuration file for Social Stream.
40
- * A database seeds file for defining Social Stream relations. You must add:
41
- SocialStream.seed!
42
- to your db/seeds.rb
40
+ * A database seeds file for defining Social Stream relations, along with an entry
41
+ in db/seeds.rb to load it.
43
42
  * A devise:install generation for authentication support
44
43
 
45
44
  == Actors and Activity Objects
data/Rakefile CHANGED
@@ -1,11 +1,14 @@
1
1
  # encoding: UTF-8
2
2
  require 'rake'
3
3
  require 'rake/rdoctask'
4
- require 'rake/gempackagetask'
4
+
5
+ require 'rubygems'
5
6
 
6
7
  require 'rspec/core'
7
8
  require 'rspec/core/rake_task'
8
9
 
10
+ require 'bundler'
11
+
9
12
  require File.join(File.dirname(__FILE__), 'lib', 'social_stream', 'version')
10
13
 
11
14
 
@@ -23,22 +26,16 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
23
26
  rdoc.rdoc_files.include('lib/**/*.rb', 'app/**/*.rb')
24
27
  end
25
28
 
26
- spec = Gem::Specification.new do |s|
27
- s.name = "social_stream"
28
- s.version = SocialStream::VERSION.dup
29
- s.summary = "Social networking features and activity streams."
30
- s.description = "Ruby on Rails plug-in supporting social networking features and activity streams."
31
- s.authors = ['Antonio Tapiador', 'Diego Carrera']
32
- s.files = FileList["[A-Z]*", "{app,config,lib}/**/*"]
33
- s.add_dependency('atd-ancestry', '~> 1.3.0')
34
- s.add_dependency('devise', '~> 1.1.3')
35
- s.add_dependency('inherited_resources', '~> 1.1.2')
29
+ class Bundler::GemHelper
30
+ def install_gem
31
+ built_gem_path = build_gem
32
+ out, err, code = sh_with_code("sudo gem install #{built_gem_path} --no-rdoc --no-ri")
33
+ if err[/ERROR/]
34
+ Bundler.ui.error err
35
+ else
36
+ Bundler.ui.confirm "#{name} (#{version}) installed"
37
+ end
38
+ end
36
39
  end
37
40
 
38
- Rake::GemPackageTask.new(spec) do |pkg|
39
- end
40
-
41
- desc "Install the gem #{spec.name}-#{spec.version}.gem"
42
- task :install => :gem do
43
- system("sudo gem install pkg/#{spec.name}-#{spec.version}.gem --no-ri --no-rdoc")
44
- end
41
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,9 @@
1
+ class GroupsController < InheritedResources::Base
2
+ protected
3
+
4
+ # Overwrite resource method to support permalink
5
+ # See InheritedResources::BaseHelpers#resource
6
+ def resource
7
+ @group ||= end_of_association_chain.find_by_permalink!(params[:id])
8
+ end
9
+ end
@@ -0,0 +1,47 @@
1
+ class LikesController < ApplicationController
2
+ # Ensure the suitable tie exists
3
+ before_filter :tie!, :only => :create
4
+
5
+ # POST /activities/1/like.js
6
+ def create
7
+ @like = activity!.children.new :verb => "like"
8
+
9
+ respond_to do |format|
10
+ if @like.save
11
+ tie!.activities << @like
12
+ format.js
13
+ else
14
+ format.js
15
+ end
16
+ end
17
+ end
18
+
19
+ def destroy
20
+ if (@like = activity!.liked_by(current_user).first)
21
+ @like.destroy
22
+ end
23
+
24
+ respond_to do |format|
25
+ format.js
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def activity
32
+ @activity ||= Activity.find(params[:activity_id])
33
+ end
34
+
35
+ def activity!
36
+ activity || raise(ActiveRecord::RecordNotFound)
37
+ end
38
+
39
+ def tie
40
+ @tie ||= current_user.sent_ties(:receiver => activity!.receiver,
41
+ :relation => activity!.relation).first
42
+ end
43
+
44
+ def tie!
45
+ tie || raise(ActiveRecord::RecordNotFound)
46
+ end
47
+ end
@@ -1,73 +1,3 @@
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
1
+ class TiesController < InheritedResources::Base
2
+ respond_to :html, :xml, :js
73
3
  end
@@ -1,6 +1,10 @@
1
1
  module ActivitiesHelper
2
2
 
3
- def like_activity(activity)
3
+ # Link to 'like' or 'unlike' depending on the like status of the activity to current_user
4
+ #
5
+ # @param [Activity]
6
+ # @return [String]
7
+ def link_like(activity)
4
8
  if (activity.liked_by?(current_user))
5
9
  link_to t('activity.unlike'), activity_like_path(activity), :method => :delete, :remote => true
6
10
  else
@@ -1,18 +1,29 @@
1
1
  module TiesHelper
2
- def suggestion_brief(subject)
2
+ def tie_brief(tie)
3
3
  "18 contacts in common"
4
4
  end
5
5
 
6
- def suggestion_link(subject, relations)
7
- relation = relations[subject.class.to_s.underscore.to_sym] # relation = relations[:user]
6
+ def tie_link(tie)
7
+ # FIXME: tie name
8
+ if tie.relation.granted
9
+ # There is granted relation, so another user must confirmate it
10
+ # We need to render ties#new with a message
11
+ link_to t("#{ tie.relation.name }.new"),
12
+ new_tie_path("tie[sender_id]" => tie.sender.id,
13
+ "tie[receiver_id]" => tie.receiver.id,
14
+ "tie[relation_name]" => tie.relation.name),
15
+ :title => t("#{ tie.relation.name }.confirm_new",
16
+ :name => tie.receiver_subject.name),
17
+ :remote => true
8
18
 
9
- raise "Relation not provided for #{ subject.class.to_s.underscore }" if relation.blank?
19
+ else
20
+ # Tie can be established at once.
21
+ render :partial => 'ties/form',
22
+ :locals => { :tie => tie }
23
+ end
24
+ end
10
25
 
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)
26
+ def link_follow_state
27
+ link_to("unfollow", home_path)
17
28
  end
18
29
  end
data/app/models/actor.rb CHANGED
@@ -2,16 +2,32 @@
2
2
  class Actor < ActiveRecord::Base
3
3
  include SocialStream::Models::Supertype
4
4
 
5
+ validates_presence_of :name, :subject_type
6
+
7
+ acts_as_url :name, :url_attribute => :permalink
8
+
9
+ has_attached_file :logo,
10
+ :styles => { :small => "30x30" },
11
+ :default_url => "/:attachment/:style/:subtype_class.png"
12
+
5
13
  has_many :sent_ties,
6
14
  :class_name => "Tie",
7
15
  :foreign_key => 'sender_id',
8
16
  :dependent => :destroy
9
17
 
18
+ has_many :senders,
19
+ :through => :received_ties,
20
+ :uniq => true
21
+
10
22
  has_many :received_ties,
11
23
  :class_name => "Tie",
12
24
  :foreign_key => 'receiver_id',
13
25
  :dependent => :destroy
14
26
 
27
+ has_many :receivers,
28
+ :through => :sent_ties,
29
+ :uniq => true
30
+
15
31
  # The subject instance for this actor
16
32
  def subject
17
33
  subtype_instance ||
@@ -81,20 +97,39 @@ class Actor < ActiveRecord::Base
81
97
 
82
98
  # This is an scaffold for a recomendations engine
83
99
  #
84
- # By now, it returns another subject without any current relation
100
+ SuggestedRelations = {
101
+ 'User' => 'friend_request',
102
+ 'Group' => 'follower'
103
+ }
104
+
105
+ # Make n suggestions
106
+ # TODO: make more
107
+ def suggestions(n)
108
+ n.times.map{ |m| suggestion }
109
+ end
110
+
111
+ # By now, it returns a tie suggesting a relation from SuggestedRelations
112
+ # to another subject without any current relation
85
113
  #
86
114
  # Options::
87
115
  # * type: the class of the recommended subject
116
+ #
117
+ # @return [Tie]
88
118
  def suggestion(options = {})
89
- type = options[:type]
119
+ type = options[:type].present? ?
120
+ options[:type].to_s.classify :
121
+ SuggestedRelations.keys[rand(SuggestedRelations.size)]
90
122
 
91
- type = type.present? ?
92
- type.to_s.classify.constantize :
93
- random_receiving_subject_type
123
+ type_class = type.constantize
94
124
 
95
- candidates = type.all - receiver_subjects(type)
125
+ # Candidates are all the instance of "type" minus all the subjects
126
+ # that are receiving any tie from this actor
127
+ candidates = type_class.all - receiver_subjects(type)
128
+
129
+ candidate = candidates[rand(candidates.size)]
96
130
 
97
- candidates[rand(candidates.size)]
131
+ sent_ties.build :receiver_id => candidate.actor_id,
132
+ :relation => Relation.mode(subject_type, type).find_by_name(SuggestedRelations[type])
98
133
  end
99
134
 
100
135
  # All the ties this actor has with subject that support activities
@@ -102,17 +137,21 @@ class Actor < ActiveRecord::Base
102
137
  sent_ties.received_by(subject).active
103
138
  end
104
139
 
140
+ def pending_ties
141
+ #TODO: optimize by SQL
142
+ @pending_ties ||=
143
+ received_ties.pending.
144
+ select{ |t| ! receivers.include?(t.sender) }.
145
+ map{ |u| Tie.new :sender_id => u.receiver_id,
146
+ :receiver_id => u.sender_id,
147
+ :relation_id => u.relation.granted_id
148
+ }
149
+ end
150
+
105
151
  # The set of activities in the wall of this actor
106
152
  # TODO: authorization
107
153
  def wall
108
154
  Activity.wall ties
109
155
  end
110
-
111
- private
112
-
113
- def random_receiving_subject_type
114
- type_candidates = subject.class.receiving_subject_classes
115
- type_candidates[rand(type_candidates.size)]
116
- end
117
156
  end
118
157
 
@@ -0,0 +1,13 @@
1
+ class Group < ActiveRecord::Base
2
+ validates_presence_of :name
3
+
4
+ scope :alphabetic, includes(:actor).order('actors.name')
5
+
6
+ def logo
7
+ "group.png"
8
+ end
9
+
10
+ def followers
11
+ sender_subjects(:user, :relations => 'follower')
12
+ end
13
+ end