social_stream-base 0.12.1 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/app/assets/images/flags/en.png +0 -0
  2. data/app/assets/images/flags/es.png +0 -0
  3. data/app/assets/javascripts/toolbar.js +22 -1
  4. data/app/assets/stylesheets/activities.css.scss +1 -1
  5. data/app/assets/stylesheets/cheesecake.css.scss +46 -4
  6. data/app/assets/stylesheets/settings.css +11 -0
  7. data/app/controllers/cheesecake_controller.rb +15 -3
  8. data/app/controllers/contacts_controller.rb +2 -0
  9. data/app/controllers/conversations_controller.rb +5 -5
  10. data/app/controllers/likes_controller.rb +1 -1
  11. data/app/helpers/notifications_helper.rb +10 -0
  12. data/app/models/activity.rb +55 -36
  13. data/app/models/activity_object.rb +3 -23
  14. data/app/models/actor.rb +20 -4
  15. data/app/models/channel.rb +13 -1
  16. data/app/models/comment.rb +4 -0
  17. data/app/models/contact.rb +55 -19
  18. data/app/models/group.rb +5 -2
  19. data/app/models/like.rb +2 -2
  20. data/app/models/relation/custom.rb +1 -1
  21. data/app/models/tie.rb +4 -3
  22. data/app/views/cheesecake/_cheesecake.html.erb +63 -0
  23. data/app/views/cheesecake/_index.html.erb +43 -86
  24. data/app/views/cheesecake/index.html.erb +2 -0
  25. data/app/views/cheesecake/update.js.erb +3 -0
  26. data/app/views/devise/passwords/new.html.erb +1 -1
  27. data/app/views/devise/registrations/new.html.erb +1 -1
  28. data/app/views/devise/sessions/new.html.erb +1 -1
  29. data/app/{assets/stylesheets/0_devise_sign.css → views/layouts/_devise_style.html.erb} +3 -1
  30. data/app/views/layouts/_header_signed_in.erb +1 -1
  31. data/app/views/message_mailer/new_message_email.html.erb +2 -1
  32. data/app/views/message_mailer/new_message_email.text.erb +2 -1
  33. data/app/views/message_mailer/reply_message_email.html.erb +2 -1
  34. data/app/views/message_mailer/reply_message_email.text.erb +2 -1
  35. data/app/views/notification_mailer/new_notification_email.html.erb +2 -1
  36. data/app/views/notification_mailer/new_notification_email.text.erb +2 -1
  37. data/app/views/notifications/activities/_post.html.erb +24 -1
  38. data/app/views/notifications/activities/_post.text.erb +22 -3
  39. data/app/views/settings/_language.html.erb +1 -1
  40. data/config/locales/en.yml +3 -2
  41. data/config/locales/es.yml +4 -3
  42. data/config/routes.rb +1 -0
  43. data/db/migrate/20120111141717_activity_channels.rb +74 -0
  44. data/lib/social_stream-base.rb +1 -0
  45. data/lib/social_stream/base/engine.rb +2 -1
  46. data/lib/social_stream/base/version.rb +1 -1
  47. data/lib/social_stream/models/channeled.rb +50 -0
  48. data/lib/social_stream/models/object.rb +4 -13
  49. data/lib/social_stream/toolbar_config/base.rb +1 -1
  50. data/lib/tasks/db/populate.rake +1 -1
  51. data/social_stream-base.gemspec +2 -2
  52. data/spec/controllers/comments_controller_spec.rb +3 -3
  53. data/spec/factories/activity.rb +3 -3
  54. data/spec/factories/contact.rb +2 -0
  55. data/spec/models/activity_authorization_spec.rb +5 -1
  56. data/spec/models/like_spec.rb +3 -3
  57. data/spec/models/tie_spec.rb +4 -4
  58. metadata +70 -64
  59. data/vendor/assets/javascripts/menu.js +0 -25
