Commit a1ac0fb5d3798eb70807456368e3017cceeceea8

Authored by Daniela Feitosa
2 parents c7afee4e 607528df

Merge branch 'stable'

Conflicts:
	db/schema.rb
app/controllers/public/search_controller.rb
... ... @@ -243,7 +243,7 @@ class SearchController < PublicController
243 243 @searching = {}
244 244 @titles = {}
245 245 @enabled_searches.each do |key, name|
246   - @titles[key] = name
  246 + @titles[key] = _(name)
247 247 @searching[key] = params[:action] == 'index' || params[:action] == key.to_s
248 248 end
249 249 @names = @titles if @names.nil?
... ...
app/helpers/application_helper.rb
... ... @@ -1094,7 +1094,7 @@ module ApplicationHelper
1094 1094 {s_('contents|Most commented') => {:href => url_for({:controller => 'search', :action => 'contents', :filter => 'more_comments'})}}
1095 1095 ]
1096 1096 if logged_in?
1097   - links.push(_('New content') => lightbox_options({:href => url_for({:controller => 'cms', :action => 'new', :profile => current_user.login, :cms => true})}))
  1097 + links.push(_('New content') => colorbox_options({:href => url_for({:controller => 'cms', :action => 'new', :profile => current_user.login, :cms => true})}))
1098 1098 end
1099 1099  
1100 1100 link_to(content_tag(:span, _('Contents'), :class => 'icon-menu-articles'), {:controller => "search", :action => 'contents', :category_path => ''}, :id => 'submenu-contents') +
... ... @@ -1183,6 +1183,10 @@ module ApplicationHelper
1183 1183 ], :class => 'limited-text-area')
1184 1184 end
1185 1185  
  1186 + def expandable_text_area(object_name, method, text_area_id, options = {})
  1187 + text_area(object_name, method, { :id => text_area_id, :onkeyup => "grow_text_area('#{text_area_id}')" }.merge(options))
  1188 + end
  1189 +
1186 1190 def pluralize_without_count(count, singular, plural = nil)
1187 1191 count == 1 ? singular : (plural || singular.pluralize)
1188 1192 end
... ...
app/models/article.rb
... ... @@ -54,6 +54,11 @@ class Article < ActiveRecord::Base
54 54 end
55 55 end
56 56  
  57 + after_destroy :destroy_activity
  58 + def destroy_activity
  59 + self.activity.destroy if self.activity
  60 + end
  61 +
