social_stream 0.0.1

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.
Files changed (47) hide show
  1. data/Gemfile +16 -0
  2. data/Gemfile.lock +117 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +63 -0
  5. data/Rakefile +43 -0
  6. data/app/controllers/home_controller.rb +3 -0
  7. data/app/helpers/activities_helper.rb +10 -0
  8. data/app/models/activity.rb +75 -0
  9. data/app/models/activity_object.rb +18 -0
  10. data/app/models/activity_object_activity.rb +4 -0
  11. data/app/models/activity_verb.rb +14 -0
  12. data/app/models/actor.rb +31 -0
  13. data/app/models/permission.rb +4 -0
  14. data/app/models/relation.rb +73 -0
  15. data/app/models/relation_permission.rb +4 -0
  16. data/app/models/tie.rb +207 -0
  17. data/app/models/user.rb +82 -0
  18. data/app/views/activities/_activity.html.erb +5 -0
  19. data/app/views/activities/_activity_options.html.erb +8 -0
  20. data/app/views/activities/_jquery.html.erb +52 -0
  21. data/app/views/activities/_new.html.erb +13 -0
  22. data/app/views/activities/_root_activity.html.erb +44 -0
  23. data/app/views/activities/_subactivity.html.erb +23 -0
  24. data/app/views/activities/_subactivity_options.html.erb +7 -0
  25. data/app/views/devise/registrations/new.html.erb +21 -0
  26. data/app/views/home/_activities.html.erb +19 -0
  27. data/app/views/home/_location.html.erb +3 -0
  28. data/app/views/home/index.html.erb +4 -0
  29. data/app/views/ties/_pending.html.erb +33 -0
  30. data/config/locales/en.yml +29 -0
  31. data/lib/generators/social_stream/USAGE +9 -0
  32. data/lib/generators/social_stream/install_generator.rb +30 -0
  33. data/lib/generators/social_stream/templates/initializer.rb +14 -0
  34. data/lib/generators/social_stream/templates/migration.rb +131 -0
  35. data/lib/generators/social_stream/templates/seeds.yml +29 -0
  36. data/lib/social_stream.rb +49 -0
  37. data/lib/social_stream/models/activity_object.rb +59 -0
  38. data/lib/social_stream/models/actor.rb +30 -0
  39. data/lib/social_stream/models/supertype.rb +41 -0
  40. data/lib/social_stream/rails.rb +13 -0
  41. data/lib/social_stream/rails/common.rb +34 -0
  42. data/lib/social_stream/rails/engine.rb +7 -0
  43. data/lib/social_stream/rails/railtie.rb +7 -0
  44. data/lib/social_stream/rails/routes.rb +17 -0
  45. data/lib/social_stream/seed.rb +47 -0
  46. data/lib/social_stream/version.rb +3 -0
  47. metadata +144 -0