Binary file
Binary file
@@ -1 +1,22 @@
1
- //= require menu
1
+ function initMenu() {
2
+ $('.toolbar_menu ul li ul').hide();
3
+ $('.toolbar_menu li a').click( function() {
4
+ $(this).next().slideToggle('normal');
5
+ }
6
+ );
7
+ //Logo menu for current subject
8
+ //Full Caption Sliding (Hidden to Visible)
9
+ $('.logo_grid.logo_full').hover( function() {
10
+ $(".logo_menu", this).stop().animate({top:'101px'},{queue:false,duration:160});
11
+ }, function() {
12
+ $(".logo_menu", this).stop().animate({top:'1119px'},{queue:false,duration:160});
13
+ });
14
+ }
15
+
16
+ function expandSubMenu(id) {
17
+ $('#' + id + '_menu').next().show();
18
+ }
19
+
20
+ $(document).ready(function() {
21
+ initMenu();
22
+ });
@@ -33,7 +33,7 @@
33
33
  .super_activity{width: 95%;}
34
34
  .activity { text-align:left; display: block; vertical-align: top; padding: 10px 0px 5px 0px;
35
35
  display: inline-block; color: $sentence-color; font-size: 13px; color: $main-color;border-bottom:1px solid #E9E9E9;}
36
- .actor_logo { width: 38px; padding: 8px 0px 5px 5px; display: inline-block; vertical-align: top;}
36
+ .actor_logo { width: 38px; padding: 0px 0px 5px 5px; display: inline-block; vertical-align: top;}
37
37
  .activity_content { padding: 0px; display: inline-block; color: $sentence-color; width: 89%; word-wrap: break-word; }
38
38
  .actor_name {font-size: 13px;}
39
39
  .actor_name a{font-weight: bold;}
@@ -3,11 +3,13 @@
3
3
  #cheesecake {
4
4
  position: relative;
5
5
  padding: 20px;
6
+ padding-top: 0px;
6
7
  }
7
8
  #contacts_cheesecake {
8
9
  width: 440px;
9
10
  height: 440px;
10
- padding: 0px;
11
+ padding: 0px;
12
+ margin-top: 45px;
11
13
  float: left;
12
14
  }
13
15
  #contacts_filter {
@@ -39,19 +41,59 @@
39
41
  }
40
42
  #contacts_grid_extra {
41
43
  width: 270px;
42
- padding: 5px;
43
- height: 10px;
44
- border: solid 1px $input-border-color;
45
44
  text-align: center;
46
45
  float: right;
47
46
  margin-right: 20px;
48
47
  cursor: pointer;
48
+ vertical-align: middle;
49
+ padding-top: 6px;
50
+ background: #DEEFF8;
51
+ padding-left: 10px;
52
+ display: block;
53
+ height: 20px;
54
+ font-weight: bold;
55
+ }
56
+ #contacts_save {
57
+ width: 270px;
58
+ padding-right: 5px;
59
+ height: 25px;
60
+ text-align: right;
61
+ float: right;
62
+ margin-right: 20px;
63
+ }
64
+ #contacts_save_form {
65
+ overflow: visible;
66
+ }
67
+ #contacts_changes {
68
+ width: 705px;
69
+ margin-left: 20px;
70
+ }
71
+ #contacts_changes_title {
72
+ vertical-align: middle;
73
+ padding-top: 6px;
74
+ background: $secondary-color;
75
+ padding-left: 10px;
76
+ display: block;
77
+ height: 20px;
78
+ font-weight: bold;
79
+ cursor: pointer;
80
+ }
81
+ #contacts_changes_details {
82
+ border: solid 1px $secondary-color;
83
+ border-top: 0px;
84
+ padding: 5px;
85
+ display: none;
86
+ max-height: 200px;
87
+ }
88
+ #contacts_changes_details ul{
89
+ padding-left: 20px;
49
90
  }
50
91
  #contacts_grid .actor {
51
92
  width: 48px;
52
93
  height: 48px;
53
94
  float: left;
54
95
  margin: 4px;
96
+ display: none;
55
97
  }
56
98
  #contacts_grid .actor.focused {
57
99
  border: 2px solid $main-color;
@@ -3,6 +3,17 @@
3
3
  display:block;
4
4
  padding-left:10px;
5
5
  }