57 62 xss_terminate :only => [ :name ], :on => 'validation', :with => 'white_list'
58 63  
59 64 named_scope :in_category, lambda { |category|
... ...
app/models/input.rb
... ... @@ -9,6 +9,8 @@ class Input < ActiveRecord::Base
9 9  
10 10 belongs_to :unit
11 11  
  12 + named_scope :relevant_to_price, :conditions => { :relevant_to_price => true }
  13 +
12 14 include FloatHelper
13 15  
14 16 def price_per_unit=(value)
... ...
app/models/location_block.rb
1 1 class LocationBlock < Block
2 2  
3   - settings_items :zoom, :type => :integer , :default => 4
4   - settings_items :map_type, :type => :string , :default => 'roadmap'
  3 + settings_items :zoom, :type => :integer, :default => 4
  4 + settings_items :map_type, :type => :string, :default => 'roadmap'
5 5  
6 6 def self.description
7 7 _('Location map')
... ... @@ -12,18 +12,10 @@ class LocationBlock &lt; Block
12 12 end
13 13  
14 14 def content(args={})
  15 + block = self
15 16 profile = self.owner
16   - title = self.title
17   - if profile.lat
18   - block_title(title) +
19   - content_tag('div',
20   - '<img src="http://maps.google.com/maps/api/staticmap?center=' + profile.lat.to_s() +
21   - ',' + profile.lng.to_s() + '&zoom=' + zoom.to_s() +
22   - '&size=190x250&maptype=' + map_type + '&markers=' + profile.lat.to_s() + ',' +
23   - profile.lng.to_s() + ',green' + '&sensor=false"/>',
24   - :class => 'the-localization-map' )
25   - else
26   - content_tag('i', _('This profile has no geographical position registered.'))
  17 + lambda do
  18 + render :file => 'blocks/location', :locals => {:block => block, :profile => profile}
27 19 end
28 20 end
29 21  
... ...
app/models/mailing.rb
... ... @@ -9,7 +9,11 @@ class Mailing &lt; ActiveRecord::Base
9 9 xss_terminate :only => [ :subject, :body ], :with => 'white_list', :on => 'validation'
10 10  
11 11 after_create do |mailing|
12   - Delayed::Job.enqueue MailingJob.new(mailing.id)
  12 + mailing.schedule
  13 + end
  14 +
  15 + def schedule
  16 + Delayed::Job.enqueue MailingJob.new(self.id)
13 17 end
14 18  
15 19 def generate_from
... ... @@ -30,8 +34,14 @@ class Mailing &lt; ActiveRecord::Base
30 34  
31 35 def deliver
32 36 each_recipient do |recipient|
33   - Mailing::Sender.deliver_mail(self, recipient.email)
34   - self.mailing_sents.create(:person => recipient)
  37 + begin
  38 + Mailing::Sender.deliver_mail(self, recipient.email)
  39 + self.mailing_sents.create(:person => recipient)
  40 + rescue Exception
  41 + # FIXME should not discard errors silently. An idea is to collect all
  42 + # errors and generate a task (notification) for the +source+
  43 + # (environment/organization) listing these errors.
  44 + end
35 45 end
36 46 end
37 47  
... ...
app/models/price_detail.rb
... ... @@ -4,9 +4,13 @@ class PriceDetail &lt; ActiveRecord::Base
4 4 validates_presence_of :product_id
5 5  
6 6 belongs_to :production_cost
7   - validates_presence_of :production_cost_id
  7 + validates_presence_of :production_cost
8 8 validates_uniqueness_of :production_cost_id, :scope => :product_id
9 9  
  10 + def name
  11 + production_cost.name
  12 + end
  13 +
10 14 def price
11 15 self[:price] || 0
12 16 end
... ...
app/models/product.rb
... ... @@ -158,7 +158,7 @@ class Product &lt; ActiveRecord::Base
158 158  
159 159 def inputs_cost
160 160 return 0 if inputs.empty?
161   - inputs.map(&:cost).inject { |sum,price| sum + price }
  161 + inputs.relevant_to_price.map(&:cost).inject { |sum,price| sum + price }
162 162 end
163 163  
164 164 def total_production_cost
... ... @@ -201,6 +201,7 @@ class Product &lt; ActiveRecord::Base
201 201 self.inputs(true).each{ |i| t_i += 1; se_i += 1 if i.is_from_solidarity_economy }
202 202 t_i = 1 if t_i == 0 # avoid division by 0
203 203 p = case (se_i.to_f/t_i)*100
  204 + when 0 then [0, '']
204 205 when 0..24.999 then [0, _("0%")];
205 206 when 25..49.999 then [25, _("25%")];
206 207 when 50..74.999 then [50, _("50%")];
... ...
app/models/production_cost.rb
... ... @@ -5,4 +5,5 @@ class ProductionCost &lt; ActiveRecord::Base
5 5 validates_presence_of :name
6 6 validates_length_of :name, :maximum => 30, :allow_blank => true
7 7 validates_uniqueness_of :name, :scope => [:owner_id, :owner_type]
  8 +
8 9 end
... ...
app/models/profile.rb
... ... @@ -206,7 +206,7 @@ class Profile &lt; ActiveRecord::Base
206 206 end
207 207  
208 208 belongs_to :region
209   -
  209 +
210 210 def location(separator = ' - ')
211 211 myregion = self.region
212 212 if myregion
... ... @@ -293,12 +293,12 @@ class Profile &lt; ActiveRecord::Base
293 293 true
294 294 end
295 295  
296   - # registar callback for creating boxes after the object is created.
  296 + # registar callback for creating boxes after the object is created.
297 297 after_create :create_default_set_of_boxes
298 298  
299 299 # creates the initial set of boxes when the profile is created. Can be
300 300 # overriden for each subclass to create a custom set of boxes for its
301   - # instances.
  301 + # instances.
302 302 def create_default_set_of_boxes
303 303 if template
304 304 apply_template(template, :copy_articles => false)
... ... @@ -418,7 +418,7 @@ class Profile &lt; ActiveRecord::Base
418 418  
419 419 # returns +false+
420 420 def person?
421   - self.kind_of?(Person)
  421 + self.kind_of?(Person)
422 422 end
423 423  
424 424 def enterprise?
... ... @@ -526,7 +526,7 @@ private :generate_url, :url_options
526 526  
527 527 after_create :insert_default_article_set
528 528 def insert_default_article_set
529   - if template
  529 + if template
530 530 copy_articles_from template
531 531 else
532 532 default_set_of_articles.each do |article|
... ... @@ -596,7 +596,7 @@ private :generate_url, :url_options
596 596 raise _("%s can't have members") % self.class.name
597 597 end
598 598 end
599   -
  599 +
600 600 def remove_member(person)
601 601 self.disaffiliate(person, Profile::Roles.all_roles(environment.id))
602 602 end
... ... @@ -893,7 +893,7 @@ private :generate_url, :url_options
893 893  
894 894 def self.f_enabled_proc(enabled)
895 895 enabled = enabled == "true" ? true : false
896   - enabled ? _('Enabled') : _('Not enabled')
  896 + enabled ? s_('facets|Enabled') : s_('facets|Not enabled')
897 897 end
898 898 def f_enabled
899 899 self.enabled
... ... @@ -922,7 +922,7 @@ private :generate_url, :url_options
922 922 acts_as_searchable :fields => facets_fields_for_solr + [:extra_data_for_index,
923 923 # searched fields
924 924 {:name => {:type => :text, :boost => 2.0}},
925   - {:identifier => :text}, {:address => :text}, {:nickname => :text},
  925 + {:identifier => :text}, {:nickname => :text},
926 926 # filtered fields
927 927 {:public => :boolean}, {:environment_id => :integer},
928 928 {:category_filter => :integer},
... ... @@ -942,7 +942,7 @@ private :generate_url, :url_options
942 942  
943 943 def control_panel_settings_button
944 944 {:title => _('Profile Info and settings'), :icon => 'edit-profile'}
945   - end
  945 + end
946 946  
947 947 def followed_by?(person)
948 948 person.is_member_of?(self)
... ...
app/models/user.rb
... ... @@ -21,12 +21,11 @@ class User &lt; ActiveRecord::Base
21 21 end
22 22 end
23 23  
24   - before_create :make_activation_code
25   -
26 24 before_create do |user|
27 25 if user.environment.nil?
28 26 user.environment = Environment.default
29 27 end
  28 + user.send(:make_activation_code) unless user.environment.enabled?('skip_new_user_email_confirmation')
30 29 end
31 30  
32 31 after_create do |user|
... ... @@ -35,7 +34,7 @@ class User &lt; ActiveRecord::Base
35 34 user.person.name ||= user.login
36 35 user.person.visible = false unless user.activated?
37 36 user.person.save!
38   - if user.environment && user.environment.enabled?('skip_new_user_email_confirmation')
  37 + if user.environment.enabled?('skip_new_user_email_confirmation')
39 38 user.activate
40 39 end
41 40 end
... ... @@ -118,7 +117,7 @@ class User &lt; ActiveRecord::Base
118 117 self.activated_at = Time.now.utc
119 118 self.activation_code = nil
120 119 self.person.visible = true
121   - self.person.save! && self.save
  120 + self.person.save! && self.save!
122 121 end
123 122  
124 123 def activated?
... ...
app/views/blocks/location.html.erb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +<% if profile.lat %>
  2 + <%= block_title block.title %>
  3 + <div class='the-localization-map'>
  4 + <img src="http://maps.google.com/maps/api/staticmap?center=<%=profile.lat%>,<%=profile.lng%>&zoom=<%=block.zoom%>&size=190x250&maptype=<%=block.map_type%>&markers=<%=profile.lat%>,<%=profile.lng%>&sensor=false"/>
  5 + </div>
  6 +</div>
  7 +<% else %>
  8 + <i><%= _('This profile has no geographical position registered.') %></i>
  9 +<% end %>
... ...
app/views/catalog/index.rhtml
... ... @@ -56,7 +56,7 @@
56 56 <div>
57 57 <div class="arrow"></div>
58 58 <div class="content" id="product-price-composition">
59   - <% product.inputs.each do |i| %>
  59 + <% product.inputs.relevant_to_price.each do |i| %>
60 60 <div class="search-product-input-dots-to-price">
61 61 <div class="search-product-input-name"><%= i.product_category.name %></div>
62 62 <%= price_span i.cost, :class => 'search-product-input-price' %>
... ...
app/views/maps/_google_map.js.erb
... ... @@ -5,27 +5,113 @@ var marker;
5 5 var center;
6 6 var move = true;
7 7 var previousCenter;
  8 +var mapZoom = 15;
  9 +var delay_autocomplete = 500;
8 10  
9   -function getAddress(latlng) {
  11 +function pointToAddress(latlng) {
10 12 $('location-fields').addClassName("loading");
11 13  
12   - if (latlng != null) {
13   - geocoder.geocode( {'latLng': latlng}, showAddress);
14   - }
  14 + if (latlng == null)
  15 + return;
  16 +
  17 + geocoder.geocode( {'latLng': latlng}, function(results, status) {
  18 + if (status != google.maps.GeocoderStatus.OK) {
  19 + alert("<%=_("Address not found, reason:")%>" + statusErrorMessage(status));
  20 + return;
  21 + }
  22 +
  23 + var place = results[0];
  24 +
  25 + $('location-fields').removeClassName("loading");
  26 +
  27 + var position = marker.getPosition();
  28 + $('profile_data_lat').value = position.lat();
  29 + $('profile_data_lng').value = position.lng();
  30 +
  31 + form = jQuery('#location-form')[0];
  32 + form.lat = marker.getPosition().lat();
  33 + form.lng = marker.getPosition().lng();
  34 +
  35 + var components_len = place.address_components.size();
  36 + if (components_len < 2)
  37 + return;
  38 +
  39 + var country_code = "";
  40 + var state = "";
  41 + var city = "";
  42 + var zip_code = "";
  43 + var route = "";
  44 + var number = "";
  45 + var sublocality = "";
  46 + var address = "";
  47 +
  48 + var i;
  49 + var has_postal_code = false;
  50 + for (i=0; i < components_len; i++) {
  51 + type = place.address_components[i].types[0];
  52 + if (type == 'postal_code')
  53 + has_postal_code = true;
  54 + }
  55 +
  56 + for (i=0; i < components_len; i++) {
  57 + type = place.address_components[i].types[0];
  58 + value = place.address_components[i];
  59 +
  60 + if (type == 'country')
  61 + country_code = value.short_name;
  62 + else if (type == 'administrative_area_level_1')
  63 + state = value.long_name;
  64 + else if (type == 'locality')
  65 + city = value.long_name;
  66 + else if (type == 'postal_code')
  67 + zip_code = value.short_name;
  68 + if (has_postal_code) {
  69 + if (type == "route")
  70 + route = value.long_name;
  71 + else if (type == "street_number")
  72 + number = value.short_name;
  73 + else if (type == 'sublocality')
  74 + sublocality = value.long_name;
  75 + }
  76 + }
  77 +
  78 + // build address
  79 + if (route) {
  80 + address = route;
  81 + if (number)
  82 + address = address + ', ' + number;
  83 + if (sublocality && sublocality != city)
  84 + address = address + ', ' + sublocality;
  85 + }
  86 +
  87 + if (country_code)
  88 + $('profile_data_country').value = country_code;
  89 + if (state)
  90 + $('profile_data_state').value = state;
  91 + if (city)
  92 + $('profile_data_city').value = city;
  93 + if (zip_code)
  94 + $('profile_data_zip_code').value = zip_code;
  95 + if (address)
  96 + $('profile_data_address').value = address;
  97 +
  98 + map.setCenter(marker.getPosition());
  99 + });
15 100 }
16 101  
17   -function codeAddress() {
  102 +function addressToPoint() {
18 103 $('location-fields').addClassName("loading");
19 104  
20 105 var country_option = $('profile_data_country').value;
21   - var address = $('profile_data_address').value + "-" + $('profile_data_zip_code').value + "," + $('profile_data_city').value+ "-" + $('profile_data_state').value + "," + country_option;
  106 + var address = $('profile_data_address').value + ", " + $('profile_data_zip_code').value + ", "
  107 + + $('profile_data_city').value+ ", " + $('profile_data_state').value + ", " + country_option;
22 108  
23 109 if (geocoder) {
24   - geocoder.geocode( { 'address': address}, function(results, status) {
  110 + geocoder.geocode({ 'address': address}, function(results, status) {
25 111 if (status == google.maps.GeocoderStatus.OK) {
26 112 map.setCenter(results[0].geometry.location);
27 113 marker.setPosition(results[0].geometry.location);
28   - getAddress(marker.getPosition());
  114 + pointToAddress(marker.getPosition());
29 115  
30 116 $('profile_data_lat').value = results[0].geometry.location.lat();
31 117 $('profile_data_lng').value = results[0].geometry.location.lng();
... ... @@ -33,17 +119,15 @@ function codeAddress() {
33 119 enable_save();
34 120 } else {
35 121 $('location-fields').removeClassName("loading");
36   - alert('<%=_("Address not found, reason:")%>' + translate_status(status));
  122 + alert('<%=_("Address not found, reason:")%>' + statusErrorMessage(status));
37 123 }
38 124 });
39 125 }
40 126  
41   - map.setZoom(11);
42   -
43 127 return false;
44 128 }
45 129  
46   -function translate_status(status)
  130 +function statusErrorMessage(status)
47 131 {
48 132 var translated_status = '';
49 133  
... ... @@ -59,136 +143,42 @@ function translate_status(status)
59 143 return translated_status;
60 144 }
61 145  
62   -function getAddressData() {
63   - var text = '';
64   - var fields = [
65   - 'profile_data_country',
66   - 'profile_data_state',
67   - 'profile_data_city',
68   - 'profile_data_address',
69   - 'profile_data_zip_code'
70   - ];
71   - for (var i = 0; i < fields.length; i++) {
72   - var field = fields[i];
73   - if ($(field)) {
74   - text += $(field).value + " ";
75   - }
76   - }
77   - return text;
78   -}
79   -
80   -function showAddress(results, status) {
81   -
82   - if (status == google.maps.GeocoderStatus.OK) {
83   - map.setCenter(results[0].geometry.location);
84   - updateFields(results[0]);
85   -
86   - } else {
87   - alert("<%=_("Address not found, reason:")%>" + translate_status(status));
88   - }
89   -
90   -}
91   -
92   -function updateFields(place) {
93   - var position = marker.getPosition();
94   - $('profile_data_lat').value = position.lat();
95   - $('profile_data_lng').value = position.lng();
96   - $('location-fields').removeClassName("loading");
97   -
98   - form = jQuery('#location-form')[0];
99   - form.lat = marker.getPosition().lat();
100   - form.lng = marker.getPosition().lng();
101   -
102   - var components_len = place.address_components.size();
103   -
104   - if(components_len < 2)
105   - {
106   - return false;
107   - }
108   -
109   - var components = place.address_components;
110   - var address = "";
111   - var zip_code = "";
112   - var city = "";
113   - var state = "";
114   - var country_code = "";
115   - var i = 0;
116   -
117   - for( i =0 ; i < components_len; i ++)
118   - {
119   -
120   - if (components[i].types[0] == 'country')
121   - country_code = components[i].short_name;
122   - else if (components[i].types[0] == 'administrative_area_level_1')
123   - state = components[i].long_name;
124   - else if (components[i].types[0] == 'locality')
125   - city = components[i].long_name;
126   - else if (components[i].types[0] == 'sublocality')
127   - address = components[i].long_name + "-" + address;
128   - else if (components[i].types[0] == "route")
129   - address = components[i].long_name + address;
130   - else if (components[i].types[0] == "street_number")
131   - address = address + "," + components[i].short_name ;
132   - else if (components[i].types[0] == 'postal_code')
133   - zip_code = components[i].short_name;
134   - }
135   -
136   - $('profile_data_country').value = country_code;
137   - $('profile_data_state').value = state;
138   - $('profile_data_address').value = address;
139   - $('profile_data_city').value = city;
140   - $('profile_data_zip_code').value = zip_code;
141   -}
142   -
143   -
144   -function initialize_map() {
  146 +function initializeMap() {
145 147 geocoder = new google.maps.Geocoder();
146 148  
147 149 var lat = <%= profile.lat || 'false' %>;
148 150 var lng = <%= profile.lng || 'false' %>;
149   -
150 151 if ( !(lat && lng) ) {
151 152 lat = -15.7605361485013;
152 153 lng = -47.933349609375;
153 154 }
154 155  
155   - var latlng = new google.maps.LatLng(lat,lng);
156   -
157   - var myOptions = {
158   - zoom: 8,
159   - center: latlng,
160   - mapTypeId: google.maps.MapTypeId.ROADMAP
161   - }
162   -
163   - center = latlng;
164   -
165   - map = new google.maps.Map(document.getElementById("location-map"), myOptions);
166   -
167   - continueLoadMapV3()
168   -}
169   -
170   -function continueLoadMapV3() {
  156 + var center = new google.maps.LatLng(lat,lng);;
  157 + map = new google.maps.Map(document.getElementById("location-map"), {
  158 + zoom: mapZoom,
  159 + center: center,
  160 + mapTypeId: google.maps.MapTypeId.HYBRID
  161 + });
171 162  
172   - marker = new google.maps.Marker({
173   - position: center,
174   - map: map,
175   - draggable: true
176   - });
  163 + marker = new google.maps.Marker({
  164 + position: center,
  165 + map: map,
  166 + draggable: true
  167 + });
177 168  
178   - google.maps.event.addListener(marker, "dragend", function() {
179   - move = false;
180   - getAddress(marker.getPosition());
181   - enable_save();
182   - });
  169 + google.maps.event.addListener(marker, "dragend", function() {
  170 + move = false;
  171 + pointToAddress(marker.getPosition());
  172 + map.setCenter(marker.getPosition());
  173 + enable_save();
  174 + });
183 175  
184 176 }
185 177  
186   -window.onload = initialize_map;
187   -
188   -var delay_autocomplete = 500;
189   -
190 178 jQuery.noConflict();
191   -jQuery(document).ready(function (){
  179 +jQuery(document).ready(function () {
  180 +
  181 + initializeMap();
192 182  
193 183 jQuery.widget( "custom.catcomplete",jQuery.ui.autocomplete, {
194 184 _renderMenu: function( ul, items ) {
... ... @@ -204,7 +194,6 @@ jQuery(document).ready(function (){
204 194 }
205 195 });
206 196  
207   -
208 197 jQuery("#profile_data_city").catcomplete({
209 198 source: "../maps/search_city",
210 199 minLength: 3,
... ... @@ -219,21 +208,13 @@ jQuery(document).ready(function (){
219 208 });
220 209  
221 210 jQuery("#profile_data_city").keyup(function(){
222   -
223 211 disable_save();
224   -
225 212 });
226   -
227 213 jQuery("#profile_data_state").keyup(function(){
228   -
229 214 disable_save();
230   -
231 215 });
232   -
233 216 jQuery("#profile_data_country").change(function(){
234   -
235 217 disable_save();
236   -
237 218 });
238 219  
239 220 });
... ...
app/views/maps/edit_location.rhtml
... ... @@ -12,7 +12,7 @@
12 12 <%= labelled_form_field _('ZIP code'), text_field(:profile_data, :zip_code) %>
13 13 <%= labelled_form_field _('Address (street and number)'), text_field(:profile_data, :address) %>
14 14 <% button_bar do %>
15   - <%= button_to_function :search, _('Locate in the map'), "codeAddress()", :title => _("Locate the address informed above in the map below (note that you'll probably need to adjust the marker to get a precise position)") %>
  15 + <%= button_to_function :search, _('Locate in the map'), "addressToPoint()", :title => _("Locate the address informed above in the map below (note that you'll probably need to adjust the marker to get a precise position)") %>
16 16 <%= submit_button 'save', _('Save') %>
17 17 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>
18 18 <% end %>
... ...
app/views/profile/_profile_comment_form.rhtml
... ... @@ -3,15 +3,17 @@
3 3 <p class='profile-wall-reply'>
4 4 <% update_area = tab_action == 'wall' ? 'profile_activities' : 'network-activities' %>
5 5 <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_comment_on_activity', :tab_action => tab_action}, :html => { :class => 'profile-wall-reply-form', 'data-update' => update_area } do %>
6   - <%= text_area :comment, :body, {:id => "reply_content_#{activity.id}",
7   - :cols => 50,
8   - :rows => 1,
9   - :class => 'submit-with-keypress',
10   - :title => _('Leave your comment'),
11   - :onfocus => ('if(this.value==this.title){this.value="";this.style.color="#000"};this.style.backgroundImage="url(' + profile_icon(current_person, :icon, false) + ')"' if logged_in?),
12   - :onblur => ('if(this.value==""){this.value=this.title;this.style.color="#ccc"};this.style.backgroundImage="none"' if logged_in?),
13   - :value => _('Leave your comment'),
14   - :style => 'color: #ccc' } %>
  6 + <%= expandable_text_area :comment,
  7 + :body,
  8 + "reply_content_#{activity.id}",
  9 + :cols => 50,
  10 + :rows => 1,
  11 + :class => 'submit-with-keypress',
  12 + :title => _('Leave your comment'),
  13 + :onfocus => ('if(this.value==this.title){this.value="";this.style.color="#000"};this.style.backgroundImage="url(' + profile_icon(current_person, :icon, false) + ')"' if logged_in?),
  14 + :onblur => ('if(this.value==""){this.value=this.title;this.style.color="#ccc"};this.style.backgroundImage="none"' if logged_in?),
  15 + :value => _('Leave your comment'),
  16 + :style => 'color: #ccc' %>
15 17 <%= hidden_field_tag :source_id, activity.id, :id => "activity_id_#{activity.id}" %>
16 18 <% end %>
17 19 </p>
... ...
app/views/profile/_profile_scrap_reply_form.rhtml
... ... @@ -2,15 +2,16 @@
2 2 <div id='profile-wall-reply-form-<%= scrap.id%>' style='display:none'>
3 3 <p class='profile-wall-reply'>
4 4 <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap'}, :update => "profile_activities", :html => { :class => 'profile-wall-reply-form'} do %>
5   - <%= text_area :scrap, :content, { :id => "reply_content_#{scrap.id}",
6   - :cols => 50,
7   - :rows => 1,
8   - :class => 'submit-with-keypress',
9   - :title => _('Leave your comment'),
10   - :onfocus => ('if(this.value==this.title){this.value="";this.style.color="#000"};this.style.backgroundImage="url(' + profile_icon(current_person, :icon, false) + ')"' if logged_in?),
11   - :onblur => ('if(this.value==""){this.value=this.title;this.style.color="#ccc"};this.style.backgroundImage="none"' if logged_in?),
12   - :value => _('Leave your comment')
13   - } %>
  5 + <%= expandable_text_area :scrap,
  6 + :content,
  7 + "reply_content_#{scrap.id}",
  8 + :cols => 50,
  9 + :rows => 1,
  10 + :class => 'submit-with-keypress',
  11 + :title => _('Leave your comment'),
  12 + :onfocus => ('if(this.value==this.title){this.value="";this.style.color="#000"};this.style.backgroundImage="url(' + profile_icon(current_person, :icon, false) + ')"' if logged_in?),
  13 + :onblur => ('if(this.value==""){this.value=this.title;this.style.color="#ccc"};this.style.backgroundImage="none"' if logged_in?),
  14 + :value => _('Leave your comment') %>
14 15 <%= hidden_field_tag 'scrap[scrap_id]', scrap.id %>
15 16 <%= hidden_field_tag 'receiver_id', scrap.sender.id %>
16 17 <% end %>
... ...
app/views/profile/index.rhtml
... ... @@ -29,7 +29,6 @@
29 29 <% if logged_in? && current_person.follows?(@profile) %>
30 30 <% tabs << {:title => _('Wall'), :id => 'profile-wall', :content => (render :partial => 'profile_wall')} %>
31 31 <% end %>
32   - <% tabs << {:title => _('What\'s new'), :id => 'profile-network', :content => (render :partial => 'profile_network')} %>
33 32 <% elsif @profile.person? %>
34 33 <% tabs << {:title => _('Profile'), :id => 'person-profile', :content => (render :partial => 'person_profile')} %>
35 34 <% if logged_in? && current_person.follows?(@profile) %>
... ...
app/views/search/_product.rhtml
... ... @@ -27,9 +27,9 @@
27 27 <% end %>
28 28  
29 29 <% if product.price_described? %>
30   - <% title = (product.inputs + product.price_details).map{ |i|
  30 + <% title = (product.inputs.relevant_to_price + product.price_details).map{ |i|
31 31 '<div class="search-product-input-dots-to-price">' +
32   - '<div class="search-product-input-name">' + i.product_category.name + '</div>' +
  32 + '<div class="search-product-input-name">' + i.name + '</div>' +
33 33 price_span(i.price, :class => 'search-product-input-price') +
34 34 '</div>' }.join('') %>
35 35 <%= link_to_function _("Open Price"), '', :title => title, :class => "search-product-price-details" %>
... ...
db/migrate/20120813163139_set_activation_code_to_nil_if_already_activated.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class SetActivationCodeToNilIfAlreadyActivated < ActiveRecord::Migration
  2 + def self.up
  3 + update("UPDATE users SET activation_code = null WHERE activated_at IS NOT NULL")
  4 + end
  5 +
  6 + def self.down
  7 + say('Can not be reverted.')
  8 + end
  9 +end
... ...
db/migrate/20120818030329_remove_action_tracker_with_target_nil.rb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +class RemoveActionTrackerWithTargetNil < ActiveRecord::Migration
  2 + def self.up
  3 + select_all("SELECT id FROM action_tracker").each do |tracker|
  4 + activity = ActionTracker::Record.find_by_id(tracker['id'])
  5 + if activity && activity.target.nil?
  6 + activity.destroy
  7 + end
  8 + end
  9 + end
  10 +
  11 + def self.down
  12 + say "this migration can't be reverted"
  13 + end
  14 +end
... ...
db/schema.rb
... ... @@ -9,7 +9,7 @@
9 9 #
10 10 # It's strongly recommended to check this file into your version control system.
11 11  
12   -ActiveRecord::Schema.define(:version => 20120718162001) do
  12 +ActiveRecord::Schema.define(:version => 20120818030329) do
13 13  
14 14 create_table "abuse_reports", :force => true do |t|
15 15 t.integer "reporter_id"
... ...
debian/changelog
  1 +noosfero (0.38.1) unstable; urgency=low
  2 +
  3 + * Bugfixes release
  4 +
  5 + -- Daniela Soares Feitosa <daniela@colivre.coop.br> Sat, 18 Aug 2012 07:49:59 -0300
  6 +
1 7 noosfero (0.38.0) unstable; urgency=low
2 8  
3 9 * Features version release
... ...
etc/logrotate.d/noosfero
1   -/var/log/noosfero/*.log /home/noosfero/current/log/*.log {
  1 +/var/log/noosfero/*.log {
2 2 daily
3 3 missingok
4 4 rotate 30
... ...
features/private_profile.feature
... ... @@ -30,16 +30,6 @@ Feature: private profiles
30 30 When I go to shygirl's homepage
31 31 Then I should not see "Add friend"
32 32  
33   - Scenario: viewing a private community profile shouldn't show the news if not logged or not a member
34   - Given I am on Safernet's homepage
35   - Then I should not see "What's new"
36   - And I am logged in as "joao"
37   - When I am on Safernet's homepage
38   - Then I should not see "What's new"
39   - And "joao" is a member of "Safernet"
40   - When I am on Safernet's homepage
41   - Then I should see "What's new"
42   -
43 33 Scenario: person private profiles should not display sensible information
44 34 Given I am logged in as "joao"
45 35 When I go to shygirl's homepage
... ...
lib/noosfero.rb
... ... @@ -2,7 +2,7 @@ require &#39;fast_gettext&#39;
2 2  
3 3 module Noosfero
4 4 PROJECT = 'noosfero'
5   - VERSION = '0.38.0'
  5 + VERSION = '0.38.1'
6 6  
7 7 def self.pattern_for_controllers_in_directory(dir)
8 8 disjunction = controllers_in_directory(dir).join('|')
... ...
plugins/stoa/public/javascripts/signup_complement.js
... ... @@ -11,13 +11,13 @@ jQuery(&quot;#usp_id_field&quot;).observe_field(1, function(){
11 11 jQuery('#signup-birth-date').hide();
12 12 jQuery('#signup-cpf').show();
13 13 jQuery('#confirmation_field').remove();
14   - jQuery('#signup-form').append('<input id="confirmation_field" type="hidden" value="cpf" name="confirmation_field">')
  14 + jQuery('<input id="confirmation_field" type="hidden" value="cpf" name="confirmation_field">').insertAfter('#usp_id_field');
15 15 }
16 16 else {
17 17 jQuery('#signup-cpf').hide();
18 18 jQuery('#signup-birth-date').show();
19 19 jQuery('#confirmation_field').remove();
20   - jQuery('#signup-form').append('<input id="confirmation_field" type="hidden" value="birth_date" name="confirmation_field">')
  20 + jQuery('<input id="confirmation_field" type="hidden" value="birth_date" name="confirmation_field">').insertAfter('#usp_id_field');
21 21 }
22 22 jQuery('#signup-form .submit').attr('disabled', false);
23 23 jQuery(me).removeClass('checking').addClass('validated');
... ...
public/javascripts/application.js
... ... @@ -622,7 +622,7 @@ function hide_and_show(hide_elements, show_elements) {
622 622  
623 623 function limited_text_area(textid, limit) {
624 624 var text = jQuery('#' + textid).val();
625   - jQuery('#' + textid).css('height', jQuery('#' + textid).attr('scrollHeight') + 'px');
  625 + grow_text_area(textid);
626 626 var textlength = text.length;
627 627 jQuery('#' + textid + '_left span').html(limit - textlength);
628 628 if (textlength > limit) {
... ... @@ -637,6 +637,15 @@ function limited_text_area(textid, limit) {
637 637 }
638 638 }
639 639  
  640 +function grow_text_area(textid) {
  641 + var height = jQuery('#' + textid).attr('scrollHeight');
  642 + if (jQuery.browser.webkit) {
  643 + height -= parseInt(jQuery('#' + textid).css('padding-top')) +
  644 + parseInt(jQuery('#' + textid).css('padding-bottom'));
  645 + }
  646 + jQuery('#' + textid).css('height', height + 'px');
  647 +}
  648 +
640 649 jQuery(function($) {
641 650 $('a').each(function() {
642 651 if (this.href == document.location.href) {
... ...
public/stylesheets/application.css
... ... @@ -5074,7 +5074,7 @@ h1#agenda-title {
5074 5074  
5075 5075 #profile-network li textarea:focus,
5076 5076 #profile-wall li textarea:focus {
5077   - background-position: left center;
  5077 + background-position: left top;
5078 5078 background-repeat: no-repeat;
5079 5079 text-indent: 28px;
5080 5080 }
... ... @@ -5151,8 +5151,8 @@ h1#agenda-title {
5151 5151  
5152 5152 #profile-wall .profile-wall-activities-comments img,
5153 5153 #profile-network .profile-wall-activities-comments img {
5154   - max-width: 50px;
5155   - max-height: 50px;
  5154 + max-width: 32px;
  5155 + max-height: 32px;
5156 5156 }
5157 5157  
5158 5158 #profile-wall .profile-wall-activities-comments .comment_reply,
... ... @@ -5164,7 +5164,8 @@ h1#agenda-title {
5164 5164  
5165 5165 #profile-wall .profile-wall-activities-comments .comment-picture,
5166 5166 #profile-network .profile-wall-activities-comments .comment-picture {
5167   - width: 50px;
  5167 + width: 32px;
  5168 + margin-right: 5px;
5168 5169 text-align: center;
5169 5170 }
5170 5171  
... ...
test/functional/account_controller_test.rb
... ... @@ -610,6 +610,15 @@ class AccountControllerTest &lt; ActionController::TestCase
610 610 assert_equal 'example.com', Person['testuser'].organization
611 611 end
612 612  
  613 + should 'activate user after signup if environment is set to skip confirmation' do
  614 + env = Environment.default
  615 + env.enable('skip_new_user_email_confirmation')
  616 + env.save!
  617 + new_user(:login => 'activated_user')
  618 + user = User.find_by_login('activated_user')
  619 + assert user.activated?
  620 + end
  621 +
613 622 should 'redirect to initial page after logout' do
614 623 login_as :johndoe
615 624 get :logout
... ...
test/test_helper.rb
... ... @@ -79,7 +79,7 @@ class ActiveSupport::TestCase
79 79  
80 80 destname = 'test_should_' + name.gsub(/[^a-zA-z0-9]+/, '_')
81 81 if @shoulds.include?(destname)
82   - raise "there is already a test named \"#{destname}\""
  82 + raise "there is already a test named \"#{destname}\""
83 83 end
84 84  
85 85 @shoulds << destname
... ... @@ -121,7 +121,7 @@ class ActiveSupport::TestCase
121 121 object.valid?
122 122 assert !object.errors.invalid?(attribute)
123 123 end
124   -
  124 +
125 125 def assert_subclass(parent, child)
126 126 assert_equal parent, child.superclass, "Class #{child} expected to be a subclass of #{parent}"
127 127 end
... ... @@ -150,7 +150,7 @@ class ActiveSupport::TestCase
150 150 get action, params
151 151 end
152 152 doc = Hpricot @response.body
153   -
  153 +
154 154 # Test style references:
155 155 (doc/'style').each do |s|
156 156 s = s.to_s().gsub( /\/\*.*\*\//, '' ).
... ... @@ -193,6 +193,12 @@ class ActiveSupport::TestCase
193 193 assert !tag, "expected no tag #{options.inspect}, but tag found in #{text.inspect}"
194 194 end
195 195  
  196 + # For models that render views (blocks, articles, ...)
  197 + def render(*args)
  198 + view_paths = @explicit_view_paths || ActionController::Base.view_paths
  199 + ActionView::Base.new(view_paths, {}).render(*args)
  200 + end
  201 +
196 202 private
197 203  
198 204 def uses_host(name)
... ...
test/unit/article_test.rb
... ... @@ -977,9 +977,9 @@ class ArticleTest &lt; ActiveSupport::TestCase
977 977 assert_equivalent [p1,p2,community], ActionTrackerNotification.find_all_by_action_tracker_id(activity.id).map(&:profile)
978 978 end
979 979  
980   - should 'not track action when a published article is removed' do
  980 + should 'destroy activity when a published article is removed' do
981 981 a = create(TinyMceArticle, :profile_id => profile.id)
982   - assert_no_difference ActionTracker::Record, :count do
  982 + assert_difference ActionTracker::Record, :count, -1 do
983 983 a.destroy
984 984 end
985 985 end
... ... @@ -1115,6 +1115,51 @@ class ArticleTest &lt; ActiveSupport::TestCase
1115 1115 assert_equal 3, ActionTrackerNotification.find_all_by_action_tracker_id(article2.activity.id).count
1116 1116 end
1117 1117  
  1118 + should 'destroy activity and notifications of friends when destroying an article' do
  1119 + friend = fast_create(Person)
  1120 + profile.add_friend(friend)
  1121 + Article.destroy_all
  1122 + ActionTracker::Record.destroy_all
  1123 + ActionTrackerNotification.destroy_all
  1124 + UserStampSweeper.any_instance.expects(:current_user).returns(profile).at_least_once
  1125 + article = create(TinyMceArticle, :profile_id => profile.id)
  1126 + activity = article.activity
  1127 +
  1128 + process_delayed_job_queue
  1129 + assert_equal 2, ActionTrackerNotification.find_all_by_action_tracker_id(activity.id).count
  1130 +
  1131 + assert_difference ActionTrackerNotification, :count, -2 do
  1132 + article.destroy
  1133 + end
  1134 +
  1135 + assert_raise ActiveRecord::RecordNotFound do
  1136 + ActionTracker::Record.find(activity.id)
  1137 + end
  1138 + end
  1139 +
  1140 + should 'destroy action_tracker and notifications when an article is destroyed in a community' do
  1141 + community = fast_create(Community)
  1142 + p1 = fast_create(Person)
  1143 + p2 = fast_create(Person)
  1144 + community.add_member(p1)
  1145 + community.add_member(p2)
  1146 + UserStampSweeper.any_instance.expects(:current_user).returns(p1).at_least_once
  1147 +
  1148 + article = create(TinyMceArticle, :profile_id => community.id)
  1149 + activity = article.activity
  1150 +
  1151 + process_delayed_job_queue
  1152 + assert_equal 3, ActionTrackerNotification.find_all_by_action_tracker_id(activity.id).count
  1153 +
  1154 + assert_difference ActionTrackerNotification, :count, -3 do
  1155 + article.destroy
  1156 + end
  1157 +
  1158 + assert_raise ActiveRecord::RecordNotFound do
  1159 + ActionTracker::Record.find(activity.id)
  1160 + end
  1161 + end
  1162 +
1118 1163 should 'found articles with published date between a range' do
1119 1164 start_date = DateTime.parse('2010-07-06')
1120 1165 end_date = DateTime.parse('2010-08-02')
... ...
test/unit/input_test.rb
... ... @@ -177,4 +177,18 @@ class InputTest &lt; ActiveSupport::TestCase
177 177 assert_equal 0.00, input.cost
178 178 end
179 179  
  180 + should 'list inputs relevants to price' do
  181 + product_category = fast_create(ProductCategory)
  182 + product = fast_create(Product, :product_category_id => product_category.id)
  183 +
  184 + i1 = Input.create!(:product => product, :product_category => product_category, :relevant_to_price => true)
  185 +
  186 + i2 = Input.create!(:product => product, :product_category => product_category, :relevant_to_price => false)
  187 +
  188 + i1.save!
  189 + i2.save!
  190 + assert_includes Input.relevant_to_price, i1
  191 + assert_not_includes Input.relevant_to_price, i2
  192 + end
  193 +
180 194 end
... ...
test/unit/location_block_test.rb
... ... @@ -2,6 +2,9 @@ require File.dirname(__FILE__) + &#39;/../test_helper&#39;
2 2  
3 3 class LocationBlockTest < ActiveSupport::TestCase
4 4  
  5 + ActionView::Base.send :include, BlockHelper
  6 + include BoxesHelper
  7 +
5 8 def setup
6 9 @profile = create_user('lele').person
7 10 @block = LocationBlock.new
... ... @@ -15,7 +18,7 @@ class LocationBlockTest &lt; ActiveSupport::TestCase
15 18 end
16 19  
17 20 should 'display no localization map without lat' do
18   - assert_tag_in_string block.content, :tag => 'i'
  21 + assert_tag_in_string extract_block_content(block.content), :tag => 'i'
19 22 end
20 23  
21 24 should 'be editable' do
... ... @@ -28,8 +31,10 @@ class LocationBlockTest &lt; ActiveSupport::TestCase
28 31  
29 32 should 'use google maps api v3' do
30 33 @block.owner.lat = '-12.34'; @block.owner.save!
31   - assert_match 'http://maps.google.com/maps/api/staticmap', @block.content
32   - assert_no_match /key=/, @block.content
  34 + content = extract_block_content(@block.content)
  35 +
  36 + assert_match 'http://maps.google.com/maps/api/staticmap', content
  37 + assert_no_match /key=/, content
33 38 end
34 39  
35 40 end
... ...
test/unit/mailing_test.rb
... ... @@ -93,10 +93,21 @@ class MailingTest &lt; ActiveSupport::TestCase
93 93 assert_equal '', mailing.url
94 94 end
95 95  
96   - should 'deliver mailing to each recipient after create' do
97   - person = Person['user_one']
98   - mailing = Mailing.create(:source => environment, :subject => 'Hello', :body => 'We have some news', :person => person)
99   - process_delayed_job_queue
100   - assert_equal [], ActionMailer::Base.deliveries
  96 + should 'process the entire batch even if individual emails crash' do
  97 + mailing = Mailing.new(:source => environment, :person => Person['user_one'], :body => 'test', :subject => 'test')
  98 + def mailing.each_recipient
  99 + user_one = Person['user_one']
  100 + user_two = Person['user_two']
  101 + user_one.stubs(:email).raises(RuntimeError.new)
  102 + [user_one, user_two].each do |p|
  103 + yield p
  104 + end
  105 + end
  106 + mailing.stubs(:schedule)
  107 + mailing.save!
  108 + mailing.deliver
  109 +
  110 + assert_equal 1, ActionMailer::Base.deliveries.size
101 111 end
  112 +
102 113 end
... ...
test/unit/price_detail_test.rb
... ... @@ -54,7 +54,7 @@ class PriceDetailTest &lt; ActiveSupport::TestCase
54 54 p = PriceDetail.new
55 55 p.valid?
56 56  
57   - assert p.errors.invalid?(:production_cost_id)
  57 + assert p.errors.invalid?(:production_cost)
58 58 end
59 59  
60 60 should 'th production cost be unique on scope of product' do
... ... @@ -78,4 +78,14 @@ class PriceDetailTest &lt; ActiveSupport::TestCase
78 78 assert_equal "10.00", price_detail.formatted_value(:price)
79 79 end
80 80  
  81 + should 'have the production cost name as name' do
  82 + product = fast_create(Product)
  83 + cost = fast_create(ProductionCost, :name => 'Energy',:owner_id => Environment.default.id, :owner_type => 'environment')
  84 +
  85 + detail = product.price_details.create(:production_cost => cost, :price => 10)
  86 +
  87 + assert_equal 'Energy', detail.name
  88 + end
  89 +
  90 +
81 91 end
... ...
test/unit/product_test.rb
... ... @@ -381,6 +381,15 @@ class ProductTest &lt; ActiveSupport::TestCase
381 381 assert_equal 50.0, product.inputs_cost
382 382 end
383 383  
  384 + should 'return total value only of inputs relevant to price' do
  385 + product = fast_create(Product)
  386 + first_relevant = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 20.0, :amount_used => 2)
  387 + second_relevant = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 10.0, :amount_used => 1)
  388 + not_relevant = fast_create(Input, :product_id => product.id, :product_category_id => fast_create(ProductCategory).id, :price_per_unit => 10.0, :amount_used => 1, :relevant_to_price => false)
  389 +
  390 + assert_equal 50.0, product.inputs_cost
  391 + end
  392 +
384 393 should 'return 0 on total value of inputs if has no input' do
385 394 product = fast_create(Product)
386 395  
... ... @@ -750,6 +759,8 @@ class ProductTest &lt; ActiveSupport::TestCase
750 759 end
751 760  
752 761 should 'return more recent products' do
  762 + Product.destroy_all
  763 +
753 764 prod1 = Product.create!(:name => 'Damaged LP', :enterprise_id => @profile.id, :product_category_id => @product_category.id)
754 765 prod2 = Product.create!(:name => 'Damaged CD', :enterprise_id => @profile.id, :product_category_id => @product_category.id)
755 766 prod3 = Product.create!(:name => 'Damaged DVD', :enterprise_id => @profile.id, :product_category_id => @product_category.id)
... ...
test/unit/profile_test.rb
... ... @@ -1862,7 +1862,6 @@ class ProfileTest &lt; ActiveSupport::TestCase
1862 1862  
1863 1863 # fields
1864 1864 assert_includes Profile.find_by_contents('Hiro')[:results].docs, p
1865   - assert_includes Profile.find_by_contents('Stor')[:results].docs, p
1866 1865 assert_includes Profile.find_by_contents('Protagonist')[:results].docs, p
1867 1866 # filters
1868 1867 assert_includes Profile.find_by_contents('Hiro', {}, { :filter_queries => ["public:true"]})[:results].docs, p
... ... @@ -1872,13 +1871,15 @@ class ProfileTest &lt; ActiveSupport::TestCase
1872 1871 assert_includes Profile.find_by_contents("Inglewood")[:results].docs, p
1873 1872 assert_includes Profile.find_by_contents("California")[:results].docs, p
1874 1873 assert_includes Profile.find_by_contents("Science")[:results].docs, p
  1874 + # not includes
  1875 + assert_not_includes Profile.find_by_contents('Stor')[:results].docs, p
1875 1876 end
1876 1877  
1877 1878 should 'boost name matches' do
1878 1879 TestSolr.enable
1879 1880 in_addr = create(Person, :name => 'something', :address => 'bananas in the address!', :user_id => fast_create(User).id)
1880 1881 in_name = create(Person, :name => 'bananas in the name!', :user_id => fast_create(User).id)
1881   - assert_equal [in_name, in_addr], Person.find_by_contents('bananas')[:results].docs
  1882 + assert_equal [in_name], Person.find_by_contents('bananas')[:results].docs
1882 1883 end
1883 1884  
1884 1885 should 'reindex articles after saving' do
... ...
test/unit/textile_article_test.rb
... ... @@ -70,20 +70,20 @@ class TextileArticleTest &lt; ActiveSupport::TestCase
70 70 end
71 71 end
72 72  
73   - should 'not notify activity on destroy' do
  73 + should 'remove activity after destroying article' do
74 74 ActionTracker::Record.delete_all
75 75 a = TextileArticle.create! :name => 'bar', :profile_id => fast_create(Profile).id, :published => true
76   - assert_no_difference ActionTracker::Record, :count do
  76 + assert_difference ActionTracker::Record, :count, -1 do
77 77 a.destroy
78 78 end
79 79 end
80 80  
81   - should 'not notify when an article is destroyed' do
  81 + should 'remove activity after article is destroyed' do
82 82 ActionTracker::Record.delete_all
83 83 a1 = TextileArticle.create! :name => 'bar', :profile_id => fast_create(Profile).id, :published => true
84 84 a2 = TextileArticle.create! :name => 'another bar', :profile_id => fast_create(Profile).id, :published => true
85 85 assert_equal 2, ActionTracker::Record.count
86   - assert_no_difference ActionTracker::Record, :count do
  86 + assert_difference ActionTracker::Record, :count, -2 do
87 87 a1.destroy
88 88 a2.destroy
89 89 end
... ...
test/unit/tiny_mce_article_test.rb
... ... @@ -168,11 +168,11 @@ class TinyMceArticleTest &lt; ActiveSupport::TestCase
168 168 end
169 169 end
170 170  
171   - should 'not notify when an article is destroyed' do
  171 + should 'remove activity when an article is destroyed' do
172 172 ActionTracker::Record.delete_all
173 173 a1 = TinyMceArticle.create! :name => 'bar', :profile_id => fast_create(Profile).id, :published => true
174 174 a2 = TinyMceArticle.create! :name => 'another bar', :profile_id => fast_create(Profile).id, :published => true
175   - assert_no_difference ActionTracker::Record, :count do
  175 + assert_difference ActionTracker::Record, :count, -2 do
176 176 a1.destroy
177 177 a2.destroy
178 178 end
... ...