Commit 90f4f1c1a162989d3361779b97078849da9a7562
Exists in
staging
and in
42 other branches
Merge branch 'master' of gitlab.com:noosfero/noosfero
Showing
768 changed files
with
11745 additions
and
55672 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 768 files displayed.
AUTHORS.md
@@ -198,6 +198,7 @@ Martín Olivera <molivera@solar.org.ar> | @@ -198,6 +198,7 @@ Martín Olivera <molivera@solar.org.ar> | ||
198 | Moises Machado <moises@colivre.coop.br> | 198 | Moises Machado <moises@colivre.coop.br> |
199 | Naíla Alves <naila@colivre.coop.br> | 199 | Naíla Alves <naila@colivre.coop.br> |
200 | Nanda Lopes <nanda.listas+psl@gmail.com> | 200 | Nanda Lopes <nanda.listas+psl@gmail.com> |
201 | +Parley Martins <parleypachecomartins@gmail.com> | ||
201 | Paulo Meirelles + Alessandro Palmeira + João M. M. da Silva <paulo@softwarelivre.org> | 202 | Paulo Meirelles + Alessandro Palmeira + João M. M. da Silva <paulo@softwarelivre.org> |
202 | Paulo Meirelles + Alessandro Palmeira <paulo@softwarelivre.org> | 203 | Paulo Meirelles + Alessandro Palmeira <paulo@softwarelivre.org> |
203 | Paulo Meirelles + Carlos Morais <paulo@softwarelivre.org> | 204 | Paulo Meirelles + Carlos Morais <paulo@softwarelivre.org> |
Gemfile
@@ -18,6 +18,7 @@ gem 'rake', :require => false | @@ -18,6 +18,7 @@ gem 'rake', :require => false | ||
18 | gem 'rest-client', '~> 1.6.7' | 18 | gem 'rest-client', '~> 1.6.7' |
19 | gem 'exception_notification', '~> 4.0.1' | 19 | gem 'exception_notification', '~> 4.0.1' |
20 | gem 'gettext', '~> 2.2.1', :require => false, :group => :development | 20 | gem 'gettext', '~> 2.2.1', :require => false, :group => :development |
21 | +gem 'locale', '~> 2.0.5' | ||
21 | 22 | ||
22 | # FIXME list here all actual dependencies (i.e. the ones in debian/control), | 23 | # FIXME list here all actual dependencies (i.e. the ones in debian/control), |
23 | # with their GEM names (not the Debian package names) | 24 | # with their GEM names (not the Debian package names) |
@@ -40,8 +41,9 @@ group :cucumber do | @@ -40,8 +41,9 @@ group :cucumber do | ||
40 | gem 'selenium-webdriver', '~> 2.39.0' | 41 | gem 'selenium-webdriver', '~> 2.39.0' |
41 | end | 42 | end |
42 | 43 | ||
43 | -# include plugin gemfiles | ||
44 | -Dir.glob(File.join('config', 'plugins', '*')).each do |plugin| | ||
45 | - plugin_gemfile = File.join(plugin, 'Gemfile') | ||
46 | - eval File.read(plugin_gemfile) if File.exists?(plugin_gemfile) | 44 | +# include gemfiles from enabled plugins |
45 | +# plugins in baseplugins/ are not included on purpose. They should not have any | ||
46 | +# dependencies. | ||
47 | +Dir.glob('config/plugins/*/Gemfile').each do |gemfile| | ||
48 | + eval File.read(gemfile) | ||
47 | end | 49 | end |
INSTALL.md
@@ -186,8 +186,8 @@ Apache instalation | @@ -186,8 +186,8 @@ Apache instalation | ||
186 | 186 | ||
187 | # apt-get install apache2 | 187 | # apt-get install apache2 |
188 | 188 | ||
189 | -Apache configuration | ||
190 | --------------------- | 189 | +Configuration - noosfero at / |
190 | +----------------------------- | ||
191 | 191 | ||
192 | First you have to enable the following some apache modules: | 192 | First you have to enable the following some apache modules: |
193 | 193 | ||
@@ -257,6 +257,62 @@ Now restart your apache server (as root): | @@ -257,6 +257,62 @@ Now restart your apache server (as root): | ||
257 | 257 | ||
258 | # invoke-rc.d apache2 restart | 258 | # invoke-rc.d apache2 restart |
259 | 259 | ||
260 | +Configuration - noosfero at a /subdirectory | ||
261 | +------------------------------------------- | ||
262 | + | ||
263 | +This section describes how to configure noosfero at a subdirectory, what is | ||
264 | +specially useful when you want Noosfero to share a domain name with other | ||
265 | +applications. For example you can host noosfero at yourdomain.com/social, a | ||
266 | +webmail application at yourdomain.com/webmail, and have a static HTML website | ||
267 | +at yourdomain.com/. | ||
268 | + | ||
269 | +**NOTE:** Some plugins might not work well with this setting. Before deploying | ||
270 | +this setting, make sure you test that everything you need works properly with | ||
271 | +it. | ||
272 | + | ||
273 | +The configuration is similar to the main configuration instructions, except for | ||
274 | +the following points. In the description below, replace '/subdirectory' with | ||
275 | +the actual subdirectory you want. | ||
276 | + | ||
277 | +1) add a `prefix: /subdirectory` line to your thin configuration file (thin.yml). | ||
278 | + | ||
279 | +1.1) remember to restart the noosfero application server whenever you make | ||
280 | +changes to that configuration file. | ||
281 | + | ||
282 | + # service noosfero restart | ||
283 | + | ||
284 | +2) add a line saying `export RAILS_RELATIVE_URL_ROOT=/subdirectory` to | ||
285 | +/etc/default/noosfero (you can create it with just this line if it does not | ||
286 | +exist already). | ||
287 | + | ||
288 | +3) You should add the following apache configuration to an existing virtual | ||
289 | +host (plus the `<Proxy balancer://noosfero>` section as displayed above): | ||
290 | + | ||
291 | +``` | ||
292 | +Alias /subdirectory /path/to/noosfero/public | ||
293 | +<Directory "/path/to/noosfero/public"> | ||
294 | + Options FollowSymLinks | ||
295 | + AllowOverride None | ||
296 | + Order Allow,Deny | ||
297 | + Allow from all | ||
298 | + | ||
299 | + Include /path/to/noosfero/etc/noosfero/apache/cache.conf | ||
300 | + | ||
301 | + RewriteEngine On | ||
302 | + RewriteBase /subdirectory | ||
303 | + # Rewrite index to check for static index.html | ||
304 | + RewriteRule ^$ index.html [QSA] | ||
305 | + # Rewrite to check for Rails cached page | ||
306 | + RewriteRule ^([^.]+)$ $1.html [QSA] | ||
307 | + RewriteCond %{REQUEST_FILENAME} !-f | ||
308 | + RewriteRule ^(.*)$ http://localhost:3000%{REQUEST_URI} [P,QSA,L] | ||
309 | +</Directory> | ||
310 | +``` | ||
311 | + | ||
312 | +3.1) remember to reload the apache server whenever any apache configuration | ||
313 | +file changes. | ||
314 | + | ||
315 | + # sudo service apache2 reload | ||
260 | 316 | ||
261 | Enabling exception notifications | 317 | Enabling exception notifications |
262 | ================================ | 318 | ================================ |
app/controllers/my_profile/profile_editor_controller.rb
@@ -16,14 +16,16 @@ class ProfileEditorController < MyProfileController | @@ -16,14 +16,16 @@ class ProfileEditorController < MyProfileController | ||
16 | if request.post? | 16 | if request.post? |
17 | params[:profile_data][:fields_privacy] ||= {} if profile.person? && params[:profile_data].is_a?(Hash) | 17 | params[:profile_data][:fields_privacy] ||= {} if profile.person? && params[:profile_data].is_a?(Hash) |
18 | Profile.transaction do | 18 | Profile.transaction do |
19 | - Image.transaction do | ||
20 | - if @profile_data.update_attributes(params[:profile_data]) | ||
21 | - redirect_to :action => 'index', :profile => profile.identifier | ||
22 | - else | ||
23 | - profile.identifier = params[:profile] if profile.identifier.blank? | 19 | + Image.transaction do |
20 | + begin | ||
21 | + @plugins.dispatch(:profile_editor_transaction_extras) | ||
22 | + @profile_data.update_attributes!(params[:profile_data]) | ||
23 | + redirect_to :action => 'index', :profile => profile.identifier | ||
24 | + rescue Exception => ex | ||
25 | + profile.identifier = params[:profile] if profile.identifier.blank? | ||
26 | + end | ||
24 | end | 27 | end |
25 | end | 28 | end |
26 | - end | ||
27 | end | 29 | end |
28 | end | 30 | end |
29 | 31 |
app/controllers/public/account_controller.rb
@@ -193,7 +193,7 @@ class AccountController < ApplicationController | @@ -193,7 +193,7 @@ class AccountController < ApplicationController | ||
193 | else | 193 | else |
194 | @change_password.errors[:base] << _('Could not find any user with %s equal to "%s".') % [fields_label, params[:value]] | 194 | @change_password.errors[:base] << _('Could not find any user with %s equal to "%s".') % [fields_label, params[:value]] |
195 | end | 195 | end |
196 | - rescue ActiveRecord::RecordInvald | 196 | + rescue ActiveRecord::RecordInvalid |
197 | @change_password.errors[:base] << _('Could not perform password recovery for the user.') | 197 | @change_password.errors[:base] << _('Could not perform password recovery for the user.') |
198 | end | 198 | end |
199 | end | 199 | end |
app/controllers/public/chat_controller.rb
@@ -19,7 +19,7 @@ class ChatController < PublicController | @@ -19,7 +19,7 @@ class ChatController < PublicController | ||
19 | def avatar | 19 | def avatar |
20 | profile = environment.profiles.find_by_identifier(params[:id]) | 20 | profile = environment.profiles.find_by_identifier(params[:id]) |
21 | filename, mimetype = profile_icon(profile, :minor, true) | 21 | filename, mimetype = profile_icon(profile, :minor, true) |
22 | - if filename =~ /^https?:/ | 22 | + if filename =~ /^(https?:)?\/\// |
23 | redirect_to filename | 23 | redirect_to filename |
24 | else | 24 | else |
25 | data = File.read(File.join(Rails.root, 'public', filename)) | 25 | data = File.read(File.join(Rails.root, 'public', filename)) |
app/controllers/public/content_viewer_controller.rb
@@ -126,7 +126,7 @@ class ContentViewerController < ApplicationController | @@ -126,7 +126,7 @@ class ContentViewerController < ApplicationController | ||
126 | elsif !@page.display_to?(user) | 126 | elsif !@page.display_to?(user) |
127 | if !profile.public? | 127 | if !profile.public? |
128 | private_profile_partial_parameters | 128 | private_profile_partial_parameters |
129 | - render :template => 'profile/_private_profile', :status => 403 | 129 | + render :template => 'profile/_private_profile', :status => 403, :formats => [:html] |
130 | allowed = false | 130 | allowed = false |
131 | else #if !profile.visible? | 131 | else #if !profile.visible? |
132 | render_access_denied | 132 | render_access_denied |
app/controllers/public/profile_controller.rb
@@ -17,7 +17,11 @@ class ProfileController < PublicController | @@ -17,7 +17,11 @@ class ProfileController < PublicController | ||
17 | end | 17 | end |
18 | @tags = profile.article_tags | 18 | @tags = profile.article_tags |
19 | unless profile.display_info_to?(user) | 19 | unless profile.display_info_to?(user) |
20 | - profile.visible? ? private_profile : invisible_profile | 20 | + if profile.visible? |
21 | + private_profile | ||
22 | + else | ||
23 | + invisible_profile | ||
24 | + end | ||
21 | end | 25 | end |
22 | end | 26 | end |
23 | 27 | ||
@@ -61,13 +65,13 @@ class ProfileController < PublicController | @@ -61,13 +65,13 @@ class ProfileController < PublicController | ||
61 | 65 | ||
62 | def friends | 66 | def friends |
63 | if is_cache_expired?(profile.friends_cache_key(params)) | 67 | if is_cache_expired?(profile.friends_cache_key(params)) |
64 | - @friends = profile.friends.includes(relations_to_include).paginate(:per_page => per_page, :page => params[:npage]) | 68 | + @friends = profile.friends.includes(relations_to_include).paginate(:per_page => per_page, :page => params[:npage], :total_entries => profile.friends.count) |
65 | end | 69 | end |
66 | end | 70 | end |
67 | 71 | ||
68 | def members | 72 | def members |
69 | if is_cache_expired?(profile.members_cache_key(params)) | 73 | if is_cache_expired?(profile.members_cache_key(params)) |
70 | - @members = profile.members_by_name.includes(relations_to_include).paginate(:per_page => members_per_page, :page => params[:npage]) | 74 | + @members = profile.members_by_name.includes(relations_to_include).paginate(:per_page => members_per_page, :page => params[:npage], :total_entries => profile.members.count) |
71 | end | 75 | end |
72 | end | 76 | end |
73 | 77 | ||
@@ -315,7 +319,7 @@ class ProfileController < PublicController | @@ -315,7 +319,7 @@ class ProfileController < PublicController | ||
315 | abuse_report = AbuseReport.new(params[:abuse_report]) | 319 | abuse_report = AbuseReport.new(params[:abuse_report]) |
316 | if !params[:content_type].blank? | 320 | if !params[:content_type].blank? |
317 | article = params[:content_type].constantize.find(params[:content_id]) | 321 | article = params[:content_type].constantize.find(params[:content_id]) |
318 | - abuse_report.content = instance_eval(&article.reported_version) | 322 | + abuse_report.content = article_reported_version(article) |
319 | end | 323 | end |
320 | 324 | ||
321 | user.register_report(abuse_report, profile) | 325 | user.register_report(abuse_report, profile) |
@@ -394,6 +398,7 @@ class ProfileController < PublicController | @@ -394,6 +398,7 @@ class ProfileController < PublicController | ||
394 | 398 | ||
395 | def private_profile | 399 | def private_profile |
396 | private_profile_partial_parameters | 400 | private_profile_partial_parameters |
401 | + render :action => 'index', :status => 403 | ||
397 | end | 402 | end |
398 | 403 | ||
399 | def invisible_profile | 404 | def invisible_profile |
app/controllers/public/search_controller.rb
@@ -90,10 +90,14 @@ class SearchController < PublicController | @@ -90,10 +90,14 @@ class SearchController < PublicController | ||
90 | end | 90 | end |
91 | 91 | ||
92 | def events | 92 | def events |
93 | - year = (params[:year] ? params[:year].to_i : Date.today.year) | ||
94 | - month = (params[:month] ? params[:month].to_i : Date.today.month) | ||
95 | - day = (params[:day] ? params[:day].to_i : Date.today.day) | ||
96 | - @date = build_date(year, month, day) | 93 | + if params[:year].blank? && params[:year].blank? && params[:day].blank? |
94 | + @date = Date.today | ||
95 | + else | ||
96 | + year = (params[:year] ? params[:year].to_i : Date.today.year) | ||
97 | + month = (params[:month] ? params[:month].to_i : Date.today.month) | ||
98 | + day = (params[:day] ? params[:day].to_i : 1) | ||
99 | + @date = build_date(year, month, day) | ||
100 | + end | ||
97 | date_range = (@date - 1.month).at_beginning_of_month..(@date + 1.month).at_end_of_month | 101 | date_range = (@date - 1.month).at_beginning_of_month..(@date + 1.month).at_end_of_month |
98 | 102 | ||
99 | @events = [] | 103 | @events = [] |
app/helpers/application_helper.rb
@@ -304,7 +304,7 @@ module ApplicationHelper | @@ -304,7 +304,7 @@ module ApplicationHelper | ||
304 | def partial_for_class(klass, prefix=nil, suffix=nil) | 304 | def partial_for_class(klass, prefix=nil, suffix=nil) |
305 | raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil? | 305 | raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil? |
306 | name = klass.name.underscore | 306 | name = klass.name.underscore |
307 | - controller.view_paths.reverse_each do |view_path| | 307 | + controller.view_paths.each do |view_path| |
308 | partial = partial_for_class_in_view_path(klass, view_path, prefix, suffix) | 308 | partial = partial_for_class_in_view_path(klass, view_path, prefix, suffix) |
309 | return partial if partial | 309 | return partial if partial |
310 | end | 310 | end |
@@ -907,13 +907,15 @@ module ApplicationHelper | @@ -907,13 +907,15 @@ module ApplicationHelper | ||
907 | end | 907 | end |
908 | 908 | ||
909 | def page_title | 909 | def page_title |
910 | - (@page ? @page.title + ' - ' : '') + | ||
911 | - (@topic ? @topic.title + ' - ' : '') + | ||
912 | - (@section ? @section.title + ' - ' : '') + | ||
913 | - (@toc ? _('Online Manual') + ' - ' : '') + | ||
914 | - (controller.controller_name == 'chat' ? _('Chat') + ' - ' : '') + | ||
915 | - (profile ? profile.short_name : environment.name) + | ||
916 | - (@category ? " - #{@category.full_name}" : '') | 910 | + CGI.escapeHTML( |
911 | + (@page ? @page.title + ' - ' : '') + | ||
912 | + (@topic ? @topic.title + ' - ' : '') + | ||
913 | + (@section ? @section.title + ' - ' : '') + | ||
914 | + (@toc ? _('Online Manual') + ' - ' : '') + | ||
915 | + (controller.controller_name == 'chat' ? _('Chat') + ' - ' : '') + | ||
916 | + (profile ? profile.short_name : environment.name) + | ||
917 | + (@category ? " - #{@category.full_name}" : '') | ||
918 | + ) | ||
917 | end | 919 | end |
918 | 920 | ||
919 | # DEPRECATED. Do not use this. | 921 | # DEPRECATED. Do not use this. |
@@ -1285,11 +1287,13 @@ module ApplicationHelper | @@ -1285,11 +1287,13 @@ module ApplicationHelper | ||
1285 | end | 1287 | end |
1286 | 1288 | ||
1287 | def delete_article_message(article) | 1289 | def delete_article_message(article) |
1288 | - if article.folder? | ||
1289 | - _("Are you sure that you want to remove the folder \"%s\"? Note that all the items inside it will also be removed!") % article.name | ||
1290 | - else | ||
1291 | - _("Are you sure that you want to remove the item \"%s\"?") % article.name | ||
1292 | - end | 1290 | + CGI.escapeHTML( |
1291 | + if article.folder? | ||
1292 | + _("Are you sure that you want to remove the folder \"%s\"? Note that all the items inside it will also be removed!") % article.name | ||
1293 | + else | ||
1294 | + _("Are you sure that you want to remove the item \"%s\"?") % article.name | ||
1295 | + end | ||
1296 | + ) | ||
1293 | end | 1297 | end |
1294 | 1298 | ||
1295 | def expirable_link_to(expired, content, url, options = {}) | 1299 | def expirable_link_to(expired, content, url, options = {}) |
@@ -1377,7 +1381,7 @@ module ApplicationHelper | @@ -1377,7 +1381,7 @@ module ApplicationHelper | ||
1377 | # are old things that do not support it we are keeping this hot spot. | 1381 | # are old things that do not support it we are keeping this hot spot. |
1378 | html = @plugins.pipeline(:parse_content, html, source).first | 1382 | html = @plugins.pipeline(:parse_content, html, source).first |
1379 | end | 1383 | end |
1380 | - html | 1384 | + html && html.html_safe |
1381 | end | 1385 | end |
1382 | 1386 | ||
1383 | def convert_macro(html, source) | 1387 | def convert_macro(html, source) |
app/helpers/article_helper.rb
@@ -3,6 +3,12 @@ module ArticleHelper | @@ -3,6 +3,12 @@ module ArticleHelper | ||
3 | include PrototypeHelper | 3 | include PrototypeHelper |
4 | include TokenHelper | 4 | include TokenHelper |
5 | 5 | ||
6 | + def article_reported_version(article) | ||
7 | + search_path = Rails.root.join('app', 'views', 'shared', 'reported_versions') | ||
8 | + partial_path = File.join('shared', 'reported_versions', 'profile', partial_for_class_in_view_path(article.class, search_path)) | ||
9 | + render_to_string(:partial => partial_path, :locals => {:article => article}) | ||
10 | + end | ||
11 | + | ||
6 | def custom_options_for_article(article, tokenized_children) | 12 | def custom_options_for_article(article, tokenized_children) |
7 | @article = article | 13 | @article = article |
8 | 14 |
app/helpers/layout_helper.rb
@@ -91,7 +91,7 @@ module LayoutHelper | @@ -91,7 +91,7 @@ module LayoutHelper | ||
91 | end | 91 | end |
92 | 92 | ||
93 | def meta_description_tag(article=nil) | 93 | def meta_description_tag(article=nil) |
94 | - article ? truncate(strip_tags(article.body.to_s), :length => 200) : environment.name | 94 | + article ? CGI.escapeHTML(truncate(strip_tags(article.body.to_s), :length => 200)) : environment.name |
95 | end | 95 | end |
96 | end | 96 | end |
97 | 97 |
app/helpers/profile_helper.rb
1 | module ProfileHelper | 1 | module ProfileHelper |
2 | 2 | ||
3 | COMMON_CATEGORIES = ActiveSupport::OrderedHash.new | 3 | COMMON_CATEGORIES = ActiveSupport::OrderedHash.new |
4 | - COMMON_CATEGORIES[:content] = [:blogs, :image_galleries, :events, :tags] | 4 | + COMMON_CATEGORIES[:content] = [:blogs, :image_galleries, :events, :article_tags] |
5 | COMMON_CATEGORIES[:interests] = [:interests] | 5 | COMMON_CATEGORIES[:interests] = [:interests] |
6 | COMMON_CATEGORIES[:general] = nil | 6 | COMMON_CATEGORIES[:general] = nil |
7 | 7 | ||
@@ -41,6 +41,8 @@ module ProfileHelper | @@ -41,6 +41,8 @@ module ProfileHelper | ||
41 | :birth_date => _('Date of birth'), | 41 | :birth_date => _('Date of birth'), |
42 | :created_at => _('Profile created at'), | 42 | :created_at => _('Profile created at'), |
43 | :members_count => _('Members'), | 43 | :members_count => _('Members'), |
44 | + :privacy_setting => _('Privacy setting'), | ||
45 | + :article_tags => _('Tags') | ||
44 | } | 46 | } |
45 | 47 | ||
46 | EXCEPTION = { | 48 | EXCEPTION = { |
@@ -63,7 +65,7 @@ module ProfileHelper | @@ -63,7 +65,7 @@ module ProfileHelper | ||
63 | 65 | ||
64 | def title(field, entry = nil) | 66 | def title(field, entry = nil) |
65 | return self.send("#{field}_custom_title", entry) if MULTIPLE[kind].include?(field) && entry.present? | 67 | return self.send("#{field}_custom_title", entry) if MULTIPLE[kind].include?(field) && entry.present? |
66 | - CUSTOM_LABELS[field.to_sym] || field.to_s.humanize | 68 | + CUSTOM_LABELS[field.to_sym] || _(field.to_s.humanize) |
67 | end | 69 | end |
68 | 70 | ||
69 | def display_field(field) | 71 | def display_field(field) |
@@ -73,15 +75,18 @@ module ProfileHelper | @@ -73,15 +75,18 @@ module ProfileHelper | ||
73 | return '' | 75 | return '' |
74 | end | 76 | end |
75 | value = begin profile.send(field) rescue nil end | 77 | value = begin profile.send(field) rescue nil end |
76 | - p field | ||
77 | - if !value.blank? | 78 | + return '' if value.blank? |
79 | + if value.kind_of?(Hash) | ||
80 | + content = self.send("treat_#{field}", value) | ||
81 | + content_tag('tr', content_tag('td', title(field), :class => 'field-name') + content_tag('td', content)) | ||
82 | + else | ||
78 | entries = multiple ? value : [] << value | 83 | entries = multiple ? value : [] << value |
79 | entries.map do |entry| | 84 | entries.map do |entry| |
80 | content = self.send("treat_#{field}", entry) | 85 | content = self.send("treat_#{field}", entry) |
81 | - content_tag('tr', content_tag('td', title(field, entry), :class => 'field-name') + content_tag('td', content)) | 86 | + unless content.blank? |
87 | + content_tag('tr', content_tag('td', title(field, entry), :class => 'field-name') + content_tag('td', content)) | ||
88 | + end | ||
82 | end.join("\n") | 89 | end.join("\n") |
83 | - else | ||
84 | - '' | ||
85 | end | 90 | end |
86 | end | 91 | end |
87 | 92 | ||
@@ -98,7 +103,6 @@ module ProfileHelper | @@ -98,7 +103,6 @@ module ProfileHelper | ||
98 | end | 103 | end |
99 | 104 | ||
100 | def treat_date(date) | 105 | def treat_date(date) |
101 | - puts date.inspect | ||
102 | show_date(date.to_date) | 106 | show_date(date.to_date) |
103 | end | 107 | end |
104 | alias :treat_birth_date :treat_date | 108 | alias :treat_birth_date :treat_date |
@@ -133,12 +137,10 @@ module ProfileHelper | @@ -133,12 +137,10 @@ module ProfileHelper | ||
133 | end | 137 | end |
134 | 138 | ||
135 | def treat_blogs(blog) | 139 | def treat_blogs(blog) |
136 | - p blog | ||
137 | link_to(n_('One post', '%{num} posts', blog.posts.published.count) % { :num => blog.posts.published.count }, blog.url) | 140 | link_to(n_('One post', '%{num} posts', blog.posts.published.count) % { :num => blog.posts.published.count }, blog.url) |
138 | end | 141 | end |
139 | 142 | ||
140 | def treat_image_galleries(gallery) | 143 | def treat_image_galleries(gallery) |
141 | - p gallery | ||
142 | link_to(n_('One picture', '%{num} pictures', gallery.images.published.count) % { :num => gallery.images.published.count }, gallery.url) | 144 | link_to(n_('One picture', '%{num} pictures', gallery.images.published.count) % { :num => gallery.images.published.count }, gallery.url) |
143 | end | 145 | end |
144 | 146 | ||
@@ -146,7 +148,7 @@ module ProfileHelper | @@ -146,7 +148,7 @@ module ProfileHelper | ||
146 | link_to events.published.count, :controller => 'events', :action => 'events' | 148 | link_to events.published.count, :controller => 'events', :action => 'events' |
147 | end | 149 | end |
148 | 150 | ||
149 | - def treat_tags(tags) | 151 | + def treat_article_tags(tags) |
150 | tag_cloud @tags, :id, { :action => 'tags' }, :max_size => 18, :min_size => 10 | 152 | tag_cloud @tags, :id, { :action => 'tags' }, :max_size => 18, :min_size => 10 |
151 | end | 153 | end |
152 | 154 |
app/helpers/role_helper.rb
app/helpers/sweeper_helper.rb
@@ -56,12 +56,12 @@ module SweeperHelper | @@ -56,12 +56,12 @@ module SweeperHelper | ||
56 | if profile | 56 | if profile |
57 | profile.blocks.each {|block| | 57 | profile.blocks.each {|block| |
58 | conditions = block.class.expire_on | 58 | conditions = block.class.expire_on |
59 | - blocks_to_expire << block unless (conditions[:profile] & causes).empty? | 59 | + blocks_to_expire << block unless (conditions[:profile] & causes).blank? |
60 | } | 60 | } |
61 | end | 61 | end |
62 | environment.blocks.each {|block| | 62 | environment.blocks.each {|block| |
63 | conditions = block.class.expire_on | 63 | conditions = block.class.expire_on |
64 | - blocks_to_expire << block unless (conditions[:environment] & causes).empty? | 64 | + blocks_to_expire << block unless (conditions[:environment] & causes).blank? |
65 | } | 65 | } |
66 | 66 | ||
67 | blocks_to_expire.uniq! | 67 | blocks_to_expire.uniq! |
@@ -0,0 +1,51 @@ | @@ -0,0 +1,51 @@ | ||
1 | +module TinymceHelper | ||
2 | + include MacrosHelper | ||
3 | + | ||
4 | + def tinymce_js | ||
5 | + output = '' | ||
6 | + output += javascript_include_tag 'tinymce/js/tinymce/tinymce.min.js' | ||
7 | + output += javascript_include_tag 'tinymce/js/tinymce/jquery.tinymce.min.js' | ||
8 | + output += javascript_include_tag 'tinymce.js' | ||
9 | + output += include_macro_js_files.to_s | ||
10 | + output | ||
11 | + end | ||
12 | + | ||
13 | + def tinymce_init_js options = {} | ||
14 | + options.merge! :document_base_url => environment.top_url, | ||
15 | + :content_css => "/stylesheets/tinymce.css,#{macro_css_files}", | ||
16 | + :plugins => %w[compat3x advlist autolink lists link image charmap print preview hr anchor pagebreak | ||
17 | + searchreplace wordcount visualblocks visualchars code fullscreen | ||
18 | + insertdatetime media nonbreaking save table contextmenu directionality | ||
19 | + emoticons template paste textcolor colorpicker textpattern], | ||
20 | + :language => tinymce_language | ||
21 | + | ||
22 | + options[:toolbar1] = "insertfile undo redo | copy paste | bold italic underline | styleselect fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image" | ||
23 | + if options[:mode] == 'simple' | ||
24 | + options[:menubar] = false | ||
25 | + else | ||
26 | + options[:menubar] = 'edit insert view tools' | ||
27 | + options[:toolbar2] = 'print preview code media | table' | ||
28 | + | ||
29 | + options[:toolbar2] += ' | macros' | ||
30 | + macros_with_buttons.each do |macro| | ||
31 | + options[:toolbar2] += " #{macro.identifier}" | ||
32 | + end | ||
33 | + end | ||
34 | + | ||
35 | + options[:macros_setup] = macros_with_buttons.map do |macro| | ||
36 | + <<-EOS | ||
37 | + ed.addButton('#{macro.identifier}', { | ||
38 | + title: #{macro_title(macro).to_json}, | ||
39 | + onclick: #{generate_macro_config_dialog macro}, | ||
40 | + image : '#{macro.configuration[:icon_path]}' | ||
41 | + }); | ||
42 | + EOS | ||
43 | + end | ||
44 | + | ||
45 | + #cleanup non tinymce options | ||
46 | + options = options.except :mode | ||
47 | + | ||
48 | + "noosfero.tinymce.init(#{options.to_json})" | ||
49 | + end | ||
50 | + | ||
51 | +end |
app/models/article.rb
@@ -285,13 +285,6 @@ class Article < ActiveRecord::Base | @@ -285,13 +285,6 @@ class Article < ActiveRecord::Base | ||
285 | end | 285 | end |
286 | end | 286 | end |
287 | 287 | ||
288 | - def reported_version(options = {}) | ||
289 | - article = self | ||
290 | - search_path = Rails.root.join('app', 'views', 'shared', 'reported_versions') | ||
291 | - partial_path = File.join('shared', 'reported_versions', partial_for_class_in_view_path(article.class, search_path)) | ||
292 | - lambda { render_to_string(:partial => partial_path, :locals => {:article => article}) } | ||
293 | - end | ||
294 | - | ||
295 | # returns the data of the article. Must be overriden in each subclass to | 288 | # returns the data of the article. Must be overriden in each subclass to |
296 | # provide the correct content for the article. | 289 | # provide the correct content for the article. |
297 | def data | 290 | def data |
app/models/block.rb
@@ -192,7 +192,7 @@ class Block < ActiveRecord::Base | @@ -192,7 +192,7 @@ class Block < ActiveRecord::Base | ||
192 | 192 | ||
193 | # Override in your subclasses. | 193 | # Override in your subclasses. |
194 | # Define which events and context should cause the block cache to expire | 194 | # Define which events and context should cause the block cache to expire |
195 | - # Possible events are: :article, :profile, :friendship, :category | 195 | + # Possible events are: :article, :profile, :friendship, :category, :role_assignment |
196 | # Possible contexts are: :profile, :environment | 196 | # Possible contexts are: :profile, :environment |
197 | def self.expire_on | 197 | def self.expire_on |
198 | { | 198 | { |
@@ -234,4 +234,9 @@ class Block < ActiveRecord::Base | @@ -234,4 +234,9 @@ class Block < ActiveRecord::Base | ||
234 | duplicated_block | 234 | duplicated_block |
235 | end | 235 | end |
236 | 236 | ||
237 | + def copy_from(block) | ||
238 | + self.settings = block.settings | ||
239 | + self.position = block.position | ||
240 | + end | ||
241 | + | ||
237 | end | 242 | end |
app/models/community.rb
@@ -50,16 +50,6 @@ class Community < Organization | @@ -50,16 +50,6 @@ class Community < Organization | ||
50 | super + FIELDS | 50 | super + FIELDS |
51 | end | 51 | end |
52 | 52 | ||
53 | - validate :presence_of_required_fieds | ||
54 | - | ||
55 | - def presence_of_required_fieds | ||
56 | - self.required_fields.each do |field| | ||
57 | - if self.send(field).blank? | ||
58 | - self.errors.add_on_blank(field) | ||
59 | - end | ||
60 | - end | ||
61 | - end | ||
62 | - | ||
63 | def active_fields | 53 | def active_fields |
64 | environment ? environment.active_community_fields : [] | 54 | environment ? environment.active_community_fields : [] |
65 | end | 55 | end |
app/models/enterprise.rb
@@ -59,16 +59,6 @@ class Enterprise < Organization | @@ -59,16 +59,6 @@ class Enterprise < Organization | ||
59 | super + FIELDS | 59 | super + FIELDS |
60 | end | 60 | end |
61 | 61 | ||
62 | - validate :presence_of_required_fieds | ||
63 | - | ||
64 | - def presence_of_required_fieds | ||
65 | - self.required_fields.each do |field| | ||
66 | - if self.send(field).blank? | ||
67 | - self.errors.add_on_blank(field) | ||
68 | - end | ||
69 | - end | ||
70 | - end | ||
71 | - | ||
72 | def active_fields | 62 | def active_fields |
73 | environment ? environment.active_enterprise_fields : [] | 63 | environment ? environment.active_enterprise_fields : [] |
74 | end | 64 | end |
app/models/environment.rb
@@ -660,6 +660,7 @@ class Environment < ActiveRecord::Base | @@ -660,6 +660,7 @@ class Environment < ActiveRecord::Base | ||
660 | url = 'http://' | 660 | url = 'http://' |
661 | url << (Noosfero.url_options.key?(:host) ? Noosfero.url_options[:host] : default_hostname) | 661 | url << (Noosfero.url_options.key?(:host) ? Noosfero.url_options[:host] : default_hostname) |
662 | url << ':' << Noosfero.url_options[:port].to_s if Noosfero.url_options.key?(:port) | 662 | url << ':' << Noosfero.url_options[:port].to_s if Noosfero.url_options.key?(:port) |
663 | + url << Noosfero.root('') | ||
663 | url | 664 | url |
664 | end | 665 | end |
665 | 666 |
app/models/external_feed.rb
@@ -13,6 +13,7 @@ class ExternalFeed < ActiveRecord::Base | @@ -13,6 +13,7 @@ class ExternalFeed < ActiveRecord::Base | ||
13 | attr_accessible :address, :enabled | 13 | attr_accessible :address, :enabled |
14 | 14 | ||
15 | def add_item(title, link, date, content) | 15 | def add_item(title, link, date, content) |
16 | + return if content.blank? | ||
16 | doc = Hpricot(content) | 17 | doc = Hpricot(content) |
17 | doc.search('*').each do |p| | 18 | doc.search('*').each do |p| |
18 | if p.instance_of? Hpricot::Elem | 19 | if p.instance_of? Hpricot::Elem |
app/models/link_list_block.rb
@@ -78,8 +78,13 @@ class LinkListBlock < Block | @@ -78,8 +78,13 @@ class LinkListBlock < Block | ||
78 | address | 78 | address |
79 | end | 79 | end |
80 | if add !~ /^[a-z]+:\/\// && add !~ /^\// | 80 | if add !~ /^[a-z]+:\/\// && add !~ /^\// |
81 | - 'http://' + add | 81 | + '//' + add |
82 | else | 82 | else |
83 | + if root = Noosfero.root | ||
84 | + if !add.starts_with?(root) | ||
85 | + add = root + add | ||
86 | + end | ||
87 | + end | ||
83 | add | 88 | add |
84 | end | 89 | end |
85 | end | 90 | end |
@@ -96,4 +101,5 @@ class LinkListBlock < Block | @@ -96,4 +101,5 @@ class LinkListBlock < Block | ||
96 | sanitizer = HTML::WhiteListSanitizer.new | 101 | sanitizer = HTML::WhiteListSanitizer.new |
97 | sanitizer.sanitize(text) | 102 | sanitizer.sanitize(text) |
98 | end | 103 | end |
104 | + | ||
99 | end | 105 | end |
app/models/organization.rb
@@ -30,6 +30,16 @@ class Organization < Profile | @@ -30,6 +30,16 @@ class Organization < Profile | ||
30 | 30 | ||
31 | scope :more_popular, :order => 'members_count DESC' | 31 | scope :more_popular, :order => 'members_count DESC' |
32 | 32 | ||
33 | + validate :presence_of_required_fieds, :unless => :is_template | ||
34 | + | ||
35 | + def presence_of_required_fieds | ||
36 | + self.required_fields.each do |field| | ||
37 | + if self.send(field).blank? | ||
38 | + self.errors.add_on_blank(field) | ||
39 | + end | ||
40 | + end | ||
41 | + end | ||
42 | + | ||
33 | def validation_methodology | 43 | def validation_methodology |
34 | self.validation_info ? self.validation_info.validation_methodology : nil | 44 | self.validation_info ? self.validation_info.validation_methodology : nil |
35 | end | 45 | end |
app/models/person.rb
@@ -161,7 +161,7 @@ class Person < Profile | @@ -161,7 +161,7 @@ class Person < Profile | ||
161 | FIELDS | 161 | FIELDS |
162 | end | 162 | end |
163 | 163 | ||
164 | - validate :presence_of_required_fields | 164 | + validate :presence_of_required_fields, :unless => :is_template |
165 | 165 | ||
166 | def presence_of_required_fields | 166 | def presence_of_required_fields |
167 | self.required_fields.each do |field| | 167 | self.required_fields.each do |field| |
app/models/profile.rb
@@ -97,7 +97,7 @@ class Profile < ActiveRecord::Base | @@ -97,7 +97,7 @@ class Profile < ActiveRecord::Base | ||
97 | end | 97 | end |
98 | 98 | ||
99 | def members_by_name | 99 | def members_by_name |
100 | - members.order(:name) | 100 | + members.order('profiles.name') |
101 | end | 101 | end |
102 | 102 | ||
103 | class << self | 103 | class << self |
@@ -346,16 +346,17 @@ class Profile < ActiveRecord::Base | @@ -346,16 +346,17 @@ class Profile < ActiveRecord::Base | ||
346 | end | 346 | end |
347 | 347 | ||
348 | def copy_blocks_from(profile) | 348 | def copy_blocks_from(profile) |
349 | + template_boxes = profile.boxes.select{|box| box.position} | ||
349 | self.boxes.destroy_all | 350 | self.boxes.destroy_all |
350 | - profile.boxes.each do |box| | ||
351 | - new_box = Box.new | 351 | + self.boxes = template_boxes.size.times.map { Box.new } |
352 | + | ||
353 | + template_boxes.each_with_index do |box, i| | ||
354 | + new_box = self.boxes[i] | ||
352 | new_box.position = box.position | 355 | new_box.position = box.position |
353 | - self.boxes << new_box | ||
354 | box.blocks.each do |block| | 356 | box.blocks.each do |block| |
355 | new_block = block.class.new(:title => block[:title]) | 357 | new_block = block.class.new(:title => block[:title]) |
356 | - new_block.settings = block.settings | ||
357 | - new_block.position = block.position | ||
358 | - self.boxes[-1].blocks << new_block | 358 | + new_block.copy_from(block) |
359 | + new_box.blocks << new_block | ||
359 | end | 360 | end |
360 | end | 361 | end |
361 | end | 362 | end |
app/models/task.rb
@@ -285,8 +285,9 @@ class Task < ActiveRecord::Base | @@ -285,8 +285,9 @@ class Task < ActiveRecord::Base | ||
285 | # If | 285 | # If |
286 | def send_notification(action) | 286 | def send_notification(action) |
287 | if sends_email? | 287 | if sends_email? |
288 | - if self.requestor | ||
289 | - TaskMailer.generic_message("task_#{action}", self) | 288 | + if self.requestor && !self.requestor.notification_emails.empty? |
289 | + message = TaskMailer.generic_message("task_#{action}", self) | ||
290 | + message.deliver if message | ||
290 | end | 291 | end |
291 | end | 292 | end |
292 | end | 293 | end |
app/models/user.rb
@@ -354,6 +354,7 @@ class User < ActiveRecord::Base | @@ -354,6 +354,7 @@ class User < ActiveRecord::Base | ||
354 | end | 354 | end |
355 | 355 | ||
356 | def delay_activation_check | 356 | def delay_activation_check |
357 | + return if person.is_template? | ||
357 | Delayed::Job.enqueue(UserActivationJob.new(self.id), {:priority => 0, :run_at => 72.hours.from_now}) | 358 | Delayed::Job.enqueue(UserActivationJob.new(self.id), {:priority => 0, :run_at => 72.hours.from_now}) |
358 | end | 359 | end |
359 | end | 360 | end |
app/sweepers/role_assignment_sweeper.rb
@@ -13,20 +13,22 @@ class RoleAssignmentSweeper < ActiveRecord::Observer | @@ -13,20 +13,22 @@ class RoleAssignmentSweeper < ActiveRecord::Observer | ||
13 | protected | 13 | protected |
14 | 14 | ||
15 | def expire_caches(role_assignment) | 15 | def expire_caches(role_assignment) |
16 | - expire_cache(role_assignment.accessor) | ||
17 | - expire_cache(role_assignment.resource) if role_assignment.resource.respond_to?(:cache_keys) | 16 | + expire_cache(role_assignment.accessor) if role_assignment.accessor.kind_of?(Profile) |
17 | + expire_cache(role_assignment.resource) if role_assignment.resource.kind_of?(Profile) | ||
18 | end | 18 | end |
19 | 19 | ||
20 | def expire_cache(profile) | 20 | def expire_cache(profile) |
21 | per_page = Noosfero::Constants::PROFILE_PER_PAGE | 21 | per_page = Noosfero::Constants::PROFILE_PER_PAGE |
22 | - profile.cache_keys(:per_page => per_page).each { |ck| | ||
23 | - expire_timeout_fragment(ck) | ||
24 | - } | 22 | + |
23 | + profile.cache_keys(:per_page => per_page).each { |ck| expire_timeout_fragment(ck) } | ||
24 | + expire_timeout_fragment(profile.members_cache_key(:per_page => per_page)) | ||
25 | 25 | ||
26 | profile.blocks_to_expire_cache.each { |block| | 26 | profile.blocks_to_expire_cache.each { |block| |
27 | blocks = profile.blocks.select{|b| b.kind_of?(block)} | 27 | blocks = profile.blocks.select{|b| b.kind_of?(block)} |
28 | BlockSweeper.expire_blocks(blocks) | 28 | BlockSweeper.expire_blocks(blocks) |
29 | } | 29 | } |
30 | + | ||
31 | + expire_blocks_cache(profile, [:role_assignment]) | ||
30 | end | 32 | end |
31 | 33 | ||
32 | end | 34 | end |
app/views/events/_month.html.erb
@@ -13,8 +13,8 @@ | @@ -13,8 +13,8 @@ | ||
13 | date.day, | 13 | date.day, |
14 | :url => {:action => 'events_by_day', :year => date.year, :month => date.month, :day => date.day, :category_id => @category_id}, | 14 | :url => {:action => 'events_by_day', :year => date.year, :month => date.month, :day => date.day, :category_id => @category_id}, |
15 | :update => 'events-of-the-day', | 15 | :update => 'events-of-the-day', |
16 | - :loading => '$("events-of-the-day").addClassName("loading")', | ||
17 | - :complete => '$("events-of-the-day").removeClassName("loading")' | 16 | + :loading => "$('events-of-the-day').addClassName('loading')", |
17 | + :complete => "$('events-of-the-day').removeClassName('loading')" | ||
18 | ) : | 18 | ) : |
19 | date.day | 19 | date.day |
20 | %> | 20 | %> |
app/views/file_presenter/_generic.html.erb
1 | <span class="download-link"> | 1 | <span class="download-link"> |
2 | <span>Download</span> | 2 | <span>Download</span> |
3 | - <strong><%= link_to generic.filename, generic.public_filename %></strong> | 3 | + <strong><%= link_to generic.filename, [Noosfero.root, generic.public_filename].join %></strong> |
4 | </span> | 4 | </span> |
5 | 5 | ||
6 | <div class="uploaded-file-description <%= 'empty' if generic.abstract.blank? %>"> | 6 | <div class="uploaded-file-description <%= 'empty' if generic.abstract.blank? %>"> |
app/views/file_presenter/_image.html.erb
@@ -28,7 +28,7 @@ | @@ -28,7 +28,7 @@ | ||
28 | 28 | ||
29 | <%# image_tag(article.public_filename(:display), :class => article.css_class_name, :style => 'max-width: 100%') %> | 29 | <%# image_tag(article.public_filename(:display), :class => article.css_class_name, :style => 'max-width: 100%') %> |
30 | 30 | ||
31 | -<img src="<%=image.public_filename(:display)%>" class="<%=image.css_class_name%>"> | 31 | +<img src="<%= [Noosfero.root, image.public_filename(:display)].join %>" class="<%=image.css_class_name%>"> |
32 | 32 | ||
33 | <div class="uploaded-file-description <%= 'empty' if image.abstract.blank? %>"> | 33 | <div class="uploaded-file-description <%= 'empty' if image.abstract.blank? %>"> |
34 | <%= image.abstract %> | 34 | <%= image.abstract %> |
app/views/home/index.html.erb
@@ -61,9 +61,6 @@ | @@ -61,9 +61,6 @@ | ||
61 | <%= submit_button(:search, _('Search')) %> | 61 | <%= submit_button(:search, _('Search')) %> |
62 | </div> | 62 | </div> |
63 | 63 | ||
64 | - <div> | ||
65 | - <%= lightbox_link_to _('More options'), :controller => 'search', :action => 'popup' %> | ||
66 | - </div> | ||
67 | <% end %> | 64 | <% end %> |
68 | </div> | 65 | </div> |
69 | <% end %> | 66 | <% end %> |
app/views/layouts/application-ng.html.erb
@@ -17,7 +17,10 @@ | @@ -17,7 +17,10 @@ | ||
17 | <meta property="og:url" content="<%= @page ? url_for(@page.url) : @environment.top_url %>"> | 17 | <meta property="og:url" content="<%= @page ? url_for(@page.url) : @environment.top_url %>"> |
18 | <meta property="og:title" content="<%= h page_title %>"> | 18 | <meta property="og:title" content="<%= h page_title %>"> |
19 | <meta property="og:site_name" content="<%= profile ? profile.name : @environment.name %>"> | 19 | <meta property="og:site_name" content="<%= profile ? profile.name : @environment.name %>"> |
20 | - <meta property="og:description" content="<%= @page ? truncate(strip_tags(@page.body.to_s), :length => 200) : @environment.name %>"> | 20 | + <meta property="og:description" content="<%= meta_description_tag(@page) %>"> |
21 | + | ||
22 | + <!-- site root --> | ||
23 | + <meta property="noosfero:root" content="<%= Noosfero.root %>"/> | ||
21 | 24 | ||
22 | <% if @page %> | 25 | <% if @page %> |
23 | <meta property="article:published_time" content="<%= show_date(@page.published_at) %>"> | 26 | <meta property="article:published_time" content="<%= show_date(@page.published_at) %>"> |
app/views/manage_products/_edit_description.html.erb
1 | <%= render :file => 'shared/tiny_mce', :locals => {:mode => 'simple'} %> | 1 | <%= render :file => 'shared/tiny_mce', :locals => {:mode => 'simple'} %> |
2 | <%= remote_form_for(@product, | 2 | <%= remote_form_for(@product, |
3 | :loading => "small_loading('product-description-form')", | 3 | :loading => "small_loading('product-description-form')", |
4 | - :before => ("tinyMCE.triggerSave()" unless Rails.env == 'test'), | ||
5 | :update => 'product-description', | 4 | :update => 'product-description', |
6 | :url => {:controller => 'manage_products', :action => 'edit', :id => @product, :field => 'description'}, | 5 | :url => {:controller => 'manage_products', :action => 'edit', :id => @product, :field => 'description'}, |
7 | :html => {:id => 'product-description-form', :method => 'post'}) do |f| %> | 6 | :html => {:id => 'product-description-form', :method => 'post'}) do |f| %> |
app/views/profile/_profile_comment_form.html.erb
@@ -10,8 +10,8 @@ | @@ -10,8 +10,8 @@ | ||
10 | :rows => 1, | 10 | :rows => 1, |
11 | :class => 'submit-with-keypress', | 11 | :class => 'submit-with-keypress', |
12 | :title => _('Leave your comment'), | 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?), | 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'), | 15 | :value => _('Leave your comment'), |
16 | :style => 'color: #ccc' %> | 16 | :style => 'color: #ccc' %> |
17 | <%= hidden_field_tag :source_id, activity.id, :id => "activity_id_#{activity.id}" %> | 17 | <%= hidden_field_tag :source_id, activity.id, :id => "activity_id_#{activity.id}" %> |
app/views/profile/_profile_scrap_reply_form.html.erb
@@ -9,8 +9,8 @@ | @@ -9,8 +9,8 @@ | ||
9 | :rows => 1, | 9 | :rows => 1, |
10 | :class => 'submit-with-keypress', | 10 | :class => 'submit-with-keypress', |
11 | :title => _('Leave your comment'), | 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?), | 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 | :value => _('Leave your comment') %> |
15 | <%= hidden_field_tag 'scrap[scrap_id]', scrap.id %> | 15 | <%= hidden_field_tag 'scrap[scrap_id]', scrap.id %> |
16 | <%= hidden_field_tag 'receiver_id', scrap.sender.id %> | 16 | <%= hidden_field_tag 'receiver_id', scrap.sender.id %> |
app/views/profile_editor/_person_form.html.erb
@@ -27,6 +27,10 @@ | @@ -27,6 +27,10 @@ | ||
27 | <%= optional_field(@person, 'district', labelled_form_field(_('District'), text_field(:profile_data, :district, :rel => _('District')))) %> | 27 | <%= optional_field(@person, 'district', labelled_form_field(_('District'), text_field(:profile_data, :district, :rel => _('District')))) %> |
28 | <%= optional_field(@person, 'image', labelled_form_field(_('Image'), file_field(:file, :image, :rel => _('Image')))) %> | 28 | <%= optional_field(@person, 'image', labelled_form_field(_('Image'), file_field(:file, :image, :rel => _('Image')))) %> |
29 | 29 | ||
30 | +<% @plugins.dispatch(:extra_optional_fields).each do |field| %> | ||
31 | + <%= optional_field(@person, field[:name], labelled_form_field(field[:label], text_field(field[:object_name], field[:method], :rel => field[:label], :value => field[:value]))) %> | ||
32 | +<% end %> | ||
33 | + | ||
30 | <% optional_field(@person, 'schooling') do %> | 34 | <% optional_field(@person, 'schooling') do %> |
31 | <div class="formfieldline"> | 35 | <div class="formfieldline"> |
32 | <label class='formlabel' for='profile_data_schooling'><%= _('Schooling') %></label> | 36 | <label class='formlabel' for='profile_data_schooling'><%= _('Schooling') %></label> |
app/views/role/_form.html.erb
@@ -6,10 +6,14 @@ | @@ -6,10 +6,14 @@ | ||
6 | 6 | ||
7 | <%= required f.text_field(:name) %> | 7 | <%= required f.text_field(:name) %> |
8 | 8 | ||
9 | - <p><%= _('Permissions:') %><p> | ||
10 | - <% permissions.keys.each do |p| %> | ||
11 | - <%= check_box_tag("role[permissions][]", p, role.has_permission?(p), { :id => p }) %> | ||
12 | - <%= content_tag(:label, permission_name(p), { :for => p }) %><br/> | 9 | + <% permissions.each do |key| %> |
10 | + <div class="permissions <%= key.downcase %>"> | ||
11 | + <h4><%= _('%s Permissions:' % key) %></h4> | ||
12 | + <% ActiveRecord::Base::PERMISSIONS[key].keys.each do |p| %> | ||
13 | + <%= check_box_tag("role[permissions][]", p, role.has_permission?(p), { :id => p }) %> | ||
14 | + <%= content_tag(:label, permission_name(p), { :for => p }) %><br/> | ||
15 | + <% end %> | ||
16 | + </div> | ||
13 | <% end %> | 17 | <% end %> |
14 | 18 | ||
15 | <% button_bar do %> | 19 | <% button_bar do %> |
app/views/role/edit.html.erb
1 | <h2> <%= _("Editing #{@role.name}") %> </h2> | 1 | <h2> <%= _("Editing #{@role.name}") %> </h2> |
2 | 2 | ||
3 | -<%= render :partial => 'form', :locals => { :mode => :edit, :role => @role, :permissions => ActiveRecord::Base::PERMISSIONS[@role.kind] } %> | 3 | +<%= render :partial => 'form', :locals => { :mode => :edit, :role => @role, :permissions => role_available_permissions(@role) } %> |
app/views/role/new.html.erb
1 | <h2> <%= _("Create a new role") %> </h2> | 1 | <h2> <%= _("Create a new role") %> </h2> |
2 | 2 | ||
3 | -<%= render :partial => 'form', :locals => { :mode => :create, :role => @role, :permissions => ActiveRecord::Base::PERMISSIONS[@role.kind] } %> | 3 | +<%= render :partial => 'form', :locals => { :mode => :create, :role => @role, :permissions => role_available_permissions(@role) } %> |
app/views/shared/reported_versions/_article.html.erb
@@ -1,10 +0,0 @@ | @@ -1,10 +0,0 @@ | ||
1 | -<ul> | ||
2 | - <li><%= (content_tag('strong', _('Title') + ': ') + article.title) if article.title %> </li> | ||
3 | - <li><%= (content_tag('strong', _('Type') + ': ') + article.class.short_description) %> </li> | ||
4 | - <li> | ||
5 | - <%= (content_tag('strong', _('Original content') + ': ') + link_to(article.name, article.url)) %> <br /> | ||
6 | - <%= content_tag('small', _('This link might be unavailable if the content is removed')) %> | ||
7 | - </li> | ||
8 | -</ul> | ||
9 | - | ||
10 | -<%= article_to_html(article) %> |
app/views/shared/reported_versions/_comment.html.erb
@@ -1,10 +0,0 @@ | @@ -1,10 +0,0 @@ | ||
1 | -<ul> | ||
2 | - <li><%= (content_tag('strong', _('Title') + ': ') + comment.title) if comment.title %> </li> | ||
3 | - <li><%= content_tag('strong', _('Type') + ': ') + _('Comment') %> </li> | ||
4 | - <li> | ||
5 | - <%= (content_tag('strong', _('Original content') + ': ') + link_to(comment.title || url_for(comment.url), comment.url)) %> <br /> | ||
6 | - <%= content_tag('small', _('This link might be unavailable if the content is removed')) %> | ||
7 | - </li> | ||
8 | -</ul> | ||
9 | - | ||
10 | -<p><%= article_to_html(comment) %></p> |
app/views/shared/reported_versions/_folder.html.erb
@@ -1 +0,0 @@ | @@ -1 +0,0 @@ | ||
1 | -<%= _('Reported folder') + ': ' + link_to(article.name, article.url) %> |
app/views/shared/reported_versions/profile/_article.html.erb
0 → 100644
@@ -0,0 +1,10 @@ | @@ -0,0 +1,10 @@ | ||
1 | +<ul> | ||
2 | + <li><%= (content_tag('strong', _('Title') + ': ') + article.title) if article.title %> </li> | ||
3 | + <li><%= (content_tag('strong', _('Type') + ': ') + article.class.short_description) %> </li> | ||
4 | + <li> | ||
5 | + <%= (content_tag('strong', _('Original content') + ': ') + link_to(article.name, article.url)) %> <br /> | ||
6 | + <%= content_tag('small', _('This link might be unavailable if the content is removed')) %> | ||
7 | + </li> | ||
8 | +</ul> | ||
9 | + | ||
10 | +<%= article_to_html(article) %> |
app/views/shared/reported_versions/profile/_comment.html.erb
0 → 100644
@@ -0,0 +1,10 @@ | @@ -0,0 +1,10 @@ | ||
1 | +<ul> | ||
2 | + <li><%= (content_tag('strong', _('Title') + ': ') + comment.title) if comment.title %> </li> | ||
3 | + <li><%= content_tag('strong', _('Type') + ': ') + _('Comment') %> </li> | ||
4 | + <li> | ||
5 | + <%= (content_tag('strong', _('Original content') + ': ') + link_to(comment.title || url_for(comment.url), comment.url)) %> <br /> | ||
6 | + <%= content_tag('small', _('This link might be unavailable if the content is removed')) %> | ||
7 | + </li> | ||
8 | +</ul> | ||
9 | + | ||
10 | +<p><%= article_to_html(comment) %></p> |
app/views/shared/reported_versions/profile/_folder.html.erb
0 → 100644
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | +<%= _('Reported folder') + ': ' + link_to(article.name, article.url) %> |
app/views/shared/tiny_mce.html.erb
1 | -<% extend MacrosHelper %> | ||
2 | -<%= javascript_include_tag 'tinymce/jscripts/tiny_mce/tiny_mce.js' %> | ||
3 | -<%= include_macro_js_files %> | ||
4 | -<script type="text/javascript"> | ||
5 | - var myplugins = "searchreplace,print,table,contextmenu,-macrosPlugin"; | ||
6 | - var first_line, second_line; | ||
7 | - var mode = '<%= mode ||= false %>' | ||
8 | - <% if mode %> | ||
9 | - first_line = "fontsizeselect,bold,italic,underline,bullist,numlist,justifyleft,justifycenter,justifyright,link,unlink" | ||
10 | - second_line = "" | ||
11 | - <% else %> | ||
12 | - first_line = "print,separator,copy,paste,separator,undo,redo,separator,search,replace,separator,forecolor,fontsizeselect,formatselect" | ||
13 | - second_line = "bold,italic,underline,strikethrough,separator,bullist,numlist,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,link,unlink,image,table,separator,cleanup,code,macros" | ||
14 | - <% macros_with_buttons.each do |macro| %> | ||
15 | - second_line += ',<%=macro.identifier %>' | ||
16 | - <% end %> | ||
17 | - <% end %> | ||
18 | - | ||
19 | - if (tinymce.isIE) { | ||
20 | - // the paste plugin is only useful in Internet Explorer | ||
21 | - myplugins = "paste," + myplugins; | ||
22 | - } | 1 | +<% |
2 | +extend TinymceHelper | ||
3 | +mode ||= false | ||
4 | +%> | ||
23 | 5 | ||
6 | +<%= tinymce_js %> | ||
7 | +<script type="text/javascript"> | ||
24 | tinymce.create('tinymce.plugins.MacrosPlugin', { | 8 | tinymce.create('tinymce.plugins.MacrosPlugin', { |
25 | createControl: function(n, cm) { | 9 | createControl: function(n, cm) { |
26 | switch (n) { | 10 | switch (n) { |
@@ -49,56 +33,21 @@ tinymce.create('tinymce.plugins.MacrosPlugin', { | @@ -49,56 +33,21 @@ tinymce.create('tinymce.plugins.MacrosPlugin', { | ||
49 | } | 33 | } |
50 | }); | 34 | }); |
51 | 35 | ||
36 | +function tinymce_macros_setup(editor) { | ||
37 | + <% macros_with_buttons.each do |macro| %> | ||
38 | + editor.addButton('<%= macro.identifier %>', { | ||
39 | + title: <%= macro_title(macro).to_json %>, | ||
40 | + onclick: <%= generate_macro_config_dialog(macro) %>, | ||
41 | + image : '<%= macro.configuration[:icon_path]%>' | ||
42 | + }); | ||
43 | + <% end %> | ||
44 | +} | ||
45 | + | ||
52 | // Register plugin with a short name | 46 | // Register plugin with a short name |
53 | tinymce.PluginManager.add('macrosPlugin', tinymce.plugins.MacrosPlugin); | 47 | tinymce.PluginManager.add('macrosPlugin', tinymce.plugins.MacrosPlugin); |
54 | 48 | ||
55 | -tinyMCE.init({ | ||
56 | - mode : "textareas", | ||
57 | - editor_selector : "mceEditor", | ||
58 | - theme : "advanced", | ||
59 | - relative_urls : false, | ||
60 | - remove_script_host : false, | ||
61 | - document_base_url : <%= environment.top_url.to_json %>, | ||
62 | - plugins: myplugins, | ||
63 | - theme_advanced_toolbar_location : "top", | ||
64 | - theme_advanced_layout_manager: 'SimpleLayout', | ||
65 | - theme_advanced_buttons1 : first_line, | ||
66 | - theme_advanced_buttons2 : second_line, | ||
67 | - theme_advanced_buttons3 : "", | ||
68 | - theme_advanced_blockformats :"p,address,pre,h2,h3,h4,h5,h6", | ||
69 | - paste_auto_cleanup_on_paste : true, | ||
70 | - paste_insert_word_content_callback : "convertWord", | ||
71 | - paste_use_dialog: false, | ||
72 | - apply_source_formatting : true, | ||
73 | - extended_valid_elements : "applet[style|archive|codebase|code|height|width],comment,iframe[src|style|allowtransparency|frameborder|width|height|scrolling],embed[title|src|type|height|width],audio[controls|autoplay],video[controls|autoplay],source[src|type]", | ||
74 | - content_css: '/stylesheets/tinymce.css,<%= macro_css_files %>', | ||
75 | - language: <%= tinymce_language.inspect %>, | ||
76 | - entity_encoding: 'raw', | ||
77 | - setup : function(ed) { | ||
78 | - <% macros_with_buttons.each do |macro| %> | ||
79 | - ed.addButton('<%= macro.identifier %>', { | ||
80 | - title: <%= macro_title(macro).to_json %>, | ||
81 | - onclick: <%= generate_macro_config_dialog(macro) %>, | ||
82 | - image : '<%= macro.configuration[:icon_path]%>' | ||
83 | - }); | ||
84 | - <% end %> | ||
85 | - } | 49 | +jQuery(document).ready(function () { |
50 | + <%= tinymce_init_js :mode => mode %> | ||
86 | }); | 51 | }); |
87 | - | ||
88 | -function convertWord(type, content) { | ||
89 | - switch (type) { | ||
90 | - // Gets executed before the built in logic performes it's cleanups | ||
91 | - case "before": | ||
92 | - //content = content.toLowerCase(); // Some dummy logic | ||
93 | - break; | ||
94 | - | ||
95 | - // Gets executed after the built in logic performes it's cleanups | ||
96 | - case "after": | ||
97 | - content = content.replace(/<!--\s*-->/, ''); | ||
98 | - break; | ||
99 | - } | ||
100 | - | ||
101 | - return content; | ||
102 | -} | ||
103 | - | ||
104 | </script> | 52 | </script> |
53 | + |
app/views/task_mailer/task_activated.text.erb
app/views/task_mailer/task_cancelled.text.erb
app/views/task_mailer/task_created.text.erb
app/views/task_mailer/task_finished.text.erb
config/application.rb
@@ -115,6 +115,12 @@ module Noosfero | @@ -115,6 +115,12 @@ module Noosfero | ||
115 | :key => '_noosfero_session', | 115 | :key => '_noosfero_session', |
116 | } | 116 | } |
117 | 117 | ||
118 | + config.time_zone = File.read('/etc/timezone').split("\n").first | ||
119 | + config.active_record.default_timezone = :local | ||
120 | + | ||
121 | + config.paths['db/migrate'] += Dir.glob "#{Rails.root}/{baseplugins,config/plugins}/*/db/migrate" | ||
122 | + config.i18n.load_path += Dir.glob "#{Rails.root}/{baseplugins,config/plugins}/*/locales/*.{rb,yml}" | ||
123 | + | ||
118 | Noosfero::Plugin.setup(config) | 124 | Noosfero::Plugin.setup(config) |
119 | 125 | ||
120 | end | 126 | end |
config/initializers/i18n.rb
1 | # necessary for I18n.default_locale to work | 1 | # necessary for I18n.default_locale to work |
2 | require 'i18n/backend/fallbacks' | 2 | require 'i18n/backend/fallbacks' |
3 | I18n.backend.class.send :include, I18n::Backend::Fallbacks | 3 | I18n.backend.class.send :include, I18n::Backend::Fallbacks |
4 | - | 4 | +I18n.enforce_available_locales = false |
db/migrate/20140708121356_index_articles_filtered_fields.rb
1 | class IndexArticlesFilteredFields < ActiveRecord::Migration | 1 | class IndexArticlesFilteredFields < ActiveRecord::Migration |
2 | def self.up | 2 | def self.up |
3 | %w[articles article_versions].each do |table| | 3 | %w[articles article_versions].each do |table| |
4 | - add_index table, [:path] | ||
5 | - add_index table, [:path, :profile_id] | 4 | + add_index table.to_sym, [:path] |
5 | + add_index table.to_sym, [:path, :profile_id] | ||
6 | end | 6 | end |
7 | add_index :articles, [:type] | 7 | add_index :articles, [:type] |
8 | add_index :articles, [:type, :parent_id] | 8 | add_index :articles, [:type, :parent_id] |
db/migrate/20140709212646_add_spam_comments_counter_cache_to_articles.rb
@@ -2,7 +2,10 @@ class AddSpamCommentsCounterCacheToArticles < ActiveRecord::Migration | @@ -2,7 +2,10 @@ class AddSpamCommentsCounterCacheToArticles < ActiveRecord::Migration | ||
2 | def self.up | 2 | def self.up |
3 | add_column :articles, :spam_comments_count, :integer, :default => 0 | 3 | add_column :articles, :spam_comments_count, :integer, :default => 0 |
4 | add_column :article_versions, :spam_comments_count, :integer, :default => 0 | 4 | add_column :article_versions, :spam_comments_count, :integer, :default => 0 |
5 | - execute "update articles set spam_comments_count = (select count(*) from comments where comments.source_id = articles.id and comments.source_type = 'Article' and comments.spam = 't');" | 5 | + |
6 | + execute("SELECT comments.source_id as source_id, count(comments.id) as comments_count FROM comments LEFT OUTER JOIN articles ON articles.id = source_id WHERE comments.source_type = 'Article' AND comments.spam = 't' GROUP BY comments.source_id;").each do |data| | ||
7 | + execute("UPDATE articles SET spam_comments_count = '#{data['comments_count']}' WHERE id = #{data['source_id']}") | ||
8 | + end | ||
6 | end | 9 | end |
7 | 10 | ||
8 | def self.down | 11 | def self.down |
db/migrate/20140709224246_create_real_relation_between_article_and_author.rb
@@ -4,8 +4,10 @@ class CreateRealRelationBetweenArticleAndAuthor < ActiveRecord::Migration | @@ -4,8 +4,10 @@ class CreateRealRelationBetweenArticleAndAuthor < ActiveRecord::Migration | ||
4 | add_column :article_versions, :author_id, :integer | 4 | add_column :article_versions, :author_id, :integer |
5 | 5 | ||
6 | # Set article's author as the first version's last_changed_by_id. | 6 | # Set article's author as the first version's last_changed_by_id. |
7 | - execute "update articles set author_id = (select article_versions.last_changed_by_id from article_versions where article_versions.article_id = articles.id and article_versions.version = 1 limit 1)" | ||
8 | - end | 7 | + execute("UPDATE article_versions SET author_id = last_changed_by_id") |
8 | + | ||
9 | + execute("UPDATE articles SET author_id = article_versions.author_id FROM article_versions WHERE article_versions.article_id = articles.id AND article_versions.version = 1") | ||
10 | + end | ||
9 | 11 | ||
10 | def self.down | 12 | def self.down |
11 | remove_column :articles, :author_id | 13 | remove_column :articles, :author_id |
db/migrate/20140724134601_fix_yaml_encoding.rb
1 | class FixYamlEncoding < ActiveRecord::Migration | 1 | class FixYamlEncoding < ActiveRecord::Migration |
2 | def self.up | 2 | def self.up |
3 | - fix_encoding(Block, 'settings') | ||
4 | - fix_encoding(Product, 'data') | ||
5 | - fix_encoding(Environment, 'settings') | ||
6 | - fix_encoding(Profile, 'data') | ||
7 | - fix_encoding(ActionTracker::Record, 'params') | ||
8 | - fix_encoding(Article, 'setting') | ||
9 | - fix_encoding(Task, 'data') | 3 | + ActiveRecord::Base.transaction do |
4 | + fix_encoding(Environment, 'settings') | ||
5 | + fix_encoding(Profile, 'data') | ||
6 | + fix_encoding(Product, 'data') | ||
7 | + fix_encoding(ActionTracker::Record, 'params') | ||
8 | + fix_encoding(Article, 'setting') | ||
9 | + fix_encoding(Task, 'data') | ||
10 | + fix_encoding(Block, 'settings') | ||
11 | + end | ||
10 | end | 12 | end |
11 | 13 | ||
12 | def self.down | 14 | def self.down |
@@ -16,15 +18,34 @@ class FixYamlEncoding < ActiveRecord::Migration | @@ -16,15 +18,34 @@ class FixYamlEncoding < ActiveRecord::Migration | ||
16 | private | 18 | private |
17 | 19 | ||
18 | def self.fix_encoding(model, param) | 20 | def self.fix_encoding(model, param) |
19 | - result = model.find(:all, :conditions => "#{param} LIKE '%!binary%'") | 21 | + result = model.all |
20 | puts "Fixing #{result.count} rows of #{model} (#{param})" | 22 | puts "Fixing #{result.count} rows of #{model} (#{param})" |
21 | - result.each {|r| r.update_column(param, deep_fix(r.send(param)).to_yaml)} | 23 | + result.each do |r| |
24 | + begin | ||
25 | + yaml = r.send(param) | ||
26 | + # if deserialization failed then a string is returned | ||
27 | + if yaml.is_a? String | ||
28 | + yaml.gsub! ': `', ': ' | ||
29 | + yaml = YAML.load yaml | ||
30 | + end | ||
31 | + r.update_column param, deep_fix(yaml).to_yaml | ||
32 | + rescue => e | ||
33 | + puts "FAILED #{r.inspect}" | ||
34 | + puts e.message | ||
35 | + end | ||
36 | + end | ||
22 | end | 37 | end |
23 | 38 | ||
24 | def self.deep_fix(hash) | 39 | def self.deep_fix(hash) |
25 | hash.each do |value| | 40 | hash.each do |value| |
26 | - value.force_encoding('UTF-8') if value.is_a?(String) && !value.frozen? && value.encoding == Encoding::ASCII_8BIT | ||
27 | deep_fix(value) if value.respond_to?(:each) | 41 | deep_fix(value) if value.respond_to?(:each) |
42 | + if value.is_a? String and not value.frozen? | ||
43 | + if value.encoding == Encoding::ASCII_8BIT | ||
44 | + value.force_encoding "utf-8" | ||
45 | + else | ||
46 | + value.encode!("iso-8859-1").force_encoding("utf-8") | ||
47 | + end | ||
48 | + end | ||
28 | end | 49 | end |
29 | end | 50 | end |
30 | 51 |
db/migrate/20140724180943_add_index_to_blog_posts_sort.rb
1 | class AddIndexToBlogPostsSort < ActiveRecord::Migration | 1 | class AddIndexToBlogPostsSort < ActiveRecord::Migration |
2 | def self.up | 2 | def self.up |
3 | %w[articles article_versions].each do |table| | 3 | %w[articles article_versions].each do |table| |
4 | - add_index table, [:published_at, :id] | 4 | + add_index table.to_sym, [:published_at, :id] |
5 | end | 5 | end |
6 | end | 6 | end |
7 | 7 | ||
8 | def self.down | 8 | def self.down |
9 | %w[articles article_versions].each do |table| | 9 | %w[articles article_versions].each do |table| |
10 | - remove_index table, [:published_at, :id] | 10 | + remove_index table.to_sym, [:published_at, :id] |
11 | end | 11 | end |
12 | end | 12 | end |
13 | end | 13 | end |
debian/bundle/config
debian/changelog
1 | +noosfero (1.0~rc4) wheezy-test; urgency=low | ||
2 | + | ||
3 | + * Fourth release candidate | ||
4 | + | ||
5 | + -- Antonio Terceiro <vagrant@wheezy-base> Wed, 19 Nov 2014 10:31:16 -0300 | ||
6 | + | ||
1 | noosfero (1.0~rc3) wheezy-test; urgency=low | 7 | noosfero (1.0~rc3) wheezy-test; urgency=low |
2 | 8 | ||
3 | * Third release candidate to Noosfero 1.0 | 9 | * Third release candidate to Noosfero 1.0 |
@@ -22,6 +28,12 @@ noosfero (0.99.0~rc20140618202455) wheezy-test; urgency=low | @@ -22,6 +28,12 @@ noosfero (0.99.0~rc20140618202455) wheezy-test; urgency=low | ||
22 | 28 | ||
23 | -- Rodrigo Souto <rodrigo@colivre.coop.br> Wed, 18 Jun 2014 20:25:01 +0000 | 29 | -- Rodrigo Souto <rodrigo@colivre.coop.br> Wed, 18 Jun 2014 20:25:01 +0000 |
24 | 30 | ||
31 | +noosfero (0.47.5) unstable; urgency=low | ||
32 | + | ||
33 | + * Bugfixes release | ||
34 | + | ||
35 | + -- Daniela Soares Feitosa <daniela@colivre.coop.br> Thu, 23 Oct 2014 02:24:14 +0000 | ||
36 | + | ||
25 | noosfero (0.47.4) unstable; urgency=low | 37 | noosfero (0.47.4) unstable; urgency=low |
26 | 38 | ||
27 | * Bugfixes and performance optimizations | 39 | * Bugfixes and performance optimizations |
debian/control
@@ -51,6 +51,7 @@ Depends: | @@ -51,6 +51,7 @@ Depends: | ||
51 | ruby-hpricot, | 51 | ruby-hpricot, |
52 | ruby-nokogiri, | 52 | ruby-nokogiri, |
53 | ruby-acts-as-taggable-on, | 53 | ruby-acts-as-taggable-on, |
54 | + ruby-progressbar, | ||
54 | ruby-prototype-rails, | 55 | ruby-prototype-rails, |
55 | ruby-rails-autolink, | 56 | ruby-rails-autolink, |
56 | memcached, | 57 | memcached, |
debian/noosfero.install
@@ -7,9 +7,6 @@ util usr/share/noosfero | @@ -7,9 +7,6 @@ util usr/share/noosfero | ||
7 | Rakefile usr/share/noosfero | 7 | Rakefile usr/share/noosfero |
8 | vendor usr/share/noosfero | 8 | vendor usr/share/noosfero |
9 | 9 | ||
10 | -Gemfile usr/share/noosfero | ||
11 | -debian/bundle/config usr/share/noosfero/.bundle | ||
12 | - | ||
13 | config/application.rb usr/share/noosfero/config | 10 | config/application.rb usr/share/noosfero/config |
14 | config/boot.rb usr/share/noosfero/config | 11 | config/boot.rb usr/share/noosfero/config |
15 | config/environment.rb usr/share/noosfero/config | 12 | config/environment.rb usr/share/noosfero/config |
debian/noosfero.links
@@ -15,4 +15,4 @@ var/lib/noosfero-data/public/thumbnails usr/share/noosfero/public/th | @@ -15,4 +15,4 @@ var/lib/noosfero-data/public/thumbnails usr/share/noosfero/public/th | ||
15 | usr/share/noosfero/public/designs/themes/noosfero usr/share/noosfero/public/designs/themes/default | 15 | usr/share/noosfero/public/designs/themes/noosfero usr/share/noosfero/public/designs/themes/default |
16 | usr/share/noosfero/public/designs/icons/tango usr/share/noosfero/public/designs/icons/default | 16 | usr/share/noosfero/public/designs/icons/tango usr/share/noosfero/public/designs/icons/default |
17 | usr/share/noosfero/script/noosfero-plugins usr/sbin/noosfero-plugins | 17 | usr/share/noosfero/script/noosfero-plugins usr/sbin/noosfero-plugins |
18 | -usr/share/noosfero/Gemfile.lock /dev/null | 18 | +/dev/null usr/share/noosfero/Gemfile.lock |
debian/rules
@@ -20,6 +20,10 @@ override_dh_link: | @@ -20,6 +20,10 @@ override_dh_link: | ||
20 | dh_link usr/lib/noosfero/dbinstall usr/share/dbconfig-common/scripts/noosfero/install/$$db; \ | 20 | dh_link usr/lib/noosfero/dbinstall usr/share/dbconfig-common/scripts/noosfero/install/$$db; \ |
21 | done | 21 | done |
22 | 22 | ||
23 | +override_dh_auto_install: | ||
24 | + dh_auto_install | ||
25 | + debian/filter-gemfile > $(CURDIR)/debian/noosfero/usr/share/noosfero/Gemfile | ||
26 | + | ||
23 | override_dh_installinit: | 27 | override_dh_installinit: |
24 | dh_installinit -pnoosfero --onlyscripts | 28 | dh_installinit -pnoosfero --onlyscripts |
25 | 29 |
etc/noosfero/varnish-accept-language.vcl
@@ -6,7 +6,14 @@ C{ | @@ -6,7 +6,14 @@ C{ | ||
6 | /* | 6 | /* |
7 | * Accept-language header normalization | 7 | * Accept-language header normalization |
8 | * | 8 | * |
9 | - * Cosimo, 21/01/2010 | 9 | + * - Parses client Accept-Language HTTP header |
10 | + * - Tries to find the best match with the supported languages | ||
11 | + * - Writes the best match as req.http.X-Varnish-Accept-Language | ||
12 | + * | ||
13 | + * First version: Cosimo, 21/Jan/2010 | ||
14 | + * Last update: Cosimo, 03/Nov/2011 | ||
15 | + * | ||
16 | + * http://github.com/cosimo/varnish-accept-language | ||
10 | * | 17 | * |
11 | */ | 18 | */ |
12 | 19 | ||
@@ -16,11 +23,12 @@ C{ | @@ -16,11 +23,12 @@ C{ | ||
16 | #include <string.h> | 23 | #include <string.h> |
17 | 24 | ||
18 | #define DEFAULT_LANGUAGE "en" | 25 | #define DEFAULT_LANGUAGE "en" |
19 | -#define SUPPORTED_LANGUAGES ":de:fr:es:ru:pt:hy:en:" | 26 | +#define SUPPORTED_LANGUAGES ":de:eo:es:fr:hy:it:pt:ru:" |
20 | 27 | ||
21 | #define vcl_string char | 28 | #define vcl_string char |
22 | -#define LANG_LIST_SIZE 16 | ||
23 | -#define LANG_MAXLEN 16 | 29 | +#define LANG_LIST_SIZE 16 |
30 | +#define HDR_MAXLEN 256 | ||
31 | +#define LANG_MAXLEN 8 | ||
24 | #define RETURN_LANG(x) { \ | 32 | #define RETURN_LANG(x) { \ |
25 | strncpy(lang, x, LANG_MAXLEN); \ | 33 | strncpy(lang, x, LANG_MAXLEN); \ |
26 | return; \ | 34 | return; \ |
@@ -64,9 +72,8 @@ int is_supported(vcl_string *lang) { | @@ -64,9 +72,8 @@ int is_supported(vcl_string *lang) { | ||
64 | strncat(match_str, lang, LANG_MAXLEN); | 72 | strncat(match_str, lang, LANG_MAXLEN); |
65 | strncat(match_str, ":\0", 2); | 73 | strncat(match_str, ":\0", 2); |
66 | 74 | ||
67 | - if (strstr(supported_languages, match_str)) { | 75 | + if (strstr(supported_languages, match_str)) |
68 | is_supported = 1; | 76 | is_supported = 1; |
69 | - } | ||
70 | 77 | ||
71 | return is_supported; | 78 | return is_supported; |
72 | } | 79 | } |
@@ -90,6 +97,7 @@ void select_language(const vcl_string *incoming_header, char *lang) { | @@ -90,6 +97,7 @@ void select_language(const vcl_string *incoming_header, char *lang) { | ||
90 | vcl_string *lang_tok = NULL; | 97 | vcl_string *lang_tok = NULL; |
91 | vcl_string root_lang[3]; | 98 | vcl_string root_lang[3]; |
92 | vcl_string *header; | 99 | vcl_string *header; |
100 | + vcl_string header_copy[HDR_MAXLEN]; | ||
93 | vcl_string *pos = NULL; | 101 | vcl_string *pos = NULL; |
94 | vcl_string *q_spec = NULL; | 102 | vcl_string *q_spec = NULL; |
95 | unsigned int curr_lang = 0, i = 0; | 103 | unsigned int curr_lang = 0, i = 0; |
@@ -106,7 +114,7 @@ void select_language(const vcl_string *incoming_header, char *lang) { | @@ -106,7 +114,7 @@ void select_language(const vcl_string *incoming_header, char *lang) { | ||
106 | RETURN_DEFAULT_LANG; | 114 | RETURN_DEFAULT_LANG; |
107 | 115 | ||
108 | /* Tokenize Accept-Language */ | 116 | /* Tokenize Accept-Language */ |
109 | - header = (vcl_string *) incoming_header; | 117 | + header = strncpy(header_copy, incoming_header, sizeof(header_copy)); |
110 | 118 | ||
111 | while ((lang_tok = strtok_r(header, " ,", &pos))) { | 119 | while ((lang_tok = strtok_r(header, " ,", &pos))) { |
112 | 120 | ||
@@ -137,7 +145,8 @@ void select_language(const vcl_string *incoming_header, char *lang) { | @@ -137,7 +145,8 @@ void select_language(const vcl_string *incoming_header, char *lang) { | ||
137 | header = NULL; | 145 | header = NULL; |
138 | 146 | ||
139 | /* Break out if stored max no. of languages */ | 147 | /* Break out if stored max no. of languages */ |
140 | - if (curr_lang >= LANG_MAXLEN) break; | 148 | + if (curr_lang >= LANG_LIST_SIZE) |
149 | + break; | ||
141 | } | 150 | } |
142 | 151 | ||
143 | /* Sort by priority */ | 152 | /* Sort by priority */ |
@@ -157,12 +166,11 @@ void vcl_rewrite_accept_language(const struct sess *sp) { | @@ -157,12 +166,11 @@ void vcl_rewrite_accept_language(const struct sess *sp) { | ||
157 | vcl_string *in_hdr; | 166 | vcl_string *in_hdr; |
158 | vcl_string lang[LANG_MAXLEN]; | 167 | vcl_string lang[LANG_MAXLEN]; |
159 | 168 | ||
160 | - memset(lang, 0, LANG_MAXLEN); | ||
161 | - | ||
162 | /* Get Accept-Language header from client */ | 169 | /* Get Accept-Language header from client */ |
163 | in_hdr = VRT_GetHdr(sp, HDR_REQ, "\020Accept-Language:"); | 170 | in_hdr = VRT_GetHdr(sp, HDR_REQ, "\020Accept-Language:"); |
164 | 171 | ||
165 | /* Normalize and filter out by list of supported languages */ | 172 | /* Normalize and filter out by list of supported languages */ |
173 | + memset(lang, 0, sizeof(lang)); | ||
166 | select_language(in_hdr, lang); | 174 | select_language(in_hdr, lang); |
167 | 175 | ||
168 | /* By default, use a different header name: don't mess with backend logic */ | 176 | /* By default, use a different header name: don't mess with backend logic */ |
@@ -191,3 +199,4 @@ sub vcl_fetch { | @@ -191,3 +199,4 @@ sub vcl_fetch { | ||
191 | set beresp.http.Vary = "X-Varnish-Accept-Language"; | 199 | set beresp.http.Vary = "X-Varnish-Accept-Language"; |
192 | } | 200 | } |
193 | } | 201 | } |
202 | + |
features/change_organization_name.feature
@@ -1,36 +0,0 @@ | @@ -1,36 +0,0 @@ | ||
1 | -Feature: change organization name | ||
2 | - As an organization's admin | ||
3 | - I want to change it's name | ||
4 | - In order to keep it's name consistent | ||
5 | - | ||
6 | - Scenario: changing community's name | ||
7 | - Given the following communities | ||
8 | - | identifier | name | | ||
9 | - | sample-community | Sample Community | | ||
10 | - And the following users | ||
11 | - | login | name | | ||
12 | - | joaosilva | Joao Silva | | ||
13 | - And "Joao Silva" is admin of "Sample Community" | ||
14 | - And I am logged in as "joaosilva" | ||
15 | - And I am on sample-community's control panel | ||
16 | - And I follow "Community Info and settings" | ||
17 | - And I fill in "Name" with "New Sample Community" | ||
18 | - When I press "Save" | ||
19 | - Then I should be on sample-community's control panel | ||
20 | - And I should see "New Sample Community" within "title" | ||
21 | - | ||
22 | - Scenario: changing enterprise's name | ||
23 | - Given the following enterprises | ||
24 | - | identifier | name | | ||
25 | - | sample-enterprise | Sample Enterprise | | ||
26 | - And the following users | ||
27 | - | login | name | | ||
28 | - | joaosilva | Joao Silva | | ||
29 | - And "Joao Silva" is admin of "Sample Enterprise" | ||
30 | - And I am logged in as "joaosilva" | ||
31 | - And I am on sample-enterprise's control panel | ||
32 | - And I follow "Enterprise Info and settings" | ||
33 | - And I fill in "Name" with "New Sample Enterprise" | ||
34 | - When I press "Save" | ||
35 | - Then I should be on sample-enterprise's control panel | ||
36 | - And I should see "New Sample Enterprise" within "title" |
features/chat.feature
@@ -1,145 +0,0 @@ | @@ -1,145 +0,0 @@ | ||
1 | -Feature: chat | ||
2 | - As a Noosfero user | ||
3 | - I want to chat with my friends | ||
4 | - | ||
5 | - Background: | ||
6 | - Given the following users | ||
7 | - | login | name | | ||
8 | - | tame | Tame | | ||
9 | - | mariasilva | Maria Silva | | ||
10 | - | josesilva | Jose Silva | | ||
11 | - And "tame" is online in chat | ||
12 | - And "mariasilva" is online in chat | ||
13 | - And "josesilva" is online in chat | ||
14 | - And "tame" is friend of "mariasilva" | ||
15 | - And "tame" is friend of "josesilva" | ||
16 | - | ||
17 | - @selenium | ||
18 | - Scenario: provide link to open chat | ||
19 | - Given feature "xmpp_chat" is enabled on environment | ||
20 | - And I am logged in as "tame" | ||
21 | - Then I should see "Open chat" within "#user" | ||
22 | - | ||
23 | - @selenium | ||
24 | - Scenario: provide the chat online users content | ||
25 | - Given feature "xmpp_chat" is enabled on environment | ||
26 | - And I am logged in as "tame" | ||
27 | - Then I should see "Friends in chat " | ||
28 | - | ||
29 | - @selenium | ||
30 | - Scenario: provide the chat online users list | ||
31 | - Given the profile "tame" has no blocks | ||
32 | - And feature "xmpp_chat" is enabled on environment | ||
33 | - And I am logged in as "tame" | ||
34 | - And I go to tame's profile | ||
35 | - When I follow "chat-online-users-title" | ||
36 | - Then I should see "Maria Silva" | ||
37 | - And I should see "Jose Silva" | ||
38 | - | ||
39 | - Scenario: not provide link to chat when environment not support that | ||
40 | - Given I am logged in as "tame" | ||
41 | - Then I should not see "Open chat" within "#user" | ||
42 | - | ||
43 | - Scenario: not provide link to chat when the user is logged out | ||
44 | - Given I am on tame's homepage | ||
45 | - Then I should not see "Open chat" within "#user" | ||
46 | - | ||
47 | - @selenium | ||
48 | - Scenario: not provide the chat online users list when environment not support that | ||
49 | - Given I am logged in as "tame" | ||
50 | - Then I should not see "Friends in chat " | ||
51 | - | ||
52 | - Scenario: block access to chat when environment not support that | ||
53 | - Given I am logged in as "tame" | ||
54 | - When I go to chat | ||
55 | - Then I should see "There is no such page" | ||
56 | - | ||
57 | - Scenario: block access to chat for guest users | ||
58 | - Given feature "xmpp_chat" is enabled on environment | ||
59 | - When I go to chat | ||
60 | - Then I should be on login page | ||
61 | - | ||
62 | - @selenium | ||
63 | - Scenario: open chat in a new window | ||
64 | - Given feature "xmpp_chat" is enabled on environment | ||
65 | - And I am logged in as "tame" | ||
66 | - When I follow "Open chat" | ||
67 | - And I select window "noosfero_chat" | ||
68 | - Then I should see "Chat - Colivre.net - Friends online (0)" | ||
69 | - | ||
70 | - @selenium | ||
71 | - Scenario: open chat with an online user in a new window | ||
72 | - Given the profile "tame" has no blocks | ||
73 | - And feature "xmpp_chat" is enabled on environment | ||
74 | - And I am logged in as "tame" | ||
75 | - And I go to tame's profile | ||
76 | - When I follow "chat-online-users-title" | ||
77 | - And I follow "Maria Silva" | ||
78 | - And I select window "noosfero_chat" | ||
79 | - Then I should see "Chat - Colivre.net - Friends online (0)" | ||
80 | - | ||
81 | - @selenium | ||
82 | - Scenario: chat starts disconnected by default | ||
83 | - Given feature "xmpp_chat" is enabled on environment | ||
84 | - And I am logged in as "tame" | ||
85 | - When I follow "Open chat" | ||
86 | - And I select window "noosfero_chat" | ||
87 | - Then I should see "Offline" within "a" | ||
88 | - | ||
89 | - @selenium | ||
90 | - Scenario: view options to change my chat status through menu | ||
91 | - Given feature "xmpp_chat" is enabled on environment | ||
92 | - And I am logged in as "tame" | ||
93 | - And I follow "Open chat" | ||
94 | - When I select window "noosfero_chat" | ||
95 | - Then "Online" should not be visible within "#user-status" | ||
96 | - And "Busy" should not be visible within "#user-status" | ||
97 | - And "Sign out of chat" should not be visible within "#user-status" | ||
98 | - When I follow "Offline" | ||
99 | - Then "Online" should be visible within "#user-status" | ||
100 | - And "Busy" should be visible within "#user-status" | ||
101 | - And "Sign out of chat" should be visible within "#user-status" | ||
102 | - | ||
103 | - @selenium | ||
104 | - Scenario: link to open chatroom of a community | ||
105 | - Given the following communities | ||
106 | - | identifier | name | | ||
107 | - | autoramas | Autoramas | | ||
108 | - And "Tame" is a member of "Autoramas" | ||
109 | - And feature "xmpp_chat" is enabled on environment | ||
110 | - And I am logged in as "tame" | ||
111 | - When I go to autoramas's profile | ||
112 | - Then I should see "Enter chat room" | ||
113 | - | ||
114 | - @selenium | ||
115 | - Scenario: not see link to open chatroom of a community if not a member | ||
116 | - Given the following communities | ||
117 | - | identifier | name | | ||
118 | - | autoramas | Autoramas | | ||
119 | - And feature "xmpp_chat" is enabled on environment | ||
120 | - And I am logged in as "tame" | ||
121 | - When I go to autoramas's profile | ||
122 | - Then I should not see "Enter chat room" within "a" | ||
123 | - | ||
124 | - @selenium | ||
125 | - Scenario: not see link to open chatroom of a community if xmpp_chat disabled | ||
126 | - Given the following communities | ||
127 | - | identifier | name | | ||
128 | - | autoramas | Autoramas | | ||
129 | - And "Tame" is a member of "Autoramas" | ||
130 | - And I am logged in as "tame" | ||
131 | - When I go to autoramas's profile | ||
132 | - Then I should not see "Enter chat room" within "a" | ||
133 | - | ||
134 | - @selenium | ||
135 | - Scenario: open chatroom of a community in a new window | ||
136 | - Given feature "xmpp_chat" is enabled on environment | ||
137 | - And the following communities | ||
138 | - | identifier | name | | ||
139 | - | autoramas | Autoramas | | ||
140 | - And "Tame" is a member of "Autoramas" | ||
141 | - And I am logged in as "tame" | ||
142 | - When I go to autoramas's profile | ||
143 | - And I follow "Enter chat room" | ||
144 | - And I select window "noosfero_chat" | ||
145 | - Then I should see "Chat - Colivre.net - Friends online (0)" |
features/edit_profile.feature
@@ -27,44 +27,3 @@ Feature: edit profile | @@ -27,44 +27,3 @@ Feature: edit profile | ||
27 | And I press "Save" | 27 | And I press "Save" |
28 | Then I should not see "Birth date is invalid" | 28 | Then I should not see "Birth date is invalid" |
29 | And I should not see "Birth date is mandatory" | 29 | And I should not see "Birth date is mandatory" |
30 | - | ||
31 | - @selenium | ||
32 | - Scenario: Alert about url change | ||
33 | - Given the following community | ||
34 | - | identifier | name | owner | | ||
35 | - | o-rappa | O Rappa | joao | | ||
36 | - And feature "enable_organization_url_change" is enabled on environment | ||
37 | - And I go to o-rappa's control panel | ||
38 | - When I follow "Community Info and settings" | ||
39 | - Then I should not see "WARNING" within "#identifier-change-confirmation" | ||
40 | - And I fill in "Address" with "banda-o-rappa" | ||
41 | - When I leave the "#profile_data_identifier" field | ||
42 | - Then I should see "WARNING" within "#identifier-change-confirmation" | ||
43 | - | ||
44 | - @selenium | ||
45 | - Scenario: Confirm url change | ||
46 | - Given the following community | ||
47 | - | identifier | name | owner | | ||
48 | - | o-rappa | O Rappa | joao | | ||
49 | - And feature "enable_organization_url_change" is enabled on environment | ||
50 | - And I go to o-rappa's control panel | ||
51 | - And I follow "Community Info and settings" | ||
52 | - And I fill in "Address" with "banda-o-rappa" | ||
53 | - When I leave the "#profile_data_identifier" field | ||
54 | - Then I should see "WARNING" within "#identifier-change-confirmation" | ||
55 | - When I follow "Yes" | ||
56 | - Then I should not see "WARNING" within "#identifier-change-confirmation" | ||
57 | - | ||
58 | - @selenium | ||
59 | - Scenario: Cancel url change | ||
60 | - Given the following community | ||
61 | - | identifier | name | owner | | ||
62 | - | o-rappa | O Rappa | joao | | ||
63 | - And feature "enable_organization_url_change" is enabled on environment | ||
64 | - And I go to o-rappa's control panel | ||
65 | - And I follow "Community Info and settings" | ||
66 | - And I fill in "Address" with "banda-o-rappa" | ||
67 | - When I leave the "#profile_data_identifier" field | ||
68 | - Then I should see "WARNING" within "#identifier-change-confirmation" | ||
69 | - When I follow "No" | ||
70 | - Then I should not see "WARNING" within "#identifier-change-confirmation" |
features/gallery_navigation.feature
@@ -1,86 +0,0 @@ | @@ -1,86 +0,0 @@ | ||
1 | -Feature: gallery_navigation | ||
2 | - As a noosfero user | ||
3 | - I want to navigate over image gallery | ||
4 | - | ||
5 | - Background: | ||
6 | - Given the following users | ||
7 | - | login | | ||
8 | - | marciopunk | | ||
9 | - And the following galleries | ||
10 | - | owner | name | | ||
11 | - | marciopunk | my-gallery | | ||
12 | - | marciopunk | other-gallery | | ||
13 | - And the following files | ||
14 | - | owner | file | mime | parent | | ||
15 | - | marciopunk | rails.png | image/png | my-gallery | | ||
16 | - | marciopunk | rails.png | image/png | other-gallery | | ||
17 | - | marciopunk | other-pic.jpg | image/jpeg | my-gallery | | ||
18 | - | ||
19 | - Scenario: provide link to go to next image | ||
20 | - Given I am on /marciopunk/my-gallery/other-pic.jpg?view=true | ||
21 | - Then I should see "Next »" | ||
22 | - | ||
23 | - @selenium | ||
24 | - Scenario: view next image when follow next link | ||
25 | - Given I am on /marciopunk/my-gallery/other-pic.jpg?view=true | ||
26 | - When I follow "Next »" | ||
27 | - Then I should see "rails.png" within ".title" | ||
28 | - | ||
29 | - Scenario: not link to next when in last image | ||
30 | - When I am on /marciopunk/my-gallery/rails.png?view=true | ||
31 | - Then I should see "« Previous" within ".gallery-navigation a" | ||
32 | - And I should not see "Next »" within ".gallery-navigation a" | ||
33 | - | ||
34 | - Scenario: provide link to go to previous image | ||
35 | - Given I am on /marciopunk/my-gallery/other-pic.jpg?view=true | ||
36 | - Then I should see "« Previous" | ||
37 | - | ||
38 | - @selenium | ||
39 | - Scenario: view previous image when follow previous link | ||
40 | - Given I am on /marciopunk/my-gallery/rails.png?view=true | ||
41 | - When I follow "« Previous" | ||
42 | - Then I should see "other-pic.jpg" within ".title" | ||
43 | - | ||
44 | - Scenario: not link to previous when in first image | ||
45 | - When I am on /marciopunk/my-gallery/other-pic.jpg?view=true | ||
46 | - Then I should see "Next »" within ".gallery-navigation a" | ||
47 | - And I should not see "« Previous" within ".gallery-navigation a" | ||
48 | - | ||
49 | - Scenario: display number of current and total of images | ||
50 | - Given I am on /marciopunk/my-gallery/other-pic.jpg?view=true | ||
51 | - Then I should see "image 1 of 2" within ".gallery-navigation" | ||
52 | - | ||
53 | - Scenario: increment current number when follow next | ||
54 | - Given I am on /marciopunk/my-gallery/other-pic.jpg?view=true | ||
55 | - Then I should see "image 1 of 2" within ".gallery-navigation" | ||
56 | - When I follow "Next »" | ||
57 | - Then I should see "image 2 of 2" within ".gallery-navigation" | ||
58 | - | ||
59 | - Scenario: decrement current number when follow next | ||
60 | - Given I am on /marciopunk/my-gallery/rails.png?view=true | ||
61 | - Then I should see "image 2 of 2" within ".gallery-navigation" | ||
62 | - When I follow "« Previous" | ||
63 | - Then I should see "image 1 of 2" within ".gallery-navigation" | ||
64 | - | ||
65 | - Scenario: provide button to go back to gallery | ||
66 | - Given I am on /marciopunk/my-gallery/rails.png?view=true | ||
67 | - Then I should see "Go back to my-gallery" | ||
68 | - When I follow "Go back to my-gallery" | ||
69 | - Then I should be on /marciopunk/my-gallery | ||
70 | - | ||
71 | - # Looking for page title is problematic on selenium since it considers the | ||
72 | - # title to be invibible. Checkout some information about this: | ||
73 | - # * https://github.com/jnicklas/capybara/issues/863 | ||
74 | - # * https://github.com/jnicklas/capybara/pull/953 | ||
75 | - @selenium | ||
76 | - Scenario: image title in window title | ||
77 | - Given I am logged in as "marciopunk" | ||
78 | - When I go to /marciopunk/other-gallery/rails.png?view=true | ||
79 | - Then I should see "rails.png" within any "h1" | ||
80 | -# And the page title should be "rails.png" | ||
81 | - And I follow "Edit" | ||
82 | - And I fill in "Title" with "Rails is cool" | ||
83 | - And I press "Save" | ||
84 | - When I go to /marciopunk/other-gallery/rails.png?view=true | ||
85 | - Then I should see "Rails is cool" within any "h1" | ||
86 | - #Then the page title should be "Rails is cool" |
features/gravatar_support.feature
@@ -20,11 +20,11 @@ Feature: Gravatar Support | @@ -20,11 +20,11 @@ Feature: Gravatar Support | ||
20 | Scenario: The Aurium's gravatar picture must link to his gravatar profile | 20 | Scenario: The Aurium's gravatar picture must link to his gravatar profile |
21 | # because Aurium has his picture registered at garvatar.com. | 21 | # because Aurium has his picture registered at garvatar.com. |
22 | When I go to article "My Article" | 22 | When I go to article "My Article" |
23 | - Then I should see "Aurium" linking to "http://www.gravatar.com/24a625896a07aa37fdb2352e302e96de" | 23 | + Then I should see "Aurium" linking to "//www.gravatar.com/24a625896a07aa37fdb2352e302e96de" |
24 | 24 | ||
25 | @selenium | 25 | @selenium |
26 | Scenario: The NoOne's gravatar picture must link to Gravatar homepage | 26 | Scenario: The NoOne's gravatar picture must link to Gravatar homepage |
27 | # because NoOne <nobody@colivre.coop.br> has no picture registered. | 27 | # because NoOne <nobody@colivre.coop.br> has no picture registered. |
28 | When I go to article "My Article" | 28 | When I go to article "My Article" |
29 | - Then I should see "NoOne" linking to "http://www.gravatar.com" | 29 | + Then I should see "NoOne" linking to "//www.gravatar.com" |
30 | 30 |
features/highlights_block.feature
@@ -1,44 +0,0 @@ | @@ -1,44 +0,0 @@ | ||
1 | -Feature: Edit Highlight Block | ||
2 | - As a user | ||
3 | - I want to edit the highlight block | ||
4 | - | ||
5 | - Background: | ||
6 | - Given I am on the homepage | ||
7 | - And the following users | ||
8 | - | login | name | | ||
9 | - | jose | Jose Silva | | ||
10 | - And I am logged in as "jose" | ||
11 | - | ||
12 | - @selenium | ||
13 | - Scenario: Add new highlight | ||
14 | - Given I follow "Control panel" | ||
15 | - And I follow "Edit sideboxes" | ||
16 | - And I follow "Add a block" | ||
17 | - And I choose "Highlights" | ||
18 | - And I press "Add" | ||
19 | - And I follow "Edit" within ".highlights-block"#Need to hover the mouse on the box | ||
20 | - And I follow "New highlight" | ||
21 | - And I fill in "block_images__address" with "/" | ||
22 | - And I fill in "block_images__position" with "0" | ||
23 | - And I fill in "block_images__title" with "test highlights" | ||
24 | - And I press "Save" | ||
25 | - And I follow "Edit" within ".highlights-block" | ||
26 | - Then I should see "Title" | ||
27 | - | ||
28 | - @selenium-fixme | ||
29 | - Scenario: Remove one saved highlight | ||
30 | - Given I follow "Control panel" | ||
31 | - And I follow "Edit sideboxes" | ||
32 | - And I follow "Add a block" | ||
33 | - And I choose "Highlights" | ||
34 | - And I press "Add" | ||
35 | - And I follow "Edit" within ".highlights-block" | ||
36 | - And I follow "New highlight" | ||
37 | - And I fill in "block_images__address" with "/" | ||
38 | - And I fill in "block_images__position" with "0" | ||
39 | - And I fill in "block_images__title" with "test highlights"#Need to hover the mouse on the box | ||
40 | - And I press "Save" | ||
41 | - And I follow "Edit" within ".highlights-block" | ||
42 | - And I follow "" within ".delete-highlight" | ||
43 | - And I confirm the browser dialog | ||
44 | - Then I should not see "Title" | ||
45 | \ No newline at end of file | 0 | \ No newline at end of file |
features/http_caching.feature
@@ -1,69 +0,0 @@ | @@ -1,69 +0,0 @@ | ||
1 | -Feature: HTTP caching | ||
2 | - | ||
3 | - As a sysdamin | ||
4 | - I want Noosfero to provide appropriate cache headers | ||
5 | - So that Varnish can serve content from the cache, everything works faster and everyone is happy | ||
6 | - | ||
7 | - Background: | ||
8 | - Given the following user | ||
9 | - | login | name | | ||
10 | - | joao | João Silva | | ||
11 | - | ||
12 | - Scenario: home page, default configuration | ||
13 | - When I go to the homepage | ||
14 | - Then the response should be valid for 5 minutes | ||
15 | - And the cache should be public | ||
16 | - | ||
17 | - Scenario: home page, custom configuration | ||
18 | - Given the following environment configuration | ||
19 | - | home_cache_in_minutes | 10 | | ||
20 | - When I go to the homepage | ||
21 | - Then the response should be valid for 10 minutes | ||
22 | - | ||
23 | - Scenario: search results, default configuration | ||
24 | - Given I am on the search page | ||
25 | - When I fill in "query" with "anything" | ||
26 | - And I press "Search" | ||
27 | - Then the response should be valid for 15 minutes | ||
28 | - | ||
29 | - Scenario: search results, custom configuration | ||
30 | - Given the following environment configuration | ||
31 | - | general_cache_in_minutes | 90 | | ||
32 | - When I go to the search page | ||
33 | - And I fill in "query" with "anything" | ||
34 | - And I press "Search" | ||
35 | - Then the response should be valid for 90 minutes | ||
36 | - | ||
37 | - Scenario: profile pages, default configuaration | ||
38 | - When I go to joao's homepage | ||
39 | - Then the response should be valid for 15 minutes | ||
40 | - | ||
41 | - Scenario: profile pages, custom configuration | ||
42 | - Given the following environment configuration | ||
43 | - | profile_cache_in_minutes | 90 | | ||
44 | - When I go to joao's homepage | ||
45 | - Then the response should be valid for 90 minutes | ||
46 | - | ||
47 | - Scenario: account controller should not be cached at all | ||
48 | - When I go to /account/login | ||
49 | - Then there must be no cache at all | ||
50 | - | ||
51 | - Scenario: profile administration | ||
52 | - Given I am logged in as "joao" | ||
53 | - When I go to joao's control panel | ||
54 | - Then there must be no cache at all | ||
55 | - | ||
56 | - Scenario: environment administration | ||
57 | - Given I am logged in as admin | ||
58 | - When I go to /admin | ||
59 | - Then there must be no cache at all | ||
60 | - | ||
61 | - Scenario: logged in user in the homepage | ||
62 | - Given I am logged in as "joao" | ||
63 | - When I go to the homepage | ||
64 | - Then there must be no cache at all | ||
65 | - | ||
66 | - Scenario: logged in user in a profile page | ||
67 | - Given I am logged in as "joao" | ||
68 | - When I go to /joao | ||
69 | - Then there must be no cache at all |
features/manage_inputs.feature
@@ -1,247 +0,0 @@ | @@ -1,247 +0,0 @@ | ||
1 | -Feature: manage inputs | ||
2 | - As an enterprise owner | ||
3 | - I want to manage my product's inputs | ||
4 | - | ||
5 | - Background: | ||
6 | - Given the following users | ||
7 | - | login | name | | ||
8 | - | joaosilva | Joao Silva | | ||
9 | - And the following enterprises | ||
10 | - | identifier | owner | name | enabled | | ||
11 | - | redemoinho | joaosilva | Rede Moinho | true | | ||
12 | - Given the following product_category | ||
13 | - | name | | ||
14 | - | Music | | ||
15 | - And the following product_categories | ||
16 | - | name | parent | | ||
17 | - | Rock | music | | ||
18 | - | CD Player | music | | ||
19 | - And the following product | ||
20 | - | owner | category | name | | ||
21 | - | redemoinho | rock | Abbey Road | | ||
22 | - And feature "products_for_enterprises" is enabled on environment | ||
23 | - And the following units | ||
24 | - | singular | plural | | ||
25 | - | Meter | Meters | | ||
26 | - | Litre | Litres | | ||
27 | - | ||
28 | - @selenium | ||
29 | - Scenario: add first input to a product | ||
30 | - Given I am logged in as "joaosilva" | ||
31 | - When I go to Rede Moinho's page of product Abbey Road | ||
32 | - And I follow "Inputs" | ||
33 | - Then I should not see "Add new input or raw material" | ||
34 | - And I follow "Add the inputs or raw material used by this product" | ||
35 | - And I select "Music »" from "category_id" within "#categories_container_level0" | ||
36 | - And I select "Rock" from "category_id" within "#categories_container_level1" | ||
37 | - And I press "Save and continue" | ||
38 | - Then I should see "Rock" | ||
39 | - | ||
40 | - @selenium | ||
41 | - Scenario: add input to a product that already has inputs | ||
42 | - Given the following input | ||
43 | - | product | category | | ||
44 | - | Abbey Road | music | | ||
45 | - And I am logged in as "joaosilva" | ||
46 | - When I go to Rede Moinho's page of product Abbey Road | ||
47 | - And I follow "Inputs" | ||
48 | - And I should not see "Add the inputs or raw material used by this product" | ||
49 | - And I follow "Add new input or raw material" | ||
50 | - And I select "Music »" from "category_id" within "#categories_container_level0" | ||
51 | - And I select "Rock" from "category_id" within "#categories_container_level1" | ||
52 | - And I press "Save and continue" | ||
53 | - Then I should see "Rock" | ||
54 | - | ||
55 | - @selenium | ||
56 | - Scenario: cancel addition of a product input | ||
57 | - Given I am logged in as "joaosilva" | ||
58 | - When I go to Rede Moinho's page of product Abbey Road | ||
59 | - And I follow "Inputs" | ||
60 | - And I follow "Add the inputs or raw material used by this product" | ||
61 | - And I should see "Cancel" within "#categories_selection_actionbar" | ||
62 | - And I follow "Cancel" within "#categories_selection_actionbar" | ||
63 | - Then I should see "Abbey Road" | ||
64 | - And I should see "Add the inputs or raw material used by this product" | ||
65 | - | ||
66 | - Scenario: show input name and link to add details | ||
67 | - Given the following input | ||
68 | - | product | category | | ||
69 | - | Abbey Road | music | | ||
70 | - And I am logged in as "joaosilva" | ||
71 | - When I go to Rede Moinho's page of product Abbey Road | ||
72 | - And I follow "Inputs and raw material" | ||
73 | - Then I should see "Music" within ".input-name" | ||
74 | - And I should see "Click here to add price and the amount used" | ||
75 | - | ||
76 | - Scenario: Not show input edit button when dont have details yet | ||
77 | - Given the following input | ||
78 | - | product | category | | ||
79 | - | Abbey Road | music | | ||
80 | - And I am logged in as "joaosilva" | ||
81 | - When I go to Rede Moinho's page of product Abbey Road | ||
82 | - And I follow "Inputs and raw material" | ||
83 | - Then I should not see "Edit" within ".input-item" | ||
84 | - | ||
85 | - Scenario: Show button to edit input | ||
86 | - Given the following input | ||
87 | - | product | category | price_per_unit | | ||
88 | - | Abbey Road | music | 10.0 | | ||
89 | - And I am logged in as "joaosilva" | ||
90 | - When I go to Rede Moinho's page of product Abbey Road | ||
91 | - And I follow "Inputs and raw material" | ||
92 | - Then I should see "Edit" within ".input-item" | ||
93 | - | ||
94 | - @selenium-fixme | ||
95 | - Scenario: Order inputs by position | ||
96 | - Given the following product_categories | ||
97 | - | name | | ||
98 | - | Instrumental | | ||
99 | - And the following inputs | ||
100 | - | product | category | position | | ||
101 | - | Abbey Road | Instrumental | 2 | | ||
102 | - | Abbey Road | Rock | 1 | | ||
103 | - | Abbey Road | CD Player | 3 | | ||
104 | - And I am logged in as "joaosilva" | ||
105 | - When I go to Rede Moinho's page of product Abbey Road | ||
106 | - And I follow "Inputs" | ||
107 | - Then I should see "Rock" above of "Instrumental" | ||
108 | - And I should see "Instrumental" above of "CD Player" | ||
109 | - | ||
110 | - @selenium | ||
111 | - Scenario: Save price of input | ||
112 | - Given the following input | ||
113 | - | product | category | | ||
114 | - | Abbey Road | music | | ||
115 | - And I am logged in as "joaosilva" | ||
116 | - When I go to Rede Moinho's page of product Abbey Road | ||
117 | - And I follow "Inputs" | ||
118 | - Then I should see "Music" | ||
119 | - When I follow "Click here to add price and the amount used" | ||
120 | - And I should see "Price" | ||
121 | - And I fill in "Price" with "10.50" | ||
122 | - And I press "Save" | ||
123 | - Then I should not see "Save" | ||
124 | - | ||
125 | - @selenium | ||
126 | - Scenario: Update label of input price with selected unit | ||
127 | - Given the following input | ||
128 | - | product | category | | ||
129 | - | Abbey Road | music | | ||
130 | - And I am logged in as "joaosilva" | ||
131 | - When I go to Rede Moinho's page of product Abbey Road | ||
132 | - And I follow "Inputs" | ||
133 | - And I follow "Click here to add price and the amount used" | ||
134 | - And I should not see "Price by Meter ($)" | ||
135 | - When I select "Meter" from "input_unit_id" within ".edit_input" | ||
136 | - Then I should see "Price by Meter ($)" | ||
137 | - | ||
138 | - @selenium | ||
139 | - Scenario: Save all price details of input | ||
140 | - Given the following input | ||
141 | - | product | category | | ||
142 | - | Abbey Road | music | | ||
143 | - And I am logged in as "joaosilva" | ||
144 | - When I go to Rede Moinho's page of product Abbey Road | ||
145 | - And I follow "Inputs" | ||
146 | - And I follow "Click here to add price and the amount used" | ||
147 | - And I fill in "Amount used" with "2.5" | ||
148 | - And I fill in "Price" with "11.50" | ||
149 | - And I select "Meter" from "input_unit_id" within ".edit_input" | ||
150 | - And I press "Save" | ||
151 | - Then I should see "2.5" | ||
152 | - And I should see "Meter" | ||
153 | - And I should not see "$ 11.50" | ||
154 | - | ||
155 | - @selenium | ||
156 | - Scenario: Save and then edit price details of input | ||
157 | - Given the following input | ||
158 | - | product | category | | ||
159 | - | Abbey Road | music | | ||
160 | - And I am logged in as "joaosilva" | ||
161 | - When I go to Rede Moinho's page of product Abbey Road | ||
162 | - And I follow "Inputs" | ||
163 | - And I follow "Click here to add price and the amount used" | ||
164 | - And I fill in "Amount used" with "2.5" | ||
165 | - And I fill in "Price" with "11.50" | ||
166 | - And I select "Meter" from "input_unit_id" within ".edit_input" | ||
167 | - And I press "Save" | ||
168 | - Then I should see "2.5" | ||
169 | - And I should see "Meter" | ||
170 | - When I follow "Edit" within ".input-details" | ||
171 | - And I fill in "Amount used" with "3.0" | ||
172 | - And I fill in "Price" with "23.31" | ||
173 | - And I select "Litre" from "input_unit_id" within ".edit_input" | ||
174 | - And I press "Save" | ||
175 | - Then I should see "3" | ||
176 | - And I should see "Litre" | ||
177 | - | ||
178 | - @selenium | ||
179 | - Scenario: Cancel edition of a input | ||
180 | - Given the following input | ||
181 | - | product | category | | ||
182 | - | Abbey Road | music | | ||
183 | - And I am logged in as "joaosilva" | ||
184 | - When I go to Rede Moinho's page of product Abbey Road | ||
185 | - And I follow "Inputs" | ||
186 | - And I follow "Click here to add price and the amount used" | ||
187 | - Then I should see "Cancel" | ||
188 | - And I should see "Amount used" | ||
189 | - And I should see "Price" | ||
190 | - And I should see "This input or raw material inpact on the final price of the product?" | ||
191 | - When I follow "Cancel" within ".edit_input" | ||
192 | - Then I should see "Click here to add price and the amount used" | ||
193 | - | ||
194 | - @selenium | ||
195 | - Scenario: Cancel edition of an input then edit again | ||
196 | - Given the following input | ||
197 | - | product | category | price_per_unit | unit | | ||
198 | - | Abbey Road | music | 10.0 | Meter | | ||
199 | - And I am logged in as "joaosilva" | ||
200 | - When I go to Rede Moinho's page of product Abbey Road | ||
201 | - And I follow "Inputs" | ||
202 | - And I follow "Edit" within ".input-details" | ||
203 | - And I should see "Cancel" within ".edit_input" | ||
204 | - And I follow "Cancel" within ".edit_input" | ||
205 | - And I follow "Edit" within ".input-details" | ||
206 | - Then I should see "Amount used" | ||
207 | - And I should see "Price by Meter" | ||
208 | - | ||
209 | - @selenium | ||
210 | - Scenario: remove input | ||
211 | - Given the following input | ||
212 | - | product | category | | ||
213 | - | Abbey Road | rock | | ||
214 | - And I am logged in as "joaosilva" | ||
215 | - And I go to Rede Moinho's page of product Abbey Road | ||
216 | - And I follow "Inputs" | ||
217 | - Then I should see "Rock" | ||
218 | - And I should not see "Add the inputs or raw material used by this product" | ||
219 | - When I follow "Remove" | ||
220 | - And I confirm the browser dialog | ||
221 | - Then I should see "Add the inputs or raw material used by this product" | ||
222 | - | ||
223 | - @selenium-fixme | ||
224 | - Scenario: Order input list | ||
225 | - Given the following product_category | ||
226 | - | name | | ||
227 | - | Movie | | ||
228 | - And the following product | ||
229 | - | owner | category | name | | ||
230 | - | redemoinho | Movie | Ramones | | ||
231 | - And the following inputs | ||
232 | - | product | category | | ||
233 | - | Ramones | Rock | | ||
234 | - | Ramones | Music | | ||
235 | - | Ramones | CD Player | | ||
236 | - And I am logged in as "joaosilva" | ||
237 | - When I go to Rede Moinho's page of product Ramones | ||
238 | - And I follow "Inputs" | ||
239 | - Then I should see "Rock" above of "Music" | ||
240 | - And I should see "Music" above of "CD Player" | ||
241 | - When I drag "Rock" to "Music" | ||
242 | - Then I should see "Music" above of "Rock" | ||
243 | - And I should see "Rock" above of "CD Player" | ||
244 | - When I follow "Back to the product listing" | ||
245 | - And I go to Rede Moinho's page of product Ramones | ||
246 | - Then I should see "Music" above of "Rock" | ||
247 | - And I should see "Rock" above of "CD Player" |
features/manage_product_price_details.feature
@@ -1,179 +0,0 @@ | @@ -1,179 +0,0 @@ | ||
1 | -Feature: manage product price details | ||
2 | - As an enterprise owner | ||
3 | - I want to manage the details of product's price | ||
4 | - | ||
5 | - Background: | ||
6 | - Given the following users | ||
7 | - | login | name | | ||
8 | - | joaosilva | Joao Silva | | ||
9 | - And the following enterprises | ||
10 | - | identifier | owner | name | enabled | | ||
11 | - | redemoinho | joaosilva | Rede Moinho | true | | ||
12 | - Given the following product_category | ||
13 | - | name | | ||
14 | - | Music | | ||
15 | - And the following product_categories | ||
16 | - | name | parent | | ||
17 | - | Rock | music | | ||
18 | - | CD Player | music | | ||
19 | - And the following product | ||
20 | - | owner | category | name | price | | ||
21 | - | redemoinho | rock | Abbey Road | 80.0 | | ||
22 | - And feature "products_for_enterprises" is enabled on environment | ||
23 | - And the following inputs | ||
24 | - | product | category | price_per_unit | amount_used | | ||
25 | - | Abbey Road | Rock | 10.0 | 2 | | ||
26 | - | Abbey Road | CD Player | 20.0 | 2 | | ||
27 | - And the following production cost | ||
28 | - | name | owner | | ||
29 | - | Taxes | environment | | ||
30 | - And I am logged in as "joaosilva" | ||
31 | - | ||
32 | - @selenium | ||
33 | - Scenario: list total value of inputs as price details | ||
34 | - Given I go to Rede Moinho's page of product Abbey Road | ||
35 | - And I follow "Price composition" | ||
36 | - And I follow "Describe here the cost of production" | ||
37 | - Then I should see "Inputs" | ||
38 | - And I should see "60.0" within ".inputs-cost" | ||
39 | - | ||
40 | - @selenium | ||
41 | - Scenario: return to product after save | ||
42 | - Given I go to Rede Moinho's page of product Abbey Road | ||
43 | - And I follow "Price composition" | ||
44 | - And I follow "Describe here the cost of production" | ||
45 | - And I press "Save" | ||
46 | - Then I should be on Rede Moinho's page of product Abbey Road | ||
47 | - | ||
48 | - @selenium | ||
49 | - Scenario: add first item on price details | ||
50 | - Given I go to Rede Moinho's page of product Abbey Road | ||
51 | - And I follow "Price composition" | ||
52 | - And I follow "Describe here the cost of production" | ||
53 | - And I follow "New cost" | ||
54 | - And I select "Taxes" from "price_details__production_cost_id" within "#display-product-price-details" | ||
55 | - And I fill in "$" with "5.00" | ||
56 | - And I leave the "#price_details__price" field | ||
57 | - And I press "Save" | ||
58 | - Then I should not see "Save" | ||
59 | - And I should see "Describe here the cost of production" | ||
60 | - | ||
61 | - @selenium | ||
62 | - Scenario: edit a production cost | ||
63 | - Given the following production cost | ||
64 | - | name | owner | | ||
65 | - | Energy | environment | | ||
66 | - When I go to Rede Moinho's page of product Abbey Road | ||
67 | - And I follow "Price composition" | ||
68 | - And I follow "Describe here the cost of production" | ||
69 | - And I follow "New cost" | ||
70 | - And I select "Taxes" from "price_details__production_cost_id" within "#display-product-price-details" | ||
71 | - And I fill in "$" with "20.00" | ||
72 | - And I leave the ".price-details-price" field | ||
73 | - And I press "Save" | ||
74 | - Then I should not see "Save" | ||
75 | - And I should see "Taxes" within "#display-price-details" | ||
76 | - When I follow "Describe here the cost of production" | ||
77 | - And I select "Energy" from "price_details__production_cost_id" within "#display-product-price-details" | ||
78 | - And I leave the "#price_details__price" field | ||
79 | - And I press "Save" | ||
80 | - And I should not see "Taxes" within "#display-price-details" | ||
81 | - And I should see "Energy" within "#display-price-details" | ||
82 | - | ||
83 | - Scenario: not display price composition if product does not have input | ||
84 | - Given the following product | ||
85 | - | owner | category | name | | ||
86 | - | redemoinho | rock | Yellow Submarine | | ||
87 | - And the following user | ||
88 | - | login | name | | ||
89 | - | mariasouza | Maria Souza | | ||
90 | - And I am logged in as "mariasouza" | ||
91 | - When I go to Rede Moinho's page of product Yellow Submarine | ||
92 | - Then I should not see "Price composition" | ||
93 | - | ||
94 | - Scenario: not display price composition if price is not fully described | ||
95 | - Given I am not logged in | ||
96 | - And I go to Rede Moinho's page of product Abbey Road | ||
97 | - Then I should not see "Price composition" | ||
98 | - | ||
99 | - @selenium | ||
100 | - Scenario: display price details if price is fully described | ||
101 | - Given I go to Rede Moinho's page of product Abbey Road | ||
102 | - And I follow "Price composition" | ||
103 | - And I follow "Describe here the cost of production" | ||
104 | - And I follow "New cost" | ||
105 | - And I select "Taxes" from "price_details__production_cost_id" within "#display-product-price-details" | ||
106 | - And I fill in "$" with "20.00" | ||
107 | - And I press "Save" | ||
108 | - And I go to Rede Moinho's page of product Abbey Road | ||
109 | - Then I should see "Inputs" within ".price-detail-name" | ||
110 | - And I should see "60.0" within ".price-detail-price" | ||
111 | - | ||
112 | - @selenium | ||
113 | - Scenario: create a new cost clicking on select | ||
114 | - Given I go to Rede Moinho's page of product Abbey Road | ||
115 | - And I follow "Price composition" | ||
116 | - And I follow "Describe here the cost of production" | ||
117 | - And I follow "New cost" | ||
118 | - And I select "Other cost" from "price_details__production_cost_id" within "#display-product-price-details" | ||
119 | - And I want to add "Energy" as cost | ||
120 | - And I fill in "$" with "10.00" | ||
121 | - And I leave the "#price_details__price" field | ||
122 | - And I press "Save" | ||
123 | - When I follow "Describe here the cost of production" | ||
124 | - Then I should see "Energy" within ".production-cost-selection" | ||
125 | - | ||
126 | - @selenium | ||
127 | - Scenario: add created cost on new-cost-fields | ||
128 | - Given I go to Rede Moinho's page of product Abbey Road | ||
129 | - And I follow "Price composition" | ||
130 | - And I follow "Describe here the cost of production" | ||
131 | - And I follow "New cost" | ||
132 | - And I select "Other cost" from "price_details__production_cost_id" within "#display-product-price-details" | ||
133 | - And I want to add "Energy" as cost | ||
134 | - Then I should see "Energy" within "#display-product-price-details" | ||
135 | - | ||
136 | - @selenium | ||
137 | - Scenario: remove price detail | ||
138 | - Given the following price detail | ||
139 | - | product | production_cost | price | | ||
140 | - | Abbey Road | Taxes | 20.0 | | ||
141 | - And I go to Rede Moinho's page of product Abbey Road | ||
142 | - And I follow "Price composition" | ||
143 | - And I follow "Describe here the cost of production" | ||
144 | - And I should see "Taxes" within "#manage-product-details-form" | ||
145 | - When I follow "Remove" within "#manage-product-details-form" | ||
146 | - And I confirm the browser dialog | ||
147 | - And I press "Save" | ||
148 | - And I follow "Describe here the cost of production" | ||
149 | - Then I should not see "Taxes" within "#manage-product-details-form" | ||
150 | - | ||
151 | - Scenario: display progressbar | ||
152 | - Given I go to Rede Moinho's page of product Abbey Road | ||
153 | - And I follow "Price composition" | ||
154 | - And I follow "Describe here the cost of production" | ||
155 | - Then I should see "$ 60.00 of $ 80.00" within "#progressbar-text" | ||
156 | - | ||
157 | - @selenium | ||
158 | - Scenario: update value on progressbar after addition of new cost | ||
159 | - Given I go to Rede Moinho's page of product Abbey Road | ||
160 | - And I follow "Price composition" | ||
161 | - And I follow "Describe here the cost of production" | ||
162 | - Then I should see "$ 60.00 of $ 80.00" within "#progressbar-text" | ||
163 | - And I follow "New cost" | ||
164 | - And I fill in "$" with "10.00" | ||
165 | - And I leave the "#price_details__price" field | ||
166 | - Then I should see "$ 70.00 of $ 80.00" within "#progressbar-text" | ||
167 | - | ||
168 | - @selenium | ||
169 | - Scenario: update value on progressbar after editing an input | ||
170 | - Given I go to Rede Moinho's page of product Abbey Road | ||
171 | - And I follow "Price composition" | ||
172 | - And I follow "Describe here the cost of production" | ||
173 | - Then I should see "$ 60.00 of $ 80.00" within "#progressbar-text" | ||
174 | - When I follow "Inputs" | ||
175 | - And I follow "Edit" within ".input-details" | ||
176 | - And I fill in "Price" with "23.31" | ||
177 | - And I press "Save" | ||
178 | - Then I follow "Price composition" | ||
179 | - And I should see "$ 86.62 of $ 80.00" within "#progressbar-text" |
features/manage_products.feature
@@ -1,520 +0,0 @@ | @@ -1,520 +0,0 @@ | ||
1 | -Feature: manage products | ||
2 | - As an enterprise owner | ||
3 | - I want to manage my products | ||
4 | - | ||
5 | - Background: | ||
6 | - Given the following users | ||
7 | - | login | name | | ||
8 | - | joaosilva | Joao Silva | | ||
9 | - And the following enterprises | ||
10 | - | identifier | owner | name | enabled | | ||
11 | - | redemoinho | joaosilva | Rede Moinho | true | | ||
12 | - And feature "products_for_enterprises" is enabled on environment | ||
13 | - | ||
14 | - Scenario: display "create new product" button | ||
15 | - Given I am logged in as "joaosilva" | ||
16 | - And I am on redemoinho's control panel | ||
17 | - When I follow "Manage Products/Services" | ||
18 | - Then I should see "New product or service" | ||
19 | - | ||
20 | - Scenario: paginate public listing products and services | ||
21 | - Given the following product_category | ||
22 | - | name | | ||
23 | - | Bicycle | | ||
24 | - And the following products | ||
25 | - | owner | category | name | description | created_at | | ||
26 | - | redemoinho | bicycle | Bike A | bicycle 1 | 2014-04-01 01:00:00 | | ||
27 | - | redemoinho | bicycle | Bike B | bicycle 2 | 2014-04-01 02:00:00 | | ||
28 | - | redemoinho | bicycle | Bike C | bicycle 3 | 2014-04-01 03:00:00 | | ||
29 | - | redemoinho | bicycle | Bike D | bicycle 4 | 2014-04-01 04:00:00 | | ||
30 | - | redemoinho | bicycle | Bike E | bicycle 5 | 2014-04-01 05:00:00 | | ||
31 | - | redemoinho | bicycle | Bike F | bicycle 6 | 2014-04-01 06:00:00 | | ||
32 | - | redemoinho | bicycle | Bike G | bicycle 7 | 2014-04-01 07:00:00 | | ||
33 | - | redemoinho | bicycle | Bike H | bicycle 8 | 2014-04-01 08:00:00 | | ||
34 | - | redemoinho | bicycle | Bike I | bicycle 9 | 2014-04-01 09:00:00 | | ||
35 | - | redemoinho | bicycle | Bike J | bicycle 10 | 2014-04-01 10:00:00 | | ||
36 | - | redemoinho | bicycle | Bike K | bicycle 11 | 2014-04-01 11:00:00 | | ||
37 | - When I go to redemoinho's products page | ||
38 | - Then I should see "Bike A" within "#product-list" | ||
39 | - And I should see "Bike B" within "#product-list" | ||
40 | - And I should see "Bike C" within "#product-list" | ||
41 | - And I should see "Bike D" within "#product-list" | ||
42 | - And I should see "Bike E" within "#product-list" | ||
43 | - And I should see "Bike F" within "#product-list" | ||
44 | - And I should not see "Bike G" within "#product-list" | ||
45 | - And I should not see "Bike H" within "#product-list" | ||
46 | - And I should not see "Bike I" within "#product-list" | ||
47 | - And I should not see "Bike J" within "#product-list" | ||
48 | - And I should not see "Bike K" within "#product-list" | ||
49 | - When I follow "Next" | ||
50 | - Then I should see "Bike G" within "#product-list" | ||
51 | - Then I should see "Bike H" within "#product-list" | ||
52 | - Then I should see "Bike I" within "#product-list" | ||
53 | - Then I should see "Bike J" within "#product-list" | ||
54 | - Then I should see "Bike K" within "#product-list" | ||
55 | - | ||
56 | - Scenario: listing products and services | ||
57 | - Given I am logged in as "joaosilva" | ||
58 | - And I am on redemoinho's control panel | ||
59 | - And I follow "Manage Products/Services" | ||
60 | - Then I should see "Listing products and services" | ||
61 | - | ||
62 | - Scenario: see button to back in categories hierarchy | ||
63 | - Given I am logged in as "joaosilva" | ||
64 | - And I am on redemoinho's control panel | ||
65 | - And I follow "Manage Products/Services" | ||
66 | - When I follow "New product or service" | ||
67 | - Then I should see "Back to the product listing" link | ||
68 | - | ||
69 | - Scenario: see toplevel categories | ||
70 | - Given the following product_categories | ||
71 | - | name | | ||
72 | - | Products | | ||
73 | - | Services | | ||
74 | - Given I am logged in as "joaosilva" | ||
75 | - And I go to redemoinho's new product page | ||
76 | - Then I should see "Products" | ||
77 | - And I should see "Service" | ||
78 | - | ||
79 | - @selenium | ||
80 | - Scenario: select a toplevel category and see subcategories | ||
81 | - Given the following product_categories | ||
82 | - | name | | ||
83 | - | Products level0 | | ||
84 | - And the following product_categories | ||
85 | - | name | parent | | ||
86 | - | Computers level1 | products-level0 | | ||
87 | - | DVDs level1 | products-level0 | | ||
88 | - Given I am logged in as "joaosilva" | ||
89 | - And I go to redemoinho's new product page | ||
90 | - And I select "Products level0 »" from "category_id" within "#categories_container_level0" | ||
91 | - Then I should see "Computers level1" | ||
92 | - And I should see "DVDs level1" | ||
93 | - | ||
94 | - @selenium | ||
95 | - Scenario: hide subcategories when select other toplevel category | ||
96 | - Given the following product_categories | ||
97 | - | name | | ||
98 | - | Products level0 | | ||
99 | - | Services level0 | | ||
100 | - And the following product_categories | ||
101 | - | name | parent | | ||
102 | - | Computers level1 | products-level0 | | ||
103 | - | Software development level1 | services-level0 | | ||
104 | - Given I am logged in as "joaosilva" | ||
105 | - And I go to redemoinho's new product page | ||
106 | - And I should not see /Computers level/ | ||
107 | - And I select "Products level0 »" from "category_id" within "#categories_container_wrapper" | ||
108 | - And I should see /Computers level/ | ||
109 | - And I should not see /Software develop/ | ||
110 | - And I select "Services level0 »" from "category_id" within "#categories_container_wrapper" | ||
111 | - Then I should see /Software develop/ | ||
112 | - And I should not see /Computers level/ | ||
113 | - | ||
114 | - @selenium | ||
115 | - Scenario: show hierarchy of categories | ||
116 | - Given the following product_categories | ||
117 | - | name | | ||
118 | - | Products | | ||
119 | - And the following product_category | ||
120 | - | name | parent | | ||
121 | - | Computers | products | | ||
122 | - Given I am logged in as "joaosilva" | ||
123 | - And I go to redemoinho's new product page | ||
124 | - And I select "Products »" from "category_id" within "#categories_container_level0" | ||
125 | - And I select "Computers" from "category_id" within "#categories_container_level1" | ||
126 | - Then I should see "Products → Computers" | ||
127 | - | ||
128 | - @selenium | ||
129 | - Scenario: show links in hierarchy of categories and not link current category | ||
130 | - Given the following product_category | ||
131 | - | name | | ||
132 | - | Toplevel Product Categories | | ||
133 | - Given the following product_category | ||
134 | - | name | parent | | ||
135 | - | Category Level 1 | toplevel-product-categories | | ||
136 | - Given I am logged in as "joaosilva" | ||
137 | - And I go to redemoinho's new product page | ||
138 | - And I select "Toplevel Product Categories »" from "category_id" within "#categories_container_level0" | ||
139 | - And I select "Category Level 1" from "category_id" within "#categories_container_level1" | ||
140 | - Then I should see "Toplevel Product Categories" link | ||
141 | - And I should not see "Category Level 1" link | ||
142 | - | ||
143 | - @selenium | ||
144 | - Scenario: save button come initialy disabled | ||
145 | - Given the following product_category | ||
146 | - | name | | ||
147 | - | Only for test | | ||
148 | - And I am logged in as "joaosilva" | ||
149 | - When I go to redemoinho's new product page | ||
150 | - Then the "#save_and_continue" button should be disabled | ||
151 | - | ||
152 | - @selenium | ||
153 | - Scenario: enable save button when select one category | ||
154 | - Given I am logged in as "joaosilva" | ||
155 | - And the following product_category | ||
156 | - | name | | ||
157 | - | Browsers (accept categories) | | ||
158 | - When I go to redemoinho's new product page | ||
159 | - And I select "Browsers (accept categories)" from "category_id" within "#categories_container_wrapper" | ||
160 | - Then the "#save_and_continue" button should be enabled | ||
161 | - | ||
162 | - @selenium | ||
163 | - Scenario: dont enable save button when select category with not accept products | ||
164 | - Given the following product_category | ||
165 | - | name | accept_products | | ||
166 | - | Browsers | false | | ||
167 | - Given I am logged in as "joaosilva" | ||
168 | - When I go to redemoinho's new product page | ||
169 | - And I select "Browsers" from "category_id" within "#categories_container_wrapper" | ||
170 | - Then the "#save_and_continue" button should be disabled | ||
171 | - | ||
172 | - @selenium | ||
173 | - Scenario: save product | ||
174 | - Given the following product_category | ||
175 | - | name | | ||
176 | - | Bicycle | | ||
177 | - Given I am logged in as "joaosilva" | ||
178 | - When I go to redemoinho's new product page | ||
179 | - And I select "Bicycle" from "category_id" within "#categories_container_wrapper" | ||
180 | - And I press "Save and continue" | ||
181 | - When I go to redemoinho's products page | ||
182 | - And I follow "Bicycle" within "#product-list" | ||
183 | - Then I should see "Bicycle" within "#show_product" | ||
184 | - And I should see "Change category" | ||
185 | - | ||
186 | - Scenario: a user with permission can see edit links | ||
187 | - Given the following product_category | ||
188 | - | name | | ||
189 | - | Bicycle | | ||
190 | - And the following products | ||
191 | - | owner | category | name | description | | ||
192 | - | redemoinho | bicycle | Bike | Red bicycle | | ||
193 | - And I am logged in as "joaosilva" | ||
194 | - When I go to Rede Moinho's page of product Bike | ||
195 | - Then I should see "Change category" | ||
196 | - And I should see "Edit name" | ||
197 | - And I should see "Edit description" | ||
198 | - And I should see "Change image" | ||
199 | - | ||
200 | - Scenario: an allowed user will see a different button when has no description | ||
201 | - Given the following product_category | ||
202 | - | name | | ||
203 | - | Bicycle | | ||
204 | - And the following products | ||
205 | - | owner | category | name | | ||
206 | - | redemoinho | bicycle | Bike | | ||
207 | - And I am logged in as "joaosilva" | ||
208 | - When I go to Rede Moinho's page of product Bike | ||
209 | - Then I should see "Change category" | ||
210 | - And I should see "Edit name" | ||
211 | - And I should see "Add some description to your product" | ||
212 | - And I should see "Add price and other basic information" | ||
213 | - And I should see "Change image" | ||
214 | - | ||
215 | - Scenario: an allowed user will see a different button when has no basic info | ||
216 | - Given the following product_category | ||
217 | - | name | | ||
218 | - | Bicycle | | ||
219 | - And the following products | ||
220 | - | owner | category | name | | ||
221 | - | redemoinho | bicycle | Bike | | ||
222 | - And I am logged in as "joaosilva" | ||
223 | - When I go to Rede Moinho's page of product Bike | ||
224 | - Then I should see "Change category" | ||
225 | - And I should see "Edit name" | ||
226 | - And I should see "Add price and other basic information" | ||
227 | - And I should see "Change image" | ||
228 | - | ||
229 | - Scenario: a not logged user cannot see edit links | ||
230 | - Given I am not logged in | ||
231 | - And the following product_category | ||
232 | - | name | | ||
233 | - | Bicycle | | ||
234 | - And the following products | ||
235 | - | owner | category | name | description | | ||
236 | - | redemoinho | bicycle | Bike | Red bicycle | | ||
237 | - When I go to Rede Moinho's page of product Bike | ||
238 | - Then I should not see "Change category" | ||
239 | - And I should not see "Edit name" | ||
240 | - And I should not see "Edit description" | ||
241 | - And I should not see "Edit basic information" | ||
242 | - And I should not see "Change image" | ||
243 | - | ||
244 | - Scenario: a not allowed user cannot see edit links | ||
245 | - Given the following users | ||
246 | - | login | name | | ||
247 | - | mariasantos | Maria Santos | | ||
248 | - And the following product_category | ||
249 | - | name | | ||
250 | - | Bicycle | | ||
251 | - And the following products | ||
252 | - | owner | category | name | description | | ||
253 | - | redemoinho | bicycle | Bike | Red bicycle | | ||
254 | - And I am logged in as "mariasantos" | ||
255 | - When I go to Rede Moinho's page of product Bike | ||
256 | - Then I should not see "Change category" | ||
257 | - And I should not see "Edit name" | ||
258 | - And I should not see "Edit description" | ||
259 | - And I should not see "Edit basic information" | ||
260 | - And I should not see "Change image" | ||
261 | - | ||
262 | - @selenium | ||
263 | - Scenario: edit name of a product | ||
264 | - Given the following product_category | ||
265 | - | name | | ||
266 | - | Bicycle | | ||
267 | - And the following products | ||
268 | - | owner | category | name | | ||
269 | - | redemoinho | bicycle | Bike | | ||
270 | - And I am logged in as "joaosilva" | ||
271 | - When I go to Rede Moinho's page of product Bike | ||
272 | - And I follow "Edit name" | ||
273 | - And I fill in "Red bicycle" for "product_name" | ||
274 | - And I press "Save" | ||
275 | - Then I should see "Red bicycle" | ||
276 | - And I should be on Rede Moinho's page of product Red bicycle | ||
277 | - | ||
278 | - @selenium | ||
279 | - Scenario: cancel edition of a product name | ||
280 | - Given the following product_category | ||
281 | - | name | | ||
282 | - | Bicycle | | ||
283 | - And the following products | ||
284 | - | owner | category | name | | ||
285 | - | redemoinho | bicycle | Bike | | ||
286 | - And I am logged in as "joaosilva" | ||
287 | - When I go to Rede Moinho's page of product Bike | ||
288 | - And I follow "Edit name" | ||
289 | - When I follow "Cancel" | ||
290 | - Then I should see "Bike" | ||
291 | - | ||
292 | - @selenium | ||
293 | - Scenario: edit category of a product | ||
294 | - Given the following product_category | ||
295 | - | name | | ||
296 | - | Eletronics | | ||
297 | - And the following product_categories | ||
298 | - | name | parent | | ||
299 | - | Computers | eletronics | | ||
300 | - | DVDs | eletronics | | ||
301 | - And the following products | ||
302 | - | owner | category | name | | ||
303 | - | redemoinho | computers | Generic pc | | ||
304 | - And I am logged in as "joaosilva" | ||
305 | - When I go to Rede Moinho's page of product Generic pc | ||
306 | - And I follow "Change category" | ||
307 | - And I select "Eletronics »" from "category_id" within "#categories_container_level0" | ||
308 | - Then I select "DVDs" from "category_id" within "#categories_container_level1" | ||
309 | - And I press "Save and continue" | ||
310 | - When I go to Rede Moinho's page of product Generic pc | ||
311 | - Then I should see "Eletronics → DVDs" within ".hierarchy-category" | ||
312 | - | ||
313 | - @selenium | ||
314 | - Scenario: cancel edition of a product category | ||
315 | - Given the following product_category | ||
316 | - | name | | ||
317 | - | Eletronics | | ||
318 | - And the following product_categories | ||
319 | - | name | parent | | ||
320 | - | Computers | eletronics | | ||
321 | - | DVDs | eletronics | | ||
322 | - And the following products | ||
323 | - | owner | category | name | | ||
324 | - | redemoinho | computers | Generic pc | | ||
325 | - And I am logged in as "joaosilva" | ||
326 | - When I go to Rede Moinho's page of product Generic pc | ||
327 | - And I follow "Change category" | ||
328 | - When I follow "Back to product" | ||
329 | - Then I should see "Eletronics → Computers" | ||
330 | - | ||
331 | - | ||
332 | - @selenium | ||
333 | - Scenario: edit image of a product | ||
334 | - Given the following product_category | ||
335 | - | name | | ||
336 | - | Eletronics | | ||
337 | - And the following product_categories | ||
338 | - | name | parent | | ||
339 | - | Computers | eletronics | | ||
340 | - | DVDs | eletronics | | ||
341 | - And the following products | ||
342 | - | owner | category | name | | ||
343 | - | redemoinho | computers | Generic pc | | ||
344 | - And I am logged in as "joaosilva" | ||
345 | - When I go to Rede Moinho's page of product Generic pc | ||
346 | - And I follow "Change image" | ||
347 | - When I follow "Cancel" | ||
348 | - Then I should be on Rede Moinho's page of product Generic pc | ||
349 | - | ||
350 | - # FIXME Not working because of tinyMCE plus selenium | ||
351 | - # @selenium | ||
352 | - # Scenario: edit description of a product | ||
353 | - # Given the following product_category | ||
354 | - # | name | | ||
355 | - # | Bicycle | | ||
356 | - # And the following products | ||
357 | - # | owner | category | name | description | | ||
358 | - # | redemoinho | bicycle | Bike | A new red bicycle | | ||
359 | - # And I am logged in as "joaosilva" | ||
360 | - # When I go to Rede Moinho's page of product Bike | ||
361 | - # Then I should see "A new red bicycle" | ||
362 | - # And I follow "Edit basic information" | ||
363 | - # And I type in tinyMCE field "Description" the text "An used red bicycle" | ||
364 | - # And I press "Save" | ||
365 | - # Then I should not see "A new red bicycle" | ||
366 | - # And I should see "An used red bicycle" | ||
367 | - # And I should be on Rede Moinho's page of product Bike | ||
368 | - | ||
369 | - @selenium | ||
370 | - Scenario: cancel edition of a product description | ||
371 | - Given the following product_category | ||
372 | - | name | | ||
373 | - | Bicycle | | ||
374 | - And the following products | ||
375 | - | owner | category | name | description | | ||
376 | - | redemoinho | bicycle | Bike | A new red bicycle | | ||
377 | - And I am logged in as "joaosilva" | ||
378 | - When I go to Rede Moinho's page of product Bike | ||
379 | - Then I should see "A new red bicycle" | ||
380 | - And I follow "Edit description" | ||
381 | - When I follow "Cancel" | ||
382 | - Then I should see "A new red bicycle" | ||
383 | - And I should be on Rede Moinho's page of product Bike | ||
384 | - | ||
385 | - @selenium | ||
386 | - Scenario: Edit product category and save without select any category | ||
387 | - Given the following product_category | ||
388 | - | name | | ||
389 | - | Eletronics | | ||
390 | - And the following product_category | ||
391 | - | name | parent | | ||
392 | - | Computers | eletronics | | ||
393 | - And the following products | ||
394 | - | owner | category | name | | ||
395 | - | redemoinho | computers | Generic pc | | ||
396 | - And I am logged in as "joaosilva" | ||
397 | - When I go to Rede Moinho's page of product Generic pc | ||
398 | - And I follow "Change category" | ||
399 | - And I press "Save and continue" | ||
400 | - Then I should not see "Product category can't be blank" | ||
401 | - When I go to Rede Moinho's page of product Generic pc | ||
402 | - Then I should see "Eletronics → Computers" within ".hierarchy-category" | ||
403 | - | ||
404 | - And I should see "Generic pc" | ||
405 | - | ||
406 | - @selenium | ||
407 | - Scenario: Scroll categories selection to right when editing | ||
408 | - Given the following product_category | ||
409 | - | name | | ||
410 | - | Eletronics | | ||
411 | - And the following product_category | ||
412 | - | name | parent | | ||
413 | - | Quantum Computers | eletronics | | ||
414 | - And the following product_category | ||
415 | - | name | parent | | ||
416 | - | Laptops from Mars | Quantum Computers | | ||
417 | - And the following product_category | ||
418 | - | name | parent | | ||
419 | - | Netbook from Venus | Laptops from Mars | | ||
420 | - And the following product_category | ||
421 | - | name | parent | | ||
422 | - | Nanonote nanotech with long name | Netbook from Venus | | ||
423 | - And the following products | ||
424 | - | owner | category | name | | ||
425 | - | redemoinho | Nanonote nanotech with long name | Generic pc | | ||
426 | - And I am logged in as "joaosilva" | ||
427 | - When I go to Rede Moinho's page of product Generic pc | ||
428 | - And I follow "Change category" | ||
429 | - Then "Netbook from Venus" should be visible within "#categories_container_wrapper" | ||
430 | - | ||
431 | - @selenium | ||
432 | - Scenario: Truncate long category name in selection of category | ||
433 | - Given the following product_category | ||
434 | - | name | | ||
435 | - | Super Quantum Computers with teraflops | | ||
436 | - | Nanonote nanotech with long long name | | ||
437 | - And the following product_category | ||
438 | - | name | parent | | ||
439 | - | Netbook Quantum | Super Quantum Computers with teraflops | | ||
440 | - And I am logged in as "joaosilva" | ||
441 | - When I go to redemoinho's new product page | ||
442 | - Then I should see "Nanonote nanotech with long lo..." | ||
443 | - And I should see "Super Quantum Computers with t... »" | ||
444 | - | ||
445 | - @selenium | ||
446 | - Scenario: Edit unit of a product together your name | ||
447 | - Given the following product_category | ||
448 | - | name | | ||
449 | - | Bicycle | | ||
450 | - And the following products | ||
451 | - | owner | category | name | | ||
452 | - | redemoinho | bicycle | Bike | | ||
453 | - And the following units | ||
454 | - | singular | plural | | ||
455 | - | Kilo | Kilos | | ||
456 | - And I am logged in as "joaosilva" | ||
457 | - When I go to Rede Moinho's page of product Bike | ||
458 | - And I follow "Edit name and unit" | ||
459 | - And I fill in "Red bicycle" for "product_name" | ||
460 | - And I select "Kilo" from "product_unit_id" within "#product-name-form" | ||
461 | - And I press "Save" | ||
462 | - Then I should see "Red bicycle - kilo" | ||
463 | - | ||
464 | - @selenium | ||
465 | - Scenario: Show info about unavailable product | ||
466 | - Given the following product_category | ||
467 | - | name | | ||
468 | - | Bicycle | | ||
469 | - And the following products | ||
470 | - | owner | category | name | | ||
471 | - | redemoinho | bicycle | Bike | | ||
472 | - And I am logged in as "joaosilva" | ||
473 | - When I go to Rede Moinho's page of product Bike | ||
474 | - And I follow "Add price and other basic information" | ||
475 | - And I fill in "10" for "product_price" | ||
476 | - And I choose "No" | ||
477 | - And I press "Save" | ||
478 | - Then I should see "Product not available!" | ||
479 | - | ||
480 | - @selenium | ||
481 | - Scenario: Add and remove some qualifiers | ||
482 | - Given the following product_category | ||
483 | - | name | | ||
484 | - | Bicycle | | ||
485 | - And the following products | ||
486 | - | owner | category | name | | ||
487 | - | redemoinho | bicycle | Bike | | ||
488 | - And the following qualifiers | ||
489 | - | name | | ||
490 | - | Organic | | ||
491 | - And the following certifiers | ||
492 | - | name | qualifiers | | ||
493 | - | Colivre | Organic | | ||
494 | - And I am logged in as "joaosilva" | ||
495 | - When I go to Rede Moinho's page of product Bike | ||
496 | - And I follow "Add price and other basic information" | ||
497 | - And I follow "Add new qualifier" | ||
498 | - And I select "Organic" from "selected_qualifier" within "#product-qualifiers-list" | ||
499 | - And I press "Save" | ||
500 | - And I go to Rede Moinho's page of product Bike | ||
501 | - Then I should see "Organic (Self declared)" | ||
502 | - When I follow "Edit basic information" | ||
503 | - And I follow "Delete qualifier" | ||
504 | - And I press "Save" | ||
505 | - And I go to Rede Moinho's page of product Bike | ||
506 | - Then I should not see "Organic (Self declared)" | ||
507 | - | ||
508 | - @selenium | ||
509 | - Scenario: Show checkbox to mark product as highlight | ||
510 | - Given the following product_category | ||
511 | - | name | | ||
512 | - | Bicycle | | ||
513 | - And the following products | ||
514 | - | owner | category | name | | ||
515 | - | redemoinho | bicycle | Bike | | ||
516 | - And I am logged in as "joaosilva" | ||
517 | - When I go to Rede Moinho's page of product Bike | ||
518 | - And I follow "Add price and other basic information" | ||
519 | - Then I should see "Highlight this product?" | ||
520 | - And I check "Highlight this product?" |
features/my_network_block.feature
@@ -1,79 +0,0 @@ | @@ -1,79 +0,0 @@ | ||
1 | -Feature: my_network_block | ||
2 | - As a blog owner | ||
3 | - I want to see a summary of my network | ||
4 | - | ||
5 | - Background: | ||
6 | - Given the following users | ||
7 | - | login | name | | ||
8 | - | joaosilva | Joao Silva | | ||
9 | - And the following blocks | ||
10 | - | owner | type | | ||
11 | - | joaosilva | MyNetworkBlock | | ||
12 | - | joaosilva | FriendsBlock | | ||
13 | - And the following communities | ||
14 | - | identifier | name | public_profile | | ||
15 | - | public-community | Public Community | true | | ||
16 | - And plugin FriendsBlock is enabled on environment | ||
17 | - | ||
18 | - @selenium | ||
19 | - Scenario: display how many public/private communities I am member | ||
20 | - Given I am logged in as "joaosilva" | ||
21 | - And the following communities | ||
22 | - | identifier | name | owner | public_profile | | ||
23 | - | other-public-community | Other Public Community | joaosilva | true | | ||
24 | - | private-community | Private Community | joaosilva | false | | ||
25 | - And I am on joaosilva's homepage | ||
26 | - And I should see "2 communities" | ||
27 | - When I go to public-community's homepage | ||
28 | - And I follow "Join" | ||
29 | - And I go to joaosilva's homepage | ||
30 | - Then I should see "3 communities" | ||
31 | - | ||
32 | - @selenium | ||
33 | - Scenario: not display how many invisible communities I am member | ||
34 | - Given I am logged in as "joaosilva" | ||
35 | - And the following communities | ||
36 | - | identifier | name | owner | visible | | ||
37 | - | visible-community | Visible Community | joaosilva | true | | ||
38 | - | not-visible-community | Not Visible Community | joaosilva | false | | ||
39 | - And I am on joaosilva's homepage | ||
40 | - And I should see "One community" | ||
41 | - When I go to public-community's homepage | ||
42 | - And I follow "Join" | ||
43 | - And I go to joaosilva's homepage | ||
44 | - Then I should see "2 communities" | ||
45 | - | ||
46 | - Scenario: display how many public/private friends I have | ||
47 | - Given the following users | ||
48 | - | login | name | public_profile | | ||
49 | - | mariasilva | Maria Silva | true | | ||
50 | - | josesilva | Jose Silva | false | | ||
51 | - And the following blocks | ||
52 | - | owner | type | | ||
53 | - | mariasilva | FriendsBlock | | ||
54 | - | josesilva | FriendsBlock | | ||
55 | - And "joaosilva" is friend of "mariasilva" | ||
56 | - And I am logged in as "joaosilva" | ||
57 | - And I am on joaosilva's homepage | ||
58 | - Then I should see "1 friend" | ||
59 | - And "joaosilva" is friend of "josesilva" | ||
60 | - When I go to joaosilva's homepage | ||
61 | - Then I should see "2 friends" | ||
62 | - | ||
63 | - Scenario: not display how many invisible friends I have | ||
64 | - Given the following users | ||
65 | - | login | name | | ||
66 | - | mariasilva | Maria Silva | | ||
67 | - | josesilva | Jose Silva | | ||
68 | - And the following blocks | ||
69 | - | owner | type | | ||
70 | - | mariasilva | FriendsBlock | | ||
71 | - | josesilva | FriendsBlock | | ||
72 | - And "josesilva" is invisible | ||
73 | - And "joaosilva" is friend of "mariasilva" | ||
74 | - And I am logged in as "joaosilva" | ||
75 | - When I go to joaosilva's homepage | ||
76 | - Then I should see "1 friend" | ||
77 | - And "joaosilva" is friend of "josesilva" | ||
78 | - When I go to joaosilva's homepage | ||
79 | - Then I should see "1 friend" |
features/profile_tags.feature
@@ -1,20 +0,0 @@ | @@ -1,20 +0,0 @@ | ||
1 | -Feature: profile tags | ||
2 | - As a Noosfero user | ||
3 | - I want to to view content tagged | ||
4 | - So that I can follow the subjects I care about | ||
5 | - | ||
6 | - Background: | ||
7 | - Given the following users | ||
8 | - | login | | ||
9 | - | terceiro | | ||
10 | - And the following articles | ||
11 | - | owner | name | body | tag_list | | ||
12 | - | terceiro | text 1 | text 1 content | tag1, tag2 | | ||
13 | - | terceiro | text 2 | text 2 content | tag1, tag3 | | ||
14 | - | ||
15 | - Scenario: tag feed | ||
16 | - When I go to terceiro's profile | ||
17 | - And I follow "tag1" | ||
18 | - And I follow "Feed for this tag" | ||
19 | - Then I should see "text 1" | ||
20 | - And I should see "text 2" |
features/session_and_cookies_handling.feature
@@ -1,40 +0,0 @@ | @@ -1,40 +0,0 @@ | ||
1 | -Feature: session and cookies handling | ||
2 | - | ||
3 | - As a Noosfero system administrator | ||
4 | - I want Noosfero to manage well it usage of sessions and cookies | ||
5 | - So that we can use HTTP caching effectively | ||
6 | - | ||
7 | - @fixme | ||
8 | - Scenario: home page, logged in | ||
9 | - Given the following users | ||
10 | - | login | | ||
11 | - | joaosilva | | ||
12 | - When I am logged in as "joaosilva" | ||
13 | - And I go to the homepage | ||
14 | - Then there must be a cookie "_noosfero_session" | ||
15 | - | ||
16 | - Scenario: home page, not logged in | ||
17 | - When I go to the homepage | ||
18 | - Then there must be no cookies | ||
19 | - | ||
20 | - @fixme | ||
21 | - Scenario: user_data, not logged in | ||
22 | - When I make a AJAX request to the user data path | ||
23 | - Then there must be no cookies | ||
24 | - | ||
25 | - @fixme | ||
26 | - Scenario: user_data, logged in | ||
27 | - Given I am logged in as admin | ||
28 | - When I make a AJAX request to the user data path | ||
29 | - Then there must be a cookie "_noosfero_session" | ||
30 | - | ||
31 | - # FIXME for some reason I could not test this scenario, although manual tests | ||
32 | - # indicate this works! | ||
33 | - # Scenario: logout | ||
34 | - # Given the following users | ||
35 | - # | login | | ||
36 | - # | joao | | ||
37 | - # When I am logged in as "joao" | ||
38 | - # And I log off | ||
39 | - # And I go to the homepage | ||
40 | - # Then there must be no cookies |
features/signup.feature
@@ -278,28 +278,6 @@ Feature: signup | @@ -278,28 +278,6 @@ Feature: signup | ||
278 | Then "José da Silva" should be a member of "Free Software" | 278 | Then "José da Silva" should be a member of "Free Software" |
279 | 279 | ||
280 | @selenium | 280 | @selenium |
281 | - Scenario: join community on direct signup | ||
282 | - Given the following users | ||
283 | - | login | name | | ||
284 | - | mariasilva | Maria Silva | | ||
285 | - And the following communities | ||
286 | - | name | identifier | owner | | ||
287 | - | Free Software | freesoftware | mariasilva | | ||
288 | - And feature "skip_new_user_email_confirmation" is enabled on environment | ||
289 | - And I am on /freesoftware | ||
290 | - When I follow "Join" | ||
291 | - And I follow "New user" | ||
292 | - And I fill in the following within ".no-boxes": | ||
293 | - | e-Mail | josesilva@example.com | | ||
294 | - | Username | josesilva | | ||
295 | - | Password | secret | | ||
296 | - | Password confirmation | secret | | ||
297 | - | Full name | José da Silva | | ||
298 | - And wait for the captcha signup time | ||
299 | - And I press "Create my account" | ||
300 | - Then "José da Silva" should be a member of "Free Software" | ||
301 | - | ||
302 | - @selenium | ||
303 | Scenario: user registration is moderated by admin | 281 | Scenario: user registration is moderated by admin |
304 | Given feature "admin_must_approve_new_users" is enabled on environment | 282 | Given feature "admin_must_approve_new_users" is enabled on environment |
305 | And feature "skip_new_user_email_confirmation" is disabled on environment | 283 | And feature "skip_new_user_email_confirmation" is disabled on environment |
@@ -349,4 +327,4 @@ Feature: signup | @@ -349,4 +327,4 @@ Feature: signup | ||
349 | And I fill in "Username / Email" with "teste" | 327 | And I fill in "Username / Email" with "teste" |
350 | And I fill in "Password" with "123456" | 328 | And I fill in "Password" with "123456" |
351 | And I press "Log in" | 329 | And I press "Log in" |
352 | - Then I should not see "teste" | ||
353 | \ No newline at end of file | 330 | \ No newline at end of file |
331 | + Then I should not see "teste" |
features/step_definitions/http_caching_steps.rb
@@ -1,21 +0,0 @@ | @@ -1,21 +0,0 @@ | ||
1 | -Then /^the response should be valid for (.+) minutes$/ do |n| | ||
2 | - page.response_headers['Cache-Control'].split(/,\s*/).should include("max-age=#{n.to_i * 60}") | ||
3 | -end | ||
4 | - | ||
5 | -Then /^the cache should be public/ do | ||
6 | - page.response_headers['Cache-Control'].split(/,\s*/).should include("public") | ||
7 | -end | ||
8 | - | ||
9 | -Then /^there must be no cache at all$/ do | ||
10 | - parts = page.response_headers['Cache-Control'].split(/,\s*/) | ||
11 | - parts.should include('must-revalidate') | ||
12 | - parts.should include('max-age=0') | ||
13 | -end | ||
14 | - | ||
15 | -Then 'there must be no cookies' do | ||
16 | - cookies.to_hash.should == {} | ||
17 | -end | ||
18 | - | ||
19 | -Then /^there must be a cookie "(.+)"$/ do |cookie_name| | ||
20 | - cookies.keys.should include(cookie_name) | ||
21 | -end |
features/step_definitions/noosfero_steps.rb
@@ -692,11 +692,6 @@ Given /^the cache is turned (on|off)$/ do |state| | @@ -692,11 +692,6 @@ Given /^the cache is turned (on|off)$/ do |state| | ||
692 | ActionController::Base.perform_caching = (state == 'on') | 692 | ActionController::Base.perform_caching = (state == 'on') |
693 | end | 693 | end |
694 | 694 | ||
695 | -When /^I make a AJAX request to (.*)$/ do |page| | ||
696 | - header 'X-Requested-With', 'XMLHttpRequest' | ||
697 | - visit(path_to(page)) | ||
698 | -end | ||
699 | - | ||
700 | Given /^the environment is configured to (.*) after login$/ do |option| | 695 | Given /^the environment is configured to (.*) after login$/ do |option| |
701 | redirection = case option | 696 | redirection = case option |
702 | when 'stay on the same page' | 697 | when 'stay on the same page' |
@@ -767,3 +762,11 @@ When /^I confirm the "(.*)" dialog$/ do |confirmation| | @@ -767,3 +762,11 @@ When /^I confirm the "(.*)" dialog$/ do |confirmation| | ||
767 | assert_equal confirmation, a.text | 762 | assert_equal confirmation, a.text |
768 | a.accept | 763 | a.accept |
769 | end | 764 | end |
765 | + | ||
766 | +Given /^the field (.*) is public for all users$/ do |field| | ||
767 | + Person.all.each do |person| | ||
768 | + person.fields_privacy = Hash.new if person.fields_privacy.nil? | ||
769 | + person.fields_privacy[field] = "public" | ||
770 | + person.save! | ||
771 | + end | ||
772 | +end | ||
770 | \ No newline at end of file | 773 | \ No newline at end of file |
lib/log_memory_consumption_job.rb
1 | class LogMemoryConsumptionJob < Struct.new(:last_stat) | 1 | class LogMemoryConsumptionJob < Struct.new(:last_stat) |
2 | # Number of entries do display | 2 | # Number of entries do display |
3 | N = 20 | 3 | N = 20 |
4 | - # In seconds | ||
5 | - PERIOD = 10 | ||
6 | 4 | ||
7 | def perform | 5 | def perform |
8 | logpath = File.join(Rails.root, 'log', "#{ENV['RAILS_ENV']}_memory_consumption.log") | 6 | logpath = File.join(Rails.root, 'log', "#{ENV['RAILS_ENV']}_memory_consumption.log") |
lib/noosfero.rb
@@ -3,6 +3,10 @@ | @@ -3,6 +3,10 @@ | ||
3 | require 'fast_gettext' | 3 | require 'fast_gettext' |
4 | module Noosfero | 4 | module Noosfero |
5 | 5 | ||
6 | + def self.root(default = nil) | ||
7 | + ENV.fetch('RAILS_RELATIVE_URL_ROOT', default) | ||
8 | + end | ||
9 | + | ||
6 | def self.pattern_for_controllers_in_directory(dir) | 10 | def self.pattern_for_controllers_in_directory(dir) |
7 | disjunction = controllers_in_directory(dir).join('|') | 11 | disjunction = controllers_in_directory(dir).join('|') |
8 | pattern = disjunction.blank? ? '' : ('(' + disjunction + ')') | 12 | pattern = disjunction.blank? ? '' : ('(' + disjunction + ')') |
lib/noosfero/gravatar.rb
1 | module Noosfero::Gravatar | 1 | module Noosfero::Gravatar |
2 | def gravatar_profile_image_url(email, options = {}) | 2 | def gravatar_profile_image_url(email, options = {}) |
3 | - "http://www.gravatar.com/avatar/#{Digest::MD5.hexdigest(email.to_s)}?" + { | 3 | + "//www.gravatar.com/avatar/#{Digest::MD5.hexdigest(email.to_s)}?" + { |
4 | :only_path => false, | 4 | :only_path => false, |
5 | }.merge(options).map{|k,v| '%s=%s' % [ k,v ] }.join('&') | 5 | }.merge(options).map{|k,v| '%s=%s' % [ k,v ] }.join('&') |
6 | end | 6 | end |
7 | 7 | ||
8 | def gravatar_profile_url(email) | 8 | def gravatar_profile_url(email) |
9 | - 'http://www.gravatar.com/'+ Digest::MD5.hexdigest(email.to_s) | 9 | + '//www.gravatar.com/'+ Digest::MD5.hexdigest(email.to_s) |
10 | end | 10 | end |
11 | end | 11 | end |
lib/noosfero/plugin.rb
@@ -12,6 +12,12 @@ class Noosfero::Plugin | @@ -12,6 +12,12 @@ class Noosfero::Plugin | ||
12 | 12 | ||
13 | attr_writer :should_load | 13 | attr_writer :should_load |
14 | 14 | ||
15 | + # Called for each ActiveRecord class with parents | ||
16 | + # See http://apidock.com/rails/ActiveRecord/ModelSchema/ClassMethods/full_table_name_prefix | ||
17 | + def table_name_prefix | ||
18 | + @table_name_prefix ||= "#{name.to_s.underscore}_" | ||
19 | + end | ||
20 | + | ||
15 | def should_load | 21 | def should_load |
16 | @should_load.nil? && true || @boot | 22 | @should_load.nil? && true || @boot |
17 | end | 23 | end |
@@ -525,6 +531,18 @@ class Noosfero::Plugin | @@ -525,6 +531,18 @@ class Noosfero::Plugin | ||
525 | nil | 531 | nil |
526 | end | 532 | end |
527 | 533 | ||
534 | + # -> Perform extra transactions related to profile in profile editor | ||
535 | + # returns = true in success or raise and exception if it could not update the data | ||
536 | + def profile_editor_transaction_extras | ||
537 | + nil | ||
538 | + end | ||
539 | + | ||
540 | + # -> Return a list of hashs with the needed information to create optional fields | ||
541 | + # returns = a list of hashs as {:name => "string", :label => "string", :object_name => :key, :method => :key} | ||
542 | + def extra_optional_fields | ||
543 | + [] | ||
544 | + end | ||
545 | + | ||
528 | # -> Adds additional blocks to profiles and environments. | 546 | # -> Adds additional blocks to profiles and environments. |
529 | # Your plugin must implements a class method called 'extra_blocks' | 547 | # Your plugin must implements a class method called 'extra_blocks' |
530 | # that returns a hash with the following syntax. | 548 | # that returns a hash with the following syntax. |
lib/noosfero/version.rb
@@ -0,0 +1,48 @@ | @@ -0,0 +1,48 @@ | ||
1 | +namespace :ci do | ||
2 | + | ||
3 | + desc 'Continuous integration smoke test' | ||
4 | + task :smoke do | ||
5 | + | ||
6 | + current_branch = `git rev-parse --abbrev-ref HEAD`.strip | ||
7 | + from = ENV['PREV_HEAD'] || "origin/#{current_branch}" | ||
8 | + to = ENV['HEAD'] || current_branch | ||
9 | + changed_files = `git diff --name-only #{from}..#{to}`.split.select do |f| | ||
10 | + File.exist?(f) && f.split(File::SEPARATOR).first != 'vendor' | ||
11 | + end | ||
12 | + | ||
13 | + changed_plugin_files = changed_files.select do |f| | ||
14 | + f.split(File::SEPARATOR).first == 'plugins' | ||
15 | + end | ||
16 | + changed_plugins = changed_plugin_files.map do |f| | ||
17 | + f.split(File::SEPARATOR)[1] | ||
18 | + end.uniq | ||
19 | + | ||
20 | + changed_files -= changed_plugin_files | ||
21 | + | ||
22 | + # explicitly changed tests | ||
23 | + tests = changed_files.select { |f| f =~ /test\/.*_test\.rb$/ } | ||
24 | + features = changed_files.select { |f| f =~ /\.feature$/ } | ||
25 | + | ||
26 | + # match changed code files to their respective tests | ||
27 | + changed_files.each do |f| | ||
28 | + if f =~ /^(app|lib)\// | ||
29 | + basename = File.basename(f, '.rb') | ||
30 | + Dir.glob("test/**/#{basename}_test.rb").each do |t| | ||
31 | + tests << t unless tests.include?(t) | ||
32 | + end | ||
33 | + end | ||
34 | + end | ||
35 | + | ||
36 | + sh 'testrb', '-Itest', *tests unless tests.empty? | ||
37 | + sh 'cucumber', *features unless features.empty? | ||
38 | + sh 'xvfb-run', 'cucumber', '-p', 'selenium', *features unless features.empty? | ||
39 | + | ||
40 | + changed_plugins.each do |plugin| | ||
41 | + task = "test:noosfero_plugins:#{plugin}" | ||
42 | + puts "Running #{task}" | ||
43 | + Rake::Task[task].execute | ||
44 | + end | ||
45 | + | ||
46 | + end | ||
47 | + | ||
48 | +end |
lib/tasks/plugins.rake
@@ -6,17 +6,6 @@ namespace :noosfero do | @@ -6,17 +6,6 @@ namespace :noosfero do | ||
6 | 6 | ||
7 | plugin_migration_dirs = Dir.glob(Rails.root.join('{baseplugins,config/plugins}', '*', 'db', 'migrate')) | 7 | plugin_migration_dirs = Dir.glob(Rails.root.join('{baseplugins,config/plugins}', '*', 'db', 'migrate')) |
8 | 8 | ||
9 | - task :load_config do | ||
10 | - dirs = Dir.glob("{baseplugins,config/plugins}/*").uniq do |dir| | ||
11 | - File.basename(dir) | ||
12 | - end.map do |dir| | ||
13 | - File.join(dir, 'db/migrate') | ||
14 | - end | ||
15 | - dirs.each do |dir| | ||
16 | - ActiveRecord::Migrator.migrations_paths << dir | ||
17 | - end | ||
18 | - end | ||
19 | - | ||
20 | task :migrate do | 9 | task :migrate do |
21 | plugin_migration_dirs.each do |path| | 10 | plugin_migration_dirs.each do |path| |
22 | ActiveRecord::Migrator.migrate(path, ENV["VERSION"] ? | 11 | ActiveRecord::Migrator.migrate(path, ENV["VERSION"] ? |
@@ -26,5 +15,3 @@ namespace :noosfero do | @@ -26,5 +15,3 @@ namespace :noosfero do | ||
26 | end | 15 | end |
27 | end | 16 | end |
28 | 17 | ||
29 | -task 'db:migrate' => 'noosfero:plugins:load_config' | ||
30 | -task 'db:schema:load' => 'noosfero:plugins:load_config' |
lib/tasks/plugins_tests.rake
1 | +@broken_plugins = %w[ | ||
2 | + anti_spam | ||
3 | + bsc | ||
4 | + comment_classification | ||
5 | + ldap | ||
6 | + solr | ||
7 | +] | ||
8 | + | ||
1 | @all_plugins = Dir.glob('plugins/*').map { |f| File.basename(f) } - ['template'] | 9 | @all_plugins = Dir.glob('plugins/*').map { |f| File.basename(f) } - ['template'] |
2 | @all_plugins.sort! | 10 | @all_plugins.sort! |
3 | @all_tasks = [:units, :functionals, :integration, :cucumber, :selenium] | 11 | @all_tasks = [:units, :functionals, :integration, :cucumber, :selenium] |
@@ -104,7 +112,7 @@ def run_test(name, files) | @@ -104,7 +112,7 @@ def run_test(name, files) | ||
104 | end | 112 | end |
105 | 113 | ||
106 | def run_testrb(files) | 114 | def run_testrb(files) |
107 | - sh 'testrb', '-Itest', *files | 115 | + sh 'testrb', '-I.:test', *files |
108 | end | 116 | end |
109 | 117 | ||
110 | def run_cucumber(profile, files) | 118 | def run_cucumber(profile, files) |
@@ -167,6 +175,7 @@ def test_sequence(plugins, tasks) | @@ -167,6 +175,7 @@ def test_sequence(plugins, tasks) | ||
167 | end | 175 | end |
168 | end | 176 | end |
169 | rollback_plugins_state | 177 | rollback_plugins_state |
178 | + yield(failed) if block_given? | ||
170 | fail 'There are broken tests to be fixed!' if fail_flag | 179 | fail 'There are broken tests to be fixed!' if fail_flag |
171 | end | 180 | end |
172 | 181 | ||
@@ -195,13 +204,39 @@ namespace :test do | @@ -195,13 +204,39 @@ namespace :test do | ||
195 | @all_tasks.each do |taskname| | 204 | @all_tasks.each do |taskname| |
196 | desc "Run #{taskname} tests for all plugins" | 205 | desc "Run #{taskname} tests for all plugins" |
197 | task taskname do | 206 | task taskname do |
198 | - test_sequence(@all_plugins, taskname) | 207 | + test_sequence(@all_plugins - @broken_plugins, taskname) |
199 | end | 208 | end |
200 | end | 209 | end |
201 | end | 210 | end |
202 | 211 | ||
203 | desc "Run all tests for all plugins" | 212 | desc "Run all tests for all plugins" |
204 | task :noosfero_plugins do | 213 | task :noosfero_plugins do |
205 | - test_sequence(@all_plugins, @all_tasks) | 214 | + test_sequence(@all_plugins - @broken_plugins, @all_tasks) do |failed| |
215 | + plugins_status_report(failed) | ||
216 | + end | ||
206 | end | 217 | end |
207 | end | 218 | end |
219 | + | ||
220 | +def plugins_status_report(failed) | ||
221 | + w = @all_plugins.map { |s| s.size }.max | ||
222 | + | ||
223 | + puts | ||
224 | + printf ('=' * (w + 21)) + "\n" | ||
225 | + puts 'Plugins status report' | ||
226 | + printf ('=' * (w + 21)) + "\n" | ||
227 | + printf "%-#{w}s %s\n", "Plugin", "Status" | ||
228 | + printf ('-' * w) + ' ' + ('-' * 20) + "\n" | ||
229 | + | ||
230 | + @all_plugins.each do |plugin| | ||
231 | + if @broken_plugins.include?(plugin) | ||
232 | + status = "SKIP" | ||
233 | + elsif !failed[plugin] || failed[plugin].empty? | ||
234 | + status = "PASS" | ||
235 | + else | ||
236 | + status = "FAIL: #{failed[plugin].join(', ')}" | ||
237 | + end | ||
238 | + printf "%-#{w}s %s\n", plugin, status | ||
239 | + end | ||
240 | + printf ('=' * (w + 21)) + "\n" | ||
241 | + puts | ||
242 | +end |
lib/tasks/release.rake
@@ -222,7 +222,7 @@ EOF | @@ -222,7 +222,7 @@ EOF | ||
222 | puts "I: please upload the package manually!" | 222 | puts "I: please upload the package manually!" |
223 | end | 223 | end |
224 | 224 | ||
225 | - rm_f "rm tmp/pending-release" | 225 | + rm_f "tmp/pending-release" |
226 | end | 226 | end |
227 | 227 | ||
228 | desc 'Build Debian packages' | 228 | desc 'Build Debian packages' |
lib/user_activation_job.rb
1 | class UserActivationJob < Struct.new(:user_id) | 1 | class UserActivationJob < Struct.new(:user_id) |
2 | def perform | 2 | def perform |
3 | user = User.find(user_id) | 3 | user = User.find(user_id) |
4 | - user.destroy unless user.activated? | 4 | + user.destroy unless user.activated? || user.person.is_template? |
5 | end | 5 | end |
6 | end | 6 | end |
lib/white_list_filter.rb
@@ -9,7 +9,7 @@ module WhiteListFilter | @@ -9,7 +9,7 @@ module WhiteListFilter | ||
9 | unless iframe =~ /src=['"].*src=['"]/ | 9 | unless iframe =~ /src=['"].*src=['"]/ |
10 | trusted_sites.each do |trusted_site| | 10 | trusted_sites.each do |trusted_site| |
11 | re_dom = trusted_site.gsub('.', '\.') | 11 | re_dom = trusted_site.gsub('.', '\.') |
12 | - if iframe =~ /src=["']https?:\/\/(www\.)?#{re_dom}\// | 12 | + if iframe =~ /src=["'](https?:)?\/\/(www\.)?#{re_dom}\// |
13 | result = iframe | 13 | result = iframe |
14 | end | 14 | end |
15 | end | 15 | end |
plugins/comment_group/views/comment_group_plugin_profile/view_comments.rjs
@@ -8,5 +8,5 @@ page.replace_html "comment-count-#{@group_id}", @comments_count | @@ -8,5 +8,5 @@ page.replace_html "comment-count-#{@group_id}", @comments_count | ||
8 | if @no_more_pages | 8 | if @no_more_pages |
9 | page.replace_html "comments_list_group_#{@group_id}_more", "" | 9 | page.replace_html "comments_list_group_#{@group_id}_more", "" |
10 | else | 10 | else |
11 | - page.replace_html "comments_list_group_#{@group_id}_more", link_to_remote(_('More'), :url => { :profile => profile.identifier, :controller => 'comment_group_plugin_profile', :action => 'view_comments', :group_id => @group_id, :article_id => @article_id, :group_comment_page => @group_comment_page + 1}, :loaded => visual_effect(:highlight, "comments_list_group_#{@group_id}"), :method => :post, :complete => "loadCompleted(#{@group_id})") | 11 | + page.replace_html "comments_list_group_#{@group_id}_more", link_to_remote(_('More'), :url => { :profile => profile.identifier, :controller => 'comment_group_plugin_profile', :action => 'view_comments', :group_id => @group_id, :article_id => @article_id, :group_comment_page => @group_comment_page + 1}, :method => :get) |
12 | end | 12 | end |
plugins/community_block/test/functional/commmunity_block_plugin_profile_controller_test.rb
0 → 100644
@@ -0,0 +1,83 @@ | @@ -0,0 +1,83 @@ | ||
1 | +require File.dirname(__FILE__) + '/../test_helper' | ||
2 | + | ||
3 | +# Re-raise errors caught by the controller. | ||
4 | +class ProfileController | ||
5 | + append_view_path File.join(File.dirname(__FILE__) + '/../../views') | ||
6 | + def rescue_action(e) | ||
7 | + raise e | ||
8 | + end | ||
9 | +end | ||
10 | + | ||
11 | +class ProfileControllerTest < ActionController::TestCase | ||
12 | + | ||
13 | + def setup | ||
14 | + @user = create_user('testinguser').person | ||
15 | + login_as(@user.identifier) | ||
16 | + | ||
17 | + @community = fast_create(Community, :environment_id => Environment.default) | ||
18 | + @community.add_member @user | ||
19 | + @community.add_admin @user | ||
20 | + | ||
21 | + @environment = @community.environment | ||
22 | + @environment.enabled_plugins = ['CommunityBlock'] | ||
23 | + @environment.save! | ||
24 | + | ||
25 | + CommunityBlock.delete_all | ||
26 | + @box1 = create(Box, :owner => @community) | ||
27 | + @community.boxes = [@box1] | ||
28 | + | ||
29 | + @block = CommunityBlock.new | ||
30 | + @block.box = @box1 | ||
31 | + @block.save! | ||
32 | + | ||
33 | + @community.blocks<<@block | ||
34 | + @community.save! | ||
35 | + end | ||
36 | + | ||
37 | + should 'display community-block' do | ||
38 | + get :index, :profile => @community.identifier | ||
39 | + assert_tag :div, :attributes => {:class => 'community-block-logo'} | ||
40 | + assert_tag :div, :attributes => {:class => 'community-block-info'} | ||
41 | + assert_tag :div, :attributes => {:class => 'community-block-title'} | ||
42 | + assert_tag :div, :attributes => {:class => 'community-block-description'} | ||
43 | + end | ||
44 | + | ||
45 | + should 'display *leave* button when the user is logged in and is a member of the community' do | ||
46 | + get :index, :profile => @community.identifier | ||
47 | + assert_tag :span, :attributes => {:class => 'community-block-button icon-remove'} | ||
48 | + end | ||
49 | + | ||
50 | + should 'display *send email to administrators* button when the user is logged in and is a member of the community' do | ||
51 | + get :index, :profile => @community.identifier | ||
52 | + assert_match /\{"Send an e-mail":\{"href":"\/contact\/#{@community.identifier}\/new"\}\}/, @response.body | ||
53 | + end | ||
54 | + | ||
55 | + should 'display *report* button when the user is logged in and is a member of the community' do | ||
56 | + get :index, :profile => @community.identifier | ||
57 | + assert_match /\{"Report abuse":\{"href":"\/profile\/#{@community.identifier}\/report_abuse"\}\}/, @response.body | ||
58 | + end | ||
59 | + | ||
60 | + should 'display *join* button when the user is logged in and is not a member of the community' do | ||
61 | + @community.remove_member @user | ||
62 | + get :index, :profile => @community.identifier | ||
63 | + assert_tag :span, :attributes => {:class => 'community-block-button icon-add'} | ||
64 | + end | ||
65 | + | ||
66 | + should 'display *control panel* link option when the user is logged in and is community admin' do | ||
67 | + get :index, :profile => @community.identifier | ||
68 | + assert_match /\{"Control panel":\{"href":"\/myprofile\/#{@community.identifier}"\}\}/, @response.body | ||
69 | + end | ||
70 | + | ||
71 | + should 'display *join* button when the user is not logged in' do | ||
72 | + logout | ||
73 | + get :index, :profile => @community.identifier | ||
74 | + assert_tag :span, :attributes => {:class => 'community-block-button icon-add'} | ||
75 | + end | ||
76 | + | ||
77 | + should 'not display *arrow* button when the user is not logged in' do | ||
78 | + logout | ||
79 | + get :index, :profile => @community.identifier | ||
80 | + assert_no_tag :span, :attributes => {:class => 'community-block-button icon-arrow'} | ||
81 | + end | ||
82 | + | ||
83 | +end |
plugins/community_block/test/functional/commmunity_block_plugin_profile_design_controller_test.rb
@@ -1,87 +0,0 @@ | @@ -1,87 +0,0 @@ | ||
1 | -require File.dirname(__FILE__) + '/../test_helper' | ||
2 | - | ||
3 | -# Re-raise errors caught by the controller. | ||
4 | -class ProfileController | ||
5 | - append_view_path File.join(File.dirname(__FILE__) + '/../../views') | ||
6 | - def rescue_action(e) | ||
7 | - raise e | ||
8 | - end | ||
9 | -end | ||
10 | - | ||
11 | -class ProfileControllerTest < ActionController::TestCase | ||
12 | - | ||
13 | - def setup | ||
14 | - @controller = ProfileController.new | ||
15 | - @request = ActionController::TestRequest.new | ||
16 | - @response = ActionController::TestResponse.new | ||
17 | - | ||
18 | - @user = create_user('testinguser').person | ||
19 | - login_as(@user.identifier) | ||
20 | - | ||
21 | - @community = fast_create(Community, :environment_id => Environment.default) | ||
22 | - @community.add_member @user | ||
23 | - @community.add_admin @user | ||
24 | - | ||
25 | - @environment = @community.environment | ||
26 | - @environment.enabled_plugins = ['CommunityBlock'] | ||
27 | - @environment.save! | ||
28 | - | ||
29 | - CommunityBlock.delete_all | ||
30 | - @box1 = create(Box, :owner => @community) | ||
31 | - @community.boxes = [@box1] | ||
32 | - | ||
33 | - @block = CommunityBlock.new | ||
34 | - @block.box = @box1 | ||
35 | - @block.save! | ||
36 | - | ||
37 | - @community.blocks<<@block | ||
38 | - @community.save! | ||
39 | - end | ||
40 | - | ||
41 | - should 'display community-block' do | ||
42 | - get :index, :profile => @community.identifier | ||
43 | - assert_tag :div, :attributes => {:class => 'community-block-logo'} | ||
44 | - assert_tag :div, :attributes => {:class => 'community-block-info'} | ||
45 | - assert_tag :div, :attributes => {:class => 'community-block-title'} | ||
46 | - assert_tag :div, :attributes => {:class => 'community-block-description'} | ||
47 | - end | ||
48 | - | ||
49 | - should 'display *leave* button when the user is logged in and is a member of the community' do | ||
50 | - get :index, :profile => @community.identifier | ||
51 | - assert_tag :span, :attributes => {:class => 'community-block-button icon-remove'} | ||
52 | - end | ||
53 | - | ||
54 | - should 'display *send email to administrators* button when the user is logged in and is a member of the community' do | ||
55 | - get :index, :profile => @community.identifier | ||
56 | - assert_match /\{"Send an e-mail":\{"href":"\/contact\/#{@community.identifier}\/new"\}\}/, @response.body | ||
57 | - end | ||
58 | - | ||
59 | - should 'display *report* button when the user is logged in and is a member of the community' do | ||
60 | - get :index, :profile => @community.identifier | ||
61 | - assert_match /\{"Report abuse":\{"href":"\/profile\/#{@community.identifier}\/report_abuse"\}\}/, @response.body | ||
62 | - end | ||
63 | - | ||
64 | - should 'display *join* button when the user is logged in and is not a member of the community' do | ||
65 | - @community.remove_member @user | ||
66 | - get :index, :profile => @community.identifier | ||
67 | - assert_tag :span, :attributes => {:class => 'community-block-button icon-add'} | ||
68 | - end | ||
69 | - | ||
70 | - should 'display *control panel* link option when the user is logged in and is community admin' do | ||
71 | - get :index, :profile => @community.identifier | ||
72 | - assert_match /\{"Control panel":\{"href":"\/myprofile\/#{@community.identifier}"\}\}/, @response.body | ||
73 | - end | ||
74 | - | ||
75 | - should 'display *join* button when the user is not logged in' do | ||
76 | - logout | ||
77 | - get :index, :profile => @community.identifier | ||
78 | - assert_tag :span, :attributes => {:class => 'community-block-button icon-add'} | ||
79 | - end | ||
80 | - | ||
81 | - should 'not display *arrow* button when the user is not logged in' do | ||
82 | - logout | ||
83 | - get :index, :profile => @community.identifier | ||
84 | - assert_no_tag :span, :attributes => {:class => 'community-block-button icon-arrow'} | ||
85 | - end | ||
86 | - | ||
87 | -end |
plugins/community_block/views/community_block.html.erb
@@ -23,7 +23,7 @@ | @@ -23,7 +23,7 @@ | ||
23 | <%= link_to( | 23 | <%= link_to( |
24 | content_tag('span','',:class => 'community-block-button icon-arrow'), | 24 | content_tag('span','',:class => 'community-block-button icon-arrow'), |
25 | '#', | 25 | '#', |
26 | - :onclick => "toggleSubmenu(this,'',#{j links.to_json}); return false;", | 26 | + :onclick => "toggleSubmenu(this,'',#{CGI::escapeHTML(links.to_json)}); return false;", |
27 | :class => 'simplemenu-trigger') %> | 27 | :class => 'simplemenu-trigger') %> |
28 | 28 | ||
29 | <% end %> | 29 | <% end %> |
@@ -32,11 +32,11 @@ | @@ -32,11 +32,11 @@ | ||
32 | <% if profile.members.include?(user) || profile.already_request_membership?(user) %> | 32 | <% if profile.members.include?(user) || profile.already_request_membership?(user) %> |
33 | <%= link_to( | 33 | <%= link_to( |
34 | content_tag('span', '', :class => 'community-block-button icon-remove'), | 34 | content_tag('span', '', :class => 'community-block-button icon-remove'), |
35 | - profile.leave_url) %> | 35 | + profile.leave_url, :class => 'join-community') %> |
36 | <% else %> | 36 | <% else %> |
37 | <%= link_to( | 37 | <%= link_to( |
38 | content_tag('span', '', :class => 'community-block-button icon-add'), | 38 | content_tag('span', '', :class => 'community-block-button icon-add'), |
39 | - profile.join_url) %> | 39 | + profile.join_url, :class => 'join-community') %> |
40 | <% end %> | 40 | <% end %> |
41 | <% else %> | 41 | <% else %> |
42 | <%= link_to( | 42 | <%= link_to( |
plugins/community_track/test/functional/community_track_plugin_content_viewer_controller_test.rb
@@ -101,9 +101,6 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -101,9 +101,6 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
101 | should 'render tracks in track list block' do | 101 | should 'render tracks in track list block' do |
102 | @block = CommunityTrackPlugin::TrackListBlock.create!(:box => @profile.boxes.last) | 102 | @block = CommunityTrackPlugin::TrackListBlock.create!(:box => @profile.boxes.last) |
103 | get :view_page, @step.url | 103 | get :view_page, @step.url |
104 | - file = File.open('result.html', 'w+') | ||
105 | - file.write(@response.body) | ||
106 | - file.close | ||
107 | assert_tag :tag => 'div', :attributes => { :class => "item category_#{@track.category_name}" }, :descendant => { :tag => 'div', :attributes => { :class => 'steps' }, :descendant => { :tag => 'span', :attributes => { :class => "step #{@block.status_class(@step)}" } } } | 104 | assert_tag :tag => 'div', :attributes => { :class => "item category_#{@track.category_name}" }, :descendant => { :tag => 'div', :attributes => { :class => 'steps' }, :descendant => { :tag => 'span', :attributes => { :class => "step #{@block.status_class(@step)}" } } } |
108 | end | 105 | end |
109 | 106 |