6
+ select#language {
7
+ background: #fff;
8
+ }
9
+ select#language option {
10
+ padding: 3px 0 3px 30px;
11
+ background-repeat: no-repeat;
12
+ background-position: 3px center;
13
+ }
14
+ select#language option[value=browser] { padding-left: 0; }
15
+ select#language option[value=en] { background-image: url(flags/en.png); }
16
+ select#language option[value=es] { background-image: url(flags/es.png); }
6
17
  #api_token {
7
18
  font-weight: bold;
8
19
  font-style: italic;
@@ -1,9 +1,21 @@
1
1
  class CheesecakeController < ApplicationController
2
-
2
+
3
3
  before_filter :authenticate_user!
4
-
5
4
  def index
6
5
  @actors = current_subject.contact_actors(:direction => :sent)
7
6
  end
8
-
7
+
8
+ def update
9
+ changes = JSON.parse params[:contacts_save_changes] if params[:contacts_save_changes].is_a? String
10
+
11
+ if (actors = changes["actors"]).present? and actors.is_a? Array
12
+ actors.each do |actor|
13
+ next if (contact = Contact.find_by_id(actor["extraInfo"].to_i)).nil?
14
+ contact.relation_ids = actor["subsectors"]
15
+ end
16
+ end
17
+
18
+ @actors = current_subject.contact_actors(:direction => :sent)
19
+ end
20
+
9
21
  end
@@ -24,6 +24,8 @@ class ContactsController < ApplicationController
24
24
  params[:contact][:relation_ids].present? &&
25
25
  params[:contact][:relation_ids].delete("0")
26
26
 
27
+ params[:contact][:user_author] = current_user
28
+
27
29
  if @contact.update_attributes(params[:contact])
28
30
  redirect_to @contact.receiver_subject
29
31
  else
@@ -4,12 +4,12 @@ class ConversationsController < ApplicationController
4
4
  before_filter :get_mailbox, :get_box, :get_actor
5
5
  before_filter :check_current_subject_in_conversation, :only => [:show, :update, :destroy]
6
6
  def index
7
- if @box.eql?"inbox"
8
- @conversations = Kaminari.paginate_array(@mailbox.inbox).page(params[:page]).per(9)
9
- elsif @box.eql?"sentbox"
10
- @conversations = Kaminari.paginate_array(@mailbox.sentbox).page(params[:page]).per(9)
7
+ if @box.eql? "inbox"
8
+ @conversations = @mailbox.inbox.page(params[:page]).per(9)
9
+ elsif @box.eql? "sentbox"
10
+ @conversations = @mailbox.sentbox.page(params[:page]).per(9)
11
11
  else
12
- @conversations = Kaminari.paginate_array(@mailbox.trash).page(params[:page]).per(9)
12
+ @conversations = @mailbox.trash.page(params[:page]).per(9)
13
13
  end
14
14
  end
15
15
 
@@ -3,7 +3,7 @@ class LikesController < ApplicationController
3
3
 
4
4
  # POST /activities/1/like.js
5
5
  def create
6
- @like = Like.build(current_subject, @indirect_id)
6
+ @like = Like.build(current_subject, current_user, @indirect_id)
7
7
 
8
8
  respond_to do |format|
9
9
  if @like.save
@@ -0,0 +1,10 @@
1
+ module NotificationsHelper
2
+
3
+ # Set locale as per subject preference
4
+ def locale_as(subject)
5
+ if subject.respond_to? :language
6
+ I18n.locale = subject.language || I18n.default_locale
7
+ end
8
+ end
9
+
10
+ end
@@ -1,10 +1,10 @@
1
1
  # Activities follow the {Activity Streams}[http://activitystrea.ms/] standard.
2
2
  #
3
- # == Activities, Contacts and Audiences
4
- # Every activity is attached to a {Contact}, which defines the sender and the receiver of the {Activity}
3
+ # == {Activity Activities}, {Channel Channels} and Audiences
4
+ # Every activity is attached to a {Channel}, which defines the sender and the receiver of the {Activity}
5
5
  #
6
- # Besides, the activity is attached to one or more relations, which define the audicence of the activity,
7
- # the {actors Actor} that can reach it and their {permissions Permission}
6
+ # Besides, the activity is attached to one or more relations, which define the audience of the activity,
7
+ # in other words, the {actors Actor} that can reach it and their {permissions Permission}
8
8
  #
