diff --git a/config/initializers/action_tracker.rb b/config/initializers/action_tracker.rb
new file mode 100644
index 0000000..b5b95cd
--- /dev/null
+++ b/config/initializers/action_tracker.rb
@@ -0,0 +1,51 @@
+require 'noosfero/i18n'
+
+# ActionTracker plugin stuff
+
+ActionTrackerConfig.verbs = {
+ :create_article => {
+ :description => _('published %s %s: %s') % ['{{ta.get_name.size}}', '{{_(pluralize_without_count(ta.get_name.size, "article"))}}', '{{ta.collect_group_with_index(:name){ |n,i| link_to(truncate(n), ta.get_url[i])}.to_sentence(:connector => _("and"))}}'],
+ :type => :groupable
+ },
+ :update_article => {
+ :description => _('updated %s %s: %s') % ['{{ta.get_name.uniq.size}}', '{{_(pluralize_without_count(ta.get_name.uniq.size, "article"))}}', '{{ta.collect_group_with_index(:name){ |n,i| link_to(truncate(n), ta.get_url[i])}.uniq.to_sentence(:connector => _("and"))}}'],
+ :type => :groupable
+ },
+ :remove_article => {
+ :description => _('removed %s %s: %s') % ['{{ta.get_name.size}}', '{{_(pluralize_without_count(ta.get_name.size, "article"))}}', '{{ta.get_name.collect{ |n| truncate(n) }.to_sentence(:connector => _("and"))}}'],
+ :type => :groupable
+ },
+ :publish_article_in_community => {
+ :description => _('published %s %s in communities: %s') % ['{{ta.get_name.size}}', '{{_(pluralize_without_count(ta.get_name.size, "article"))}}', '{{ta.collect_group_with_index(:name){ |n, i| link_to(truncate(n), ta.get_url[i]) + " (" + _("in") + " " + link_to(ta.get_profile_name[i], ta.get_profile_url[i]) + ")"}.to_sentence(:connector => _("and"))}}'],
+ :type => :groupable
+ },
+ :new_friendship => {
+ :description => _('has made %s %s: %s') % ['{{ta.get_friend_name.size}}', '{{_(pluralize_without_count(ta.get_friend_name.size, "new friend"))}}', '{{ta.collect_group_with_index(:friend_name){ |n,i| link_to(content_tag(:img, nil, :src => (ta.get_friend_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/person-icon.png"))), ta.get_friend_url[i], :title => n)}.join}}'],
+ :type => :groupable
+ },
+ :join_community => {
+ :description => _('has joined %s %s: %s') % ['{{ta.get_resource_name.size}}', '{{_(pluralize_without_count(ta.get_resource_name.size, "community"))}}', '{{ta.collect_group_with_index(:resource_name){ |n,i| link_to(content_tag(:img, nil, :src => (ta.get_resource_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/community-icon.png"))), ta.get_resource_url[i], :title => n)}.join}}'],
+ :type => :groupable
+ },
+ :leave_community => {
+ :description => _('has left %s %s: %s') % ['{{ta.get_resource_name.size}}', '{{_(pluralize_without_count(ta.get_resource_name.size, "community"))}}', '{{ta.collect_group_with_index(:resource_name){ |n,i| link_to(content_tag(:img, nil, :src => (ta.get_resource_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/community-icon.png"))), ta.get_resource_url[i], :title => n)}.join}}'],
+ :type => :groupable
+ },
+ :upload_image => {
+ :description => _('uploaded %s %s: %s %s') % ['{{ta.get_view_url.size}}', '{{_(pluralize_without_count(ta.get_view_url.size, "image"))}}', '{{ta.collect_group_with_index(:thumbnail_path){ |t,i| content_tag(:span, link_to(content_tag(:img, nil, :src => t), ta.get_view_url[i]))}.last(3).join}}', '{{unique_with_count(ta.collect_group_with_index(:parent_name){ |n,i| link_to(n, ta.get_parent_url[i])}, _("in the gallery")).join(" ")}}'],
+ :type => :groupable
+ },
+ :leave_comment => {
+ :description => _('has left the following comment "%s" on the article %s: "%s" (%s)') % ["{{truncate(ta.get_title)}}", "{{link_to(truncate(ta.get_article_title), ta.get_article_url)}}", "{{truncate(ta.get_body, 50)}}", "{{link_to(_('read'), ta.get_url)}}"]
+ },
+ :leave_scrap => {
+ :description => _('sent a message to %s: "%s"') % ["{{link_to(ta.get_receiver_name, ta.get_receiver_url)}}", "{{auto_link_urls(ta.get_content)}}"]
+ },
+ :leave_scrap_to_self => {
+ :description => _('wrote: "%s"') % "{{auto_link_urls(ta.get_content)}}"
+ }
+}
+
+ActionTrackerConfig.current_user_method = :current_person
+
+ActionTrackerConfig.timeout = 24.hours
diff --git a/db/migrate/20100910205341_create_scraps.rb b/db/migrate/20100910205341_create_scraps.rb
new file mode 100644
index 0000000..e4b599d
--- /dev/null
+++ b/db/migrate/20100910205341_create_scraps.rb
@@ -0,0 +1,14 @@
+class CreateScraps < ActiveRecord::Migration
+ def self.up
+ create_table :scraps do |t|
+ t.text :content
+ t.integer :sender_id, :receiver_id
+ t.integer :scrap_id
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :scraps
+ end
+end
diff --git a/db/migrate/20100910205408_create_action_tracker.rb b/db/migrate/20100910205408_create_action_tracker.rb
new file mode 100644
index 0000000..e383f6d
--- /dev/null
+++ b/db/migrate/20100910205408_create_action_tracker.rb
@@ -0,0 +1,21 @@
+class CreateActionTracker < ActiveRecord::Migration
+ def self.up
+ create_table :action_tracker do |t|
+ t.belongs_to :user, :polymorphic => true
+ t.belongs_to :dispatcher, :polymorphic => true
+ t.text :params
+ t.string :verb
+ t.timestamps
+ end
+
+ change_table :action_tracker do |t|
+ t.index [:user_id, :user_type]
+ t.index [:dispatcher_id, :dispatcher_type]
+ t.index :verb
+ end
+ end
+
+ def self.down
+ drop_table :action_tracker
+ end
+end
diff --git a/db/migrate/20100910205427_create_action_tracker_notifications.rb b/db/migrate/20100910205427_create_action_tracker_notifications.rb
new file mode 100644
index 0000000..f05df8a
--- /dev/null
+++ b/db/migrate/20100910205427_create_action_tracker_notifications.rb
@@ -0,0 +1,12 @@
+class CreateActionTrackerNotifications < ActiveRecord::Migration
+ def self.up
+ create_table :action_tracker_notifications do |t|
+ t.references :action_tracker
+ t.references :profile
+ end
+ end
+
+ def self.down
+ drop_table :action_tracker_notifications
+ end
+end
diff --git a/lib/notify_activity_job.rb b/lib/notify_activity_job.rb
new file mode 100644
index 0000000..9ce4d54
--- /dev/null
+++ b/lib/notify_activity_job.rb
@@ -0,0 +1,7 @@
+class NotifyActivityJob < Struct.new(:tracked_action_id, :profile_id)
+ def perform
+ tracked_action = ActionTracker::Record.find(tracked_action_id)
+ profile = Profile.find(profile_id)
+ ActionTrackerNotification.create(:action_tracker => tracked_action, :profile => profile)
+ end
+end
diff --git a/lib/notify_activity_to_profiles_job.rb b/lib/notify_activity_to_profiles_job.rb
new file mode 100644
index 0000000..9ce20e0
--- /dev/null
+++ b/lib/notify_activity_to_profiles_job.rb
@@ -0,0 +1,16 @@
+class NotifyActivityToProfilesJob < Struct.new(:tracked_action_id, :target_profile_id)
+ def perform
+ profile = Profile.find(target_profile_id) unless target_profile_id.nil?
+ tracked_action = ActionTracker::Record.find(tracked_action_id)
+ tracked_action.user.each_friend do |friend|
+ Delayed::Job.enqueue NotifyActivityJob.new(tracked_action_id, friend.id)
+ end
+ if profile.is_a?(Community)
+ profile.each_member do |member|
+ next if member == tracked_action.user
+ Delayed::Job.enqueue NotifyActivityJob.new(tracked_action_id, member.id)
+ end
+ ActionTrackerNotification.create(:action_tracker => tracked_action, :profile => profile)
+ end
+ end
+end
diff --git a/public/designs/icons/tango/style.css b/public/designs/icons/tango/style.css
index 5c4a0f6..470b71d 100644
--- a/public/designs/icons/tango/style.css
+++ b/public/designs/icons/tango/style.css
@@ -71,3 +71,5 @@
.icon-media-next { background-image: url(Tango/16x16/actions/media-skip-forward.png) }
.icon-lock { background-image: url(Tango/16x16/actions/lock.png) }
.icon-chat { background-image: url(Tango/16x16/apps/internet-group-chat.png) }
+.icon-scrap { background-image: url(Tango/16x16/actions/format-justify-left.png) }
+.icon-reply { background-image: url(Tango/16x16/actions/edit-redo.png) }
diff --git a/public/designs/themes/noosfero/theme.yml b/public/designs/themes/noosfero/theme.yml
index b2ceccc..68ae402 100644
--- a/public/designs/themes/noosfero/theme.yml
+++ b/public/designs/themes/noosfero/theme.yml
@@ -1,3 +1,4 @@
theme: "Noosfero default theme"
layout: "application-ng"
+jquery_theme: "smoothness_mod"
icon_theme: [default, pidgin]
diff --git a/public/images/scrap-bg-gray.png b/public/images/scrap-bg-gray.png
new file mode 100644
index 0000000..b10351f
Binary files /dev/null and b/public/images/scrap-bg-gray.png differ
diff --git a/public/images/scrap-bg.png b/public/images/scrap-bg.png
new file mode 100644
index 0000000..c2637ab
Binary files /dev/null and b/public/images/scrap-bg.png differ
diff --git a/public/javascripts/application.js b/public/javascripts/application.js
index 9e48a46..2533d70 100644
--- a/public/javascripts/application.js
+++ b/public/javascripts/application.js
@@ -545,3 +545,29 @@ jQuery(function($) {
$('body').addClass('webkit');
}
});
+
+function hide_and_show(hide_elements, show_elements) {
+ for(i=0; i < hide_elements.length; i++){
+ jQuery(hide_elements[i]).hide();
+ }
+ for(i=0; i < show_elements.length; i++){
+ jQuery(show_elements[i]).show();
+ }
+}
+
+function limited_text_area(textid, limit) {
+ var text = jQuery('#' + textid).val();
+ jQuery('#' + textid).css('height', jQuery('#' + textid).attr('scrollHeight') + 'px');
+ var textlength = text.length;
+ jQuery('#' + textid + '_left span').html(limit - textlength);
+ if (textlength > limit) {
+ jQuery('#' + textid + '_left').hide();
+ jQuery('#' + textid + '_limit').show();
+ jQuery('#' + textid).val(text.substr(0,limit));
+ return false;
+ } else {
+ jQuery('#' + textid + '_left').show();
+ jQuery('#' + textid + '_limit').hide();
+ return true;
+ }
+}
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
index 9ed4fc8..e69bb5d 100644
--- a/public/stylesheets/application.css
+++ b/public/stylesheets/application.css
@@ -265,7 +265,7 @@ table.profile th {
}
table.profile td {
border: none;
- padding-left: 0px;
+ padding: 0px;
}
table.profile tr:hover td {
background: none;
@@ -4617,3 +4617,261 @@ h1#agenda-title {
text-align: center;
display: block;
}
+
+#profile-activity ul, #profile-network ul, #profile-wall ul {
+ padding-left: 0;
+ clear: both;
+}
+
+#profile-activity li, #profile-network li, #profile-wall li {
+ display: block;
+ padding: 0;
+ margin-bottom: 8px;
+}
+
+#profile-activity .profile-activity-image, #profile-network .profile-network-image, #profile-wall .profile-wall-image {
+ float: left;
+ width: 100px;
+ height: 80px;
+ margin: 0;
+ padding: 0;
+ border: 1px solid transparent;
+ text-align: center;
+}
+
+#profile-activity .profile-activity-description, #profile-network .profile-network-description, #profile-wall .profile-wall-description {
+ float: left;
+ min-height: 80px;
+ margin: 0;
+ padding: 0;
+ border: 1px solid #ccc;
+ width: 355px;
+ overflow: hidden;
+ background-color: #fff;
+ position: relative;
+}
+
+#profile-activity .profile-activity-description .icon-delete span,
+#profile-network .profile-network-description .icon-delete span,
+#profile-wall .profile-wall-description .icon-delete span {
+ display: none;
+}
+
+#profile-activity .profile-activity-description .icon-delete,
+#profile-network .profile-network-description .icon-delete,
+#profile-wall .profile-wall-description .icon-delete {
+ position: absolute;
+ top: 4px;
+ right: 4px;
+ background-position: center center;
+}
+
+#profile-activity .profile-activity-text, #profile-network .profile-network-text, #profile-wall .profile-wall-text {
+ font-size: 13px;
+ margin: 5px;
+ padding-top: 15px;
+}
+
+#profile-wall .profile-wall-text {
+ padding-top: 0;
+}
+
+#profile-activity .profile-activity-time, #profile-network .profile-network-time, #profile-wall .profile-wall-time {
+ font-size: 11px;
+ margin: 5px;
+ color: #333;
+}
+
+#profile-activity hr, #profile-network hr, #profile-wall hr {
+ clear: both;
+ border: 0;
+}
+
+#profile-activity .profile-activity-send-message, #profile-network .profile-network-send-message, #profile-wall .profile-wall-send-message {
+ text-decoration: none;
+ font-size: 11px;
+ color: #000;
+ margin: 10px 0 0 0;
+}
+
+#profile-activity .profile-activity-send-message a, #profile-network .profile-network-send-message a, #profile-wall .profile-wall-send-message a {
+ text-decoration: none;
+}
+
+#profile-activity .profile-activity-text img, #profile-network .profile-network-text img, #profile-wall .profile-wall-text img {
+ padding: 1px;
+ border: 1px solid #ccc;
+ margin: 4px 3px 0 0;
+}
+
+.profile-wall-image,
+.leave_scrap_to_self .profile-network-image,
+.leave_scrap .profile-network-image,
+.leave_scrap_to_self .profile-activity-image,
+.leave_scrap .profile-activity-image {
+ background: transparent url(/images/scrap-bg.png) 104% 10px no-repeat;
+ position: relative;
+ left: 1px;
+ z-index: 2;
+}
+
+#leave_scrap_content {
+ width: 450px;
+ border: 1px solid #ccc;
+ padding: 2px;
+}
+
+#profile-network .upload_image .profile-network-text span,
+#profile-activity .upload_image .profile-activity-text span {
+ width: 109px;
+ height: 109px;
+ overflow: hidden;
+ display: inline-block;
+ padding: 0;
+ margin: 4px 3px 0 0;
+ text-align: center;
+}
+
+#profile-network .upload_image .profile-network-text img,
+#profile-activity .upload_image .profile-activity-text img {
+ padding: 0;
+ border: 0;
+ margin: 0;
+}
+
+#leave_scrap_response {
+ font-size: 12px;
+ text-align: right;
+ font-weight: bold;
+ color: #333;
+ margin: 4px;
+}
+
+.profile-network-message-response, .profile-wall-message-response {
+ color: #204a87;
+ padding: 4px;
+ color: #333;
+ text-align: right;
+ font-size: 12px;
+}
+
+.profile-wall-sender,
+.profile-wall-time,
+.profile-wall-description,
+.profile-activity-sender,
+.profile-activity-time,
+.profile-activity-description,
+.profile-network-sender,
+.profile-network-time,
+.profile-network-description {
+ padding-left: 5px;
+}
+
+.profile-network-sender,
+.profile-wall-sender {
+ margin: 2px 0;
+}
+
+#profile-activity .profile-activity-time,
+#profile-network .profile-network-time,
+#profile-wall .profile-wall-time {
+ margin: 0;
+}
+
+#profile-network textarea,
+#profile-wall textarea {
+ margin: 4px 0;
+ width: 453px;
+ border: 1px solid #ccc;
+ padding: 2px;
+ overflow: hidden;
+}
+
+.profile-network-message,
+.profile-wall-message {
+ margin: 0;
+}
+
+.profile-send-message {
+ color: #555;
+ border: 1px solid #ccc;
+ background-color: #eee;
+ padding: 4px 4px 4px 20px;
+ background-repeat: no-repeat;
+ background-position: 4px center;
+}
+
+.ui-widget-content .profile-send-message:hover,
+.profile-send-message:hover {
+ color: #eee;
+ background-color: #555;
+}
+
+.limited-text-area p {
+ margin: 0;
+ font-size: 11px;
+ color: #333;
+ text-align: right;
+}
+
+#leave_scrap input.button {
+ float: right;
+ margin-bottom: 10px;
+}
+
+#leave_scrap_content_limit,
+#leave_scrap_content_left {
+ float: left;
+}
+
+#leave_scrap {
+ float: left;
+ padding: 4px;
+ border: 1px dotted #aaa;
+ margin-bottom: 10px;
+}
+
+#leave_scrap textarea {
+ width: 440px;
+ overflow: hidden;
+}
+
+.profile-send-reply {
+ background-color: #eee;
+ border: 1px solid #aaa;
+ padding: 2px;
+ padding-left: 20px;
+ background-repeat: no-repeat;
+ background-position: 2px center;
+ color: #aaa;
+ text-decoration: none;
+ margin-left: 8px;
+}
+
+#content .profile-send-reply:hover {
+ text-decoration: none;
+}
+
+#profile-wall .profile-wall-description .profile-wall-image {
+ background-image: url(/images/scrap-bg-gray.png);
+}
+
+#profile-wall .profile-wall-description .profile-wall-description {
+ width: 242px;
+ background-color: #eee;
+}
+
+#profile-network .profile-wall-description textarea,
+#profile-wall .profile-wall-description textarea {
+ width: 338px;
+ margin-left: 2px;
+}
+
+#profile-network .profile-wall-description .limited-text-area p,
+#profile-wall .profile-wall-description .limited-text-area p {
+ margin-right: 10px;
+}
+
+.limited-text-area div.fieldWithErrors {
+ background: transparent;
+}
diff --git a/public/stylesheets/jquery.ui/smoothness_mod/images/ui-anim_basic_16x16.gif b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-anim_basic_16x16.gif
new file mode 100644
index 0000000..085ccae
Binary files /dev/null and b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-anim_basic_16x16.gif differ
diff --git a/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_flat_0_aaaaaa_40x100.png b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_flat_0_aaaaaa_40x100.png
new file mode 100644
index 0000000..5b5dab2
Binary files /dev/null and b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_flat_0_aaaaaa_40x100.png differ
diff --git a/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_flat_75_ffffff_40x100.png b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_flat_75_ffffff_40x100.png
new file mode 100644
index 0000000..ac8b229
Binary files /dev/null and b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_flat_75_ffffff_40x100.png differ
diff --git a/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_glass_55_fbf9ee_1x400.png b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_glass_55_fbf9ee_1x400.png
new file mode 100644
index 0000000..ad3d634
Binary files /dev/null and b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_glass_55_fbf9ee_1x400.png differ
diff --git a/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_glass_65_ffffff_1x400.png b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_glass_65_ffffff_1x400.png
new file mode 100644
index 0000000..42ccba2
Binary files /dev/null and b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_glass_65_ffffff_1x400.png differ
diff --git a/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_glass_75_dadada_1x400.png b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_glass_75_dadada_1x400.png
new file mode 100644
index 0000000..5a46b47
Binary files /dev/null and b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_glass_75_dadada_1x400.png differ
diff --git a/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_glass_75_e6e6e6_1x400.png b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_glass_75_e6e6e6_1x400.png
new file mode 100644
index 0000000..86c2baa
Binary files /dev/null and b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_glass_75_e6e6e6_1x400.png differ
diff --git a/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_glass_95_fef1ec_1x400.png b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_glass_95_fef1ec_1x400.png
new file mode 100644
index 0000000..4443fdc
Binary files /dev/null and b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_glass_95_fef1ec_1x400.png differ
diff --git a/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_highlight-soft_75_cccccc_1x100.png
new file mode 100644
index 0000000..7c9fa6c
Binary files /dev/null and b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-bg_highlight-soft_75_cccccc_1x100.png differ
diff --git a/public/stylesheets/jquery.ui/smoothness_mod/images/ui-icons_222222_256x240.png b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-icons_222222_256x240.png
new file mode 100644
index 0000000..b273ff1
Binary files /dev/null and b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-icons_222222_256x240.png differ
diff --git a/public/stylesheets/jquery.ui/smoothness_mod/images/ui-icons_2e83ff_256x240.png b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-icons_2e83ff_256x240.png
new file mode 100644
index 0000000..09d1cdc
Binary files /dev/null and b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-icons_2e83ff_256x240.png differ
diff --git a/public/stylesheets/jquery.ui/smoothness_mod/images/ui-icons_454545_256x240.png b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-icons_454545_256x240.png
new file mode 100644
index 0000000..59bd45b
Binary files /dev/null and b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-icons_454545_256x240.png differ
diff --git a/public/stylesheets/jquery.ui/smoothness_mod/images/ui-icons_888888_256x240.png b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-icons_888888_256x240.png
new file mode 100644
index 0000000..6d02426
Binary files /dev/null and b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-icons_888888_256x240.png differ
diff --git a/public/stylesheets/jquery.ui/smoothness_mod/images/ui-icons_cd0a0a_256x240.png b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-icons_cd0a0a_256x240.png
new file mode 100644
index 0000000..2ab019b
Binary files /dev/null and b/public/stylesheets/jquery.ui/smoothness_mod/images/ui-icons_cd0a0a_256x240.png differ
diff --git a/public/stylesheets/jquery.ui/smoothness_mod/jquery-ui-1.8.2.custom.css b/public/stylesheets/jquery.ui/smoothness_mod/jquery-ui-1.8.2.custom.css
new file mode 100644
index 0000000..3fb1f3e
--- /dev/null
+++ b/public/stylesheets/jquery.ui/smoothness_mod/jquery-ui-1.8.2.custom.css
@@ -0,0 +1,489 @@
+/*
+* jQuery UI CSS Framework
+* Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+*/
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
+.ui-helper-clearfix { display: inline-block; }
+/* required comment for clearfix to work in Opera \*/
+* html .ui-helper-clearfix { height:1%; }
+.ui-helper-clearfix { display:block; }
+/* end clearfix */
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
+
+
+/*
+* jQuery UI CSS Framework
+* Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
+* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses.
+* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
+*/
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }
+.ui-widget .ui-widget { font-size: 1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
+.ui-widget-content { background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
+.ui-widget-content a { color: #222222; }
+.ui-widget-header { border-bottom: 1px solid #aaaaaa; color: #222222; font-weight: bold; }
+.ui-widget-header a { color: #222222; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
+.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; }
+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; }
+.ui-widget :active { outline: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
+.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
+.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-off { background-position: -96px -144px; }
+.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; }
+.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
+.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
+.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
+.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
+.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
+.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
+.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
+.ui-corner-all { -moz-border-radius-topleft: 4px; -webkit-border-radius-topleft: 4px; border-radius-topleft: 4px; -moz-border-radius-topright: 4px; -webkit-border-radius-topright: 4px; border-radius-topright: 4px;}
+
+/* Overlays */
+.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
+.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/* Resizable
+----------------------------------*/
+.ui-resizable { position: relative;}
+.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* Selectable
+----------------------------------*/
+.ui-selectable-helper { border:1px dotted black }
+/* Accordion
+----------------------------------*/
+.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
+.ui-accordion .ui-accordion-li-fix { display: inline; }
+.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
+.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
+/* IE7-/Win - Fix extra vertical space in lists */
+.ui-accordion a { zoom: 1; }
+.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
+.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
+.ui-accordion .ui-accordion-content-active { display: block; }/* Autocomplete
+----------------------------------*/
+.ui-autocomplete { position: absolute; cursor: default; }
+.ui-autocomplete-loading { background: white url('images/ui-anim_basic_16x16.gif') right center no-repeat; }
+
+/* workarounds */
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+
+/* Menu
+----------------------------------*/
+.ui-menu {
+ list-style:none;
+ padding: 2px;
+ margin: 0;
+ display:block;
+}
+.ui-menu .ui-menu {
+ margin-top: -3px;
+}
+.ui-menu .ui-menu-item {
+ margin:0;
+ padding: 0;
+ zoom: 1;
+ float: left;
+ clear: left;
+ width: 100%;
+}
+.ui-menu .ui-menu-item a {
+ text-decoration:none;
+ display:block;
+ padding:.2em .4em;
+ line-height:1.5;
+ zoom:1;
+}
+.ui-menu .ui-menu-item a.ui-state-hover,
+.ui-menu .ui-menu-item a.ui-state-active {
+ font-weight: normal;
+ margin: -1px;
+}
+/* Button
+----------------------------------*/
+
+.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
+.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
+button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
+.ui-button-icons-only { width: 3.4em; }
+button.ui-button-icons-only { width: 3.7em; }
+
+/*button text element */
+.ui-button .ui-button-text { display: block; line-height: 1.4; }
+.ui-button-text-only .ui-button-text { padding: .4em 1em; }
+.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
+.ui-button-text-icon .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
+.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
+/* no icon support for input elements, provide padding by default */
+input.ui-button { padding: .4em 1em; }
+
+/*button icon element(s) */
+.ui-button-icon-only .ui-icon, .ui-button-text-icon .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
+.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
+.ui-button-text-icon .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
+.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+
+/*button sets*/
+.ui-buttonset { margin-right: 7px; }
+.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
+
+/* workarounds */
+button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
+
+
+
+
+
+/* Dialog
+----------------------------------*/
+.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
+.ui-dialog .ui-dialog-titlebar { padding: .5em 1em .3em; position: relative; }
+.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; }
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
+.ui-dialog .ui-dialog-content { border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
+.ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; }
+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
+.ui-draggable .ui-dialog-titlebar { cursor: move; }
+/* Slider
+----------------------------------*/
+.ui-slider { position: relative; text-align: left; }
+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
+
+.ui-slider-horizontal { height: .8em; }
+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
+
+.ui-slider-vertical { width: .8em; height: 100px; }
+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
+.ui-slider-vertical .ui-slider-range-max { top: 0; }/* Tabs
+----------------------------------*/
+.ui-tabs { position: relative; padding: 0; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+.ui-tabs .ui-tabs-nav { margin: 0; padding: 0; }
+.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
+.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
+.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; border: 1px solid #aaa; border-top: 0; }
+.ui-tabs .ui-tabs-hide { display: none !important; }
+/* Datepicker
+----------------------------------*/
+.ui-datepicker { width: 17em; padding: .2em .2em 0; }
+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
+.ui-datepicker .ui-datepicker-prev { left:2px; }
+.ui-datepicker .ui-datepicker-next { right:2px; }
+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
+.ui-datepicker .ui-datepicker-next-hover { right:1px; }
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
+.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year { width: 49%;}
+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
+.ui-datepicker td { border: 0; padding: 1px; }
+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi { width:auto; }
+.ui-datepicker-multi .ui-datepicker-group { float:left; }
+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
+.ui-datepicker-row-break { clear:both; width:100%; }
+
+/* RTL support */
+.ui-datepicker-rtl { direction: rtl; }
+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+
+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
+.ui-datepicker-cover {
+ display: none; /*sorry for IE5*/
+ display/**/: block; /*sorry for IE5*/
+ position: absolute; /*must have*/
+ z-index: -1; /*must have*/
+ filter: mask(); /*must have*/
+ top: -4px; /*must have*/
+ left: -4px; /*must have*/
+ width: 200px; /*must have*/
+ height: 200px; /*must have*/
+}/* Progressbar
+----------------------------------*/
+.ui-progressbar { height:2em; text-align: left; }
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
diff --git a/test/action_tracker_test_helper.rb b/test/action_tracker_test_helper.rb
new file mode 100644
index 0000000..bc6fea3
--- /dev/null
+++ b/test/action_tracker_test_helper.rb
@@ -0,0 +1,16 @@
+class UserStampSweeper < ActionController::Caching::Sweeper
+ private
+ def current_user
+ Person.first
+ end
+end
+
+module ActionTracker
+ class Record
+ def back_in_time(time = 25.hours)
+ self.updated_at = Time.now.ago(time)
+ self.send :update_without_callbacks
+ self
+ end
+ end
+end
diff --git a/test/factories.rb b/test/factories.rb
index 5bb7dce..61ecb4c 100644
--- a/test/factories.rb
+++ b/test/factories.rb
@@ -1,7 +1,7 @@
module Noosfero::Factory
def fast_create(name, attrs = {}, options = {})
- data = defaults_for(name).merge(attrs)
+ data = defaults_for(name.to_s.gsub('::','')).merge(attrs)
klass = name.to_s.camelize.constantize
if klass.superclass != ActiveRecord::Base
data[:type] = klass.to_s
@@ -360,4 +360,44 @@ module Noosfero::Factory
alias :defaults_for_certifier :defaults_for_qualifier
+ ###############################################
+ # Scrap
+ ###############################################
+
+ def defaults_for_scrap(params = {})
+ { :content => 'soment content ', :sender_id => 1, :receiver_id => 1, :created_at => DateTime.now }.merge(params)
+ end
+
+ ###############################################
+ # ActionTrackerNotification
+ ###############################################
+
+ def defaults_for_action_tracker_notification(params = {})
+ { :action_tracker_id => 1, :profile_id => 1 }.merge(params)
+ end
+
+ ###############################################
+ # ActionTracker
+ ###############################################
+
+ def defaults_for_action_tracker_record(params = {})
+ { :created_at => DateTime.now, :verb => :leave_comment, :user_type => 'Profile', :user_id => 1 }.merge(params)
+ end
+
+ ###############################################
+ # Friendship
+ ###############################################
+
+ def defaults_for_friendship(params = {})
+ { :created_at => DateTime.now, :person_id => 1, :friend_id => 2 }.merge(params)
+ end
+
+ ###############################################
+ # RoleAssignment
+ ###############################################
+
+ def defaults_for_role_assignment(params = {})
+ { :role_id => 1, :accessor_id => 1, :accessor_type => 'Profile', :resource_id => 2, :resource_type => 'Profile' }.merge(params)
+ end
+
end
diff --git a/test/functional/profile_controller_test.rb b/test/functional/profile_controller_test.rb
index 23e0a45..d4d402d 100644
--- a/test/functional/profile_controller_test.rb
+++ b/test/functional/profile_controller_test.rb
@@ -709,4 +709,496 @@ class ProfileControllerTest < Test::Unit::TestCase
assert_match(/Last post/, @response.body) # Latest post must come in the feed
end
+ should "be logged in to leave a scrap" do
+ count = Scrap.count
+ post :leave_scrap, :profile => profile.identifier, :scrap => {:content => 'something'}
+ assert_equal count, Scrap.count
+ assert_redirected_to :controller => 'account', :action => 'login'
+ end
+
+ should "leave a scrap in the own profile" do
+ login_as(profile.identifier)
+ count = Scrap.count
+ assert profile.scraps_received.empty?
+ post :leave_scrap, :profile => profile.identifier, :scrap => {:content => 'something'}
+ assert_equal count + 1, Scrap.count
+ assert_response :success
+ assert_equal "Message successfully sent.", assigns(:message)
+ profile.reload
+ assert !profile.scraps_received.empty?
+ end
+
+ should "leave a scrap on another profile" do
+ login_as(profile.identifier)
+ count = Scrap.count
+ another_person = fast_create(Person)
+ assert another_person.scraps_received.empty?
+ post :leave_scrap, :profile => another_person.identifier, :scrap => {:content => 'something'}
+ assert_equal count + 1, Scrap.count
+ assert_response :success
+ assert_equal "Message successfully sent.", assigns(:message)
+ another_person.reload
+ assert !another_person.scraps_received.empty?
+ end
+
+ should "the owner of scrap could remove it" do
+ login_as(profile.identifier)
+ scrap = fast_create(Scrap, :sender_id => profile.id)
+ count = Scrap
+ assert_difference Scrap, :count, -1 do
+ post :remove_scrap, :profile => profile.identifier, :scrap_id => scrap.id
+ end
+ end
+
+ should "the receiver scrap remove it" do
+ login_as(profile.identifier)
+ scrap = fast_create(Scrap, :receiver_id => profile.id)
+ count = Scrap
+ assert_difference Scrap, :count, -1 do
+ post :remove_scrap, :profile => profile.identifier, :scrap_id => scrap.id
+ end
+ end
+
+ should "not remove others scraps" do
+ login_as(profile.identifier)
+ person = fast_create(Person)
+ scrap = fast_create(Scrap, :sender_id => person.id, :receiver_id => person.id)
+ count = Scrap
+ assert_difference Scrap, :count, 0 do
+ post :remove_scrap, :profile => profile.identifier, :scrap_id => scrap.id
+ end
+ end
+
+ should "be logged in to remove a scrap" do
+ count = Scrap.count
+ post :remove_scrap, :profile => profile.identifier, :scrap => {:content => 'something'}
+ assert_equal count, Scrap.count
+ assert_redirected_to :controller => 'account', :action => 'login'
+ end
+
+ should "not remove an scrap of another user" do
+ login_as(profile.identifier)
+ person = fast_create(Person)
+ scrap = fast_create(Scrap, :receiver_id => person.id)
+ count = Scrap.count
+ post :remove_scrap, :profile => person.identifier, :scrap_id => scrap.id
+ assert_equal count, Scrap.count
+ end
+
+ should "the sender be the logged user by default" do
+ login_as(profile.identifier)
+ count = Scrap.count
+ another_person = fast_create(Person)
+ post :leave_scrap, :profile => another_person.identifier, :scrap => {:content => 'something'}
+ last = Scrap.last
+ assert_equal profile, last.sender
+ end
+
+ should "the receiver be the current profile by default" do
+ login_as(profile.identifier)
+ count = Scrap.count
+ another_person = fast_create(Person)
+ post :leave_scrap, :profile => another_person.identifier, :scrap => {:content => 'something'}
+ last = Scrap.last
+ assert_equal another_person, last.receiver
+ end
+
+ should "report to user the scrap errors on creation" do
+ login_as(profile.identifier)
+ count = Scrap.count
+ post :leave_scrap, :profile => profile.identifier, :scrap => {:content => ''}
+ assert_response :success
+ assert_equal "You can't leave an empty message.", assigns(:message)
+ end
+
+ should 'see all activities of the current profile' do
+ p1= Person.first
+ p2= fast_create(Person)
+ assert !p1.is_a_friend?(p2)
+ p3= fast_create(Person)
+ assert !p1.is_a_friend?(p3)
+ ActionTracker::Record.destroy_all
+ Scrap.create!(defaults_for_scrap(:sender => p1, :receiver => p1))
+ a1 = ActionTracker::Record.last
+ UserStampSweeper.any_instance.stubs(:current_user).returns(p2)
+ Scrap.create!(defaults_for_scrap(:sender => p2, :receiver => p3))
+ a2 = ActionTracker::Record.last
+ UserStampSweeper.any_instance.stubs(:current_user).returns(p3)
+ Scrap.create!(defaults_for_scrap(:sender => p3, :receiver => p1))
+ a3 = ActionTracker::Record.last
+ login_as(profile.identifier)
+ get :index, :profile => p1.identifier
+ assert_not_nil assigns(:activities)
+ assert_equal [a1], assigns(:activities)
+ end
+
+ should 'see the activities_items paginated' do
+ p1= Person.first
+ ActionTracker::Record.destroy_all
+ 40.times{Scrap.create!(defaults_for_scrap(:sender => p1, :receiver => p1))}
+ login_as(p1.identifier)
+ get :index, :profile => p1.identifier
+ assert_equal 30, assigns(:activities).count
+ end
+
+ should 'see not see the friends activities in the current profile activity' do
+ p1= Person.first
+ p2= fast_create(Person)
+ assert !p1.is_a_friend?(p2)
+ p3= fast_create(Person)
+ p1.add_friend(p3)
+ assert p1.is_a_friend?(p3)
+ ActionTracker::Record.destroy_all
+ Scrap.create!(defaults_for_scrap(:sender => p1, :receiver => p1))
+ a1 = ActionTracker::Record.last
+ UserStampSweeper.any_instance.stubs(:current_user).returns(p2)
+ Scrap.create!(defaults_for_scrap(:sender => p2, :receiver => p3))
+ a2 = ActionTracker::Record.last
+ UserStampSweeper.any_instance.stubs(:current_user).returns(p3)
+ Scrap.create!(defaults_for_scrap(:sender => p3, :receiver => p1))
+ a3 = ActionTracker::Record.last
+ login_as(profile.identifier)
+ get :index, :profile => p1.identifier
+ assert_not_nil assigns(:activities)
+ assert_equal [a1], assigns(:activities)
+ end
+
+ should 'see all the activities in the current profile network' do
+ p1= Person.first
+ p2= fast_create(Person)
+ assert !p1.is_a_friend?(p2)
+ p3= fast_create(Person)
+ p3.add_friend(p1)
+ assert p3.is_a_friend?(p1)
+ ActionTracker::Record.destroy_all
+ Scrap.create!(defaults_for_scrap(:sender => p1, :receiver => p1))
+ a1 = ActionTracker::Record.last
+ UserStampSweeper.any_instance.stubs(:current_user).returns(p2)
+ Scrap.create!(defaults_for_scrap(:sender => p2, :receiver => p3))
+ a2 = ActionTracker::Record.last
+ UserStampSweeper.any_instance.stubs(:current_user).returns(p3)
+ Scrap.create!(defaults_for_scrap(:sender => p3, :receiver => p1))
+ a3 = ActionTracker::Record.last
+
+
+ @controller.stubs(:logged_in?).returns(true)
+ user = mock()
+ user.stubs(:person).returns(p3)
+ user.stubs(:login).returns('some')
+ @controller.stubs(:current_user).returns(user)
+ Person.any_instance.stubs(:follows?).returns(true)
+
+ process_delayed_job_queue
+ get :index, :profile => p1.identifier
+ assert_not_nil assigns(:network_activities)
+ assert_equal [], [a1,a3] - assigns(:network_activities)
+ assert_equal assigns(:network_activities) - [a1, a3], []
+ end
+
+ should 'the network activity be visible only to profile followers' do
+ p1= Person.first
+ p2= fast_create(Person)
+ assert !p1.is_a_friend?(p2)
+ p3= fast_create(Person)
+ p3.add_friend(p1)
+ assert p3.is_a_friend?(p1)
+ ActionTracker::Record.destroy_all
+ Scrap.create!(defaults_for_scrap(:sender => p1, :receiver => p1))
+ a1 = ActionTracker::Record.last
+ UserStampSweeper.any_instance.stubs(:current_user).returns(p2)
+ Scrap.create!(defaults_for_scrap(:sender => p2, :receiver => p3))
+ a2 = ActionTracker::Record.last
+ UserStampSweeper.any_instance.stubs(:current_user).returns(p3)
+ Scrap.create!(defaults_for_scrap(:sender => p3, :receiver => p1))
+ a3 = ActionTracker::Record.last
+
+ @controller.stubs(:logged_in?).returns(true)
+ user = mock()
+ user.stubs(:person).returns(p2)
+ user.stubs(:login).returns('some')
+ @controller.stubs(:current_user).returns(user)
+ get :index, :profile => p1.identifier
+ assert_equal [], assigns(:network_activities)
+
+ user = mock()
+ user.stubs(:person).returns(p3)
+ user.stubs(:login).returns('some')
+ @controller.stubs(:current_user).returns(user)
+ Person.any_instance.stubs(:follows?).returns(true)
+ process_delayed_job_queue
+ get :index, :profile => p3.identifier
+ assert_equal [], [a1,a3] - assigns(:network_activities)
+ assert_equal assigns(:network_activities) - [a1, a3], []
+ end
+
+ should 'the network activity be paginated' do
+ p1= Person.first
+ 40.times{Scrap.create!(defaults_for_scrap(:sender => p1, :receiver => p1))}
+
+ @controller.stubs(:logged_in?).returns(true)
+ user = mock()
+ user.stubs(:person).returns(p1)
+ user.stubs(:login).returns('some')
+ @controller.stubs(:current_user).returns(user)
+ get :index, :profile => p1.identifier
+ assert_equal 30, assigns(:network_activities).count
+ end
+
+ should 'the network activity be visible only to logged users' do
+ p1= ActionTracker::Record.current_user_from_model
+ p2= fast_create(Person)
+ assert !p1.is_a_friend?(p2)
+ p3= fast_create(Person)
+ p3.add_friend(p1)
+ assert p3.is_a_friend?(p1)
+ ActionTracker::Record.destroy_all
+ Scrap.create!(defaults_for_scrap(:sender => p1, :receiver => p1))
+ a1 = ActionTracker::Record.last
+ UserStampSweeper.any_instance.stubs(:current_user).returns(p2)
+ Scrap.create!(defaults_for_scrap(:sender => p2, :receiver => p3))
+ a2 = ActionTracker::Record.last
+ UserStampSweeper.any_instance.stubs(:current_user).returns(p3)
+ Scrap.create!(defaults_for_scrap(:sender => p3, :receiver => p1))
+ a3 = ActionTracker::Record.last
+
+ login_as(profile.identifier)
+ get :index, :profile => p1.identifier
+ assert_equal [], assigns(:network_activities)
+ assert_response :success
+ assert_template 'index'
+
+ get :index, :profile => p2.identifier
+ assert_equal [], assigns(:network_activities)
+ assert_response :success
+ assert_template 'index'
+
+ get :index, :profile => p3.identifier
+ assert_equal [], assigns(:network_activities)
+ assert_response :success
+ assert_template 'index'
+ end
+
+ should 'the network activity be visible to uses not logged in on communities and enteprises' do
+ p1= Person.first
+ community = fast_create(Community)
+ p2= fast_create(Person)
+ assert !p1.is_a_friend?(p2)
+ community.add_member(p1)
+ community.add_member(p2)
+ ActionTracker::Record.destroy_all
+ Article.create! :name => 'a', :profile_id => community.id
+ Article.create! :name => 'b', :profile_id => community.id
+ UserStampSweeper.any_instance.stubs(:current_user).returns(p2)
+ Article.create! :name => 'c', :profile_id => community.id
+ process_delayed_job_queue
+
+ get :index, :profile => community.identifier
+ assert_not_equal [], assigns(:network_items)
+ assert_response :success
+ assert_template 'index'
+ end
+
+ should 'the network activity be paginated on communities' do
+ community = fast_create(Community)
+ at = fast_create(ActionTracker::Record, :user_id => profile.id)
+ 40.times{ fast_create(ActionTrackerNotification, :profile_id => community.id, :action_tracker_id => at.id) }
+ get :index, :profile => community.identifier
+ assert_equal 30, assigns(:network_activities).count
+ end
+
+ should 'the self activity not crashes with user not logged in' do
+ p1= Person.first
+ p2= fast_create(Person)
+ assert !p1.is_a_friend?(p2)
+ p3= fast_create(Person)
+ p3.add_friend(p1)
+ assert p3.is_a_friend?(p1)
+ ActionTracker::Record.destroy_all
+ Scrap.create!(defaults_for_scrap(:sender => p1, :receiver => p1))
+ a1 = ActionTracker::Record.last
+ UserStampSweeper.any_instance.stubs(:current_user).returns(p2)
+ Scrap.create!(defaults_for_scrap(:sender => p2, :receiver => p3))
+ a2 = ActionTracker::Record.last
+ UserStampSweeper.any_instance.stubs(:current_user).returns(p3)
+ Scrap.create!(defaults_for_scrap(:sender => p3, :receiver => p1))
+ a3 = ActionTracker::Record.last
+
+ get :index, :profile => p1.identifier
+ assert_response :success
+ assert_template 'index'
+ end
+
+ should 'have wall_itens defined' do
+ p1= ActionTracker::Record.current_user_from_model
+ get :index, :profile => p1.identifier
+ assert_equal [], assigns(:wall_items)
+ end
+
+ should 'the wall_itens be the received scraps' do
+ p1 = ActionTracker::Record.current_user_from_model
+ p2 = fast_create(Person)
+ p3 = fast_create(Person)
+ s1 = fast_create(Scrap, :sender_id => p1.id, :receiver_id => p2.id)
+ s2 = fast_create(Scrap, :sender_id => p2.id, :receiver_id => p1.id)
+ s3 = fast_create(Scrap, :sender_id => p3.id, :receiver_id => p1.id)
+
+ @controller.stubs(:logged_in?).returns(true)
+ user = mock()
+ user.stubs(:person).returns(p1)
+ user.stubs(:login).returns('some')
+ @controller.stubs(:current_user).returns(user)
+ Person.any_instance.stubs(:follows?).returns(true)
+ get :index, :profile => p1.identifier
+ assert_equal [s2,s3], assigns(:wall_items)
+ end
+
+ should 'the wall_itens be paginated' do
+ p1 = Person.first
+ 40.times{fast_create(Scrap, :sender_id => p1.id)}
+
+ @controller.stubs(:logged_in?).returns(true)
+ user = mock()
+ user.stubs(:person).returns(p1)
+ user.stubs(:login).returns('some')
+ @controller.stubs(:current_user).returns(user)
+ Person.any_instance.stubs(:follows?).returns(true)
+ assert_equal 40, p1.scraps_received.not_replies.count
+ get :index, :profile => p1.identifier
+ assert_equal 30, assigns(:wall_items).count
+ end
+
+ should "the owner of activity could remove it" do
+ login_as(profile.identifier)
+ at = fast_create(ActionTracker::Record, :user_id => profile.id)
+ atn = fast_create(ActionTrackerNotification, :profile_id => profile.id, :action_tracker_id => at.id)
+ assert_difference ActionTrackerNotification, :count, -1 do
+ post :remove_activity, :profile => profile.identifier, :activity_id => at.id
+ end
+ end
+
+ should "not remove others activities" do
+ login_as(profile.identifier)
+ person = fast_create(Person)
+ at = fast_create(ActionTracker::Record, :user_id => profile.id)
+ atn = fast_create(ActionTrackerNotification, :profile_id => person.id, :action_tracker_id => at.id)
+ count = ActionTrackerNotification
+ assert_difference ActionTrackerNotification, :count, 0 do
+ post :remove_activity, :profile => profile.identifier, :activity_id => at.id
+ end
+ end
+
+ should "be logged in to remove the activity" do
+ at = fast_create(ActionTracker::Record, :user_id => profile.id)
+ atn = fast_create(ActionTrackerNotification, :profile_id => profile.id, :action_tracker_id => at.id)
+ count = ActionTrackerNotification.count
+ post :remove_activity, :profile => profile.identifier, :activity_id => at.id
+ assert_equal count, ActionTrackerNotification.count
+ assert_redirected_to :controller => 'account', :action => 'login'
+ end
+
+ should "not remove an activity of another user" do
+ login_as(profile.identifier)
+ person = fast_create(Person)
+ at = fast_create(ActionTracker::Record, :user_id => profile.id)
+ atn = fast_create(ActionTrackerNotification, :profile_id => person.id, :action_tracker_id => at.id)
+ count = ActionTrackerNotification.count
+ post :remove_activity, :profile => person.identifier, :activity_id => at.id
+ assert_equal count, ActionTrackerNotification.count
+ end
+
+ should "not show the scrap button on network activity if the user don't follow the user" do
+ login_as(profile.identifier)
+ person = fast_create(Person)
+ at = fast_create(ActionTracker::Record, :user_id => person.id)
+ atn = fast_create(ActionTrackerNotification, :profile_id => profile.id, :action_tracker_id => at.id)
+ get :index, :profile => profile.identifier
+ assert_no_tag :tag => 'p', :attributes => {:class => 'profile-network-send-message'}
+
+ person.add_friend(profile)
+ get :index, :profile => profile.identifier
+ assert_tag :tag => 'p', :attributes => {:class => 'profile-network-send-message'}
+ end
+
+ should "not show the scrap button on network activity if the user is himself" do
+ login_as(profile.identifier)
+ at = fast_create(ActionTracker::Record, :user_id => profile.id)
+ atn = fast_create(ActionTrackerNotification, :profile_id => profile.id, :action_tracker_id => at.id)
+ get :index, :profile => profile.identifier
+ assert_no_tag :tag => 'p', :attributes => {:class => 'profile-network-send-message'}
+ end
+
+ should "not show the scrap button on wall activity if the user don't follow the user" do
+ login_as(profile.identifier)
+ person = fast_create(Person)
+ scrap = fast_create(Scrap, :sender_id => person.id, :receiver_id => profile.id)
+ get :index, :profile => profile.identifier
+ assert_no_tag :tag => 'p', :attributes => {:class => 'profile-wall-send-message'}
+
+ person.add_friend(profile)
+ get :index, :profile => profile.identifier
+ assert_tag :tag => 'p', :attributes => {:class => 'profile-wall-send-message'}
+ end
+
+ should "not show the scrap button on wall activity if the user is himself" do
+ login_as(profile.identifier)
+ scrap = fast_create(Scrap, :sender_id => profile.id, :receiver_id => profile.id)
+ get :index, :profile => profile.identifier
+ assert_no_tag :tag => 'p', :attributes => {:class => 'profile-wall-send-message'}
+ end
+
+ should "not show the activities to offline users if the profile is private" do
+ at = fast_create(ActionTracker::Record, :user_id => profile.id)
+ profile.public_profile=false
+ profile.save
+ atn = fast_create(ActionTrackerNotification, :profile_id => profile.id, :action_tracker_id => at.id)
+ get :index, :profile => profile.identifier
+ assert_equal [at], profile.tracked_actions
+ assert_no_tag :tag => 'li', :attributes => {:id => "profile-activity-item-#{atn.id}"}
+ end
+
+ should "view more scraps paginate the scraps" do
+ login_as(profile.identifier)
+ 40.times{fast_create(Scrap, :receiver_id => profile.id)}
+ get :view_more_scraps, :profile => profile.identifier, :page => 2
+ assert_response :success
+ assert_template '_profile_scraps'
+ assert_equal 10, assigns(:scraps).count
+ end
+
+ should "be logged in to access the view_more_scraps action" do
+ get :view_more_scraps, :profile => profile.identifier
+ assert_redirected_to :controller => 'account', :action => 'login'
+ end
+
+ should "view more activities paginated" do
+ login_as(profile.identifier)
+ 40.times{ fast_create(ActionTracker::Record, :user_id => profile.id)}
+ assert_equal 40, profile.tracked_actions.count
+ get :view_more_activities, :profile => profile.identifier, :page => 2
+ assert_response :success
+ assert_template '_profile_activities'
+ assert_equal 10, assigns(:activities).count
+ end
+
+ should "be logged in to access the view_more_activities action" do
+ get :view_more_activities, :profile => profile.identifier
+ assert_redirected_to :controller => 'account', :action => 'login'
+ end
+
+ should "view more network activities paginated" do
+ login_as(profile.identifier)
+ at = fast_create(ActionTracker::Record, :user_id => profile.id)
+ 40.times{fast_create(ActionTrackerNotification, :profile_id => profile.id, :action_tracker_id => at.id) }
+ assert_equal 40, profile.tracked_notifications.count
+ get :view_more_network_activities, :profile => profile.identifier, :page => 2
+ assert_response :success
+ assert_template '_profile_network_activities'
+ assert_equal 10, assigns(:activities).count
+ end
+
+ should "be logged in to access the view_more_network_activities action" do
+ get :view_more_network_activities, :profile => profile.identifier
+ assert_redirected_to :controller => 'account', :action => 'login'
+ end
+
end
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 50dad41..a77dd13 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -8,6 +8,7 @@ require 'hpricot'
require 'noosfero/test'
require File.dirname(__FILE__) + '/factories'
require File.dirname(__FILE__) + '/noosfero_doc_test'
+require File.dirname(__FILE__) + '/action_tracker_test_helper'
FileUtils.rm_rf(File.join(RAILS_ROOT, 'index', 'test'))
diff --git a/test/unit/action_tracker_notification_test.rb b/test/unit/action_tracker_notification_test.rb
new file mode 100644
index 0000000..c0128ef
--- /dev/null
+++ b/test/unit/action_tracker_notification_test.rb
@@ -0,0 +1,51 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class ActionTrackerNotificationTest < ActiveSupport::TestCase
+
+ should "have the profile" do
+ a = ActionTrackerNotification.new
+ a.valid?
+ assert a.errors.invalid?(:profile_id)
+
+ a.profile_id= 1
+ a.valid?
+ assert !a.errors.invalid?(:profile_id)
+ end
+
+ should "have the action tracker" do
+ a = ActionTrackerNotification.new
+ a.valid?
+ assert a.errors.invalid?(:action_tracker_id)
+
+ a.action_tracker_id= 1
+ a.valid?
+ assert !a.errors.invalid?(:action_tracker_id)
+ end
+
+ should "be associated to Person" do
+ person = fast_create(Person)
+ a = ActionTrackerNotification.new
+ assert_nothing_raised do
+ a.profile = person
+ end
+ end
+
+ should "be associated to ActionTracker" do
+ action_tracker = ActionTracker::Record.new
+ a = ActionTrackerNotification.new
+ assert_nothing_raised do
+ a.action_tracker= action_tracker
+ end
+ end
+
+ should "destroy the notifications if the activity is destroyed" do
+ action_tracker = fast_create(ActionTracker::Record)
+ count = ActionTrackerNotification.count
+ fast_create(ActionTrackerNotification, :action_tracker_id => action_tracker.id)
+ fast_create(ActionTrackerNotification, :action_tracker_id => action_tracker.id)
+ fast_create(ActionTrackerNotification, :action_tracker_id => action_tracker.id)
+ action_tracker.destroy
+ assert_equal count, ActionTrackerNotification.count
+ end
+
+end
diff --git a/test/unit/application_helper_test.rb b/test/unit/application_helper_test.rb
index be71020..e974459 100644
--- a/test/unit/application_helper_test.rb
+++ b/test/unit/application_helper_test.rb
@@ -484,7 +484,7 @@ class ApplicationHelperTest < Test::Unit::TestCase
person.stubs(:url).returns('url for person')
person.stubs(:public_profile_url).returns('url for person')
links = links_for_balloon(person)
- assert_equal ['Home Page', 'Profile', 'Friends', 'Communities'], links.map{|i| i.keys.first}
+ assert_equal ['Home Page', 'Wall', 'Friends', 'Communities'], links.map{|i| i.keys.first}
end
should 'return ordered list of links to balloon to Community' do
@@ -495,7 +495,7 @@ class ApplicationHelperTest < Test::Unit::TestCase
community.stubs(:url).returns('url for community')
community.stubs(:public_profile_url).returns('url for community')
links = links_for_balloon(community)
- assert_equal ['Home Page', 'Profile', 'Members', 'Agenda'], links.map{|i| i.keys.first}
+ assert_equal ['Home Page', 'Wall', 'Members', 'Agenda'], links.map{|i| i.keys.first}
end
should 'return ordered list of links to balloon to Enterprise' do
@@ -577,6 +577,16 @@ class ApplicationHelperTest < Test::Unit::TestCase
assert_not_nil mime
end
+ should 'pluralize without count' do
+ assert_equal "tests", pluralize_without_count(2, "test")
+ assert_equal "test", pluralize_without_count(1, "test")
+ assert_equal "testes", pluralize_without_count(2, "test", "testes")
+ end
+
+ should 'unique with count' do
+ assert_equal ["1 for b", "2 for c", "3 for a"], unique_with_count(%w(a b c a c a))
+ end
+
protected
def url_for(args = {})
diff --git a/test/unit/article_test.rb b/test/unit/article_test.rb
index 924816a..0f9822d 100644
--- a/test/unit/article_test.rb
+++ b/test/unit/article_test.rb
@@ -918,4 +918,80 @@ class ArticleTest < Test::Unit::TestCase
assert_equal '', a.lead
end
+ should 'track action when a published article is created outside a community' do
+ article = Article.create! :name => 'Tracked Article', :profile_id => profile.id
+ assert article.published?
+ assert_kind_of Person, article.profile
+ ta = ActionTracker::Record.last
+ assert_equal 'Tracked Article', ta.get_name.last
+ assert_equal article.url, ta.get_url.last
+ assert_kind_of Person, ta.user
+ ta.back_in_time(26.hours)
+ article = Article.create! :name => 'Another Tracked Article', :profile_id => profile.id
+ ta = ActionTracker::Record.last
+ assert_equal ['Another Tracked Article'], ta.get_name
+ assert_equal [article.url], ta.get_url
+ end
+
+ should 'track action when a published article is created in a community' do
+ community = fast_create(Community)
+ p1 = ActionTracker::Record.current_user_from_model
+ p2 = fast_create(Person)
+ p3 = fast_create(Person)
+ community.add_member(p1)
+ community.add_member(p2)
+ assert p1.is_member_of?(community)
+ assert p2.is_member_of?(community)
+ assert !p3.is_member_of?(community)
+ Article.destroy_all
+ ActionTracker::Record.destroy_all
+ article = Article.create! :name => 'Tracked Article', :profile_id => community.id
+ assert article.published?
+ assert_kind_of Community, article.profile
+ ta = ActionTracker::Record.last
+ assert_equal 'Tracked Article', ta.get_name.last
+ assert_equal article.url, ta.get_url.last
+ assert_kind_of Person, ta.user
+ process_delayed_job_queue
+ assert_equal 3, ActionTrackerNotification.count
+ ActionTrackerNotification.all.map{|a|a.profile}.map do |profile|
+ assert [p1,p2,community].include?(profile)
+ end
+ end
+
+ should 'track action when a published article is updated' do
+ a = Article.create! :name => 'a', :profile_id => profile.id
+ a.update_attributes! :name => 'b'
+ ta = ActionTracker::Record.last
+ assert_equal ['b'], ta.get_name
+ assert_equal [a.reload.url], ta.get_url
+ a.update_attributes! :name => 'c'
+ ta = ActionTracker::Record.last
+ assert_equal ['b','c'], ta.get_name
+ assert_equal [a.url,a.reload.url], ta.get_url
+ a.update_attributes! :body => 'test'
+ ta = ActionTracker::Record.last
+ assert_equal ['b','c','c'], ta.get_name
+ assert_equal [a.url,a.reload.url,a.reload.url], ta.get_url
+ a.update_attributes! :hits => 50
+ ta = ActionTracker::Record.last
+ assert_equal ['b','c','c'], ta.get_name
+ assert_equal [a.url,a.reload.url,a.reload.url], ta.get_url
+ end
+
+ should 'track action when a published article is removed' do
+ a = Article.create! :name => 'a', :profile_id => profile.id
+ a.destroy
+ ta = ActionTracker::Record.last
+ assert_equal ['a'], ta.get_name
+ a = Article.create! :name => 'b', :profile_id => profile.id
+ a.destroy
+ ta = ActionTracker::Record.last
+ assert_equal ['a','b'], ta.get_name
+ a = Article.create! :name => 'c', :profile_id => profile.id, :published => false
+ a.destroy
+ ta = ActionTracker::Record.last
+ assert_equal ['a','b'], ta.get_name
+ end
+
end
diff --git a/test/unit/comment_test.rb b/test/unit/comment_test.rb
index 97f4558..5e90879 100644
--- a/test/unit/comment_test.rb
+++ b/test/unit/comment_test.rb
@@ -214,4 +214,16 @@ class CommentTest < Test::Unit::TestCase
assert File.exists?(File.join(Rails.root, 'public', image)), "#{image} does not exist."
end
+ should 'track action when comment is created' do
+ owner = create_user('testuser').person
+ article = owner.articles.create!(:name => 'test', :body => '...')
+ comment = article.comments.create!(:article => article, :name => 'foo', :title => 'bar', :body => 'my comment', :email => 'cracker@test.org')
+ ta = ActionTracker::Record.last
+ assert_equal 'bar', ta.get_title
+ assert_equal 'my comment', ta.get_body
+ assert_equal 'test', ta.get_article_title
+ assert_equal article.url, ta.get_article_url
+ assert_equal comment.url, ta.get_url
+ end
+
end
diff --git a/test/unit/community_test.rb b/test/unit/community_test.rb
index a6de20f..18382af 100644
--- a/test/unit/community_test.rb
+++ b/test/unit/community_test.rb
@@ -215,4 +215,63 @@ class CommunityTest < Test::Unit::TestCase
assert_no_match /[<>]/, community.description
end
+ should "the followed_by method be protected and true to the community members by default" do
+ c = fast_create(Community)
+ p1 = fast_create(Person)
+ p2 = fast_create(Person)
+ p3 = fast_create(Person)
+
+ assert !p1.is_member_of?(c)
+ c.add_member(p1)
+ assert p1.is_member_of?(c)
+
+ assert !p3.is_member_of?(c)
+ c.add_member(p3)
+ assert p3.is_member_of?(c)
+
+ assert_equal true, c.send(:followed_by?,p1)
+ assert_equal true, c.send(:followed_by?,p3)
+ assert_equal false, c.send(:followed_by?,p2)
+ end
+
+ should "be created an tracked action when the user is join to the community" do
+ p1 = Person.first
+ community = fast_create(Community)
+ p2 = fast_create(Person)
+ p3 = fast_create(Person)
+
+ RoleAssignment.delete_all
+ ActionTrackerNotification.delete_all
+ RoleAssignment.any_instance.stubs(:role_id).returns(3)
+ assert_difference(ActionTrackerNotification, :count, 3) do
+ community.add_member(p1)
+ community.add_member(p3)
+ assert p1.is_member_of?(community)
+ assert !p2.is_member_of?(community)
+ assert p3.is_member_of?(community)
+ process_delayed_job_queue
+ end
+ ActionTrackerNotification.all.map{|a|a.profile}.map do |profile|
+ assert [community,p1,p3].include?(profile)
+ end
+ end
+
+ should "be created an tracked action to the community when an community's article is commented" do
+ ActionTrackerNotification.delete_all
+ p1 = Person.first
+ community = fast_create(Community)
+ p2 = fast_create(Person)
+ p3 = fast_create(Person)
+ community.add_member(p3)
+ article = fast_create(Article, :profile_id => community.id)
+ ActionTracker::Record.destroy_all
+ assert_difference(ActionTrackerNotification, :count, 3) do
+ Comment.create!(:article_id => article.id, :title => 'some', :body => 'some', :author_id => p2.id)
+ process_delayed_job_queue
+ end
+ ActionTrackerNotification.all.map{|a|a.profile}.map do |profile|
+ assert [community,p1,p3].include?(profile)
+ end
+ end
+
end
diff --git a/test/unit/enterprise_test.rb b/test/unit/enterprise_test.rb
index 3c150d5..a7b580b 100644
--- a/test/unit/enterprise_test.rb
+++ b/test/unit/enterprise_test.rb
@@ -398,4 +398,24 @@ class EnterpriseTest < Test::Unit::TestCase
assert_equal product.inputs, enterprise.inputs
end
+ should "the followed_by? be true only to members" do
+ e = fast_create(Enterprise)
+ e.stubs(:closed?).returns(false)
+ p1 = fast_create(Person)
+ p2 = fast_create(Person)
+ p3 = fast_create(Person)
+
+ assert !p1.is_member_of?(e)
+ e.add_member(p1)
+ assert p1.is_member_of?(e)
+
+ assert !p3.is_member_of?(e)
+ e.add_member(p3)
+ assert p3.is_member_of?(e)
+
+ assert_equal true, e.send(:followed_by?,p1)
+ assert_equal true, e.send(:followed_by?,p3)
+ assert_equal false, e.send(:followed_by?,p2)
+ end
+
end
diff --git a/test/unit/friendship_test.rb b/test/unit/friendship_test.rb
index 5365cac..5917523 100644
--- a/test/unit/friendship_test.rb
+++ b/test/unit/friendship_test.rb
@@ -22,4 +22,24 @@ class FriendshipTest < Test::Unit::TestCase
end
+ should 'create tracked action' do
+ f = Friendship.create! :person => create_user('a').person, :friend => create_user('b').person
+ ta = ActionTracker::Record.last
+ person = Person.first
+ assert_equal person.name, ta.user.name
+ assert_equal 'b', ta.get_friend_name[0]
+ f = Friendship.create! :person => create_user('a').person, :friend => create_user('c').person
+ ta = ActionTracker::Record.last
+ assert_equal person.name, ta.user.name
+ assert_equal 'c', ta.get_friend_name[1]
+ end
+
+ should 'create tracked action only if they are not friends yet' do
+ a, b = create_user('a').person, create_user('b').person
+ f = Friendship.create! :person => a, :friend => b
+ assert_equal ['b'], ActionTracker::Record.last.get_friend_name
+ f = Friendship.create! :person => b, :friend => a
+ assert_equal ['b'], ActionTracker::Record.last.get_friend_name
+ end
+
end
diff --git a/test/unit/notify_activity_job_test.rb b/test/unit/notify_activity_job_test.rb
new file mode 100644
index 0000000..77bb649
--- /dev/null
+++ b/test/unit/notify_activity_job_test.rb
@@ -0,0 +1,18 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class NotifyActivityJobTest < ActiveSupport::TestCase
+
+ should 'create the ActionTrackerNotification' do
+ action_tracker = fast_create(ActionTracker::Record)
+ profile = fast_create(Profile)
+ count = ActionTrackerNotification.count
+ job = NotifyActivityJob.new(action_tracker.id, profile.id)
+ job.perform
+
+ assert_equal count + 1, ActionTrackerNotification.count
+ last = ActionTrackerNotification.last
+ assert_equal action_tracker, last.action_tracker
+ assert_equal profile, last.profile
+ end
+
+end
diff --git a/test/unit/notify_activity_to_profiles_job_test.rb b/test/unit/notify_activity_to_profiles_job_test.rb
new file mode 100644
index 0000000..9eb5225
--- /dev/null
+++ b/test/unit/notify_activity_to_profiles_job_test.rb
@@ -0,0 +1,21 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class NotifyActivityToProfilesJobTest < ActiveSupport::TestCase
+
+ should 'create the ActionTrackerNotification' do
+ person = fast_create(Person)
+ community = fast_create(Community)
+ action_tracker = fast_create(ActionTracker::Record, :user_type => 'Profile', :user_id => person.id)
+ p1, p2, m1, m2 = fast_create(Person), fast_create(Person), fast_create(Person), fast_create(Person)
+ fast_create(Friendship, :person_id => person.id, :friend_id => p1.id)
+ fast_create(Friendship, :person_id => person.id, :friend_id => p2.id)
+ fast_create(RoleAssignment, :accessor_id => m1.id, :role_id => 3, :resource_id => community.id)
+ fast_create(RoleAssignment, :accessor_id => m2.id, :role_id => 3, :resource_id => community.id)
+ ActionTrackerNotification.delete_all
+ job = NotifyActivityToProfilesJob.new(action_tracker.id, community.id)
+ job.perform
+ process_delayed_job_queue
+ assert_equal 5, ActionTrackerNotification.count
+ end
+
+end
diff --git a/test/unit/organization_test.rb b/test/unit/organization_test.rb
index c5ef7aa..d3c6b75 100644
--- a/test/unit/organization_test.rb
+++ b/test/unit/organization_test.rb
@@ -268,4 +268,23 @@ class OrganizationTest < Test::Unit::TestCase
assert_no_match /[<>]/, organization.management_information
end
+ should "the followed_by? be true only to members" do
+ o = fast_create(Organization)
+ p1 = fast_create(Person)
+ p2 = fast_create(Person)
+ p3 = fast_create(Person)
+
+ assert !p1.is_member_of?(o)
+ o.add_member(p1)
+ assert p1.is_member_of?(o)
+
+ assert !p3.is_member_of?(o)
+ o.add_member(p3)
+ assert p3.is_member_of?(o)
+
+ assert_equal true, o.send(:followed_by?,p1)
+ assert_equal true, o.send(:followed_by?,p3)
+ assert_equal false, o.send(:followed_by?,p2)
+ end
+
end
diff --git a/test/unit/person_test.rb b/test/unit/person_test.rb
index cf1625d..ae3fe44 100644
--- a/test/unit/person_test.rb
+++ b/test/unit/person_test.rb
@@ -642,4 +642,337 @@ class PersonTest < Test::Unit::TestCase
end
end
+ should "see get all sent scraps" do
+ p1 = fast_create(Person)
+ assert_equal [], p1.scraps_sent
+ fast_create(Scrap, :sender_id => p1.id)
+ fast_create(Scrap, :sender_id => p1.id)
+ assert_equal 2, p1.scraps_sent.count
+ p2 = fast_create(Person)
+ fast_create(Scrap, :sender_id => p2.id)
+ assert_equal 2, p1.scraps_sent.count
+ fast_create(Scrap, :sender_id => p1.id)
+ assert_equal 3, p1.scraps_sent.count
+ fast_create(Scrap, :receiver_id => p1.id)
+ assert_equal 3, p1.scraps_sent.count
+ end
+
+ should "see get all received scraps" do
+ p1 = fast_create(Person)
+ assert_equal [], p1.scraps_received
+ fast_create(Scrap, :receiver_id => p1.id)
+ fast_create(Scrap, :receiver_id => p1.id)
+ assert_equal 2, p1.scraps_received.count
+ p2 = fast_create(Person)
+ fast_create(Scrap, :receiver_id => p2.id)
+ assert_equal 2, p1.scraps_received.count
+ fast_create(Scrap, :receiver_id => p1.id)
+ assert_equal 3, p1.scraps_received.count
+ fast_create(Scrap, :sender_id => p1.id)
+ assert_equal 3, p1.scraps_received.count
+ end
+
+ should "see get all received scraps that are not replies" do
+ p1 = fast_create(Person)
+ s1 = fast_create(Scrap, :receiver_id => p1.id)
+ s2 = fast_create(Scrap, :receiver_id => p1.id)
+ s3 = fast_create(Scrap, :receiver_id => p1.id, :scrap_id => s1.id)
+ assert_equal 3, p1.scraps_received.count
+ assert_equal [s1,s2], p1.scraps_received.not_replies
+ p2 = fast_create(Person)
+ s4 = fast_create(Scrap, :receiver_id => p2.id)
+ s5 = fast_create(Scrap, :receiver_id => p2.id, :scrap_id => s4.id)
+ assert_equal 2, p2.scraps_received.count
+ assert_equal [s4], p2.scraps_received.not_replies
+ end
+
+ should "the followed_by method be protected and true to the person friends and herself by default" do
+ p1 = fast_create(Person)
+ p2 = fast_create(Person)
+ p3 = fast_create(Person)
+ p4 = fast_create(Person)
+
+ p1.add_friend(p2)
+ assert p1.is_a_friend?(p2)
+ p1.add_friend(p4)
+ assert p1.is_a_friend?(p4)
+
+ assert_equal true, p1.send(:followed_by?,p1)
+ assert_equal true, p1.send(:followed_by?,p2)
+ assert_equal true, p1.send(:followed_by?,p4)
+ assert_equal false, p1.send(:followed_by?,p3)
+ end
+
+ should "the person follows her friends and herself by default" do
+ p1 = fast_create(Person)
+ p2 = fast_create(Person)
+ p3 = fast_create(Person)
+ p4 = fast_create(Person)
+
+ p2.add_friend(p1)
+ assert p2.is_a_friend?(p1)
+ p4.add_friend(p1)
+ assert p4.is_a_friend?(p1)
+
+ assert_equal true, p1.follows?(p1)
+ assert_equal true, p1.follows?(p2)
+ assert_equal true, p1.follows?(p4)
+ assert_equal false, p1.follows?(p3)
+ end
+
+ should "a person member of a community follows the community" do
+ c = fast_create(Community)
+ p1 = fast_create(Person)
+ p2 = fast_create(Person)
+ p3 = fast_create(Person)
+
+ assert !p1.is_member_of?(c)
+ c.add_member(p1)
+ assert p1.is_member_of?(c)
+
+ assert !p3.is_member_of?(c)
+ c.add_member(p3)
+ assert p3.is_member_of?(c)
+
+ assert_equal true, p1.follows?(c)
+ assert_equal true, p3.follows?(c)
+ assert_equal false, p2.follows?(c)
+ end
+
+ should "the person member of a enterprise follows the enterprise" do
+ e = fast_create(Enterprise)
+ e.stubs(:closed?).returns(false)
+ p1 = fast_create(Person)
+ p2 = fast_create(Person)
+ p3 = fast_create(Person)
+
+ assert !p1.is_member_of?(e)
+ e.add_member(p1)
+ assert p1.is_member_of?(e)
+
+ assert !p3.is_member_of?(e)
+ e.add_member(p3)
+ assert p3.is_member_of?(e)
+
+ assert_equal true, p1.follows?(e)
+ assert_equal true, p3.follows?(e)
+ assert_equal false, p2.follows?(e)
+ end
+
+ should "the person see all of your scraps" do
+ person = fast_create(Person)
+ s1 = fast_create(Scrap, :sender_id => person.id)
+ assert_equal [s1], person.scraps
+ s2 = fast_create(Scrap, :sender_id => person.id)
+ assert_equal [s1,s2], person.scraps
+ s3 = fast_create(Scrap, :receiver_id => person.id)
+ assert_equal [s1,s2,s3], person.scraps
+ end
+
+ should "the person browse for a scrap with a Scrap object" do
+ person = fast_create(Person)
+ s1 = fast_create(Scrap, :sender_id => person.id)
+ s2 = fast_create(Scrap, :sender_id => person.id)
+ s3 = fast_create(Scrap, :receiver_id => person.id)
+ assert_equal s2, person.scraps(s2)
+ end
+
+ should "the person browse for a scrap with an inter and string id" do
+ person = fast_create(Person)
+ s1 = fast_create(Scrap, :sender_id => person.id)
+ s2 = fast_create(Scrap, :sender_id => person.id)
+ s3 = fast_create(Scrap, :receiver_id => person.id)
+ assert_equal s2, person.scraps(s2.id)
+ assert_equal s2, person.scraps(s2.id.to_s)
+ end
+
+ should "the tracked action be notified to person friends and herself" do
+ p1 = Person.first
+ p2 = fast_create(Person)
+ p3 = fast_create(Person)
+ p4 = fast_create(Person)
+
+ p1.add_friend(p2)
+ assert p1.is_a_friend?(p2)
+ assert !p1.is_a_friend?(p3)
+ p1.add_friend(p4)
+ assert p1.is_a_friend?(p4)
+
+ action_tracker = fast_create(ActionTracker::Record)
+ ActionTrackerNotification.delete_all
+ count = ActionTrackerNotification.count
+ Delayed::Job.destroy_all
+ Person.notify_activity(action_tracker)
+ process_delayed_job_queue
+ assert_equal count + 3, ActionTrackerNotification.count
+ ActionTrackerNotification.all.map{|a|a.profile}.map do |profile|
+ [p1,p2,p4].include?(profile)
+ end
+ end
+
+ should "the tracked action be notified to friends with delayed job" do
+ p1 = Person.first
+ p2 = fast_create(Person)
+ p3 = fast_create(Person)
+ p4 = fast_create(Person)
+
+ p1.add_friend(p2)
+ assert p1.is_a_friend?(p2)
+ assert !p1.is_a_friend?(p3)
+ p1.add_friend(p4)
+ assert p1.is_a_friend?(p4)
+
+ action_tracker = fast_create(ActionTracker::Record)
+
+ assert_difference(Delayed::Job, :count, 1) do
+ Person.notify_activity(action_tracker)
+ end
+ end
+
+ should "the tracked action notify friends with one delayed job process followed by others jobs created after run the firt job" do
+ p1 = Person.first
+ p2 = fast_create(Person)
+ p3 = fast_create(Person)
+ p4 = fast_create(Person)
+
+ p1.add_friend(p2)
+ assert p1.is_a_friend?(p2)
+ assert !p1.is_a_friend?(p3)
+ p1.add_friend(p4)
+ assert p1.is_a_friend?(p4)
+
+ action_tracker = fast_create(ActionTracker::Record)
+
+ Delayed::Job.delete_all
+ assert_difference(Delayed::Job, :count, 1) do
+ Person.notify_activity(action_tracker)
+ end
+
+ assert_difference(ActionTrackerNotification, :count, 2) do
+ process_delayed_job_queue
+ end
+ end
+
+ should "the community tracked action be notified to the author and to community members" do
+ p1 = Person.first
+ community = fast_create(Community)
+ p2 = fast_create(Person)
+ p3 = fast_create(Person)
+
+ community.add_member(p1)
+ assert p1.is_member_of?(community)
+ community.add_member(p3)
+ assert p3.is_member_of?(community)
+ assert !p2.is_member_of?(community)
+ process_delayed_job_queue
+
+ action_tracker = fast_create(ActionTracker::Record)
+ article = mock()
+ action_tracker.stubs(:dispatcher).returns(article)
+ article.stubs(:is_a?).with(Article).returns(true)
+ article.stubs(:is_a?).with(RoleAssignment).returns(false)
+ article.stubs(:is_a?).with(Comment).returns(false)
+ article.stubs(:profile).returns(community)
+ ActionTrackerNotification.delete_all
+ assert_difference(ActionTrackerNotification, :count, 3) do
+ Person.notify_activity(action_tracker)
+ process_delayed_job_queue
+ end
+ ActionTrackerNotification.all.map{|a|a.profile}.map do |profile|
+ assert [community,p1,p3].include?(profile)
+ end
+ end
+
+ should "the community tracked action be notified to members with delayed job" do
+ p1 = Person.first
+ community = fast_create(Community)
+ p2 = fast_create(Person)
+ p3 = fast_create(Person)
+ p4 = fast_create(Person)
+
+ community.add_member(p1)
+ assert p1.is_member_of?(community)
+ community.add_member(p3)
+ assert p3.is_member_of?(community)
+ community.add_member(p4)
+ assert p4.is_member_of?(community)
+ assert !p2.is_member_of?(community)
+
+ action_tracker = fast_create(ActionTracker::Record)
+ article = mock()
+ action_tracker.stubs(:dispatcher).returns(article)
+ article.stubs(:is_a?).with(Article).returns(true)
+ article.stubs(:is_a?).with(RoleAssignment).returns(false)
+ article.stubs(:is_a?).with(Comment).returns(false)
+ article.stubs(:profile).returns(community)
+ ActionTrackerNotification.delete_all
+
+ assert_difference(Delayed::Job, :count, 2) do
+ Person.notify_activity(action_tracker)
+ end
+ ActionTrackerNotification.all.map{|a|a.profile}.map do |profile|
+ assert [community,p1,p3,p4].include?(profile)
+ end
+ end
+
+ should "remove activities if the person is destroyed" do
+ ActionTracker::Record.destroy_all
+ ActionTrackerNotification.destroy_all
+ person = fast_create(Person)
+ a1 = fast_create(ActionTracker::Record, :user_id => person.id )
+ a2 = fast_create(ActionTracker::Record, :user_id => person.id )
+ a3 = fast_create(ActionTracker::Record)
+ assert_equal 3, ActionTracker::Record.count
+ fast_create(ActionTrackerNotification, :action_tracker_id => a1.id)
+ fast_create(ActionTrackerNotification, :action_tracker_id => a1.id)
+ fast_create(ActionTrackerNotification, :action_tracker_id => a3.id)
+ fast_create(ActionTrackerNotification, :action_tracker_id => a2.id)
+ assert_equal 4, ActionTrackerNotification.count
+ person.destroy
+ assert_equal 1, ActionTracker::Record.count
+ assert_equal 1, ActionTrackerNotification.count
+ end
+
+ should "control scrap if is sender or receiver" do
+ p1, p2 = fast_create(Person), fast_create(Person)
+ s = fast_create(Scrap, :sender_id => p1.id, :receiver_id => p2.id)
+ assert p1.can_control_scrap?(s)
+ assert p2.can_control_scrap?(s)
+ end
+
+ should "not control scrap if is not sender or receiver" do
+ p1, p2 = fast_create(Person), fast_create(Person)
+ s = fast_create(Scrap, :sender_id => p1.id, :receiver_id => p1.id)
+ assert p1.can_control_scrap?(s)
+ assert !p2.can_control_scrap?(s)
+ end
+
+ should "control activity or not" do
+ p1, p2 = fast_create(Person), fast_create(Person)
+ a = fast_create(ActionTracker::Record, :user_id => p2.id)
+ n = fast_create(ActionTrackerNotification, :profile_id => p2.id, :action_tracker_id => a.id)
+ assert !p1.reload.can_control_activity?(a)
+ assert p2.reload.can_control_activity?(a)
+ end
+
+ should 'track only one action when a person joins a community' do
+ ActionTracker::Record.delete_all
+ p = create_user('test_user').person
+ c = fast_create(Community, :name => "Foo")
+ c.add_member(p)
+ assert_equal ["Foo"], ActionTracker::Record.last.get_resource_name
+ c.reload.add_moderator(p.reload)
+ assert_equal ["Foo"], ActionTracker::Record.last.get_resource_name
+ end
+
+ should 'track only one action when a person leaves a community' do
+ p = create_user('test_user').person
+ c = fast_create(Community, :name => "Foo")
+ c.add_member(p)
+ c.add_moderator(p)
+ ActionTracker::Record.delete_all
+ c.remove_member(p)
+ assert_equal ["Foo"], ActionTracker::Record.last.get_resource_name
+ end
+
end
diff --git a/test/unit/profile_test.rb b/test/unit/profile_test.rb
index 285d1d7..80f2f8b 100644
--- a/test/unit/profile_test.rb
+++ b/test/unit/profile_test.rb
@@ -1798,6 +1798,13 @@ class ProfileTest < Test::Unit::TestCase
assert_equal [f1], p.image_galleries
end
+ should 'get custom profile icon' do
+ profile = build(Profile, :image_builder => {:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')})
+ assert_kind_of String, profile.profile_custom_icon
+ profile = build(Profile, :image_builder => {:uploaded_data => nil})
+ assert_nil profile.profile_custom_icon
+ end
+
private
def assert_invalid_identifier(id)
diff --git a/test/unit/rss_feed_test.rb b/test/unit/rss_feed_test.rb
index f571ecd..fbe1d5a 100644
--- a/test/unit/rss_feed_test.rb
+++ b/test/unit/rss_feed_test.rb
@@ -123,9 +123,7 @@ class RssFeedTest < Test::Unit::TestCase
feed.profile = profile
feed.save!
- profile.environment.expects(:default_hostname).returns('mysite.net').at_least_once
-
- assert_match "http://mysite.net/testuser", feed.data
+ assert_match "http://colivre.net/testuser", feed.data
end
should 'provide link to each article' do
diff --git a/test/unit/scrap_test.rb b/test/unit/scrap_test.rb
new file mode 100644
index 0000000..4fca7ed
--- /dev/null
+++ b/test/unit/scrap_test.rb
@@ -0,0 +1,197 @@
+require File.join(File.dirname(__FILE__), '..', 'test_helper')
+
+class ScrapTest < ActiveSupport::TestCase
+ should "have the content" do
+ s = Scrap.new
+ s.valid?
+ assert s.errors.invalid?(:content)
+
+ s.content = ''
+ s.valid?
+ assert s.errors.invalid?(:content)
+
+ s.content = 'some content'
+ s.valid?
+ assert !s.errors.invalid?(:content)
+ end
+
+ should "have the sender" do
+ s = Scrap.new
+ s.valid?
+ assert s.errors.invalid?(:sender_id)
+
+ s.sender_id = 1
+ s.valid?
+ assert !s.errors.invalid?(:sender_id)
+ end
+
+ should "have the receiver" do
+ s = Scrap.new
+ s.valid?
+ assert s.errors.invalid?(:receiver_id)
+
+ s.receiver_id = 1
+ s.valid?
+ assert !s.errors.invalid?(:receiver_id)
+ end
+
+ should "be associated to Person as sender" do
+ person = fast_create(Person)
+ s = Scrap.new
+ assert_nothing_raised do
+ s.sender = person
+ end
+ end
+
+ should "be associated to Person as receiver" do
+ person = fast_create(Person)
+ s = Scrap.new
+ assert_nothing_raised do
+ s.receiver = person
+ end
+ end
+
+ should "collect all scraps sent and received of a person" do
+ person = fast_create(Person)
+ s1 = fast_create(Scrap, :sender_id => person.id)
+ assert_equal [s1], Scrap.all_scraps(person)
+ s2 = fast_create(Scrap, :sender_id => person.id)
+ assert_equal [s1,s2], Scrap.all_scraps(person)
+ s3 = fast_create(Scrap, :receiver_id => person.id)
+ assert_equal [s1,s2,s3], Scrap.all_scraps(person)
+ end
+
+ should "create the leave_scrap action tracker verb on scrap creation of one user to another" do
+ p1 = ActionTracker::Record.current_user_from_model
+ p2 = fast_create(Person)
+ s = Scrap.new
+ s.sender= p1
+ s.receiver= p2
+ s.content = 'some content'
+ s.save!
+ ta = ActionTracker::Record.last
+ assert_equal s.content, ta.params['content']
+ assert_equal s.sender.name, ta.params['sender_name']
+ assert_equal s.receiver.name, ta.params['receiver_name']
+ assert_equal s.receiver.url, ta.params['receiver_url']
+ assert_equal 'leave_scrap', ta.verb
+ assert_equal p1, ta.user
+ end
+
+ should "notify leave_scrap action tracker verb to friends and itself" do
+ p1 = ActionTracker::Record.current_user_from_model
+ p2 = fast_create(Person)
+ p1.add_friend(p2)
+ ActionTrackerNotification.destroy_all
+ Delayed::Job.destroy_all
+ s = Scrap.new
+ s.sender= p1
+ s.receiver= p2
+ s.content = 'some content'
+ s.save!
+ process_delayed_job_queue
+ assert_equal 2, ActionTrackerNotification.count
+ ActionTrackerNotification.all.map{|a|a.profile}.map do |profile|
+ assert [p1,p2].include?(profile)
+ end
+ end
+
+ should "create the leave_scrap_to_self action tracker verb on scrap creation of one user to itself" do
+ p1 = Person.first
+ s = Scrap.new
+ s.sender= p1
+ s.receiver= p1
+ s.content = 'some content'
+ s.save!
+ ta = ActionTracker::Record.last
+ assert_equal s.content, ta.params['content']
+ assert_equal s.sender.name, ta.params['sender_name']
+ assert_equal 'leave_scrap_to_self', ta.verb
+ assert_equal p1, ta.user
+ end
+
+ should "notify leave_scrap_to_self action tracker verb to friends and itself" do
+ p1 = Person.first
+ p2 = fast_create(Person)
+ p1.add_friend(p2)
+ ActionTrackerNotification.destroy_all
+ Delayed::Job.destroy_all
+ s = Scrap.new
+ s.sender= p1
+ s.receiver= p1
+ s.content = 'some content'
+ s.save!
+ process_delayed_job_queue
+ assert_equal 2, ActionTrackerNotification.count
+ ActionTrackerNotification.all.map{|a|a.profile}.map do |profile|
+ assert [p1,p2].include?(profile)
+ end
+ end
+
+ should "get replies of a scrap" do
+ s = fast_create(Scrap)
+ s1 = fast_create(Scrap, :scrap_id => s.id)
+ s2 = fast_create(Scrap)
+ s3 = fast_create(Scrap, :scrap_id => s.id)
+ assert_equal [s1,s3], s.replies
+ end
+
+ should "get only replies scrap" do
+ s0 = fast_create(Scrap)
+ s1 = fast_create(Scrap, :scrap_id => s0.id)
+ s2 = fast_create(Scrap)
+ s3 = fast_create(Scrap, :scrap_id => s0.id)
+ assert_equal [s0,s2], Scrap.not_replies
+ end
+
+ should "remove the replies is the root is removed" do
+ Scrap.delete_all
+ s = fast_create(Scrap)
+ s1 = fast_create(Scrap, :scrap_id => s.id)
+ s2 = fast_create(Scrap, :scrap_id => s.id)
+ assert_equal [s1,s2], s.replies
+ assert_equal 3, Scrap.count
+ s.destroy
+ assert_equal 0, Scrap.count
+ end
+
+ should "update the scrap on reply creation" do
+ Scrap.delete_all
+ s = fast_create(Scrap, :updated_at => DateTime.parse('2010-01-01'))
+ assert_equal DateTime.parse('2010-01-01'), s.updated_at.strftime('%Y-%m-%d')
+ DateTime.stubs(:now).returns(DateTime.parse('2010-09-07'))
+ s1 = Scrap.create(defaults_for_scrap(:scrap_id => s.id))
+ s.reload
+ assert_not_equal DateTime.parse('2010-01-01'), s.updated_at.strftime('%Y-%m-%d')
+ end
+
+ should "have the root defined" do
+ s = fast_create(Scrap)
+ s1 = fast_create(Scrap, :scrap_id => s.id)
+ s2 = fast_create(Scrap, :scrap_id => s.id)
+ assert_equal s, s1.root
+ assert_equal s, s2.root
+ end
+
+ should 'strip all html tags' do
+ s, r = fast_create(Person), fast_create(Person)
+ s = Scrap.new :sender => s, :receiver => r, :content => "
Test Rails
"
+ assert_equal "Test Rails", s.strip_all_html_tags
+ end
+
+ should 'strip html before save' do
+ s, r = fast_create(Person), fast_create(Person)
+ s = Scrap.new :sender => s, :receiver => r, :content => "
Test Rails
"
+ s.save!
+ assert_equal "Test Rails", s.reload.content
+ end
+
+ should 'strip html before validate' do
+ s, r = fast_create(Person), fast_create(Person)
+ s = Scrap.new :sender => s, :receiver => r, :content => "
"
+ assert !s.valid?
+ s.content = "
Test
"
+ assert s.valid?
+ end
+
+end
diff --git a/test/unit/uploaded_file_test.rb b/test/unit/uploaded_file_test.rb
index c7c9c3d..c5e2fac 100644
--- a/test/unit/uploaded_file_test.rb
+++ b/test/unit/uploaded_file_test.rb
@@ -228,4 +228,55 @@ class UploadedFileTest < Test::Unit::TestCase
assert File.exists?(image)
end
end
+
+ should 'return a thumbnail for images' do
+ f = UploadedFile.new
+ f.expects(:image?).returns(true)
+ f.expects(:full_filename).with(:thumb).returns(File.join(RAILS_ROOT, 'public', 'images', '0000', '0005', 'x.png'))
+ assert_equal '/images/0000/0005/x.png', f.thumbnail_path
+ f = UploadedFile.new
+ f.stubs(:full_filename).with(:thumb).returns(File.join(RAILS_ROOT, 'public', 'images', '0000', '0005', 'x.png'))
+ f.expects(:image?).returns(false)
+ assert_nil f.thumbnail_path
+ end
+
+ should 'track action when a published image is uploaded in a gallery' do
+ p = fast_create(Folder, :profile_id => @profile.id)
+ p.view_as = 'image_gallery'; p.save!
+ f = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => p, :profile => @profile)
+ ta = ActionTracker::Record.last(:conditions => { :verb => "upload_image" })
+ assert_kind_of String, ta.get_thumbnail_path[0]
+ assert_equal [f.reload.view_url], ta.get_view_url
+ assert_equal [p.reload.url], ta.get_parent_url
+ assert_equal [p.name], ta.get_parent_name
+ end
+
+ should 'not track action when is not image' do
+ ActionTracker::Record.delete_all
+ p = fast_create(Folder, :profile_id => @profile.id)
+ p.view_as = 'image_gallery'; p.save!
+ f = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :parent => p, :profile => @profile)
+ assert_nil ActionTracker::Record.last(:conditions => { :verb => "upload_image" })
+ end
+
+ should 'not track action when has no parent' do
+ f = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => nil, :profile => @profile)
+ assert_nil ActionTracker::Record.last(:conditions => { :verb => "upload_image" })
+ end
+
+ should 'not track action when is not published' do
+ ActionTracker::Record.delete_all
+ p = fast_create(Folder, :profile_id => @profile.id)
+ p.view_as = 'image_gallery'; p.save!
+ f = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => p, :profile => @profile, :published => false)
+ assert_nil ActionTracker::Record.last(:conditions => { :verb => "upload_image" })
+ end
+
+ should 'not track action when parent is not gallery' do
+ ActionTracker::Record.delete_all
+ p = fast_create(Folder, :profile_id => @profile.id)
+ f = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :parent => p, :profile => @profile)
+ assert_nil ActionTracker::Record.last(:conditions => { :verb => "upload_image" })
+ end
+
end
diff --git a/vendor/plugins/access_control/lib/role_assignment.rb b/vendor/plugins/access_control/lib/role_assignment.rb
index 828ea8c..3a2f5cf 100644
--- a/vendor/plugins/access_control/lib/role_assignment.rb
+++ b/vendor/plugins/access_control/lib/role_assignment.rb
@@ -4,7 +4,11 @@ class RoleAssignment < ActiveRecord::Base
belongs_to :resource, :polymorphic => true
validates_presence_of :role, :accessor
-
+
+ track_actions :join_community, :after_create, :keep_params => ["resource.name", "resource.url", "resource.profile_custom_icon"], :if => Proc.new { |x| x.resource.is_a?(Community) && x.accessor.role_assignments.count(:conditions => { :resource_id => x.resource.id, :resource_type => 'Profile' }) == 1 }
+
+ track_actions :leave_community, :before_destroy, :keep_params => ["resource.name", "resource.url", "resource.profile_custom_icon"], :if => Proc.new { |x| x.resource.is_a?(Community) && x.accessor.role_assignments.count(:conditions => { :resource_id => x.resource.id, :resource_type => 'Profile' }) == 1 }
+
def has_permission?(perm, res)
return false unless role.has_permission?(perm.to_s) && (resource || is_global)
return true if is_global
diff --git a/vendor/plugins/action_tracker/MIT-LICENSE b/vendor/plugins/action_tracker/MIT-LICENSE
new file mode 100644
index 0000000..ec4ddd4
--- /dev/null
+++ b/vendor/plugins/action_tracker/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2010 [name of plugin creator]
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/plugins/action_tracker/README b/vendor/plugins/action_tracker/README
new file mode 100644
index 0000000..b41694a
--- /dev/null
+++ b/vendor/plugins/action_tracker/README
@@ -0,0 +1,14 @@
+=============
+ActionTracker
+=============
+Installation
+=============
+$ ./script/generate action_tracker
+
+The migration will be created.
+
+$ rake db:migrate
+
+The table will be created.
+
+Copyright (c) 2010 Caio SBA , released under the MIT license
diff --git a/vendor/plugins/action_tracker/Rakefile b/vendor/plugins/action_tracker/Rakefile
new file mode 100644
index 0000000..e668ab6
--- /dev/null
+++ b/vendor/plugins/action_tracker/Rakefile
@@ -0,0 +1,23 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the action_tracker plugin.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.libs << 'test'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+desc 'Generate documentation for the action_tracker plugin.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'ActionTracker'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
diff --git a/vendor/plugins/action_tracker/generators/action_tracker/action_tracker_generator.rb b/vendor/plugins/action_tracker/generators/action_tracker/action_tracker_generator.rb
new file mode 100644
index 0000000..1d51167
--- /dev/null
+++ b/vendor/plugins/action_tracker/generators/action_tracker/action_tracker_generator.rb
@@ -0,0 +1,7 @@
+class ActionTrackerGenerator < Rails::Generator::Base
+ def manifest
+ record do |m|
+ m.migration_template 'migration.rb', File.join('db', 'migrate'), :migration_file_name => 'create_action_tracker'
+ end
+ end
+end
diff --git a/vendor/plugins/action_tracker/generators/action_tracker/templates/migration.rb b/vendor/plugins/action_tracker/generators/action_tracker/templates/migration.rb
new file mode 100644
index 0000000..e383f6d
--- /dev/null
+++ b/vendor/plugins/action_tracker/generators/action_tracker/templates/migration.rb
@@ -0,0 +1,21 @@
+class CreateActionTracker < ActiveRecord::Migration
+ def self.up
+ create_table :action_tracker do |t|
+ t.belongs_to :user, :polymorphic => true
+ t.belongs_to :dispatcher, :polymorphic => true
+ t.text :params
+ t.string :verb
+ t.timestamps
+ end
+
+ change_table :action_tracker do |t|
+ t.index [:user_id, :user_type]
+ t.index [:dispatcher_id, :dispatcher_type]
+ t.index :verb
+ end
+ end
+
+ def self.down
+ drop_table :action_tracker
+ end
+end
diff --git a/vendor/plugins/action_tracker/init.rb b/vendor/plugins/action_tracker/init.rb
new file mode 100644
index 0000000..d875352
--- /dev/null
+++ b/vendor/plugins/action_tracker/init.rb
@@ -0,0 +1,10 @@
+require "user_stamp"
+
+UserStamp.creator_attribute = :user
+UserStamp.updater_attribute = :user
+
+class ActionController::Base
+ extend UserStamp::ClassMethods
+end
+
+require "action_tracker"
diff --git a/vendor/plugins/action_tracker/install.rb b/vendor/plugins/action_tracker/install.rb
new file mode 100644
index 0000000..f7732d3
--- /dev/null
+++ b/vendor/plugins/action_tracker/install.rb
@@ -0,0 +1 @@
+# Install hook code here
diff --git a/vendor/plugins/action_tracker/lib/action_tracker.rb b/vendor/plugins/action_tracker/lib/action_tracker.rb
new file mode 100644
index 0000000..cc6da3d
--- /dev/null
+++ b/vendor/plugins/action_tracker/lib/action_tracker.rb
@@ -0,0 +1,137 @@
+require File.join(File.dirname(__FILE__), 'action_tracker_model.rb')
+
+module ActionTracker
+
+ module ControllerMethods
+
+ def self.included(base)
+ base.send :user_stamp, ActionTracker::Record
+ base.send :extend, ClassMethods
+ end
+
+ module ClassMethods
+
+ def track_actions_after(verb, options = {}, &block)
+ track_actions_by_time(verb, :after, options, &block)
+ end
+
+ def track_actions_before(verb, options = {}, &block)
+ track_actions_by_time(verb, :before, options, &block)
+ end
+
+ def track_actions(verb, options = {}, &block)
+ track_actions_by_time(verb, ActionTrackerConfig.default_filter_time, options, &block)
+ end
+
+ def track_actions_by_time(verb, time, options = {}, &block)
+ keep_params = options.delete(:keep_params) || options.delete('keep_params') || :all
+ send("#{time}_filter", options) do |x|
+ x.save_action_for_verb(verb.to_s, keep_params)
+ block.call(x) unless block.nil?
+ end
+ send :include, InstanceMethods
+ end
+ end
+
+ module InstanceMethods
+ def save_action_for_verb(verb, keep_params = :all)
+ if keep_params.is_a? Array
+ stored_params = params.reject { |key, value| !keep_params.include?(key.to_sym) and !keep_params.include?(key.to_s) }
+ elsif keep_params.to_s == 'none'
+ stored_params = {}
+ elsif keep_params.to_s == 'all'
+ stored_params = params
+ end
+ user = send ActionTrackerConfig.current_user_method
+ tracked_action = case ActionTrackerConfig.verb_type(verb)
+ when :groupable
+ Record.add_or_create :verb => verb, :user => user, :params => stored_params
+ when :updatable
+ Record.update_or_create :verb => verb, :user => user, :params => stored_params
+ when :single
+ Record.new :verb => verb, :user => user, :params => stored_params
+ end
+ user.tracked_actions << tracked_action
+ end
+ end
+
+ end
+
+ module ModelMethods
+
+ def self.included(base)
+ base.send :extend, ClassMethods
+ end
+
+ module ClassMethods
+ def track_actions(verb, callback, options = {}, &block)
+ keep_params = options.delete(:keep_params) || options.delete('keep_params') || :all
+ post_proc = options.delete(:post_processing) || options.delete('post_processing') || Proc.new{}
+ send(callback, Proc.new { |tracked| tracked.save_action_for_verb(verb.to_s, keep_params, post_proc) }, options)
+ send :include, InstanceMethods
+ end
+
+ def acts_as_trackable(options = {})
+ has_many :tracked_actions, { :class_name => "ActionTracker::Record", :order => "updated_at DESC", :foreign_key => :user_id }.merge(options)
+ send :include, InstanceMethods
+ end
+ end
+
+ module InstanceMethods
+ def time_spent_doing(verb, conditions = {})
+ time = 0
+ tracked_actions.all(:conditions => conditions.merge({ :verb => verb.to_s })).each do |t|
+ time += t.updated_at - t.created_at
+ end
+ time.to_f
+ end
+
+ def save_action_for_verb(verb, keep_params = :all, post_proc = Proc.new{})
+ user = ActionTracker::Record.current_user_from_model
+ return nil if user.nil?
+ if keep_params.is_a? Array
+ stored_params = {}
+ keep_params.each do |param|
+ result = self
+ param.to_s.split('.').each { |m| result = result.send(m) }
+ stored_params[param.to_s.gsub(/\./, '_')] = result
+ end
+ elsif keep_params.to_s == 'none'
+ stored_params = {}
+ elsif keep_params.to_s == 'all'
+ stored_params = self.attributes
+ end
+ tracked_action = case ActionTrackerConfig.verb_type(verb)
+ when :groupable
+ Record.add_or_create :verb => verb, :params => stored_params
+ when :updatable
+ Record.update_or_create :verb => verb, :params => stored_params
+ when :single
+ Record.new :verb => verb, :params => stored_params
+ end
+ tracked_action.dispatcher = self
+ user.tracked_actions << tracked_action
+ post_proc.call tracked_action.reload
+ end
+
+ end
+
+ end
+
+ module ViewHelper
+ def describe(ta)
+ returning "" do |result|
+ if ta.is_a?(ActionTracker::Record)
+ result << ta.description.gsub(/\{\{(.*?)\}\}/) { eval $1 }
+ else
+ result << ""
+ end
+ end
+ end
+ end
+
+end
+
+ActionController::Base.send :include, ActionTracker::ControllerMethods
+ActiveRecord::Base.send :include, ActionTracker::ModelMethods
+ActionView::Base.send :include, ActionTracker::ViewHelper
diff --git a/vendor/plugins/action_tracker/lib/action_tracker_config.rb b/vendor/plugins/action_tracker/lib/action_tracker_config.rb
new file mode 100644
index 0000000..82aa930
--- /dev/null
+++ b/vendor/plugins/action_tracker/lib/action_tracker_config.rb
@@ -0,0 +1,60 @@
+class ActionTrackerConfig
+
+ def self.config
+ @action_tracker_config ||= {}
+ end
+
+ def self.config=(h)
+ @action_tracker_config = h
+ end
+
+ def self.verbs
+ config[:verbs] || {}
+ end
+
+ def self.verbs=(h)
+ config[:verbs] = h
+ end
+
+ def self.verb_names
+ verbs.keys.map(&:to_s)
+ end
+
+ def self.current_user_method
+ config[:current_user_method] || :current_user
+ end
+
+ def self.current_user_method=(method_name)
+ UserStamp.current_user_method = config[:current_user_method] = method_name
+ end
+
+ def self.default_filter_time
+ config[:default_filter_time] || :after
+ end
+
+ def self.default_filter_time=(before_or_after)
+ config[:default_filter_time] = before_or_after
+ end
+
+ def self.timeout
+ config[:timeout] || 5.minutes
+ end
+
+ def self.timeout=(seconds)
+ config[:timeout] = seconds
+ end
+
+ def self.get_verb(verb)
+ verbs[verb.to_s] || verbs[verb.to_sym] || {}
+ end
+
+ def self.verb_type(verb)
+ type = get_verb(verb.to_s)[:type] || get_verb(verb.to_s)['type'] || :single
+ verb_types.include?(type.to_sym) ? type : :single
+ end
+
+ def self.verb_types
+ [:single, :updatable, :groupable]
+ end
+
+end
diff --git a/vendor/plugins/action_tracker/lib/action_tracker_model.rb b/vendor/plugins/action_tracker/lib/action_tracker_model.rb
new file mode 100644
index 0000000..4f25eb1
--- /dev/null
+++ b/vendor/plugins/action_tracker/lib/action_tracker_model.rb
@@ -0,0 +1,101 @@
+module ActionTracker
+ class Record < ActiveRecord::Base
+
+ set_table_name 'action_tracker'
+
+ belongs_to :user, :polymorphic => true
+ belongs_to :dispatcher, :polymorphic => true
+
+ serialize :params, Hash
+
+ before_validation :stringify_verb
+
+ validates_presence_of :verb
+ validates_presence_of :user_id
+ validates_presence_of :user_type
+
+ alias_method :subject, :user
+
+ def self.current_user_from_model
+ u = new
+ u.valid?
+ u.user
+ end
+
+ def self.update_or_create(params)
+ u = params[:user] || current_user_from_model
+ return if u.nil?
+ l = last :conditions => { :user_id => u.id, :user_type => u.class.base_class.to_s, :verb => params[:verb].to_s }
+ ( !l.nil? and Time.now - l.updated_at < ActionTrackerConfig.timeout ) ? l.update_attributes(params.merge({ :updated_at => Time.now })) : l = new(params)
+ l
+ end
+
+ def self.add_or_create(params)
+ u = params[:user] || current_user_from_model
+ return if u.nil?
+ l = last :conditions => { :user_id => u.id, :user_type => u.class.base_class.to_s, :verb => params[:verb].to_s }
+ if !l.nil? and Time.now - l.updated_at < ActionTrackerConfig.timeout
+ params[:params].clone.each { |key, value| params[:params][key] = l.params[key].clone.push(value) }
+ l.update_attributes params
+ else
+ params[:params].clone.each { |key, value| params[:params][key] = [value] }
+ l = new params
+ end
+ l
+ end
+
+ def self.time_spent(conditions = {}) # In seconds
+ #FIXME Better if it could be completely done in the database, but SQLite does not support difference between two timestamps
+ time = 0
+ all(:conditions => conditions).each { |action| time += action.updated_at - action.created_at }
+ time.to_f
+ end
+
+ def duration # In seconds
+ ( updated_at - created_at ).to_f
+ end
+
+ def description
+ ActionTrackerConfig.get_verb(self.verb)[:description] || ""
+ end
+
+ def describe
+ description.gsub(/\{\{([^}]+)\}\}/) { eval $1 }
+ end
+
+ def predicate
+ self.params || {}
+ end
+
+ def phrase
+ { :subject => self.subject, :verb => self.verb, :predicate => self.predicate }
+ end
+
+ def method_missing(method, *args, &block)
+ if method.to_s =~ /^get_(.*)$/
+ param = method.to_s.gsub('get_', '')
+ predicate[param.to_s] || predicate[param.to_sym]
+ else
+ super
+ end
+ end
+
+ def collect_group_with_index(param)
+ i = -1
+ send("get_#{param}").collect{ |el| yield(el, i += 1) }
+ end
+
+ protected
+
+ def validate
+ errors.add_to_base "Verb must be one of the following: #{ActionTrackerConfig.verb_names.join(',')}" unless ActionTrackerConfig.verb_names.include?(self.verb)
+ end
+
+ private
+
+ def stringify_verb
+ self.verb = self.verb.to_s unless self.verb.nil?
+ end
+
+ end
+end
diff --git a/vendor/plugins/action_tracker/tasks/action_tracker_tasks.rake b/vendor/plugins/action_tracker/tasks/action_tracker_tasks.rake
new file mode 100644
index 0000000..3ad71b9
--- /dev/null
+++ b/vendor/plugins/action_tracker/tasks/action_tracker_tasks.rake
@@ -0,0 +1,4 @@
+# desc "Explaining what the task does"
+# task :action_tracker do
+# # Task goes here
+# end
diff --git a/vendor/plugins/action_tracker/test/action_tracker_config_test.rb b/vendor/plugins/action_tracker/test/action_tracker_config_test.rb
new file mode 100755
index 0000000..fffda80
--- /dev/null
+++ b/vendor/plugins/action_tracker/test/action_tracker_config_test.rb
@@ -0,0 +1,121 @@
+require 'test_helper'
+
+class ActionTrackerConfigTest < ActiveSupport::TestCase
+
+ def test_has_config
+ assert_not_nil ActionTrackerConfig
+ end
+
+ def test_config_is_a_hash
+ assert_kind_of Hash, ActionTrackerConfig.config
+ end
+
+ def test_config_can_be_set
+ c = { :foo => 'bar' }
+ ActionTrackerConfig.config = c
+ assert_equal c, ActionTrackerConfig.config
+ end
+
+ def test_verbs_is_a_hash
+ assert_kind_of Hash, ActionTrackerConfig.verbs
+ end
+
+ def test_verbs_can_be_set
+ v = { :search => {} }
+ ActionTrackerConfig.verbs = v
+ assert_equal v, ActionTrackerConfig.verbs
+ end
+
+ def test_verb_names_is_a_list_of_strings
+ v = { :search => {}, :delete => {}, "login" => {} }
+ ActionTrackerConfig.verbs = v
+ assert_equal 3, ActionTrackerConfig.verb_names.size
+ %w(search delete login).each { |verb| assert ActionTrackerConfig.verb_names.include?(verb) }
+ end
+
+ def test_current_user_is_default_method
+ ActionTrackerConfig.config[:current_user_method] = nil
+ assert_equal :current_user, ActionTrackerConfig.current_user_method
+ end
+
+ def test_current_user_can_be_set
+ ActionTrackerConfig.current_user_method = :logged_in_user
+ assert_equal :logged_in_user, ActionTrackerConfig.current_user_method
+ end
+
+ def test_default_filter_time_is_after
+ ActionTrackerConfig.config[:default_filter_time] = nil
+ assert_equal :after, ActionTrackerConfig.default_filter_time
+ end
+
+ def test_default_filter_time_can_be_set
+ ActionTrackerConfig.default_filter_time = :before
+ assert_equal :before, ActionTrackerConfig.default_filter_time
+ end
+
+ def test_default_timeout_is_five_minutes
+ ActionTrackerConfig.config[:timeout] = nil
+ assert_equal 5.minutes, ActionTrackerConfig.timeout
+ end
+
+ def test_timeout_can_be_set
+ ActionTrackerConfig.timeout = 10.minutes
+ assert_equal 10.minutes, ActionTrackerConfig.timeout
+ end
+
+ def test_get_verb_return_hash
+ assert_kind_of Hash, ActionTrackerConfig.get_verb(:search)
+ end
+
+ def test_get_verb_symbol_search_by_symbol
+ ActionTrackerConfig.verbs = { :search => { :description => "Got it" } }
+ assert_equal "Got it", ActionTrackerConfig.get_verb(:search)[:description]
+ end
+
+ def test_get_verb_symbol_search_by_string
+ ActionTrackerConfig.verbs = { :search => { :description => "Got it" } }
+ assert_equal "Got it", ActionTrackerConfig.get_verb("search")[:description]
+ end
+
+ def test_get_verb_string_search_by_string
+ ActionTrackerConfig.verbs = { "search" => { :description => "Got it" } }
+ assert_equal "Got it", ActionTrackerConfig.get_verb("search")[:description]
+ end
+
+ def test_get_verb_string_search_by_symbol
+ ActionTrackerConfig.verbs = { "search" => { :description => "Got it" } }
+ assert_equal "Got it", ActionTrackerConfig.get_verb(:search)[:description]
+ end
+
+ def test_default_verb_type_is_single
+ ActionTrackerConfig.verbs = { "search" => { :description => "Got it" } }
+ assert_equal :single, ActionTrackerConfig.verb_type(:search)
+ end
+
+ def test_verb_type_is_single_if_verb_type_not_valid
+ ActionTrackerConfig.verbs = { "search" => { :type => :not_valid } }
+ assert_equal :single, ActionTrackerConfig.verb_type(:search)
+ end
+
+ def test_get_verb_type_by_symbol
+ ActionTrackerConfig.verbs = { "search" => { :type => :updatable } }
+ assert_equal :updatable, ActionTrackerConfig.verb_type(:search)
+ end
+
+ def test_get_verb_type_by_string
+ ActionTrackerConfig.verbs = { "search" => { "type" => :updatable } }
+ assert_equal :updatable, ActionTrackerConfig.verb_type(:search)
+ end
+
+ def test_verb_types_is_a_list
+ assert_kind_of Array, ActionTrackerConfig.verb_types
+ end
+
+ def test_valid_verb_types
+ assert_equal 3, ActionTrackerConfig.verb_types.size
+ assert ActionTrackerConfig.verb_types.include?(:single)
+ assert ActionTrackerConfig.verb_types.include?(:updatable)
+ assert ActionTrackerConfig.verb_types.include?(:groupable)
+ end
+
+end
diff --git a/vendor/plugins/action_tracker/test/action_tracker_model_test.rb b/vendor/plugins/action_tracker/test/action_tracker_model_test.rb
new file mode 100644
index 0000000..7a79941
--- /dev/null
+++ b/vendor/plugins/action_tracker/test/action_tracker_model_test.rb
@@ -0,0 +1,297 @@
+require 'test_helper'
+
+ActiveRecord::Base.establish_connection({
+ :adapter => "sqlite3",
+ :database => ":memory:"
+})
+
+ActiveRecord::Schema.define do
+ create_table :some_table, :force => true do |t|
+ t.column :some_column, :integer
+ end
+ create_table :action_tracker do |t|
+ t.belongs_to :user, :polymorphic => true
+ t.belongs_to :dispatcher, :polymorphic => true
+ t.text :params
+ t.string :verb
+ t.timestamps
+ end
+end
+
+class SomeModel < ActiveRecord::Base
+ set_table_name :some_table
+ acts_as_trackable
+end
+
+class ActionTrackerModelTest < ActiveSupport::TestCase
+
+ def setup
+ ActionTrackerConfig.verbs = { :some_verb => { :description => "Did something" } }
+ @mymodel = SomeModel.create!
+ @othermodel = SomeModel.create!
+ @tracked_action = ActionTracker::Record.create! :verb => :some_verb, :params => { :user => "foo" }, :user => @mymodel, :dispatcher => @othermodel
+ end
+
+ def test_has_relationship
+ assert @mymodel.respond_to?(:tracked_actions)
+ end
+
+ def test_params_is_a_hash
+ assert_kind_of Hash, @tracked_action.params
+ end
+
+ def test_has_a_polymorphic_relation_with_user
+ assert_equal @mymodel.id, @tracked_action.user_id
+ assert_equal "SomeModel", @tracked_action.user_type
+ assert_equal @mymodel, @tracked_action.user
+ assert_equal [@tracked_action], @mymodel.tracked_actions
+ end
+
+ def test_has_a_polymorphic_relation_with_dispatcher
+ assert_equal @othermodel.id, @tracked_action.dispatcher_id
+ assert_equal "SomeModel", @tracked_action.dispatcher_type
+ assert_equal @othermodel, @tracked_action.dispatcher
+ end
+
+ def test_should_stringify_verb_before_validation
+ ta = ActionTracker::Record.create! :user => SomeModel.create!, :verb => :some_verb
+ assert_equal "some_verb", ta.verb
+ end
+
+ def test_verb_is_mandatory
+ ta = ActionTracker::Record.new
+ ta.valid?
+ assert ta.errors.on(:verb)
+ assert_raise ActiveRecord::RecordInvalid do
+ ta.save!
+ end
+ end
+
+ def test_verb_must_be_declared_previously
+ ActionTrackerConfig.verbs = { :some_verb => { :description => "Did something" } }
+ assert_raise ActiveRecord::RecordInvalid do
+ ta = ActionTracker::Record.create! :verb => :undeclared_verb
+ end
+ ActionTrackerConfig.verbs = { :declared_verb => { :description => "Did something" } }
+ assert_nothing_raised do
+ ta = ActionTracker::Record.create! :user => SomeModel.create!, :verb => :declared_verb
+ end
+ end
+
+ def test_update_or_create_create_if_there_is_no_last
+ ActionTrackerConfig.verbs = { :some => { :description => "Something", :type => :updatable } }
+ ActionTracker::Record.delete_all
+ assert_difference "ActionTracker::Record.count" do
+ ta = ActionTracker::Record.update_or_create :verb => :some, :user => @mymodel
+ ta.save; ta.reload
+ assert_kind_of ActionTracker::Record, ta
+ end
+ assert_equal "some", ActionTracker::Record.last.verb
+ assert_equal @mymodel, ActionTracker::Record.last.user
+ end
+
+ def test_update_or_create_create_if_no_timeout
+ ActionTrackerConfig.verbs = { :some => { :description => "Something", :type => :updatable } }
+ ActionTrackerConfig.timeout = 5.minutes
+ ActionTracker::Record.delete_all
+ ta = nil
+ assert_difference "ActionTracker::Record.count" do
+ ta = ActionTracker::Record.update_or_create :verb => :some, :user => @mymodel
+ ta.save; ta.reload
+ end
+ assert_kind_of ActionTracker::Record, ta
+ ta.updated_at = Time.now.ago(6.minutes)
+ ta.send :update_without_callbacks
+ t = ta.reload.updated_at
+ assert_difference "ActionTracker::Record.count" do
+ ta2 = ActionTracker::Record.update_or_create :verb => :some, :user => @mymodel
+ ta2.save; ta2.reload
+ assert_kind_of ActionTracker::Record, ta2
+ end
+ assert_equal t, ta.reload.updated_at
+ end
+
+ def test_update_or_create_update_if_timeout
+ ActionTrackerConfig.verbs = { :some => { :description => "Something", :type => :updatable } }
+ ActionTrackerConfig.timeout = 7.minutes
+ ActionTracker::Record.delete_all
+ ta = nil
+ assert_difference "ActionTracker::Record.count" do
+ ta = ActionTracker::Record.update_or_create :verb => :some, :user => @mymodel, :params => { :foo => 2 }
+ ta.save; ta.reload
+ end
+ assert_kind_of ActionTracker::Record, ta
+ assert_equal 2, ta.get_foo
+ ta.updated_at = Time.now.ago(6.minutes)
+ ta.send :update_without_callbacks
+ t = ta.reload.updated_at
+ assert_no_difference "ActionTracker::Record.count" do
+ ta2 = ActionTracker::Record.update_or_create :verb => :some, :user => @mymodel, :params => { :foo => 3 }
+ ta2.save; ta2.reload
+ assert_kind_of ActionTracker::Record, ta2
+ end
+ assert_not_equal t, ta.reload.updated_at
+ assert_equal 3, ta.reload.get_foo
+ end
+
+ def test_add_or_create_create_if_no_timeout
+ ActionTrackerConfig.verbs = { :some => { :description => "Something", :type => :groupable } }
+ ActionTrackerConfig.timeout = 5.minutes
+ ActionTracker::Record.delete_all
+ ta = nil
+ assert_difference "ActionTracker::Record.count" do
+ ta = ActionTracker::Record.add_or_create :verb => :some, :user => @mymodel, :params => { :foo => "bar" }
+ ta.save; ta.reload
+ end
+ assert_kind_of ActionTracker::Record, ta
+ assert_equal ["bar"], ta.reload.params[:foo]
+ ta.updated_at = Time.now.ago(6.minutes)
+ ta.send :update_without_callbacks
+ t = ta.reload.updated_at
+ assert_difference "ActionTracker::Record.count" do
+ ta2 = ActionTracker::Record.add_or_create :verb => :some, :user => @mymodel, :params => { :foo => "test" }
+ ta2.save; ta2.reload
+ assert_kind_of ActionTracker::Record, ta2
+ end
+ assert_equal t, ta.reload.updated_at
+ assert_equal ["test"], ActionTracker::Record.last.params[:foo]
+ end
+
+ def test_add_or_create_update_if_timeout
+ ActionTrackerConfig.verbs = { :some => { :description => "Something", :type => :updatable } }
+ ActionTrackerConfig.timeout = 7.minutes
+ ActionTracker::Record.delete_all
+ ta = nil
+ assert_difference "ActionTracker::Record.count" do
+ ta = ActionTracker::Record.add_or_create :verb => :some, :user => @mymodel, :params => { :foo => "test 1", :bar => 2 }
+ ta.save; ta.reload
+ end
+ assert_kind_of ActionTracker::Record, ta
+ assert_equal ["test 1"], ta.params[:foo]
+ assert_equal [2], ta.params[:bar]
+ ta.updated_at = Time.now.ago(6.minutes)
+ ta.send :update_without_callbacks
+ t = ta.reload.updated_at
+ assert_no_difference "ActionTracker::Record.count" do
+ ta2 = ActionTracker::Record.add_or_create :verb => :some, :user => @mymodel, :params => { :foo => "test 2", :bar => 1 }
+ ta2.save; ta2.reload
+ assert_kind_of ActionTracker::Record, ta2
+ end
+ assert_equal ["test 1", "test 2"], ActionTracker::Record.last.params[:foo]
+ assert_equal [2, 1], ActionTracker::Record.last.params[:bar]
+ assert_not_equal t, ta.reload.updated_at
+ assert_no_difference "ActionTracker::Record.count" do
+ ta = ActionTracker::Record.add_or_create :verb => :some, :user => @mymodel, :params => { :foo => "test 1", :bar => 1 }
+ ta.save; ta.reload
+ end
+ assert_equal ["test 1", "test 2", "test 1"], ActionTracker::Record.last.params[:foo]
+ assert_equal [2, 1, 1], ActionTracker::Record.last.params[:bar]
+ end
+
+ def test_time_spent
+ ActionTracker::Record.delete_all
+ ActionTrackerConfig.verbs = { :some => { :description => "Something", :type => :updatable } }
+ t = ActionTracker::Record.update_or_create :verb => :some, :user => @mymodel
+ t.save; t.reload
+ t.created_at = t.created_at.ago(2.days)
+ t.updated_at = t.created_at.tomorrow
+ t.send :update_without_callbacks
+ ActionTrackerConfig.timeout = 5.minutes
+ t = ActionTracker::Record.update_or_create :verb => :some, :user => @mymodel
+ t.save; t.reload
+ t.created_at = t.updated_at.ago(2.hours)
+ t.send :update_without_callbacks
+ assert_equal 2, ActionTracker::Record.count
+ assert_equal 26.hours, ActionTracker::Record.time_spent
+ end
+
+ def test_duration
+ ActionTracker::Record.delete_all
+ ActionTrackerConfig.verbs = { :some => { :description => "Something", :type => :updatable } }
+ ActionTrackerConfig.timeout = 5.minutes
+ t = ActionTracker::Record.update_or_create :verb => :some, :user => @mymodel; t.save
+ t = ActionTracker::Record.update_or_create :verb => :some, :user => @mymodel; t.save
+ t.reload
+ t.created_at = t.updated_at.ago(2.minutes)
+ t.send :update_without_callbacks
+ assert_equal 1, ActionTracker::Record.count
+ assert_equal 2.minutes, t.reload.duration
+ end
+
+ def test_describe
+ ActionTracker::Record.delete_all
+ ActionTrackerConfig.verbs = { :some => { :description => "Who done this is from class {{user.class.to_s}} and half of its value is {{params[:value].to_i/2}}" } }
+ ActionTrackerConfig.timeout = 5.minutes
+ t = ActionTracker::Record.create! :verb => :some, :user => @mymodel, :params => { :value => "10" }
+ assert_equal "Who done this is from class SomeModel and half of its value is 5", t.describe
+ end
+
+ def test_description
+ ActionTrackerConfig.verbs = { :some => { :description => "Got {{it}}" } }
+ t = ActionTracker::Record.create! :user => SomeModel.create!, :verb => :some
+ assert_equal "Got {{it}}", t.description
+ ActionTrackerConfig.verbs = { :some => nil }
+ t = ActionTracker::Record.create! :user => SomeModel.create!, :verb => :some
+ assert_equal "", t.description
+ end
+
+ def test_subject
+ ActionTrackerConfig.verbs = { :some => { :description => "Some" } }
+ u = SomeModel.create!
+ t = ActionTracker::Record.create! :verb => :some, :user => u
+ assert_equal u, t.subject
+ end
+
+ def test_predicate
+ ActionTrackerConfig.verbs = { :some => { :description => "Some" } }
+ t = ActionTracker::Record.create! :user => SomeModel.create!, :verb => :some, :params => nil
+ assert_equal({}, t.predicate)
+ t = ActionTracker::Record.create! :user => SomeModel.create!, :verb => :some, :params => { :foo => "bar" }
+ assert_equal({ :foo => "bar" }, t.predicate)
+ end
+
+ def test_phrase
+ ActionTrackerConfig.verbs = { :some => { :description => "Some" } }
+ u = SomeModel.create!
+ t = ActionTracker::Record.create! :verb => :some, :params => { :foo => "bar" }, :user => u
+ assert_equal({ :subject => u, :verb => "some", :predicate => { :foo => "bar" }}, t.phrase)
+ end
+
+ def test_method_missing
+ ActionTrackerConfig.verbs = { :some => { :description => "Some" } }
+ t = ActionTracker::Record.create! :user => SomeModel.create!, :verb => :some, :params => { :foo => "test 1", "bar" => "test 2" }
+ assert_nil t.get_test
+ assert_equal "test 1", t.get_foo
+ assert_equal "test 2", t.get_bar
+ assert_raise NoMethodError do
+ t.another_unknown_method
+ end
+ end
+
+ def test_collect_group_with_index
+ ActionTrackerConfig.verbs = { :some => { :description => "Some" }, :type => :groupable }
+ t = ActionTracker::Record.create! :user => SomeModel.create!, :verb => :some, :params => { "test" => ["foo", "bar"] }
+ assert_equal(["foo 1", "bar 2"], t.collect_group_with_index(:test){|x, i| "#{x} #{i+1}" })
+ end
+
+ def test_user_id_is_mandatory
+ ActionTrackerConfig.verbs = { :some => { :description => "Some" } }
+ ta = ActionTracker::Record.new :user_type => 'SomeModel', :verb => :some
+ ta.valid?
+ assert ta.errors.on(:user_id)
+ assert_raise ActiveRecord::RecordInvalid do
+ ta.save!
+ end
+ end
+
+ def test_user_type_is_mandatory
+ ActionTrackerConfig.verbs = { :some => { :description => "Some" } }
+ ta = ActionTracker::Record.new :user_id => 2, :verb => :some
+ ta.valid?
+ assert ta.errors.on(:user_type)
+ assert_raise ActiveRecord::RecordInvalid do
+ ta.save!
+ end
+ end
+
+end
diff --git a/vendor/plugins/action_tracker/test/action_tracker_test.rb b/vendor/plugins/action_tracker/test/action_tracker_test.rb
new file mode 100644
index 0000000..aae44ba
--- /dev/null
+++ b/vendor/plugins/action_tracker/test/action_tracker_test.rb
@@ -0,0 +1,559 @@
+require 'test_helper'
+
+ActiveRecord::Base.establish_connection({
+ :adapter => "sqlite3",
+ :database => ":memory:"
+})
+
+ActiveRecord::Schema.define do
+ create_table :some_table, :force => true do |t|
+ t.column :some_column, :string
+ end
+ create_table :other_table, :force => true do |t|
+ t.column :other_column, :string
+ t.column :another_column, :integer
+ end
+ create_table :action_tracker do |t|
+ t.belongs_to :user, :polymorphic => true
+ t.belongs_to :dispatcher, :polymorphic => true
+ t.text :params
+ t.string :verb
+ t.timestamps
+ end
+end
+
+class SomeModel < ActiveRecord::Base
+ set_table_name :some_table
+ acts_as_trackable
+end
+
+class OtherModel < ActiveRecord::Base
+ set_table_name :other_table
+end
+
+class ThingsController < ActionController::Base
+
+ def index
+ params[:foo] = params[:foo].to_i + 1
+ render :text => "test"
+ end
+
+ def test
+ render :text => "test"
+ end
+
+ def current_user
+ SomeModel.first || SomeModel.create!
+ end
+
+ def rescue_action(e)
+ raise e
+ end
+
+end
+
+ActionController::Routing::Routes.draw { |map| map.resources :things, :collection => { :test => :get } }
+
+class ActionTrackerTest < ActiveSupport::TestCase
+
+ def setup
+ UserStamp.creator_attribute = :user
+ UserStamp.updater_attribute = :user
+ ActionTrackerConfig.current_user_method = :current_user
+ ActionTracker::Record.delete_all
+ ActionTrackerConfig.verbs = { :some_verb => { :description => "Did something" } }
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ @controller = ThingsController.new
+ end
+
+ def test_index
+ get :index
+ assert_response :success
+ end
+
+ def test_track_actions_after_runs_after_action
+ @controller = create_controller { track_actions_after :some_verb }
+ assert_difference 'ActionTracker::Record.count' do
+ get :index, :foo => "4"
+ end
+ assert_equal 5, ActionTracker::Record.first.params[:foo]
+ end
+
+ def test_track_actions_after_runs_before_action
+ @controller = create_controller { track_actions_before :some_verb }
+ assert_difference 'ActionTracker::Record.count' do
+ get :index, :foo => "4"
+ end
+ assert_equal "4", ActionTracker::Record.first.params[:foo]
+ end
+
+ def test_track_actions_default_is_after
+ ActionTrackerConfig.default_filter_time = :after
+ @controller = create_controller { track_actions :some_verb }
+ assert_difference 'ActionTracker::Record.count' do
+ get :index, :foo => "4"
+ end
+ assert_equal 5, ActionTracker::Record.first.params[:foo]
+ end
+
+ def test_track_actions_default_is_before
+ ActionTrackerConfig.default_filter_time = :before
+ @controller = create_controller { track_actions :some_verb }
+ assert_difference 'ActionTracker::Record.count' do
+ get :index, :foo => "4"
+ end
+ assert_equal "4", ActionTracker::Record.first.params[:foo]
+ end
+
+ def test_track_actions_executes_block
+ @controller = create_controller do
+ track_actions :some_verb do
+ throw :some_symbol
+ end
+ end
+ assert_difference 'ActionTracker::Record.count' do
+ assert_throws :some_symbol do
+ get :index, :foo => "4"
+ end
+ end
+ assert_equal "4", ActionTracker::Record.first.params[:foo]
+ end
+
+ def test_pass_keep_params_as_symbol
+ @controller = create_controller { track_actions_before :some_verb, :keep_params => [:foo] }
+ assert_difference 'ActionTracker::Record.count' do
+ get :index, :foo => 5
+ end
+ assert_equal({ "foo" => "5" }, ActionTracker::Record.first.params)
+ end
+
+ def test_pass_keep_params_as_string
+ @controller = create_controller { track_actions_before :some_verb, "keep_params" => [:foo, :bar] }
+ assert_difference 'ActionTracker::Record.count' do
+ get :index, :foo => 5, :bar => 10
+ end
+ assert_equal({ "foo" => "5", "bar" => "10" }, ActionTracker::Record.first.params)
+ end
+
+ def test_pass_keep_params_none
+ @controller = create_controller { track_actions_before :some_verb, :keep_params => :none }
+ assert_difference 'ActionTracker::Record.count' do
+ get :index, :foo => 5
+ end
+ assert_equal({}, ActionTracker::Record.first.params)
+ ActionTracker::Record.delete_all
+ @controller = create_controller { track_actions_before :some_verb, :keep_params => "none" }
+ assert_difference 'ActionTracker::Record.count' do
+ get :index, :foo => 5
+ end
+ assert_equal({}, ActionTracker::Record.first.params)
+ end
+
+ def test_pass_keep_params_all
+ @controller = create_controller { track_actions_before :some_verb, :keep_params => :all }
+ assert_difference 'ActionTracker::Record.count' do
+ get :index, :foo => 5
+ end
+ assert_equal({"action"=>"index", "foo"=>"5", "controller"=>"things"}, ActionTracker::Record.first.params)
+ ActionTracker::Record.delete_all
+ @controller = create_controller { track_actions_before :some_verb, :keep_params => "all" }
+ assert_difference 'ActionTracker::Record.count' do
+ get :index, :foo => 5
+ end
+ assert_equal({"action"=>"index", "foo"=>"5", "controller"=>"things"}, ActionTracker::Record.first.params)
+ end
+
+ def test_keep_params_not_set_should_store_all_params
+ @controller = create_controller { track_actions_before :some_verb }
+ assert_difference 'ActionTracker::Record.count' do
+ get :index, :foo => 5
+ end
+ assert_equal({"action"=>"index", "foo"=>"5", "controller"=>"things"}, ActionTracker::Record.first.params)
+ end
+
+ def test_execute_if_some_condition_is_true
+ @controller = create_controller { track_actions_before :some_verb, :if => Proc.new { 2 < 1 } }
+ assert_no_difference 'ActionTracker::Record.count' do
+ get :index, :foo => 5
+ end
+ @controller = create_controller { track_actions_before :some_verb, :if => Proc.new { 2 > 1 } }
+ assert_difference 'ActionTracker::Record.count' do
+ get :index, :foo => 5
+ end
+ end
+
+ def test_execute_unless_some_condition_is_true
+ @controller = create_controller { track_actions_before :some_verb, :unless => Proc.new { 2 < 1 } }
+ assert_difference 'ActionTracker::Record.count' do
+ get :index, :foo => 5
+ end
+ @controller = create_controller { track_actions_before :some_verb, :unless => Proc.new { 2 > 1 } }
+ assert_no_difference 'ActionTracker::Record.count' do
+ get :index, :foo => 5
+ end
+ end
+
+ def test_execute_for_all_actions
+ @controller = create_controller { track_actions_before :some_verb }
+ assert_difference 'ActionTracker::Record.count' do
+ get :index
+ end
+ assert_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ end
+
+ def test_execute_only_for_some_action
+ @controller = create_controller { track_actions_before :some_verb, :only => [:index] }
+ assert_difference 'ActionTracker::Record.count' do
+ get :index
+ end
+ assert_no_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ end
+
+ def test_execute_except_for_some_action
+ @controller = create_controller { track_actions_before :some_verb, :except => [:index] }
+ assert_no_difference 'ActionTracker::Record.count' do
+ get :index
+ end
+ assert_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ end
+
+ def test_store_user
+ @controller = create_controller do
+ track_actions_before :some_verb
+ def current_user
+ SomeModel.create! :some_column => "test"
+ end
+ end
+ assert_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ assert_equal "test", ActionTracker::Record.last.user.some_column
+ end
+
+ def test_should_update_when_verb_is_updatable_and_no_timeout
+ ActionTrackerConfig.verbs = { :some_verb => { :description => "Did something", :type => :updatable } }
+ ActionTrackerConfig.timeout = 5.minutes
+ @controller = create_controller { track_actions_before :some_verb }
+ assert ActionTrackerConfig.verb_type(:some_verb) == :updatable
+ assert_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ t = ActionTracker::Record.last
+ t.updated_at = t.updated_at.ago(2.minutes)
+ t.send :update_without_callbacks
+ assert_no_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ end
+
+ def test_should_create_when_verb_is_updatable_and_timeout
+ ActionTrackerConfig.verbs = { :some_verb => { :description => "Did something", :type => :updatable } }
+ ActionTrackerConfig.timeout = 5.minutes
+ @controller = create_controller { track_actions_before :some_verb }
+ assert ActionTrackerConfig.verb_type(:some_verb) == :updatable
+ assert_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ t = ActionTracker::Record.last
+ t.updated_at = t.updated_at.ago(6.minutes)
+ t.send :update_without_callbacks
+ assert_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ end
+
+ def test_should_update_when_verb_is_groupable_and_no_timeout
+ ActionTrackerConfig.verbs = { :some_verb => { :description => "Did something", :type => :groupable } }
+ ActionTrackerConfig.timeout = 5.minutes
+ @controller = create_controller { track_actions_before :some_verb, :keep_params => [:foo] }
+ assert ActionTrackerConfig.verb_type(:some_verb) == :groupable
+ assert_difference 'ActionTracker::Record.count' do
+ get :test, :foo => "bar"
+ end
+ t = ActionTracker::Record.last
+ t.updated_at = t.updated_at.ago(2.minutes)
+ t.send :update_without_callbacks
+ assert_no_difference 'ActionTracker::Record.count' do
+ get :test, :foo => "test"
+ end
+ end
+
+ def test_should_create_when_verb_is_groupable_and_timeout
+ ActionTrackerConfig.verbs = { :some_verb => { :description => "Did something", :type => :groupable } }
+ ActionTrackerConfig.timeout = 5.minutes
+ @controller = create_controller { track_actions_before :some_verb, :keep_params => [:foo] }
+ assert ActionTrackerConfig.verb_type(:some_verb) == :groupable
+ assert_difference 'ActionTracker::Record.count' do
+ get :test, :foo => "bar"
+ end
+ t = ActionTracker::Record.last
+ t.updated_at = t.updated_at.ago(6.minutes)
+ t.send :update_without_callbacks
+ assert_difference 'ActionTracker::Record.count' do
+ get :test, :foo => "test"
+ end
+ end
+
+ def test_should_create_when_verb_is_single
+ ActionTrackerConfig.verbs = { :some_verb => { :description => "Did something", :type => :single } }
+ @controller = create_controller { track_actions_before :some_verb }
+ assert ActionTrackerConfig.verb_type(:some_verb) == :single
+ assert_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ assert_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ end
+
+ def test_should_act_as_trackable
+ m = SomeModel.create!
+ assert m.respond_to?(:tracked_actions)
+ assert_kind_of Array, m.tracked_actions
+ @controller = create_controller { track_actions_before :some_verb }
+ @controller.stubs(:current_user).returns(m)
+ get :index
+ sleep 2
+ get :test
+ assert ActionTracker::Record.last.updated_at > ActionTracker::Record.first.updated_at
+ assert_equal [ActionTracker::Record.last, ActionTracker::Record.first], m.reload.tracked_actions
+ end
+
+ def test_should_get_time_spent_doing_something
+ ActionTrackerConfig.verbs = { :some_verb => { :type => :updatable }, :other_verb => { :type => :updatable } }
+ m = SomeModel.create!
+ @controller = create_controller do
+ track_actions :some_verb
+ end
+ @controller.stubs(:current_user).returns(m)
+ get :index
+ t1 = ActionTracker::Record.last
+ t1.updated_at = t1.updated_at.ago(4.hours)
+ t1.created_at = t1.updated_at.ago(3.hours)
+ t1.send :update_without_callbacks
+ get :test
+ t2 = ActionTracker::Record.last
+ t2.updated_at = t2.updated_at.ago(3.hours)
+ t2.created_at = t2.updated_at.ago(2.hours)
+ t2.send :update_without_callbacks
+ assert_equal 5.hours, m.time_spent_doing(:some_verb)
+ assert_equal 3.hours, m.time_spent_doing(:some_verb, :id => t1.id)
+ assert_equal 0.0, m.time_spent_doing(:other_verb)
+ assert_equal 0.0, m.time_spent_doing(:other_verb, :verb => :some_verb)
+ end
+
+ def test_helper_describe_action_tracker_object
+ ActionTrackerConfig.verbs = { :some_verb => { :description => "Hey, {{link_to 'click here', :controller => :things}} {{ta.user.some_column}}!" } }
+ view = ActionView::Base.new
+ view.controller = @controller
+ @request.env["HTTP_REFERER"] = "http://test.com"
+ get :index
+ user = SomeModel.create! :some_column => "test"
+ t = ActionTracker::Record.create! :verb => :some_verb, :user => user
+ assert_equal 'Hey, click here test!', view.describe(t)
+ end
+
+ def test_helper_describe_non_action_tracker_object
+ view = ActionView::Base.new
+ view.controller = @controller
+ @request.env["HTTP_REFERER"] = "http://test.com"
+ get :index
+ assert_equal "", view.describe("Something")
+ end
+
+ def test_track_actions_store_user
+ ActionTrackerConfig.verbs = { :test => { :description => "Some" } }
+ model = create_model do
+ track_actions :test, :after_create
+ end
+ @controller = create_controller_for_model(model)
+ assert_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ assert_kind_of SomeModel, ActionTracker::Record.last.user
+ assert_equal "test", ActionTracker::Record.last.user.some_column
+ end
+
+ def test_track_actions_store_some_params
+ ActionTrackerConfig.verbs = { :test => { :description => "Some" } }
+ model = create_model do
+ track_actions :test, :after_create, :keep_params => [:other_column]
+ end
+ @controller = create_controller_for_model(model, :other_column => "foo", :another_column => 2)
+ assert_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ assert_equal "foo", ActionTracker::Record.last.params["other_column"]
+ assert_nil ActionTracker::Record.last.params["another_column"]
+ end
+
+ def test_replace_dots_by_underline_in_param_name
+ ActionTrackerConfig.verbs = { :test => { :description => "Some" } }
+ model = create_model do
+ track_actions :test, :after_create, :keep_params => ["other_column.size", :another_column]
+ end
+ @controller = create_controller_for_model(model, :other_column => "foo", :another_column => 5)
+ assert_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ assert_equal 3, ActionTracker::Record.last.params["other_column_size"]
+ assert_equal 5, ActionTracker::Record.last.params["another_column"]
+ end
+
+ def test_track_actions_store_all_params
+ ActionTrackerConfig.verbs = { :test => { :description => "Some" } }
+ model = create_model do
+ track_actions :test, :after_create, :keep_params => :all
+ end
+ @controller = create_controller_for_model(model, :other_column => "foo", :another_column => 2)
+ assert_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ assert_equal "foo", ActionTracker::Record.last.params["other_column"]
+ assert_equal 2, ActionTracker::Record.last.params["another_column"]
+ end
+
+ def test_track_actions_store_all_params_by_default
+ ActionTrackerConfig.verbs = { :test => { :description => "Some" } }
+ model = create_model do
+ track_actions :test, :after_create
+ end
+ @controller = create_controller_for_model(model, :other_column => "foo", :another_column => 2)
+ assert_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ assert_equal "foo", ActionTracker::Record.last.params["other_column"]
+ assert_equal 2, ActionTracker::Record.last.params["another_column"]
+ end
+
+ def test_track_actions_store_no_params
+ ActionTrackerConfig.verbs = { :test => { :description => "Some" } }
+ model = create_model do
+ track_actions :test, :after_create, :keep_params => :none
+ end
+ @controller = create_controller_for_model(model, :other_column => "foo", :another_column => 2)
+ assert_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ assert_nil ActionTracker::Record.last.params["other_column"]
+ assert_nil ActionTracker::Record.last.params["another_column"]
+ end
+
+ def test_track_actions_with_options
+ ActionTrackerConfig.verbs = { :test => { :description => "Some" } }
+ model = create_model { track_actions :test, :after_create, :keep_params => :all, :if => Proc.new { 2 > 1 } }
+ @controller = create_controller_for_model(model)
+ assert_difference('ActionTracker::Record.count') { get :test }
+
+ model = create_model { track_actions :test, :after_create, :keep_params => :all, :if => Proc.new { 2 < 1 } }
+ @controller = create_controller_for_model(model)
+ assert_no_difference('ActionTracker::Record.count') { get :test }
+
+ model = create_model { track_actions :test, :after_create, :keep_params => :all, :unless => Proc.new { 2 > 1 } }
+ @controller = create_controller_for_model(model)
+ assert_no_difference('ActionTracker::Record.count') { get :test }
+
+ model = create_model { track_actions :test, :after_create, :keep_params => :all, :unless => Proc.new { 2 < 1 } }
+ @controller = create_controller_for_model(model)
+ assert_difference('ActionTracker::Record.count') { get :test }
+ end
+
+ def test_track_actions_post_processing_as_symbol
+ ActionTrackerConfig.verbs = { :test => { :description => "Some" } }
+ model = create_model do
+ track_actions :test, :after_create, :post_processing => Proc.new { |ta| OtherModel.create!(:other_column => ta.verb) }
+ end
+ @controller = create_controller_for_model(model, :another_column => 2)
+ assert_difference 'ActionTracker::Record.count' do
+ assert_difference('OtherModel.count', 2) do
+ get :test
+ end
+ end
+ assert_equal "test", OtherModel.last.other_column
+ end
+
+ def test_track_actions_post_processing_as_string
+ ActionTrackerConfig.verbs = { :test => { :description => "Some" } }
+ model = create_model do
+ track_actions :test, :after_create, "post_processing" => Proc.new { |ta| OtherModel.create!(:other_column => ta.verb) }
+ end
+ @controller = create_controller_for_model(model, :another_column => 2)
+ assert_difference 'ActionTracker::Record.count' do
+ assert_difference('OtherModel.count', 2) do
+ get :test
+ end
+ end
+ assert_equal "test", OtherModel.last.other_column
+ end
+
+ def test_acts_as_trackable_with_options
+ ActionTrackerConfig.verbs = { :test => { :description => "Some" } }
+ @@action = create_model do
+ track_actions :test, :after_create
+ end
+ @@user = create_model do
+ acts_as_trackable :after_add => Proc.new { |x, y| raise 'I was called' }
+ end
+ @controller = create_controller do
+ def test
+ @@action.create!
+ render :text => "test"
+ end
+ def current_user
+ @@user.create!
+ end
+ end
+ assert_raise(RuntimeError, 'I was called') do
+ get :test
+ end
+ end
+
+ def test_track_actions_save_dispatcher
+ ActionTrackerConfig.verbs = { :test => { :description => "Some" } }
+ model = create_model do
+ track_actions :test, :after_create
+ end
+ @controller = create_controller_for_model(model)
+ assert_difference 'ActionTracker::Record.count' do
+ get :test
+ end
+ assert_kind_of model.base_class, ActionTracker::Record.last.dispatcher
+ end
+
+ private
+
+ def create_controller(&block)
+ klass = Class.new(ThingsController)
+ klass.module_eval &block
+ klass.stubs(:controller_path).returns('things')
+ klass.new
+ end
+
+ def create_model(&block)
+ klass = Class.new(OtherModel)
+ klass.module_eval &block
+ klass
+ end
+
+ def create_controller_for_model(model, attributes = {})
+ @@model, @@attributes = model, attributes
+ create_controller do
+ def test
+ @@model.create! @@attributes
+ render :text => "test"
+ end
+
+ def current_user
+ SomeModel.create! :some_column => "test"
+ end
+ end
+ end
+
+end
diff --git a/vendor/plugins/action_tracker/test/test_helper.rb b/vendor/plugins/action_tracker/test/test_helper.rb
new file mode 100755
index 0000000..4975b1e
--- /dev/null
+++ b/vendor/plugins/action_tracker/test/test_helper.rb
@@ -0,0 +1,5 @@
+ENV['RAILS_ROOT'] ||= File.dirname(__FILE__) + '/../../../..'
+require File.expand_path(File.join(ENV['RAILS_ROOT'], 'config/environment.rb'))
+
+ENV["RAILS_ENV"] = "test"
+require 'test_help'
diff --git a/vendor/plugins/action_tracker/uninstall.rb b/vendor/plugins/action_tracker/uninstall.rb
new file mode 100644
index 0000000..9738333
--- /dev/null
+++ b/vendor/plugins/action_tracker/uninstall.rb
@@ -0,0 +1 @@
+# Uninstall hook code here
diff --git a/vendor/plugins/user_stamp/MIT-LICENSE b/vendor/plugins/user_stamp/MIT-LICENSE
new file mode 100644
index 0000000..f5eca46
--- /dev/null
+++ b/vendor/plugins/user_stamp/MIT-LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2008 [John Nunemaker]
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/plugins/user_stamp/README b/vendor/plugins/user_stamp/README
new file mode 100644
index 0000000..3f512d6
--- /dev/null
+++ b/vendor/plugins/user_stamp/README
@@ -0,0 +1,37 @@
+= UserStamp
+
+Rails plugin that makes stamping records with a user when they are
+created and updated dirt simple. It assumes that your controller has
+a current_user method. It also assumes that any record being stamped
+has two attributes--creator_id and updater_id. You can override both
+of these assumptions easily.
+
+== Setup
+
+1. script/plugin install git://github.com/jnunemaker/user_stamp.git
+2. Add user_stamp to application.rb, like the following:
+
+ class ApplicationController < ActionController::Base
+ user_stamp Post, Asset, Job
+ end
+
+
+== Defaults
+
+ UserStamp.creator_attribute = :creator_id
+ UserStamp.updater_attribute = :updater_id
+ UserStamp.current_user_method = :current_user
+
+If your user stamped columns and current_user method are different,
+just create an initializer such as config/initializers/user_stamp.rb
+and copy and paste the defaults above, changing them to fit your app.
+
+== Problems?
+
+Use the issue tracker on Github.
+
+== Docs
+
+http://rdoc.info/projects/jnunemaker/user_stamp
+
+Copyright (c) 2008 [John Nunemaker], released under the MIT license
diff --git a/vendor/plugins/user_stamp/Rakefile b/vendor/plugins/user_stamp/Rakefile
new file mode 100644
index 0000000..cf2dd88
--- /dev/null
+++ b/vendor/plugins/user_stamp/Rakefile
@@ -0,0 +1,11 @@
+require 'rake'
+require 'spec/rake/spectask'
+
+desc 'Default: run specs.'
+task :default => :spec
+
+desc 'Run the specs'
+Spec::Rake::SpecTask.new(:spec) do |t|
+ t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
+ t.spec_files = FileList['spec/**/*_spec.rb']
+end
\ No newline at end of file
diff --git a/vendor/plugins/user_stamp/init.rb b/vendor/plugins/user_stamp/init.rb
new file mode 100644
index 0000000..18d0ac4
--- /dev/null
+++ b/vendor/plugins/user_stamp/init.rb
@@ -0,0 +1,5 @@
+require 'user_stamp'
+
+class ActionController::Base
+ extend UserStamp::ClassMethods
+end
diff --git a/vendor/plugins/user_stamp/install.rb b/vendor/plugins/user_stamp/install.rb
new file mode 100644
index 0000000..d562416
--- /dev/null
+++ b/vendor/plugins/user_stamp/install.rb
@@ -0,0 +1,15 @@
+instructions = < nil, :updater_id= => nil, :new_record? => true)
+ record.should_receive(:creator_id=).with(220).once
+ @sweeper.before_validation(record)
+ end
+
+ it "should NOT set creator_id if attribute does not exist" do
+ record = mock('Record', :new_record? => true, :updater_id= => nil, :respond_to? => false)
+ record.should_receive(:respond_to?).with("creator_id=").and_return(false)
+ record.should_not_receive(:creator_id=)
+ @sweeper.before_validation(record)
+ end
+ end
+
+ describe "(with non new record)" do
+ it "should NOT set creator_id if attribute exists" do
+ record = mock('Record', :creator_id= => nil, :updater_id= => nil, :new_record? => false)
+ record.should_not_receive(:creator_id=)
+ @sweeper.before_validation(record)
+ end
+
+ it "should NOT set creator_id if attribute does not exist" do
+ record = mock('Record', :updater_id= => nil, :new_record? => false)
+ record.should_not_receive(:creator_id=)
+ @sweeper.before_validation(record)
+ end
+ end
+
+ it "should set updater_id if attribute exists" do
+ record = mock('Record', :creator_id= => nil, :updater_id= => nil, :new_record? => :false)
+ record.should_receive(:updater_id=)
+ @sweeper.before_validation(record)
+ end
+
+ it "should NOT set updater_id if attribute does not exist" do
+ record = mock('Record', :creator_id= => nil, :updater_id= => nil, :new_record? => :false, :respond_to? => false)
+ record.should_receive(:respond_to?).with("updater_id=").and_return(false)
+ record.should_not_receive(:updater_id=)
+ @sweeper.before_validation(record)
+ end
+end
+
+describe UserStampSweeper, "#before_validation (with custom attribute names)" do
+ before do
+ UserStamp.creator_attribute = :created_by
+ UserStamp.updater_attribute = :updated_by
+ UserStamp.current_user_method = :current_user
+ @sweeper = UserStampSweeper.instance
+ @sweeper.stub!(:controller).and_return(PostsController)
+ end
+
+ describe "(with new record)" do
+ it "should set created_by if attribute exists" do
+ record = mock('Record', :created_by= => nil, :updated_by= => nil, :new_record? => true)
+ record.should_receive(:created_by=).with(220).once
+ @sweeper.before_validation(record)
+ end
+
+ it "should NOT set created_by if attribute does not exist" do
+ record = mock('Record', :new_record? => true, :updated_by= => nil, :respond_to? => false)
+ record.should_receive(:respond_to?).with("created_by=").and_return(false)
+ record.should_not_receive(:created_by=)
+ @sweeper.before_validation(record)
+ end
+ end
+
+ describe "(with non new record)" do
+ it "should NOT set created_by if attribute exists" do
+ record = mock('Record', :created_by= => nil, :updated_by= => nil, :new_record? => false)
+ record.should_not_receive(:created_by=)
+ @sweeper.before_validation(record)
+ end
+
+ it "should NOT set created_by if attribute does not exist" do
+ record = mock('Record', :updated_by= => nil, :new_record? => false)
+ record.should_not_receive(:created_by=)
+ @sweeper.before_validation(record)
+ end
+ end
+
+ it "should set updated_by if attribute exists" do
+ record = mock('Record', :created_by= => nil, :updated_by= => nil, :new_record? => :false)
+ record.should_receive(:updated_by=)
+ @sweeper.before_validation(record)
+ end
+
+ it "should NOT set updated_by if attribute does not exist" do
+ record = mock('Record', :created_by= => nil, :updated_by= => nil, :new_record? => :false, :respond_to? => false)
+ record.should_receive(:respond_to?).with("updated_by=").and_return(false)
+ record.should_not_receive(:updated_by=)
+ @sweeper.before_validation(record)
+ end
+end
+
+describe UserStampSweeper, "#current_user" do
+ before do
+ UserStamp.creator_attribute = :creator_id
+ UserStamp.updater_attribute = :updater_id
+ UserStamp.current_user_method = :current_user
+ @sweeper = UserStampSweeper.instance
+ end
+
+ it "should send current_user if controller responds to it" do
+ user = mock('User')
+ controller = mock('Controller', :current_user => user)
+ @sweeper.stub!(:controller).and_return(controller)
+ controller.should_receive(:current_user)
+ @sweeper.send(:current_user)
+ end
+
+ it "should not send current_user if controller does not respond to it" do
+ user = mock('User')
+ controller = mock('Controller', :respond_to? => false)
+ @sweeper.stub!(:controller).and_return(controller)
+ controller.should_not_receive(:current_user)
+ @sweeper.send(:current_user)
+ end
+end
+
+describe UserStampSweeper, "#current_user (with custom current_user_method)" do
+ before do
+ UserStamp.creator_attribute = :creator_id
+ UserStamp.updater_attribute = :updater_id
+ UserStamp.current_user_method = :my_user
+ @sweeper = UserStampSweeper.instance
+ end
+
+ it "should send current_user if controller responds to it" do
+ user = mock('User')
+ controller = mock('Controller', :my_user => user)
+ @sweeper.stub!(:controller).and_return(controller)
+ controller.should_receive(:my_user)
+ @sweeper.send(:current_user)
+ end
+
+ it "should not send current_user if controller does not respond to it" do
+ user = mock('User')
+ controller = mock('Controller', :respond_to? => false)
+ @sweeper.stub!(:controller).and_return(controller)
+ controller.should_not_receive(:my_user)
+ @sweeper.send(:current_user)
+ end
+end
\ No newline at end of file
--
libgit2 0.21.2