@@ -0,0 +1,4 @@
1
+ class RelationPermission < ActiveRecord::Base
2
+ belongs_to :relation
3
+ belongs_to :permission
4
+ end
data/app/models/tie.rb ADDED
@@ -0,0 +1,207 @@
1
+ # A link between two actors in a relation.
2
+ #
3
+ # The first Actor is the sender of the Tie. The second Actor is the receiver of the Tie.
4
+ #
5
+ # == Ties and Activities
6
+ # Activities are attached to ties.
7
+ # * The sender actor is the author of the Activity. It is the user that uploads
8
+ # a resource to the website or the social entity that originates the activity.
9
+ # * The receiver is the target of the Activity. The wall-profile of an actor is
10
+ # composed by the resources assigned to the ties in which the actor is the receiver.
11
+ # * The Relation sets up the mode in which the Activity is shared. It sets the rules,
12
+ # or permissions, by which actors have access to the Activity.
13
+ #
14
+ # == Inverse ties
15
+ # Relations can have its inverse. When a tie is establised, an inverse tie is establised
16
+ # as well.
17
+ #
18
+ # == Scopes
19
+ # There are several scopes defined:
20
+ # * sent_by(actor), ties whose sender is actor
21
+ # * received_by(actor), ties whose receiver is actor
22
+ # * sent_or_received_by(actor), the union of the former
23
+ # * inverse(tie), the inverse of tie
24
+ #
25
+ class Tie < ActiveRecord::Base
26
+ # Avoids loops at create_inverse after save callback
27
+ attr_accessor :_without_inverse
28
+ attr_protected :_without_inverse
29
+
30
+ # Facilitates relation assigment along with find_relation callback
31
+ attr_accessor :relation_name
32
+
33
+ validates_presence_of :sender_id, :receiver_id, :relation_id
34
+
35
+ belongs_to :sender,
36
+ :class_name => "Actor",
37
+ :include => SocialStream.actors
38
+ belongs_to :receiver,
39
+ :class_name => "Actor",
40
+ :include => SocialStream.actors
41
+ belongs_to :relation
42
+
43
+ has_many :activities
44
+
45
+ scope :sent_by, lambda { |a|
46
+ where(:sender_id => Actor_id(a))
47
+ }
48
+
49
+ scope :received_by, lambda { |a|
50
+ where(:receiver_id => Actor_id(a))
51
+ }
52
+
53
+ scope :sent_or_received_by, lambda { |a|
54
+ where(arel_table[:sender_id].eq(Actor_id(a)).
55
+ or(arel_table[:receiver_id].eq(Actor_id(a))))
56
+
57
+ }
58
+
59
+ scope :inverse, lambda { |t|
60
+ sent_by(t.receiver).
61
+ received_by(t.sender).
62
+ where(:relation_id => t.relation.inverse_id)
63
+ }
64
+
65
+ def sender_subject
66
+ sender.try(:subject)
67
+ end
68
+
69
+ def receiver_subject
70
+ receiver.try(:subject)
71
+ end
72
+
73
+ before_validation :find_relation
74
+
75
+ scope :pending, includes(:relation) & Relation.request
76
+
77
+ # The set of ties between sender and receiver
78
+ #
79
+ def relation_set(r = :nil)
80
+ set = self.class.where(:sender_id => sender_id,
81
+ :receiver_id => receiver_id)
82
+
83
+ case r
84
+ when :nil
85
+ set
86
+ when String
87
+ set.where(:relation_id => relation.mode.find_by_name(r))
88
+ else
89
+ set.where(:relation_id => r)
90
+ end
91
+ end
92
+
93
+ # The tie with relation r inside this relation_set
94
+ def related(r)
95
+ relation_set(r).first
96
+ end
97
+
98
+ after_create :complete_weak_set, :create_inverse
99
+
100
+ # Access Control
101
+
102
+ scope :with_permissions, lambda { |action, object|
103
+ includes(:relation => :permissions).
104
+ where('permissions.action' => action).
105
+ where('permissions.object' => object)
106
+ }
107
+
108
+ scope :parameterized, lambda { |tie|
109
+ where(tie_conditions(tie).
110
+ or(weak_set_conditions(tie)).
111
+ or(group_set_conditions(tie)).
112
+ or(weak_group_set_conditions(tie)))
113
+ }
114
+
115
+ scope :access_set, lambda { |tie, action, object|
116
+ with_permissions(action, object).
117
+ parameterized(tie)
118
+ }
119
+
120
+
121
+ def permissions(user, action, object)
122
+ self.class.
123
+ sent_by(user).
124
+ access_set(self, action, object)
125
+ end
126
+
127
+ def permission?(user, action, object)
128
+ permissions(user, action, object).any?
129
+ end
130
+
131
+ class << self
132
+ def tie_conditions(t)
133
+ arel_table[:sender_id].eq(t.sender_id).and(
134
+ arel_table[:receiver_id].eq(t.receiver_id)).and(
135
+ arel_table[:relation_id].eq(t.relation_id)).and(
136
+ Permission.arel_table[:parameter].eq('tie'))
137
+ end
138
+
139
+ def weak_set_conditions(t)
140
+ arel_table[:sender_id].eq(t.sender_id).and(
141
+ arel_table[:receiver_id].eq(t.receiver_id)).and(
142
+ arel_table[:relation_id].in(t.relation.stronger_or_equal)).and(
143
+ Permission.arel_table[:parameter].eq('weak_set'))
144
+ end
145
+
146
+ def group_set_conditions(t)
147
+ arel_table[:receiver_id].eq(t.receiver_id).and(
148
+ arel_table[:relation_id].eq(t.relation_id)).and(
149
+ Permission.arel_table[:parameter].eq('group_set'))
150
+ end
151
+
152
+ def weak_group_set_conditions(t)
153
+ arel_table[:receiver_id].eq(t.receiver_id).and(
154
+ arel_table[:relation_id].in(t.relation.stronger_or_equal)).and(
155
+ Permission.arel_table[:parameter].eq('weak_group_set'))
156
+ end
157
+ end
158
+
159
+ private
160
+
161
+ # Before validation callback
162
+ # Infers relation from its name and the type of the actors
163
+ def find_relation
164
+ if relation_name.present?
165
+ self.relation = Relation.mode(sender_subject.class.to_s,
166
+ receiver_subject.class.to_s).
167
+ find_by_name(relation_name)
168
+ end
169
+ end
170
+
171
+ # After create callback
172
+ # Creates ties with a weaker relations in the strength hierarchy of this tie
173
+ def complete_weak_set
174
+ relation.weaker.each do |r|
175
+ if relation_set(r).blank?
176
+ t = relation_set.build :relation => r
177
+ t._without_inverse = true
178
+ t.save!
179
+ end
180
+ end
181
+ end
182
+
183
+ # After create callback
184
+ # Creates a the inverse of this tie
185
+ def create_inverse
186
+ if !_without_inverse &&
187
+ relation.inverse.present? &&
188
+ Tie.inverse(self).blank?
189
+ t = Tie.inverse(self).build
190
+ t._without_inverse = true
191
+ t.save!
192
+ end
193
+ end
194
+
195
+ class << self
196
+ def Actor_id(a)
197
+ case a
198
+ when Integer
199
+ a
200
+ when Actor
201
+ a.id
202
+ else
203
+ a.actor.id
204
+ end
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,82 @@
1
+ class User < ActiveRecord::Base
2
+ # Include default devise modules. Others available are:
3
+ # :token_authenticatable, :confirmable, :lockable, :timeoutable, :validatable
4
+ devise :database_authenticatable, :registerable,
5
+ :recoverable, :rememberable, :trackable
6
+
7
+ # Setup accessible (or protected) attributes for your model
8
+ attr_accessible :name, :email, :password, :password_confirmation, :remember_me
9
+
10
+ validates_presence_of :name, :email
11
+ validates_format_of :email, :with => Devise.email_regexp, :allow_blank => true
12
+ # TODO: uniqueness of email, which is in actor
13
+
14
+ with_options :if => :password_required? do |v|
15
+ v.validates_presence_of :password
16
+ v.validates_confirmation_of :password
17
+ v.validates_length_of :password, :within => Devise.password_length, :allow_blank => true
18
+ end
19
+
20
+ protected
21
+
22
+ # From devise
23
+ def password_required?
24
+ !persisted? || !password.nil? || !password_confirmation.nil?
25
+ end
26
+
27
+ class << self
28
+ %w( email permalink name ).each do |a|
29
+ eval <<-EOS
30
+ def find_by_#{ a }(#{ a }) # def find_by_email(email)
31
+ find :first, # find(:first,
32
+ :include => :actor, # :include => :actor,
33
+ :conditions => # :conditions =>
34
+ { 'actors.#{ a }' => #{ a } } # { 'actors.email' => email }
35
+ end # end
36
+ EOS
37
+ end
38
+
39
+ # Overwrite devise default find method to support login with email,
40
+ # presence ID and login
41
+ def find_for_authentication(conditions)
42
+ if ( login = conditions[:email] ).present?
43
+ if login =~ /@/
44
+ find_by_email(login)
45
+ else
46
+ find_by_permalink(login)
47
+ end
48
+ else
49
+ super
50
+ end
51
+ end
52
+
53
+ def find_or_initialize_with_error_by(attribute, value, error=:invalid)
54
+ if attribute == :email
55
+ find_or_initialize_with_error_by_email(value, error)
56
+ else
57
+ super
58
+ end
59
+ end
60
+
61
+ # Overwrite devise default method to support finding with actor.email
62
+ def find_or_initialize_with_error_by_email(value, error)
63
+ if value.present?
64
+ record = find_by_email(value)
65
+ end
66
+
67
+ unless record
68
+ record = new
69
+
70
+ if value.present?
71
+ record.email = value
72
+ else
73
+ error = :blank
74
+ end
75
+
76
+ record.errors.add(:email, error)
77
+ end
78
+
79
+ record
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,5 @@
1
+ <% if activity.is_root? %>
2
+ <%= render :partial => "activities/root_activity", :object => activity %>
3
+ <% else %>
4
+ <%= render :partial => "activities/subactivity", :object => activity %>
5
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <div class="activity_options">
2
+ <ul class="activity_options" >
3
+ <li><div class="post_time_ago"><%= t('time.ago', :time => time_ago_in_words(activity.created_at)) %></div></li>
4
+ <li><div class="verb_comment"> · <%= link_to t('activity.to_comment'), "#", :class => "to_comment" %> </div></li>
5
+ <li><div class="verb_like" id="like_<%= dom_id(activity) %>"> · <%= like_activity(activity)%></div></li>
6
+ <li><div class="verb_delete"> · <%= link_to t('activity.delete'), activity.direct_object , :confirm => t('activity.confirm_delete'), :method => :delete, :remote => true %> </div></li>
7
+ </ul>
8
+ </div>
@@ -0,0 +1,52 @@
1
+ //javascript for main activities input
2
+ $("#activities_share_btn").hide();
3
+ title = "<%= t('activity.input') %>";
4
+ $("#input_activities").click(function(){
5
+ if(this.value == title){
6
+ this.value="";
7
+ $("#activities_share_btn").show();
8
+ }
9
+ });
10
+ $("#input_activities").blur(function(){
11
+ if(this.value == ""){
12
+ this.value= title;
13
+ $("#activities_share_btn").hide();
14
+ }
15
+ });
16
+
17
+ //javascript for comments
18
+ $(".input_new_comments").val("<%= t('comment.input') %>");
19
+ $(".activities_comment_btn").hide();
20
+
21
+ //usa livequery para usar el javascript luego de una accion con AJAX
22
+ $(".input_new_comments").livequery("click",function(){
23
+ if(this.value == "<%= t('comment.input') %>"){
24
+ $(this).val("");
25
+ }
26
+ $(".activities_comment_btn").hide();
27
+ $(this).parent(".new_comment").children(".activities_comment_btn").show();
28
+ });
29
+ $(".input_new_comments").livequery("blur",function(){
30
+ if(this.value == ""){
31
+ $(".activities_comment_btn").hide();
32
+ $(this).val("<%= t('comment.input') %>");
33
+ }
34
+ });
35
+
36
+ $(".input_new_comments").click(function(){
37
+ if(this.value == "<%= t('comment.input') %>"){
38
+ $(this).val("");
39
+ }
40
+ $(".activities_comment_btn").hide();
41
+ $(this).parent(".new_comment").children(".activities_comment_btn").show();
42
+ });
43
+
44
+ //javascript for tocomment option
45
+ $(".to_comment").livequery("click", function(){
46
+ $(this).parents(".activity_content").find(".input_new_comments").click();
47
+ return false;
48
+ });
49
+ $(".to_comment").livequery("blur", function(){
50
+ $(this).parents(".activity_content").find(".input_new_comments").blur();
51
+ return false;
52
+ });
@@ -0,0 +1,13 @@
1
+ <div id="activities_header" class="content_size">
2
+ <%= form_for Post.new(:text => t('activity.input'),
3
+ :_activity_tie_id => current_tie.id),
4
+ :remote => true do |f| %>
5
+ <%= f.hidden_field :_activity_tie_id %>
6
+ <%= f.text_field :text, :id => "input_activities", :size => 85 %>
7
+ <div id="activities_share_btn">
8
+ <%= image_submit_tag "buttons/btn_security.png" %>
9
+ <%= image_submit_tag "buttons/btn_share.png" %>
10
+ </div>
11
+ <% end -%>
12
+ </div>
13
+
@@ -0,0 +1,44 @@
1
+ <%= div_for root_activity do %>
2
+ <div class="actor_logo">
3
+ <%= link_to image_tag(root_activity.sender_subject.logo,
4
+ :size => "50x50",
5
+ :alt => root_activity.sender_subject.name),
6
+ root_activity.sender_subject %>
7
+ </div>
8
+
9
+ <div class="activity_content">
10
+ <div class="actor_name">
11
+ <%= link_to(root_activity.sender_subject.name, root_activity.sender_subject) %>
12
+ </div>
13
+
14
+ <div class="activity_objects">
15
+ <%= render root_activity.activity_objects %>
16
+ </div>
17
+
18
+ <%= render :partial => 'activities/activity_options',
19
+ :locals => { :activity => root_activity } %>
20
+
21
+ <div class="activity_comments" id="comments_<%= dom_id(root_activity) %>">
22
+ <%= render root_activity.comments %>
23
+ </div>
24
+
25
+ <div class="activity_new_comment">
26
+ <%= form_for Comment.new(:text => t('comment.input'),
27
+ :_activity_tie_id => current_tie.id,
28
+ :_activity_parent_id => root_activity.id),
29
+ :remote => true do |f| %>
30
+ <%= f.hidden_field :_activity_tie_id %>
31
+ <%= f.hidden_field :_activity_parent_id %>
32
+ <%= f.text_field :text, :class =>"input_new_comments" %>
33
+ <div class="activities_comment_btn">
34
+ <div class="activities_security"></div>
35
+ <%= image_submit_tag "buttons/btn_share.png" %>
36
+ </div>
37
+ <% end %>
38
+ </div>
39
+ </div>
40
+ <div class="space_comments"></div>
41
+ <div class="space_activities">
42
+ <div class="space_sub"></div>
43
+ </div>
44
+ <% end %>
@@ -0,0 +1,23 @@
1
+ <%= div_for subactivity, :class => "subactivity" do %>
2
+ <div class="actor_logo_subactivity">
3
+ <%= link_to image_tag(subactivity.sender_subject.logo,
4
+ :size => "30x30",
5
+ :alt => subactivity.sender_subject.name),
6
+ subactivity.sender_subject %>
7
+ </div>
8
+
9
+ <div class="activity_content">
10
+ <div class="actor_name-activity_objects">
11
+ <%= link_to(subactivity.sender_subject.name, subactivity.sender_subject) %>
12
+ <span class="subactivity_objects">
13
+ <%= render subactivity.activity_objects %>
14
+ </span>
15
+ </div>
16
+
17
+ <%= render :partial => 'activities/subactivity_options',
18
+ :locals => { :activity => subactivity } %>
19
+
20
+ </div>
21
+ <% end %>
22
+ <div class="space_comments">
23
+ </div>