9
9
  # == Wall
10
10
  # The Activity.wall(args) scope provides all the activities appearing in a wall
@@ -12,16 +12,15 @@
12
12
  # There are two types of wall, :home and :profile. Check {Actor#wall} for more information
13
13
  #
14
14
  class Activity < ActiveRecord::Base
15
+ # See {SocialStream::Models::Channeled}
16
+ channeled
17
+
15
18
  has_ancestry
16
19
 
17
20
  paginates_per 10
18
21
 
19
22
  belongs_to :activity_verb
20
23
 
21
- belongs_to :contact
22
- has_one :sender, :through => :contact
23
- has_one :receiver, :through => :contact
24
-
25
24
  has_many :audiences, :dependent => :destroy
26
25
  has_many :relations, :through => :audiences
27
26
 
@@ -33,7 +32,7 @@ class Activity < ActiveRecord::Base
33
32
  scope :wall, lambda { |args|
34
33
  q =
35
34
  select("DISTINCT activities.*").
36
- joins(:contact).
35
+ joins(:channel).
37
36
  joins(:audiences).
38
37
  joins(:relations).
39
38
  roots
@@ -43,13 +42,14 @@ class Activity < ActiveRecord::Base
43
42
  where('activity_objects.object_type' => args[:object_type])
44
43
  end
45
44
 
46
- contacts = Contact.arel_table
45
+ channels = Channel.arel_table
47
46
  audiences = Audience.arel_table
48
47
  relations = Relation.arel_table
49
48
 
50
49
  owner_conditions =
51
- contacts[:sender_id].eq(Actor.normalize_id(args[:owner])).
52
- or(contacts[:receiver_id].eq(Actor.normalize_id(args[:owner])))
50
+ channels[:author_id].eq(Actor.normalize_id(args[:owner])).
51
+ or(channels[:user_author_id].eq(Actor.normalize_id(args[:owner]))).
52
+ or(channels[:owner_id].eq(Actor.normalize_id(args[:owner])))
53
53
 
54
54
  audience_conditions =
55
55
  audiences[:relation_id].in(args[:relation_ids]).
@@ -59,16 +59,16 @@ class Activity < ActiveRecord::Base
59
59
  case args[:type]
60
60
  when :home
61
61
  followed_conditions =
62
- contacts[:sender_id].in(args[:followed]).
63
- or(contacts[:receiver_id].in(args[:followed]))
62
+ channels[:author_id].in(args[:followed]).
63
+ or(channels[:owner_id].in(args[:followed]))
64
64
 
65
65
  owner_conditions.
66
66
  or(followed_conditions.and(audience_conditions))
67
67
  when :profile
68
68
  if args[:for].present?
69
69
  visitor_conditions =
70
- contacts[:sender_id].eq(Actor.normalize_id(args[:for])).
71
- or(contacts[:receiver_id].eq(Actor.normalize_id(args[:for])))
70
+ channels[:author_id].eq(Actor.normalize_id(args[:for])).
71
+ or(channels[:owner_id].eq(Actor.normalize_id(args[:for])))
72
72
 
73
73
  owner_conditions.
74
74
  and(visitor_conditions.or(audience_conditions))
@@ -110,7 +110,7 @@ class Activity < ActiveRecord::Base
110
110
  # This method provides the {Actor}. Use {#sender_subject} for the {SocialStream::Models::Subject Subject}
111
111
  # ({User}, {Group}, etc..)
112
112
  def sender
113
- contact.sender
113
+ channel.author
114
114
  end
115
115
 
116
116
  # The {SocialStream::Models::Subject Subject} author of this activity
@@ -118,7 +118,7 @@ class Activity < ActiveRecord::Base
118
118
  # This method provides the {SocialStream::Models::Subject Subject} ({User}, {Group}, etc...).
119
119
  # Use {#sender} for the {Actor}.
120
120
  def sender_subject
121
- contact.sender_subject
121
+ channel.author_subject
122
122
  end
123
123
 
124
124
  # The wall where the activity is shown belongs to receiver
@@ -126,7 +126,7 @@ class Activity < ActiveRecord::Base
126
126
  # This method provides the {Actor}. Use {#receiver_subject} for the {SocialStream::Models::Subject Subject}
127
127
  # ({User}, {Group}, etc..)
128
128
  def receiver
129
- contact.receiver
129
+ channel.owner
130
130
  end
131
131
 
132
132
  # The wall where the activity is shown belongs to the receiver
@@ -134,7 +134,7 @@ class Activity < ActiveRecord::Base
134
134
  # This method provides the {SocialStream::Models::Subject Subject} ({User}, {Group}, etc...).
135
135
  # Use {#receiver} for the {Actor}.
136
136
  def receiver_subject
137
- contact.receiver_subject
137
+ channel.owner_subject
138
138
  end
139
139
 
140
140
  # The comments about this activity
@@ -148,7 +148,7 @@ class Activity < ActiveRecord::Base
148
148
  end
149
149
 
150
150
  def liked_by(user) #:nodoc:
151
- likes.joins(:contact).merge(Contact.sent_by(user))
151
+ likes.joins(:channel).merge(Channel.subject_authored_by(user))
152
152
  end
153
153
 
154
154
  # Does user like this activity?
@@ -157,9 +157,12 @@ class Activity < ActiveRecord::Base
157
157
  end
158
158
 
159
159
  # Build a new children activity where subject like this
160
- def new_like(subject)
160
+ def new_like(subject, user)
161
+ channel = Channel.new :author => Actor.normalize(subject),
162
+ :user_author => Actor.normalize(user),
163
+ :owner => owner
161
164
  a = children.new :verb => "like",
162
- :contact => subject.contact_to!(receiver),
165
+ :channel => channel,
163
166
  :relation_ids => self.relation_ids
164
167
 
165
168
  if direct_activity_object.present?
@@ -207,7 +210,7 @@ class Activity < ActiveRecord::Base
207
210
  return true if !notificable?
208
211
  #Avaible verbs: follow, like, make-friend, post, update
209
212
 
210
- if ['like','follow','make-friend','post','update'].include? verb and !contact.reflexive?
213
+ if ['like','follow','make-friend','post','update'].include? verb and !channel.reflexive?
211
214
  receiver.notify(notification_subject, "Youre not supposed to see this", self)
212
215
  end
213
216
  true
@@ -215,15 +218,15 @@ class Activity < ActiveRecord::Base
215
218
 
216
219
  # Is subject allowed to perform action on this {Activity}?
217
220
  def allow?(subject, action)
218
- return false if contact.blank?
221
+ return false if channel.blank?
219
222
 
220
223
  case action
221
224
  when 'create'
222
- return false if contact.sender_id != Actor.normalize_id(subject)
225
+ return false if subject.blank? || channel.author_id != Actor.normalize_id(subject)
223
226
 
224
227
  rels = Relation.normalize(relation_ids)
225
228
 
226
- own_rels = rels.select{ |r| r.actor_id == contact.sender_id }
229
+ own_rels = rels.select{ |r| r.actor_id == channel.author_id }
227
230
  foreign_rels = rels - own_rels
228
231
 
229
232
  # Only posting to own relations or allowed to post to foreign relations
@@ -239,12 +242,12 @@ class Activity < ActiveRecord::Base
239
242
 
240
243
  return false if subject.blank?
241
244
 
242
- return true if [contact.sender_id, contact.receiver_id].include?(Actor.normalize_id(subject))
245
+ return true if [channel.author_id, channel.owner_id].include?(Actor.normalize_id(subject))
243
246
  when 'update'
244
- return true if contact.sender_id == Actor.normalize_id(subject)
247
+ return true if [channel.author_id, channel.owner_id].include?(Actor.normalize_id(subject))
245
248
  when 'destroy'
246
249
  # We only allow destroying to sender and receiver by now
247
- return [contact.sender_id, contact.receiver_id].include?(Actor.normalize_id(subject))
250
+ return [channel.author_id, channel.owner_id].include?(Actor.normalize_id(subject))
248
251
  end
249
252
 
250
253
  Relation.
@@ -302,10 +305,10 @@ class Activity < ActiveRecord::Base
302
305
 
303
306
  # FIXME: repeated in SocialStream::Models::Object#_relation_ids
304
307
  self.relation_ids =
305
- if contact.reflexive?
308
+ if channel.reflexive?
306
309
  receiver.relation_customs.map(&:id)
307
310
  else
308
- receiver.relation_customs.allow(contact.sender, 'create', 'activity').map(&:id)
311
+ receiver.relation_customs.allow(channel.author, 'create', 'activity').map(&:id)
309
312
  end
310
313
  end
311
314
 
@@ -340,11 +343,27 @@ class Activity < ActiveRecord::Base
340
343
  :who => I18n.t('notification.who.'+ receiver.subject.class.to_s.underscore,
341
344
  :name => receiver_name))
342
345
  when 'post'
343
- I18n.t('notification.post.'+ receiver.subject.class.to_s.underscore,
346
+ if direct_object.is_a? Comment
347
+ I18n.t('notification.post.'+ receiver.subject.class.to_s.underscore,
344
348
  :sender => sender_name,
345
- :whose => I18n.t('notification.whose.'+ receiver.subject.class.to_s.underscore,
346
- :receiver => receiver_name),
347
- :thing => I18n.t(direct_object.class.to_s.underscore+'.one'))
349
+ :whose => I18n.t('notification.whose.'+ receiver.subject.class.to_s.underscore,
350
+ :receiver => receiver_name),
351
+ :title => 'Re: ' + direct_object.parent_post.text.truncate(30, :separator => ' '))
352
+ elsif direct_object.is_a? Post
353
+ I18n.t('notification.post.'+ receiver.subject.class.to_s.underscore,
354
+ :sender => sender_name,
355
+ :whose => I18n.t('notification.whose.'+ receiver.subject.class.to_s.underscore,
356
+ :receiver => receiver_name),
357
+ :title => direct_object.text.truncate(30, :separator => ' '))
358
+ elsif direct_object.respond_to? :title
359
+ I18n.t('notification.post.'+ receiver.subject.class.to_s.underscore,
360
+ :sender => sender_name,
361
+ :whose => I18n.t('notification.whose.'+ receiver.subject.class.to_s.underscore,
362
+ :receiver => receiver_name),
363
+ :title => direct_object.title.truncate(30, :separator => ' '))
364
+ else
365
+ I18n.t('notification.default')
366
+ end
348
367
  when 'update'
349
368
  I18n.t('notification.update.'+ receiver.subject.class.to_s.underscore,
350
369
  :sender => sender_name,
@@ -9,10 +9,9 @@
9
9
  # Objects are added to +config/initializers/social_stream.rb+
10
10
  #
11
11
  class ActivityObject < ActiveRecord::Base
12
- # ActivityObject is a subtype of Channel
13
- # Author, owner and user_author of this ActivityObject are defined in its channel
14
- subtype_of :channel,
15
- :belongs => { :dependent => nil }
12
+ # See {SocialStream::Models::Channeled}
13
+ channeled
14
+
16
15
  # ActivityObject is a supertype of SocialStream.objects
17
16
  supertype_of :object
18
17
 
@@ -27,8 +26,6 @@ class ActivityObject < ActiveRecord::Base
27
26
  joins(:channel).merge(Channel.authored_by(subject))
28
27
  }
29
28
 
30
- before_validation :check_existing_channel
31
-
32
29
  # The object of this activity object
33
30
  def object
34
31
  subtype_instance.is_a?(Actor) ?
@@ -45,21 +42,4 @@ class ActivityObject < ActiveRecord::Base
45
42
  def acts_as_actor?
46
43
  object_type == "Actor"
47
44
  end
48
-
49
- protected
50
-
51
- def check_existing_channel
52
- return unless channel!.new_record?
53
-
54
- existing_channel =
55
- Channel.
56
- where(:author_id => author_id,
57
- :owner_id => owner_id,
58
- :user_author_id => user_author_id).
59
- first
60
-
61
- return if existing_channel.blank?
62
-
63
- self.channel = existing_channel
64
- end
65
45
  end