Commit dfad044a51377efab384106d219a4f49866bcf08

Authored by Victor Costa
2 parents eda464a0 90f4f1c1

Merge branch 'master' into AI3279-block_store

Conflicts:
	Gemfile
	Gemfile.lock
	app/controllers/admin/environment_design_controller.rb
	app/helpers/layout_helper.rb
	app/models/block.rb
	script/quick-start
Showing 851 changed files with 90339 additions and 137025 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 851 files displayed.

.ackrc
1 1 --ignore-dir=log
2 2 --ignore-dir=tmp
3 3 --ignore-dir=pkg
  4 +--ignore-dir=public/javascripts/cache
  5 +--ignore-dir=public/stylesheets/cache
... ...
AUTHORS.md
... ... @@ -41,6 +41,7 @@ Alessandro Palmeira + Paulo Meirelles <alessandro.palmeira@gmail.com>
41 41 Alessandro Palmeira + Paulo Meirelles + João M. M. da Silva <alessandro.palmeira@gmail.com>
42 42 Alessandro Palmeira + Rafael Manzo <alessandro.palmeira@gmail.com>
43 43 Ana Losnak <analosnak@gmail.com>
  44 +Andre Bernardes <andrebsguedes@gmail.com>
44 45 Antonio Terceiro + Carlos Morais <terceiro@colivre.coop.br>
45 46 Antonio Terceiro + Paulo Meirelles <terceiro@colivre.coop.br>
46 47 Antonio Terceiro <terceiro@colivre.coop.br>
... ... @@ -132,6 +133,7 @@ Francisco Marcelo de Araújo Lima Júnior &lt;maljunior@gmail.com&gt;
132 133 Gabriela Navarro <navarro1703@gmail.com>
133 134 Grazieno Pellegrino <grazieno@gmail.com>
134 135 Gust <darksshades@hotmail.com>
  136 +Hebert Douglas <hebertdougl@gmail.com>
135 137 Hugo Melo <hugo@riseup.net>
136 138 Isaac Canan <isaac@intelletto.com.br>
137 139 Italo Valcy <italo@dcc.ufba.br>
... ... @@ -196,6 +198,7 @@ Martín Olivera &lt;molivera@solar.org.ar&gt;
196 198 Moises Machado <moises@colivre.coop.br>
197 199 Naíla Alves <naila@colivre.coop.br>
198 200 Nanda Lopes <nanda.listas+psl@gmail.com>
  201 +Parley Martins <parleypachecomartins@gmail.com>
199 202 Paulo Meirelles + Alessandro Palmeira + João M. M. da Silva <paulo@softwarelivre.org>
200 203 Paulo Meirelles + Alessandro Palmeira <paulo@softwarelivre.org>
201 204 Paulo Meirelles + Carlos Morais <paulo@softwarelivre.org>
... ... @@ -230,6 +233,8 @@ Rodrigo Souto &lt;rodrigo@colivre.coop.br&gt;
230 233 Ronny Kursawe <kursawe.ronny@googlemail.com>
231 234 root <root@debian.sdr.serpro>
232 235 Samuel R. C. Vale <srcvale@holoscopio.com>
  236 +Tallys Martins <tallysmartins@gmail.com>
  237 +tallys <tallys@tallys.(none)>
233 238 Valessio Brito <contato@valessiobrito.com.br>
234 239 Valessio Brito <contato@valessiobrito.info>
235 240 Valessio Brito <valessio@gmail.com>
... ...
Gemfile
1 1 source "https://rubygems.org"
2   -gem 'rails'
3   -gem 'fast_gettext'
4   -gem 'acts-as-taggable-on'
5   -gem 'prototype-rails'
6   -gem 'prototype_legacy_helper', '0.0.0', :path => 'vendor/prototype_legacy_helper'
7   -gem 'rails_autolink'
8   -gem 'pg'
9   -gem 'rmagick'
10   -gem 'RedCloth'
11   -gem 'will_paginate'
12   -gem 'ruby-feedparser'
13   -gem 'daemons'
14   -gem 'thin'
15   -gem 'hpricot'
16   -gem 'nokogiri'
  2 +gem 'rails', '~> 3.2.19'
  3 +gem 'fast_gettext', '~> 0.6.8'
  4 +gem 'acts-as-taggable-on', '~> 3.0.2'
  5 +gem 'prototype-rails', '~> 3.2.1'
  6 +gem 'prototype_legacy_helper', '0.0.0', :path => 'vendor/prototype_legacy_helper'
  7 +gem 'rails_autolink', '~> 1.1.5'
  8 +gem 'pg', '~> 0.13.2'
  9 +gem 'rmagick', '~> 2.13.1'
  10 +gem 'RedCloth', '~> 4.2.9'
  11 +gem 'will_paginate', '~> 3.0.3'
  12 +gem 'ruby-feedparser', '~> 0.7'
  13 +gem 'daemons', '~> 1.1.5'
  14 +gem 'thin', '~> 1.3.1'
  15 +gem 'hpricot', '~> 0.8.6'
  16 +gem 'nokogiri', '~> 1.5.5'
17 17 gem 'rake', :require => false
18   -gem 'rest-client'
19   -gem 'exception_notification'
  18 +gem 'rest-client', '~> 1.6.7'
  19 +gem 'exception_notification', '~> 4.0.1'
  20 +gem 'gettext', '~> 2.2.1', :require => false, :group => :development
  21 +gem 'locale', '~> 2.0.5'
20 22  
21 23 # FIXME list here all actual dependencies (i.e. the ones in debian/control),
22 24 # with their GEM names (not the Debian package names)
23 25  
24 26 group :production do
25   - gem 'dalli'
  27 + gem 'dalli', '~> 2.7.0'
26 28 end
27 29  
28 30 group :test do
29   - gem 'rspec'
30   - gem 'rspec-rails'
31   - gem 'mocha', :require => false
  31 + gem 'rspec', '~> 2.10.0'
  32 + gem 'rspec-rails', '~> 2.10.1'
  33 + gem 'mocha', '~> 1.1.0', :require => false
32 34 end
33 35  
34 36 group :cucumber do
35   - gem 'cucumber-rails', :require => false
36   - gem 'capybara'
37   - gem 'cucumber'
38   - gem 'database_cleaner'
39   - gem 'selenium-webdriver'
  37 + gem 'cucumber-rails', '~> 1.0.6', :require => false
  38 + gem 'capybara', '~> 2.1.0'
  39 + gem 'cucumber', '~> 1.0.6'
  40 + gem 'database_cleaner', '~> 1.2.0'
  41 + gem 'selenium-webdriver', '~> 2.39.0'
40 42 end
41 43  
42   -# include plugin gemfiles
43   -Dir.glob(File.join('config', 'plugins', '*')).each do |plugin|
44   - plugin_gemfile = File.join(plugin, 'Gemfile')
45   - 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)
46 49 end
... ...
Gemfile.lock
... ... @@ -1,191 +0,0 @@
1   -PATH
2   - remote: vendor/prototype_legacy_helper
3   - specs:
4   - prototype_legacy_helper (0.0.0)
5   -
6   -GEM
7   - remote: https://rubygems.org/
8   - specs:
9   - RedCloth (4.2.9)
10   - actionmailer (3.2.6)
11   - actionpack (= 3.2.6)
12   - mail (~> 2.4.4)
13   - actionpack (3.2.6)
14   - activemodel (= 3.2.6)
15   - activesupport (= 3.2.6)
16   - builder (~> 3.0.0)
17   - erubis (~> 2.7.0)
18   - journey (~> 1.0.1)
19   - rack (~> 1.4.0)
20   - rack-cache (~> 1.2)
21   - rack-test (~> 0.6.1)
22   - sprockets (~> 2.1.3)
23   - activemodel (3.2.6)
24   - activesupport (= 3.2.6)
25   - builder (~> 3.0.0)
26   - activerecord (3.2.6)
27   - activemodel (= 3.2.6)
28   - activesupport (= 3.2.6)
29   - arel (~> 3.0.2)
30   - tzinfo (~> 0.3.29)
31   - activeresource (3.2.6)
32   - activemodel (= 3.2.6)
33   - activesupport (= 3.2.6)
34   - activesupport (3.2.6)
35   - i18n (~> 0.6)
36   - multi_json (~> 1.0)
37   - acts-as-taggable-on (3.0.2)
38   - rails (>= 3, < 5)
39   - arel (3.0.2)
40   - builder (3.0.0)
41   - capybara (2.1.0)
42   - mime-types (>= 1.16)
43   - nokogiri (>= 1.3.3)
44   - rack (>= 1.0.0)
45   - rack-test (>= 0.5.4)
46   - xpath (~> 2.0)
47   - childprocess (0.3.3)
48   - ffi (~> 1.0.6)
49   - cucumber (1.0.6)
50   - builder (>= 2.1.2)
51   - diff-lcs (>= 1.1.2)
52   - gherkin (~> 2.4.18)
53   - json (>= 1.4.6)
54   - term-ansicolor (>= 1.0.6)
55   - cucumber-rails (1.0.6)
56   - capybara (>= 1.1.1)
57   - cucumber (>= 1.0.6)
58   - nokogiri (>= 1.5.0)
59   - daemons (1.1.5)
60   - dalli (2.7.0)
61   - database_cleaner (1.2.0)
62   - diff-lcs (1.1.3)
63   - erubis (2.7.0)
64   - eventmachine (0.12.10)
65   - exception_notification (4.0.1)
66   - actionmailer (>= 3.0.4)
67   - activesupport (>= 3.0.4)
68   - fast_gettext (0.6.8)
69   - ffi (1.0.11)
70   - gherkin (2.4.21)
71   - json (>= 1.4.6)
72   - hike (1.2.1)
73   - hpricot (0.8.6)
74   - i18n (0.6.0)
75   - journey (1.0.3)
76   - json (1.7.3)
77   - mail (2.4.4)
78   - i18n (>= 0.4.0)
79   - mime-types (~> 1.16)
80   - treetop (~> 1.4.8)
81   - metaclass (0.0.1)
82   - mime-types (1.19)
83   - mocha (0.11.3)
84   - metaclass (~> 0.0.1)
85   - multi_json (1.3.6)
86   - nokogiri (1.5.5)
87   - pg (0.13.2)
88   - polyglot (0.3.3)
89   - prototype-rails (3.2.1)
90   - rails (~> 3.2)
91   - rack (1.4.1)
92   - rack-cache (1.2)
93   - rack (>= 0.4)
94   - rack-ssl (1.3.2)
95   - rack
96   - rack-test (0.6.1)
97   - rack (>= 1.0)
98   - rails (3.2.6)
99   - actionmailer (= 3.2.6)
100   - actionpack (= 3.2.6)
101   - activerecord (= 3.2.6)
102   - activeresource (= 3.2.6)
103   - activesupport (= 3.2.6)
104   - bundler (~> 1.0)
105   - railties (= 3.2.6)
106   - rails_autolink (1.1.5)
107   - rails (> 3.1)
108   - railties (3.2.6)
109   - actionpack (= 3.2.6)
110   - activesupport (= 3.2.6)
111   - rack-ssl (~> 1.3.2)
112   - rake (>= 0.8.7)
113   - rdoc (~> 3.4)
114   - thor (>= 0.14.6, < 2.0)
115   - rake (0.9.2.2)
116   - rdoc (3.9.4)
117   - rest-client (1.6.7)
118   - mime-types (>= 1.16)
119   - rmagick (2.13.1)
120   - rspec (2.10.0)
121   - rspec-core (~> 2.10.0)
122   - rspec-expectations (~> 2.10.0)
123   - rspec-mocks (~> 2.10.0)
124   - rspec-core (2.10.1)
125   - rspec-expectations (2.10.0)
126   - diff-lcs (~> 1.1.3)
127   - rspec-mocks (2.10.1)
128   - rspec-rails (2.10.1)
129   - actionpack (>= 3.0)
130   - activesupport (>= 3.0)
131   - railties (>= 3.0)
132   - rspec (~> 2.10.0)
133   - ruby-feedparser (0.7)
134   - rubyzip (1.1.2)
135   - selenium-webdriver (2.39.0)
136   - childprocess (>= 0.2.5)
137   - multi_json (~> 1.0)
138   - rubyzip (~> 1.0)
139   - websocket (~> 1.0.4)
140   - sprockets (2.1.3)
141   - hike (~> 1.2)
142   - multi_json (~> 1.0)
143   - rack (~> 1.0)
144   - tilt (~> 1.1, != 1.3.0)
145   - term-ansicolor (1.0.7)
146   - thin (1.3.1)
147   - daemons (>= 1.0.9)
148   - eventmachine (>= 0.12.6)
149   - rack (>= 1.0.0)
150   - thor (0.15.3)
151   - tilt (1.3.3)
152   - treetop (1.4.10)
153   - polyglot
154   - polyglot (>= 0.3.1)
155   - tzinfo (0.3.33)
156   - websocket (1.0.7)
157   - will_paginate (3.0.3)
158   - xpath (2.0.0)
159   - nokogiri (~> 1.3)
160   -
161   -PLATFORMS
162   - ruby
163   -
164   -DEPENDENCIES
165   - RedCloth
166   - acts-as-taggable-on
167   - capybara
168   - cucumber
169   - cucumber-rails
170   - daemons
171   - dalli
172   - database_cleaner
173   - exception_notification
174   - fast_gettext
175   - hpricot
176   - mocha
177   - nokogiri
178   - pg
179   - prototype-rails
180   - prototype_legacy_helper (= 0.0.0)!
181   - rails
182   - rails_autolink
183   - rake
184   - rest-client
185   - rmagick
186   - rspec
187   - rspec-rails
188   - ruby-feedparser
189   - selenium-webdriver
190   - thin
191   - will_paginate
INSTALL.md
... ... @@ -186,8 +186,8 @@ Apache instalation
186 186  
187 187 # apt-get install apache2
188 188  
189   -Apache configuration
190   ---------------------
  189 +Configuration - noosfero at /
  190 +-----------------------------
191 191  
192 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 257  
258 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 317 Enabling exception notifications
262 318 ================================
... ...
Rakefile
... ... @@ -6,3 +6,13 @@
6 6 require File.expand_path('../config/application', __FILE__)
7 7  
8 8 Noosfero::Application.load_tasks
  9 +
  10 +[
  11 + "baseplugins/*/{tasks,lib/tasks,rails/tasks}/**/*.rake",
  12 + "config/plugins/*/{tasks,lib/tasks,rails/tasks}/**/*.rake",
  13 + "config/plugins/*/vendor/plugins/*/{tasks,lib/tasks,rails/tasks}/**/*.rake",
  14 +].map do |pattern|
  15 + Dir.glob(pattern).sort
  16 +end.flatten.each do |taskfile|
  17 + load taskfile
  18 +end
... ...
Vagrantfile
... ... @@ -3,7 +3,7 @@
3 3  
4 4 VAGRANTFILE_API_VERSION = "2"
5 5 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
6   - config.vm.box = "debian-wheezy"
  6 + config.vm.box = ENV.fetch('VAGRANT_BOX', "debian-wheezy")
7 7 config.vm.network :forwarded_port, host: 3000, guest: 3000
8 8 config.vm.provision :shell do |shell|
9 9 shell.inline = 'su vagrant -c /vagrant/script/vagrant'
... ...
app/controllers/admin/environment_design_controller.rb
1 1 class EnvironmentDesignController < BoxOrganizerController
2   -
  2 +
3 3 protect 'edit_environment_design', :environment
4 4  
5 5 def available_blocks
6   - @blocks ||= [ ArticleBlock, LoginBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
7   - @blocks += plugins.dispatch(:extra_blocks, :type => Environment)
  6 + @available_blocks ||= [ ArticleBlock, LoginBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
  7 + @available_blocks += plugins.dispatch(:extra_blocks, :type => Environment)
8 8 end
9 9  
10 10 def index
... ...
app/controllers/application_controller.rb
... ... @@ -8,7 +8,7 @@ class ApplicationController &lt; ActionController::Base
8 8 before_filter :init_noosfero_plugins
9 9 before_filter :allow_cross_domain_access
10 10 before_filter :login_required, :if => :private_environment?
11   - before_filter :verify_members_whitelist, :if => :user
  11 + before_filter :verify_members_whitelist, :if => [:private_environment?, :user]
12 12  
13 13 def verify_members_whitelist
14 14 render_access_denied unless user.is_admin? || environment.in_whitelist?(user)
... ... @@ -40,7 +40,7 @@ class ApplicationController &lt; ActionController::Base
40 40  
41 41 theme_layout = theme_option(:layout)
42 42 if theme_layout
43   - theme_view_file('layouts/'+theme_layout) || theme_layout
  43 + (theme_view_file('layouts/'+theme_layout) || theme_layout).to_s
44 44 else
45 45 'application'
46 46 end
... ...
app/controllers/my_profile/cms_controller.rb
... ... @@ -227,7 +227,7 @@ class CmsController &lt; MyProfileController
227 227 @article = profile.articles.find(params[:id])
228 228 if request.post?
229 229 @article.destroy
230   - session[:notice] = _("\"#{@article.name}\" was removed.")
  230 + session[:notice] = _("\"%s\" was removed." % @article.name)
231 231 referer = Rails.application.routes.recognize_path URI.parse(request.referer).path rescue nil
232 232 if referer and referer[:controller] == 'cms' and referer[:action] != 'edit'
233 233 redirect_to referer
... ...
app/controllers/my_profile/friends_controller.rb 100644 → 100755
... ... @@ -20,7 +20,7 @@ class FriendsController &lt; MyProfileController
20 20  
21 21 class << self
22 22 def per_page
23   - 10
  23 + 12
24 24 end
25 25 end
26 26 def per_page
... ...
app/controllers/my_profile/profile_design_controller.rb
... ... @@ -5,47 +5,47 @@ class ProfileDesignController &lt; BoxOrganizerController
5 5 protect 'edit_profile_design', :profile
6 6  
7 7 def available_blocks
8   - @blocks = [ ArticleBlock, TagsBlock, RecentDocumentsBlock, ProfileInfoBlock, LinkListBlock, MyNetworkBlock, FeedReaderBlock, ProfileImageBlock, LocationBlock, SlideshowBlock, ProfileSearchBlock, HighlightsBlock ]
9   - @blocks += plugins.dispatch(:extra_blocks)
  8 + @available_blocks = [ ArticleBlock, TagsBlock, RecentDocumentsBlock, ProfileInfoBlock, LinkListBlock, MyNetworkBlock, FeedReaderBlock, ProfileImageBlock, LocationBlock, SlideshowBlock, ProfileSearchBlock, HighlightsBlock ]
  9 + @available_blocks += plugins.dispatch(:extra_blocks)
10 10  
11 11 # blocks exclusive to people
12 12 if profile.person?
13   - @blocks << FavoriteEnterprisesBlock
14   - @blocks << CommunitiesBlock
15   - @blocks << EnterprisesBlock
16   - @blocks += plugins.dispatch(:extra_blocks, :type => Person)
  13 + @available_blocks << FavoriteEnterprisesBlock
  14 + @available_blocks << CommunitiesBlock
  15 + @available_blocks << EnterprisesBlock
  16 + @available_blocks += plugins.dispatch(:extra_blocks, :type => Person)
17 17 end
18 18  
19 19 # blocks exclusive to communities
20 20 if profile.community?
21   - @blocks += plugins.dispatch(:extra_blocks, :type => Community)
  21 + @available_blocks += plugins.dispatch(:extra_blocks, :type => Community)
22 22 end
23 23  
24 24 # blocks exclusive for enterprises
25 25 if profile.enterprise?
26   - @blocks << DisabledEnterpriseMessageBlock
27   - @blocks << HighlightsBlock
28   - @blocks << ProductCategoriesBlock
29   - @blocks << FeaturedProductsBlock
30   - @blocks << FansBlock
31   - @blocks += plugins.dispatch(:extra_blocks, :type => Enterprise)
  26 + @available_blocks << DisabledEnterpriseMessageBlock
  27 + @available_blocks << HighlightsBlock
  28 + @available_blocks << ProductCategoriesBlock
  29 + @available_blocks << FeaturedProductsBlock
  30 + @available_blocks << FansBlock
  31 + @available_blocks += plugins.dispatch(:extra_blocks, :type => Enterprise)
32 32 end
33 33  
34 34 # product block exclusive for enterprises in environments that permits it
35 35 if profile.enterprise? && profile.environment.enabled?('products_for_enterprises')
36   - @blocks << ProductsBlock
  36 + @available_blocks << ProductsBlock
37 37 end
38 38  
39 39 # block exclusive to profiles that have blog
40 40 if profile.has_blog?
41   - @blocks << BlogArchivesBlock
  41 + @available_blocks << BlogArchivesBlock
42 42 end
43 43  
44 44 if user.is_admin?(profile.environment)
45   - @blocks << RawHTMLBlock
  45 + @available_blocks << RawHTMLBlock
46 46 end
47 47  
48   - @blocks
  48 + @available_blocks
49 49  
50 50 end
51 51  
... ...
app/controllers/my_profile/profile_editor_controller.rb
... ... @@ -16,14 +16,16 @@ class ProfileEditorController &lt; MyProfileController
16 16 if request.post?
17 17 params[:profile_data][:fields_privacy] ||= {} if profile.person? && params[:profile_data].is_a?(Hash)
18 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 27 end
25 28 end
26   - end
27 29 end
28 30 end
29 31  
... ...
app/controllers/public/account_controller.rb
... ... @@ -97,6 +97,7 @@ class AccountController &lt; ApplicationController
97 97 @user.return_to = session[:return_to]
98 98 @person = Person.new(params[:profile_data])
99 99 @person.environment = @user.environment
  100 +
100 101 if request.post?
101 102 if may_be_a_bot
102 103 set_signup_start_time_for_now
... ... @@ -115,6 +116,14 @@ class AccountController &lt; ApplicationController
115 116 invitation.update_attributes!({:friend => @user.person})
116 117 invitation.finish
117 118 end
  119 +
  120 + unless params[:file].nil?
  121 + image = Image::new :uploaded_data=> params[:file][:image]
  122 +
  123 + @user.person.image = image
  124 + @user.person.save
  125 + end
  126 +
118 127 if @user.activated?
119 128 self.current_user = @user
120 129 check_join_in_community(@user)
... ... @@ -184,7 +193,7 @@ class AccountController &lt; ApplicationController
184 193 else
185 194 @change_password.errors[:base] << _('Could not find any user with %s equal to "%s".') % [fields_label, params[:value]]
186 195 end
187   - rescue ActiveRecord::RecordInvald
  196 + rescue ActiveRecord::RecordInvalid
188 197 @change_password.errors[:base] << _('Could not perform password recovery for the user.')
189 198 end
190 199 end
... ...
app/controllers/public/chat_controller.rb
... ... @@ -19,9 +19,13 @@ class ChatController &lt; PublicController
19 19 def avatar
20 20 profile = environment.profiles.find_by_identifier(params[:id])
21 21 filename, mimetype = profile_icon(profile, :minor, true)
22   - data = File.read(File.join(Rails.root, 'public', filename))
23   - render :text => data, :layout => false, :content_type => mimetype
24   - expires_in 24.hours
  22 + if filename =~ /^(https?:)?\/\//
  23 + redirect_to filename
  24 + else
  25 + data = File.read(File.join(Rails.root, 'public', filename))
  26 + render :text => data, :layout => false, :content_type => mimetype
  27 + expires_in 24.hours
  28 + end
25 29 end
26 30  
27 31 def index
... ...
app/controllers/public/content_viewer_controller.rb
... ... @@ -126,7 +126,7 @@ class ContentViewerController &lt; ApplicationController
126 126 elsif !@page.display_to?(user)
127 127 if !profile.public?
128 128 private_profile_partial_parameters
129   - render :template => 'profile/_private_profile', :status => 403
  129 + render :template => 'profile/_private_profile', :status => 403, :formats => [:html]
130 130 allowed = false
131 131 else #if !profile.visible?
132 132 render_access_denied
... ... @@ -216,8 +216,6 @@ class ContentViewerController &lt; ApplicationController
216 216 if @page.has_posts?
217 217 posts = get_posts(params[:year], params[:month])
218 218  
219   - posts = posts.includes(:parent, {:profile => [:domains, :environment]}, :author)
220   -
221 219 #FIXME Need to run this before the pagination because this version of
222 220 # will_paginate returns a will_paginate collection instead of a
223 221 # relation.
... ...
app/controllers/public/profile_controller.rb
... ... @@ -17,7 +17,11 @@ class ProfileController &lt; PublicController
17 17 end
18 18 @tags = profile.article_tags
19 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 25 end
22 26 end
23 27  
... ... @@ -61,13 +65,13 @@ class ProfileController &lt; PublicController
61 65  
62 66 def friends
63 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 69 end
66 70 end
67 71  
68 72 def members
69 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 75 end
72 76 end
73 77  
... ... @@ -315,7 +319,7 @@ class ProfileController &lt; PublicController
315 319 abuse_report = AbuseReport.new(params[:abuse_report])
316 320 if !params[:content_type].blank?
317 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 323 end
320 324  
321 325 user.register_report(abuse_report, profile)
... ... @@ -394,6 +398,7 @@ class ProfileController &lt; PublicController
394 398  
395 399 def private_profile
396 400 private_profile_partial_parameters
  401 + render :action => 'index', :status => 403
397 402 end
398 403  
399 404 def invisible_profile
... ...
app/controllers/public/search_controller.rb
... ... @@ -90,10 +90,14 @@ class SearchController &lt; PublicController
90 90 end
91 91  
92 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 101 date_range = (@date - 1.month).at_beginning_of_month..(@date + 1.month).at_end_of_month
98 102  
99 103 @events = []
... ...
app/helpers/application_helper.rb
... ... @@ -304,7 +304,7 @@ module ApplicationHelper
304 304 def partial_for_class(klass, prefix=nil, suffix=nil)
305 305 raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil?
306 306 name = klass.name.underscore
307   - controller.view_paths.reverse_each do |view_path|
  307 + controller.view_paths.each do |view_path|
308 308 partial = partial_for_class_in_view_path(klass, view_path, prefix, suffix)
309 309 return partial if partial
310 310 end
... ... @@ -482,7 +482,12 @@ module ApplicationHelper
482 482 '/images/icons-app/enterprise-'+ size.to_s() +'.png'
483 483 end
484 484 else
485   - '/images/icons-app/person-'+ size.to_s() +'.png'
  485 + pixels = Image.attachment_options[:thumbnails][size].split('x').first
  486 + gravatar_profile_image_url(
  487 + profile.email,
  488 + :size => pixels,
  489 + :d => gravatar_default
  490 + )
486 491 end
487 492 filename = default_or_themed_icon(icon)
488 493 end
... ... @@ -602,7 +607,7 @@ module ApplicationHelper
602 607 end
603 608  
604 609 def gravatar_default
605   - (respond_to?(:theme_option) && theme_option.present? && theme_option['gravatar']) || NOOSFERO_CONF['gravatar']
  610 + (respond_to?(:theme_option) && theme_option.present? && theme_option['gravatar']) || NOOSFERO_CONF['gravatar'] || 'mm'
606 611 end
607 612  
608 613 attr_reader :environment
... ... @@ -902,13 +907,15 @@ module ApplicationHelper
902 907 end
903 908  
904 909 def page_title
905   - (@page ? @page.title + ' - ' : '') +
906   - (@topic ? @topic.title + ' - ' : '') +
907   - (@section ? @section.title + ' - ' : '') +
908   - (@toc ? _('Online Manual') + ' - ' : '') +
909   - (controller.controller_name == 'chat' ? _('Chat') + ' - ' : '') +
910   - (profile ? profile.short_name : environment.name) +
911   - (@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 + )
912 919 end
913 920  
914 921 # DEPRECATED. Do not use this.
... ... @@ -1280,11 +1287,13 @@ module ApplicationHelper
1280 1287 end
1281 1288  
1282 1289 def delete_article_message(article)
1283   - if article.folder?
1284   - _("Are you sure that you want to remove the folder \"#{article.name}\"? Note that all the items inside it will also be removed!")
1285   - else
1286   - _("Are you sure that you want to remove the item \"#{article.name}\"?")
1287   - 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 + )
1288 1297 end
1289 1298  
1290 1299 def expirable_link_to(expired, content, url, options = {})
... ... @@ -1372,7 +1381,7 @@ module ApplicationHelper
1372 1381 # are old things that do not support it we are keeping this hot spot.
1373 1382 html = @plugins.pipeline(:parse_content, html, source).first
1374 1383 end
1375   - html
  1384 + html && html.html_safe
1376 1385 end
1377 1386  
1378 1387 def convert_macro(html, source)
... ...
app/helpers/article_helper.rb
... ... @@ -3,6 +3,12 @@ module ArticleHelper
3 3 include PrototypeHelper
4 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 12 def custom_options_for_article(article, tokenized_children)
7 13 @article = article
8 14  
... ...
app/helpers/layout_helper.rb
... ... @@ -28,7 +28,6 @@ module LayoutHelper
28 28 'lightbox',
29 29 'colorbox',
30 30 'block_store',
31   - 'inputosaurus',
32 31 pngfix_stylesheet_path,
33 32 ] + tokeninput_stylesheets
34 33 plugins_stylesheets = @plugins.select(&:stylesheet?).map { |plugin| plugin.class.public_path('style.css') }
... ...
app/helpers/profile_helper.rb
1 1 module ProfileHelper
2 2  
3   - def display_field(title, profile, field, force = false)
  3 + COMMON_CATEGORIES = ActiveSupport::OrderedHash.new
  4 + COMMON_CATEGORIES[:content] = [:blogs, :image_galleries, :events, :article_tags]
  5 + COMMON_CATEGORIES[:interests] = [:interests]
  6 + COMMON_CATEGORIES[:general] = nil
  7 +
  8 + PERSON_CATEGORIES = ActiveSupport::OrderedHash.new
  9 + PERSON_CATEGORIES[:basic_information] = [:nickname, :sex, :birth_date, :location, :privacy_setting, :created_at]
  10 + PERSON_CATEGORIES[:contact] = [:contact_phone, :cell_phone, :comercial_phone, :contact_information, :email, :personal_website, :jabber_id]
  11 + PERSON_CATEGORIES[:location] = [:address, :address_reference, :zip_code, :city, :state, :district, :country, :nationality]
  12 + PERSON_CATEGORIES[:work] = [:organization, :organization_website, :professional_activity]
  13 + PERSON_CATEGORIES[:study] = [:schooling, :formation, :area_of_study]
  14 + PERSON_CATEGORIES[:network] = [:friends, :communities, :enterprises]
  15 + PERSON_CATEGORIES.merge!(COMMON_CATEGORIES)
  16 +
  17 + ORGANIZATION_CATEGORIES = ActiveSupport::OrderedHash.new
  18 + ORGANIZATION_CATEGORIES[:basic_information] = [:display_name, :created_at, :foundation_year, :type, :language, :members_count, :location, :address_reference, :historic_and_current_context, :admins]
  19 + ORGANIZATION_CATEGORIES[:contact] = [:contact_person, :contact_phone, :contact_email, :organization_website, :jabber_id]
  20 + ORGANIZATION_CATEGORIES[:economic] = [:business_name, :acronym, :economic_activity, :legal_form, :products, :activities_short_description, :management_information]
  21 + ORGANIZATION_CATEGORIES.merge!(COMMON_CATEGORIES)
  22 +
  23 + CATEGORY_MAP = ActiveSupport::OrderedHash.new
  24 + CATEGORY_MAP[:person] = PERSON_CATEGORIES
  25 + CATEGORY_MAP[:organization] = ORGANIZATION_CATEGORIES
  26 +
  27 + FORCE = {
  28 + :person => [:privacy_setting],
  29 + :organization => [:privacy_setting, :location],
  30 + }
  31 +
  32 + MULTIPLE = {
  33 + :person => [:blogs, :image_galleries, :interests],
  34 + :organization => [:blogs, :image_galleries, :interests],
  35 + }
  36 +
  37 + CUSTOM_LABELS = {
  38 + :zip_code => _('ZIP code'),
  39 + :email => _('e-Mail'),
  40 + :jabber_id => _('Jabber'),
  41 + :birth_date => _('Date of birth'),
  42 + :created_at => _('Profile created at'),
  43 + :members_count => _('Members'),
  44 + :privacy_setting => _('Privacy setting'),
  45 + :article_tags => _('Tags')
  46 + }
  47 +
  48 + EXCEPTION = {
  49 + :person => [:image, :preferred_domain, :description, :tag_list],
  50 + :organization => [:image, :preferred_domain, :description, :tag_list, :address, :zip_code, :city, :state, :country, :district]
  51 + }
  52 +
  53 + def general_fields
  54 + categorized_fields = CATEGORY_MAP[kind].values.flatten
  55 + profile.class.fields.map(&:to_sym) - categorized_fields - EXCEPTION[kind]
  56 + end
  57 +
  58 + def kind
  59 + if profile.kind_of?(Person)
  60 + :person
  61 + else
  62 + :organization
  63 + end
  64 + end
  65 +
  66 + def title(field, entry = nil)
  67 + return self.send("#{field}_custom_title", entry) if MULTIPLE[kind].include?(field) && entry.present?
  68 + CUSTOM_LABELS[field.to_sym] || _(field.to_s.humanize)
  69 + end
  70 +
  71 + def display_field(field)
  72 + force = FORCE[kind].include?(field)
  73 + multiple = MULTIPLE[kind].include?(field)
4 74 unless force || profile.may_display_field_to?(field, user)
5 75 return ''
6 76 end
7   - value = profile.send(field)
8   - if !value.blank?
9   - if block_given?
10   - value = yield(value)
11   - end
12   - content_tag('tr', content_tag('td', title, :class => 'field-name') + content_tag('td', value))
  77 + value = begin profile.send(field) rescue nil end
  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))
13 82 else
14   - ''
  83 + entries = multiple ? value : [] << value
  84 + entries.map do |entry|
  85 + content = self.send("treat_#{field}", entry)
  86 + unless content.blank?
  87 + content_tag('tr', content_tag('td', title(field, entry), :class => 'field-name') + content_tag('td', content))
  88 + end
  89 + end.join("\n")
15 90 end
16 91 end
17 92  
18   - def display_contact(profile)
19   - fields = []
20   - fields << display_field(_('Address:'), profile, :address).html_safe
21   - fields << display_field(_('ZIP code:'), profile, :zip_code).html_safe
22   - fields << display_field(_('Contact phone:'), profile, :contact_phone).html_safe
23   - fields << display_field(_('e-Mail:'), profile, :email) { |email| link_to_email(email) }.html_safe
24   - fields << display_field(_('Personal website:'), profile, :personal_website).html_safe
25   - fields << display_field(_('Jabber:'), profile, :jabber_id).html_safe
26   - if fields.reject!(&:blank?).empty?
27   - ''
28   - else
29   - content_tag('tr', content_tag('th', _('Contact'), { :colspan => 2 })) + fields.join.html_safe
  93 + def treat_email(email)
  94 + link_to_email(email)
  95 + end
  96 +
  97 + def treat_organization_website(url)
  98 + link_to(url, url)
  99 + end
  100 +
  101 + def treat_sex(gender)
  102 + { 'male' => _('Male'), 'female' => _('Female') }[gender]
  103 + end
  104 +
  105 + def treat_date(date)
  106 + show_date(date.to_date)
  107 + end
  108 + alias :treat_birth_date :treat_date
  109 + alias :treat_created_at :treat_date
  110 +
  111 + def treat_friends(friends)
  112 + link_to friends.count, :controller => 'profile', :action => 'friends'
  113 + end
  114 +
  115 + def treat_communities(communities)
  116 + link_to communities.count, :controller => "profile", :action => 'communities'
  117 + end
  118 +
  119 + def treat_enterprises(enterprises)
  120 + if environment.disabled?('disable_asset_enterprises')
  121 + link_to enterprises.count, :controller => "profile", :action => 'enterprises'
  122 + end
  123 + end
  124 +
  125 + def treat_members_count(count)
  126 + link_to count, :controller => 'profile', :action => 'members'
  127 + end
  128 +
  129 + def treat_products(products)
  130 + if profile.kind_of?(Enterprise) && profile.environment.enabled?('products_for_enterprises')
  131 + link_to _('Products/Services'), :controller => 'catalog', :action => 'index'
30 132 end
31 133 end
32 134  
33   - def display_work_info(profile)
34   - organization = display_field(_('Organization:'), profile, :organization)
35   - organization_site = display_field(_('Organization website:'), profile, :organization_website) { |url| link_to(url, url) }
36   - if organization.blank? && organization_site.blank?
37   - ''
  135 + def treat_admins(admins)
  136 + profile.admins.map { |admin| link_to(admin.short_name, admin.url)}.join(', ')
  137 + end
  138 +
  139 + def treat_blogs(blog)
  140 + link_to(n_('One post', '%{num} posts', blog.posts.published.count) % { :num => blog.posts.published.count }, blog.url)
  141 + end
  142 +
  143 + def treat_image_galleries(gallery)
  144 + link_to(n_('One picture', '%{num} pictures', gallery.images.published.count) % { :num => gallery.images.published.count }, gallery.url)
  145 + end
  146 +
  147 + def treat_events(events)
  148 + link_to events.published.count, :controller => 'events', :action => 'events'
  149 + end
  150 +
  151 + def treat_article_tags(tags)
  152 + tag_cloud @tags, :id, { :action => 'tags' }, :max_size => 18, :min_size => 10
  153 + end
  154 +
  155 + def treat_interests(interest)
  156 + link_to interest.name, :controller => 'search', :action => 'category_index', :category_path => interest.explode_path
  157 + end
  158 +
  159 + def article_custom_title(article)
  160 + article.name
  161 + end
  162 + alias :blogs_custom_title :article_custom_title
  163 + alias :image_galleries_custom_title :article_custom_title
  164 +
  165 + def interests_custom_title(interest)
  166 + ''
  167 + end
  168 +
  169 + def method_missing(method, *args, &block)
  170 + if method.to_s =~ /^treat_(.+)$/
  171 + args[0]
  172 + elsif method.to_s =~ /^display_(.+)$/ && CATEGORY_MAP[kind].has_key?($1.to_sym)
  173 + category = $1.to_sym
  174 + fields = category == :general ? general_fields : CATEGORY_MAP[kind][category]
  175 + contents = []
  176 +
  177 + fields.each do |field|
  178 + contents << display_field(field).html_safe
  179 + end
  180 +
  181 + contents = contents.delete_if(&:blank?)
  182 +
  183 + unless contents.empty?
  184 + content_tag('tr', content_tag('th', title(category), { :colspan => 2 })) + contents.join.html_safe
  185 + else
  186 + ''
  187 + end
38 188 else
39   - content_tag('tr', content_tag('th', _('Work'), { :colspan => 2 })) + organization + organization_site
  189 + super
40 190 end
41 191 end
42 192  
... ...
app/helpers/role_helper.rb
1 1 module RoleHelper
  2 +
  3 + def role_available_permissions(role)
  4 + role.kind == "Environment" ? ['Environment', 'Profile'] : [role.kind]
  5 + end
  6 +
2 7 end
... ...
app/helpers/sweeper_helper.rb
... ... @@ -56,12 +56,12 @@ module SweeperHelper
56 56 if profile
57 57 profile.blocks.each {|block|
58 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 61 end
62 62 environment.blocks.each {|block|
63 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 67 blocks_to_expire.uniq!
... ...
app/helpers/tinymce_helper.rb 0 → 100644
... ... @@ -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
... ... @@ -157,14 +157,17 @@ class Article &lt; ActiveRecord::Base
157 157 self.profile
158 158 end
159 159  
160   - def self.human_attribute_name(attrib, options = {})
  160 + def self.human_attribute_name_with_customization(attrib, options={})
161 161 case attrib.to_sym
162 162 when :name
163 163 _('Title')
164 164 else
165   - _(self.superclass.human_attribute_name(attrib))
  165 + _(self.human_attribute_name_without_customization(attrib))
166 166 end
167 167 end
  168 + class << self
  169 + alias_method_chain :human_attribute_name, :customization
  170 + end
168 171  
169 172 def css_class_list
170 173 [self.class.name.to_css_class]
... ... @@ -282,13 +285,6 @@ class Article &lt; ActiveRecord::Base
282 285 end
283 286 end
284 287  
285   - def reported_version(options = {})
286   - article = self
287   - search_path = Rails.root.join('app', 'views', 'shared', 'reported_versions')
288   - partial_path = File.join('shared', 'reported_versions', partial_for_class_in_view_path(article.class, search_path))
289   - lambda { render_to_string(:partial => partial_path, :locals => {:article => article}) }
290   - end
291   -
292 288 # returns the data of the article. Must be overriden in each subclass to
293 289 # provide the correct content for the article.
294 290 def data
... ...
app/models/block.rb
... ... @@ -116,7 +116,7 @@ class Block &lt; ActiveRecord::Base
116 116 # Must be redefined in subclasses to match the description of each block
117 117 # type.
118 118 def self.description
119   - _('nothing')
  119 + ('dummy')
120 120 end
121 121  
122 122 # returns a short description of the block, used when the user sees a list of
... ... @@ -205,7 +205,7 @@ class Block &lt; ActiveRecord::Base
205 205  
206 206 # Override in your subclasses.
207 207 # Define which events and context should cause the block cache to expire
208   - # Possible events are: :article, :profile, :friendship, :category
  208 + # Possible events are: :article, :profile, :friendship, :category, :role_assignment
209 209 # Possible contexts are: :profile, :environment
210 210 def self.expire_on
211 211 {
... ... @@ -254,7 +254,7 @@ class Block &lt; ActiveRecord::Base
254 254  
255 255 def self.icon_path
256 256 basename = self.name.split('::').last.underscore
257   - File.join('blocks', basename, 'icon.png')
  257 + File.join('blocks', basename, 'icon.png')
258 258 end
259 259  
260 260 def self.default_icon_path
... ... @@ -265,4 +265,9 @@ class Block &lt; ActiveRecord::Base
265 265 "block_preview.png"
266 266 end
267 267  
  268 + def copy_from(block)
  269 + self.settings = block.settings
  270 + self.position = block.position
  271 + end
  272 +
268 273 end
... ...
app/models/change_password.rb
... ... @@ -2,16 +2,19 @@ class ChangePassword &lt; Task
2 2  
3 3 attr_accessor :password, :password_confirmation
4 4  
5   - def self.human_attribute_name(attrib, options = {})
  5 + def self.human_attribute_name_with_customization(attrib, options={})
6 6 case attrib.to_sym
7 7 when :password
8 8 _('Password')
9 9 when :password_confirmation
10 10 _('Password Confirmation')
11 11 else
12   - _(self.superclass.human_attribute_name(attrib))
  12 + _(self.human_attribute_name_without_customization(attrib))
13 13 end
14 14 end
  15 + class << self
  16 + alias_method_chain :human_attribute_name, :customization
  17 + end
15 18  
16 19 validates_presence_of :requestor
17 20  
... ...
app/models/community.rb
... ... @@ -50,16 +50,6 @@ class Community &lt; Organization
50 50 super + FIELDS
51 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 53 def active_fields
64 54 environment ? environment.active_community_fields : []
65 55 end
... ...
app/models/enterprise.rb
... ... @@ -59,16 +59,6 @@ class Enterprise &lt; Organization
59 59 super + FIELDS
60 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 62 def active_fields
73 63 environment ? environment.active_enterprise_fields : []
74 64 end
... ...
app/models/environment.rb
... ... @@ -660,6 +660,7 @@ class Environment &lt; ActiveRecord::Base
660 660 url = 'http://'
661 661 url << (Noosfero.url_options.key?(:host) ? Noosfero.url_options[:host] : default_hostname)
662 662 url << ':' << Noosfero.url_options[:port].to_s if Noosfero.url_options.key?(:port)
  663 + url << Noosfero.root('')
663 664 url
664 665 end
665 666  
... ... @@ -804,7 +805,7 @@ class Environment &lt; ActiveRecord::Base
804 805 end
805 806  
806 807 def notification_emails
807   - [noreply_email.blank? ? nil : noreply_email].compact + admins.map(&:email)
  808 + [contact_email].select(&:present?) + admins.map(&:email)
808 809 end
809 810  
810 811 after_create :create_templates
... ...
app/models/external_feed.rb
... ... @@ -13,6 +13,7 @@ class ExternalFeed &lt; ActiveRecord::Base
13 13 attr_accessible :address, :enabled
14 14  
15 15 def add_item(title, link, date, content)
  16 + return if content.blank?
16 17 doc = Hpricot(content)
17 18 doc.search('*').each do |p|
18 19 if p.instance_of? Hpricot::Elem
... ... @@ -30,6 +31,7 @@ class ExternalFeed &lt; ActiveRecord::Base
30 31 article.source = link
31 32 article.profile = blog.profile
32 33 article.parent = blog
  34 + article.author_name = self.feed_title
33 35 unless blog.children.exists?(:slug => article.slug)
34 36 article.save!
35 37 article.delay.create_activity
... ...
app/models/feed_reader_block.rb
... ... @@ -85,8 +85,4 @@ class FeedReaderBlock &lt; Block
85 85 block_title(title) + formatted_feed_content
86 86 end
87 87  
88   - def editable?
89   - true
90   - end
91   -
92 88 end
... ...
app/models/link_list_block.rb
... ... @@ -78,16 +78,17 @@ class LinkListBlock &lt; Block
78 78 address
79 79 end
80 80 if add !~ /^[a-z]+:\/\// && add !~ /^\//
81   - 'http://' + add
  81 + '//' + add
82 82 else
  83 + if root = Noosfero.root
  84 + if !add.starts_with?(root)
  85 + add = root + add
  86 + end
  87 + end
83 88 add
84 89 end
85 90 end
86 91  
87   - def editable?
88   - true
89   - end
90   -
91 92 def icons_options
92 93 ICONS.map do |i|
93 94 "<span title=\"#{i[1]}\" class=\"icon-#{i[0]}\" onclick=\"changeIcon(this, '#{i[0]}')\"></span>".html_safe
... ... @@ -100,4 +101,5 @@ class LinkListBlock &lt; Block
100 101 sanitizer = HTML::WhiteListSanitizer.new
101 102 sanitizer.sanitize(text)
102 103 end
  104 +
103 105 end
... ...
app/models/main_block.rb
... ... @@ -16,10 +16,6 @@ class MainBlock &lt; Block
16 16 true
17 17 end
18 18  
19   - def editable?
20   - true
21   - end
22   -
23 19 def cacheable?
24 20 false
25 21 end
... ...
app/models/organization.rb
... ... @@ -30,6 +30,16 @@ class Organization &lt; Profile
30 30  
31 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 43 def validation_methodology
34 44 self.validation_info ? self.validation_info.validation_methodology : nil
35 45 end
... ... @@ -135,7 +145,11 @@ class Organization &lt; Profile
135 145 end
136 146  
137 147 def notification_emails
138   - [contact_email.blank? ? nil : contact_email].compact + admins.map(&:email)
  148 + emails = [contact_email].select(&:present?) + admins.map(&:email)
  149 + if emails.empty?
  150 + emails << environment.contact_email
  151 + end
  152 + emails
139 153 end
140 154  
141 155 def already_request_membership?(person)
... ...
app/models/person.rb
... ... @@ -161,7 +161,7 @@ class Person &lt; Profile
161 161 FIELDS
162 162 end
163 163  
164   - validate :presence_of_required_fields
  164 + validate :presence_of_required_fields, :unless => :is_template
165 165  
166 166 def presence_of_required_fields
167 167 self.required_fields.each do |field|
... ...
app/models/profile.rb
... ... @@ -97,7 +97,7 @@ class Profile &lt; ActiveRecord::Base
97 97 end
98 98  
99 99 def members_by_name
100   - members.order(:name)
  100 + members.order('profiles.name')
101 101 end
102 102  
103 103 class << self
... ... @@ -346,16 +346,17 @@ class Profile &lt; ActiveRecord::Base
346 346 end
347 347  
348 348 def copy_blocks_from(profile)
  349 + template_boxes = profile.boxes.select{|box| box.position}
349 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 355 new_box.position = box.position
353   - self.boxes << new_box
354 356 box.blocks.each do |block|
355 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 360 end
360 361 end
361 362 end
... ...
app/models/profile_image_block.rb
... ... @@ -23,10 +23,6 @@ class ProfileImageBlock &lt; Block
23 23 end
24 24 end
25 25  
26   - def editable?
27   - true
28   - end
29   -
30 26 def cacheable?
31 27 false
32 28 end
... ...
app/models/profile_info_block.rb
... ... @@ -23,10 +23,6 @@ class ProfileInfoBlock &lt; Block
23 23 end
24 24 end
25 25  
26   - def editable?
27   - false
28   - end
29   -
30 26 def cacheable?
31 27 false
32 28 end
... ...
app/models/profile_search_block.rb
... ... @@ -11,8 +11,4 @@ class ProfileSearchBlock &lt; Block
11 11 end
12 12 end
13 13  
14   - def editable?
15   - true
16   - end
17   -
18 14 end
... ...
app/models/task.rb
... ... @@ -285,8 +285,9 @@ class Task &lt; ActiveRecord::Base
285 285 # If
286 286 def send_notification(action)
287 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 291 end
291 292 end
292 293 end
... ...
app/models/user.rb
... ... @@ -16,15 +16,18 @@ class User &lt; ActiveRecord::Base
16 16 end
17 17  
18 18 # FIXME ugly workaround
19   - def self.human_attribute_name(attrib, options={})
  19 + def self.human_attribute_name_with_customization(attrib, options={})
20 20 case attrib.to_sym
21 21 when :login
22 22 return [_('Username'), _('Email')].join(' / ')
23 23 when :email
24 24 return _('e-Mail')
25   - else _(self.superclass.human_attribute_name(attrib))
  25 + else _(self.human_attribute_name_without_customization(attrib))
26 26 end
27 27 end
  28 + class << self
  29 + alias_method_chain :human_attribute_name, :customization
  30 + end
28 31  
29 32 before_create do |user|
30 33 if user.environment.nil?
... ... @@ -198,6 +201,10 @@ class User &lt; ActiveRecord::Base
198 201 Digest::MD5.hexdigest(password)
199 202 end
200 203  
  204 + add_encryption_method :salted_md5 do |password, salt|
  205 + Digest::MD5.hexdigest(password+salt)
  206 + end
  207 +
201 208 add_encryption_method :clear do |password, salt|
202 209 password
203 210 end
... ... @@ -347,6 +354,7 @@ class User &lt; ActiveRecord::Base
347 354 end
348 355  
349 356 def delay_activation_check
  357 + return if person.is_template?
350 358 Delayed::Job.enqueue(UserActivationJob.new(self.id), {:priority => 0, :run_at => 72.hours.from_now})
351 359 end
352 360 end
... ...
app/sweepers/role_assignment_sweeper.rb
... ... @@ -13,20 +13,22 @@ class RoleAssignmentSweeper &lt; ActiveRecord::Observer
13 13 protected
14 14  
15 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 18 end
19 19  
20 20 def expire_cache(profile)
21 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 26 profile.blocks_to_expire_cache.each { |block|
27 27 blocks = profile.blocks.select{|b| b.kind_of?(block)}
28 28 BlockSweeper.expire_blocks(blocks)
29 29 }
  30 +
  31 + expire_blocks_cache(profile, [:role_assignment])
30 32 end
31 33  
32 34 end
... ...
app/views/box_organizer/index.html.erb
... ... @@ -8,12 +8,12 @@
8 8 <% end %>
9 9  
10 10 <% n_blocks_in_line = 0 %>
11   -<% last_block = @blocks.last %>
  11 +<% last_block = @available_blocks.last %>
12 12  
13 13 <div id="block-types-container">
14 14 <div id="block-types">
15 15  
16   - <% @blocks.each do |block| %>
  16 + <% @available_blocks.each do |block| %>
17 17  
18 18 <% if n_blocks_in_line == 0 %>
19 19 <div class="block-types-group">
... ...
app/views/catalog/index.html.erb
... ... @@ -14,8 +14,8 @@
14 14  
15 15 <ul id="product-list">
16 16 <% @products.each do |product| %>
17   - <% extra_content = @plugins.dispatch(:catalog_item_extras, product).collect { |content| instance_eval(&content) } %>
18   - <% extra_content_list = @plugins.dispatch(:catalog_list_item_extras, product).collect { |content| instance_eval(&content) } %>
  17 + <% extra_content = @plugins.dispatch(:catalog_item_extras, product).collect { |content| instance_exec(&content) } %>
  18 + <% extra_content_list = @plugins.dispatch(:catalog_list_item_extras, product).collect { |content| instance_exec(&content) } %>
19 19  
20 20 <% status = [] %>
21 21 <% status << 'not-available' if !product.available %>
... ...
app/views/events/_month.html.erb
... ... @@ -13,8 +13,8 @@
13 13 date.day,
14 14 :url => {:action => 'events_by_day', :year => date.year, :month => date.month, :day => date.day, :category_id => @category_id},
15 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 19 date.day
20 20 %>
... ...
app/views/file_presenter/_generic.html.erb
1 1 <span class="download-link">
2 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 4 </span>
5 5  
6 6 <div class="uploaded-file-description <%= 'empty' if generic.abstract.blank? %>">
... ...
app/views/file_presenter/_image.html.erb
... ... @@ -28,7 +28,7 @@
28 28  
29 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 33 <div class="uploaded-file-description <%= 'empty' if image.abstract.blank? %>">
34 34 <%= image.abstract %>
... ...
app/views/home/index.html.erb
... ... @@ -61,9 +61,6 @@
61 61 <%= submit_button(:search, _('Search')) %>
62 62 </div>
63 63  
64   - <div>
65   - <%= lightbox_link_to _('More options'), :controller => 'search', :action => 'popup' %>
66   - </div>
67 64 <% end %>
68 65 </div>
69 66 <% end %>
... ...
app/views/layouts/application-ng.html.erb
... ... @@ -17,7 +17,10 @@
17 17 <meta property="og:url" content="<%= @page ? url_for(@page.url) : @environment.top_url %>">
18 18 <meta property="og:title" content="<%= h page_title %>">
19 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 25 <% if @page %>
23 26 <meta property="article:published_time" content="<%= show_date(@page.published_at) %>">
... ...
app/views/manage_products/_edit_description.html.erb
1 1 <%= render :file => 'shared/tiny_mce', :locals => {:mode => 'simple'} %>
2 2 <%= remote_form_for(@product,
3 3 :loading => "small_loading('product-description-form')",
4   - :before => ("tinyMCE.triggerSave()" unless Rails.env == 'test'),
5 4 :update => 'product-description',
6 5 :url => {:controller => 'manage_products', :action => 'edit', :id => @product, :field => 'description'},
7 6 :html => {:id => 'product-description-form', :method => 'post'}) do |f| %>
... ...
app/views/manage_products/show.html.erb
... ... @@ -13,7 +13,7 @@
13 13 <%= render :partial => 'manage_products/display_image' %>
14 14 </div>
15 15 <div id='product-extra-content'>
16   - <% extra_content = @plugins.dispatch(:product_info_extras, @product).collect { |content| instance_eval(&content) } %>
  16 + <% extra_content = @plugins.dispatch(:product_info_extras, @product).collect { |content| instance_exec(&content) } %>
17 17 <%= extra_content.join("\n") %>
18 18 </div>
19 19 <div id='product-info'>
... ...
app/views/profile/_common.html.erb
1 1 <% unless @action %>
2 2 <% cache_timeout(profile.cache_key + '-profile-general-info', 4.hours) do %>
3   - <tr>
4   - <th colspan='2'>
5   - <%= _('Content') %>
6   - </th>
7   - </tr>
8   -
9   - <% profile.blogs.each do |blog| %>
10   - <tr>
11   - <td><%= blog.name + ':' %></td>
12   - <td>
13   - <%= link_to(n_('One post', '%{num} posts', blog.posts.published.count) % { :num => blog.posts.published.count }, blog.url) %>
14   - </td>
15   - </tr>
16   - <% end %>
17   - <% profile.image_galleries.each do |gallery| %>
18   - <tr>
19   - <td><%= gallery.name + ':' %></td>
20   - <td>
21   - <%= link_to(n_('One picture', '%{num} pictures', gallery.images.published.count) % { :num => gallery.images.published.count }, gallery.url) %>
22   - </td>
23   - </tr>
24   - <% end %>
25   -
26   - <tr>
27   - <td><%= _('Events:') %></td>
28   - <td>
29   - <%= link_to profile.events.published.count, :controller => 'events', :action => 'events' %>
30   - </td>
31   - </tr>
32   - <tr>
33   - <td>
34   - <%= _('Tags:') %>
35   - </td>
36   - <td>
37   - <%= tag_cloud @tags, :id, { :action => 'tags' }, :max_size => 18, :min_size => 10%>
38   - </td>
39   - </tr>
  3 + <%= display_content %>
40 4  
41 5 <% if !environment.enabled?('disable_categories') && !profile.interests.empty? %>
42   - <tr>
43   - <th colspan='2'><%= _('Interests') %></th>
44   - </tr>
45   - <% profile.interests.each do |item| %>
46   - <tr>
47   - <td></td>
48   - <td><%= link_to item.name, :controller => 'search', :action => 'category_index', :category_path => item.explode_path %></td>
49   - </tr>
50   - <% end %>
  6 + <%= display_interests %>
51 7 <% end %>
  8 +
  9 + <%= display_general %>
52 10 <% end %>
53 11 <% end %>
... ...
app/views/profile/_organization_profile.html.erb
1 1 <table>
2   - <tr>
3   - <th colspan='2'><%= _('Basic information')%></th>
4   - </tr>
5   -
6   - <tr>
7   - <td class='field-name'><%= _('Members') %></td>
8   - <td>
9   - <%= link_to profile.members_count, :controller => 'profile', :action => 'members' %>
10   - </td>
11   - </tr>
12   -
13   - <%= display_field(_('Type:'), profile, :privacy_setting, true) %>
14   -
15   - <%= display_field(_('Location:'), profile, :location, true) %>
16   -
17   - <tr>
18   - <td class='field-name'><%= _('Profile created at:') %></td>
19   - <td><%= show_date(profile.created_at) %></td>
20   - </tr>
21   -
22   - <% if profile.kind_of?(Enterprise) && profile.environment.enabled?('products_for_enterprises') %>
23   - <tr>
24   - <td></td>
25   - <td>
26   - <%= link_to _('Products/Services'), :controller => 'catalog', :action => 'index' %>
27   - </td>
28   - </tr>
29   - <% end %>
30   -
31   - <tr>
32   - <td class='field-name'><%= _('Administrators:') %></td>
33   - <td>
34   - <%= profile.admins.map { |admin| link_to(admin.short_name, admin.url)}.join(', ') %>
35   - </td>
36   - </tr>
37   -
  2 + <%= display_basic_information %>
  3 + <%= display_contact %>
  4 + <%= display_economic %>
38 5 <%= render :partial => 'common' %>
39 6 </table>
... ...
app/views/profile/_person_profile.html.erb
1 1 <table>
2   - <tr>
3   - <th colspan='2'><%= _('Basic information')%></th>
4   - </tr>
5   - <%= display_field(_('Sex:'), profile, :sex) { |gender| { 'male' => _('Male'), 'female' => _('Female') }[gender] } %>
6   - <%= display_field(_('Date of birth:'), profile, :birth_date) { |date| show_date(date) }%>
7   - <%= display_field _('Location:'), profile, :location %>
8   -
9   - <%= display_field(_('Type:'), profile, :privacy_setting, true) %>
10   -
11   - <tr>
12   - <td class='field-name'><%= _('Profile created at:') %></td>
13   - <td><%= show_date(profile.created_at) %></td>
14   - </tr>
15   -
16   - <%= display_contact profile %>
  2 + <%= display_basic_information %>
  3 + <%= display_contact %>
  4 + <%= display_location %>
17 5  
18 6 <% cache_timeout(profile.relationships_cache_key, 4.hours) do %>
19   - <%= display_work_info profile %>
20   -
21   - <tr>
22   - <th colspan='2'><%= _('Network')%></th>
23   - </tr>
24   - <tr>
25   - <td><%= _('Friends') + ':' %></td>
26   - <td><%= link_to profile.friends.count, { :controller => 'profile', :action => 'friends' } %></td>
27   - </tr>
28   - <tr>
29   - <td><%= _('Communities') + ':' %></td>
30   - <td><%= link_to profile.communities.count, :controller => "profile", :action => 'communities' %></td>
31   - </tr>
32   - <% if environment.disabled?('disable_asset_enterprises') %>
33   - <tr id="person-profile-network-enterprises">
34   - <td><%= _('Enterprises') + ':' %></td>
35   - <td><%= link_to profile.enterprises.count, :controller => "profile", :action => 'enterprises' %></td>
36   - </tr>
37   - <% end %>
  7 + <%= display_work %>
  8 + <%= display_study %>
  9 + <%= display_network %>
38 10  
39 11 <%= render :partial => 'common' %>
40   -
41 12 <% end %>
42 13 </table>
43 14  
... ...
app/views/profile/_profile_comment_form.html.erb
... ... @@ -10,8 +10,8 @@
10 10 :rows => 1,
11 11 :class => 'submit-with-keypress',
12 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 15 :value => _('Leave your comment'),
16 16 :style => 'color: #ccc' %>
17 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 9 :rows => 1,
10 10 :class => 'submit-with-keypress',
11 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 14 :value => _('Leave your comment') %>
15 15 <%= hidden_field_tag 'scrap[scrap_id]', scrap.id %>
16 16 <%= hidden_field_tag 'receiver_id', scrap.sender.id %>
... ...
app/views/profile_editor/_person_form.html.erb
... ... @@ -25,6 +25,11 @@
25 25 <%= optional_field(@person, 'address', labelled_form_field(_('Address (street and number)'), text_field(:profile_data, :address, :rel => _('Address')))) %>
26 26 <%= optional_field(@person, 'address_reference', labelled_form_field(_('Address reference'), text_field(:profile_data, :address_reference, :rel => _('Address reference')))) %>
27 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')))) %>
  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 %>
28 33  
29 34 <% optional_field(@person, 'schooling') do %>
30 35 <div class="formfieldline">
... ...
app/views/role/_form.html.erb
... ... @@ -6,10 +6,14 @@
6 6  
7 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 17 <% end %>
14 18  
15 19 <% button_bar do %>
... ...
app/views/role/edit.html.erb
1 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 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   -<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   -<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   -<%= _('Reported folder') + ': ' + link_to(article.name, article.url) %>
app/views/shared/reported_versions/profile/_article.html.erb 0 → 100644
... ... @@ -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 @@
  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 @@
  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 8 tinymce.create('tinymce.plugins.MacrosPlugin', {
25 9 createControl: function(n, cm) {
26 10 switch (n) {
... ... @@ -49,56 +33,21 @@ tinymce.create(&#39;tinymce.plugins.MacrosPlugin&#39;, {
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 46 // Register plugin with a short name
53 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 52 </script>
  53 +
... ...
app/views/task_mailer/generic_message.text.erb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +<%= _('Dear %s,') % @requestor %>
  2 +
  3 +<%= word_wrap(@message) %>
  4 +
  5 +<%= _('Greetings,') %>
  6 +
  7 +--
  8 +<%= _('%s team.') % @environment %>
  9 +<%= @url %>
... ...
app/views/task_mailer/task_activated.text.erb
... ... @@ -1 +0,0 @@
1   -task_cancelled.text.erb
2 0 \ No newline at end of file
app/views/task_mailer/task_cancelled.text.erb
... ... @@ -1,9 +0,0 @@
1   -<%= _('Dear %s,') % @requestor %>
2   -
3   -<%= word_wrap(@message) %>
4   -
5   -<%= _('Greetings,') %>
6   -
7   ---
8   -<%= _('%s team.') % @environment %>
9   -<%= @url %>
app/views/task_mailer/task_created.text.erb
... ... @@ -1 +0,0 @@
1   -task_cancelled.text.erb
2 0 \ No newline at end of file
app/views/task_mailer/task_finished.text.erb
... ... @@ -1 +0,0 @@
1   -task_cancelled.text.erb
2 0 \ No newline at end of file
config/application.rb
... ... @@ -108,13 +108,19 @@ module Noosfero
108 108  
109 109 # Your secret key for verifying cookie session data integrity.
110 110 # If you change this key, all old sessions will become invalid!
111   - # Make sure the secret is at least 30 characters and all random,
  111 + # Make sure the secret is at least 30 characters and all random,
112 112 # no regular words or you'll be exposed to dictionary attacks.
113 113 config.secret_token = noosfero_session_secret
114 114 config.action_dispatch.session = {
115 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 124 Noosfero::Plugin.setup(config)
119 125  
120 126 end
... ...
config/cucumber.yml
1 1 <% base_requires = '-r features/support -r features/step_definitions' %>
2   -<% default_options = "--color --format progress --strict --tags ~@selenium --tags ~@selenium-fixme --tags ~@fixme --exclude features/support/selenium.rb #{base_requires}" %>
  2 +<% default_options = "--format progress --strict --tags ~@selenium --tags ~@selenium-fixme --tags ~@fixme --exclude features/support/selenium.rb #{base_requires}" %>
  3 +<%
  4 + default_options += ' --color' if $stdout.isatty
  5 +%>
3 6 <% selenium_options = "--strict --tags @selenium #{base_requires}" %>
4 7  
5 8 default: <%= default_options %>
... ...
config/initializers/activities_counter_cache.rb
1   -if Delayed::Backend::ActiveRecord::Job.table_exists?
  1 +if Delayed::Backend::ActiveRecord::Job.table_exists? &&
  2 + Delayed::Backend::ActiveRecord::Job.attribute_names.include?('queue')
2 3 job = Delayed::Backend::ActiveRecord::Job.all :conditions => ['handler LIKE ?', "%ActivitiesCounterCacheJob%"]
3 4 if job.blank?
4 5 Delayed::Backend::ActiveRecord::Job.enqueue(ActivitiesCounterCacheJob.new, {:priority => -3})
... ...
config/initializers/i18n.rb
1 1 # necessary for I18n.default_locale to work
2 2 require 'i18n/backend/fallbacks'
3 3 I18n.backend.class.send :include, I18n::Backend::Fallbacks
4   -
  4 +I18n.enforce_available_locales = false
... ...
config/initializers/log_memory_consumption.rb
... ... @@ -1,5 +0,0 @@
1   -if Delayed::Backend::ActiveRecord::Job.table_exists?
2   - jobs = Delayed::Backend::ActiveRecord::Job.all :conditions => ['handler LIKE ?', "%LogMemoryConsumptionJob%"]
3   - jobs.map(&:destroy) if jobs.present?
4   - Delayed::Backend::ActiveRecord::Job.enqueue(LogMemoryConsumptionJob.new)
5   -end
config/initializers/newrelic.rb 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +# Load newrelic agent if its config file is defined.
  2 +require 'newrelic_rpm' if File.exist?(File.dirname(__FILE__) + '/../newrelic.yml')
... ...
config/initializers/person_notification.rb
1   -if Delayed::Backend::ActiveRecord::Job.table_exists?
  1 +if Delayed::Backend::ActiveRecord::Job.table_exists? &&
  2 + Delayed::Backend::ActiveRecord::Job.attribute_names.include?('queue')
2 3 PersonNotifier.schedule_all_next_notification_mail
3 4 end
... ...
db/migrate/20140708115518_index_domains_filtered_fields.rb 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +class IndexDomainsFilteredFields < ActiveRecord::Migration
  2 +
  3 + def self.up
  4 + add_index :domains, [:name]
  5 + add_index :domains, [:is_default]
  6 + add_index :domains, [:owner_id, :owner_type]
  7 + add_index :domains, [:owner_id, :owner_type, :is_default]
  8 + end
  9 +
  10 +end
... ...
db/migrate/20140708121356_index_articles_filtered_fields.rb 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +class IndexArticlesFilteredFields < ActiveRecord::Migration
  2 + def self.up
  3 + %w[articles article_versions].each do |table|
  4 + add_index table.to_sym, [:path]
  5 + add_index table.to_sym, [:path, :profile_id]
  6 + end
  7 + add_index :articles, [:type]
  8 + add_index :articles, [:type, :parent_id]
  9 + add_index :articles, [:type, :profile_id]
  10 + end
  11 +
  12 +end
... ...
db/migrate/20140709212646_add_spam_comments_counter_cache_to_articles.rb
... ... @@ -2,7 +2,10 @@ class AddSpamCommentsCounterCacheToArticles &lt; ActiveRecord::Migration
2 2 def self.up
3 3 add_column :articles, :spam_comments_count, :integer, :default => 0
4 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 9 end
7 10  
8 11 def self.down
... ...
db/migrate/20140709224246_create_real_relation_between_article_and_author.rb
... ... @@ -4,8 +4,10 @@ class CreateRealRelationBetweenArticleAndAuthor &lt; ActiveRecord::Migration
4 4 add_column :article_versions, :author_id, :integer
5 5  
6 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 12 def self.down
11 13 remove_column :articles, :author_id
... ...
db/migrate/20140724134601_fix_yaml_encoding.rb
1 1 class FixYamlEncoding < ActiveRecord::Migration
2 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 12 end
11 13  
12 14 def self.down
... ... @@ -16,15 +18,34 @@ class FixYamlEncoding &lt; ActiveRecord::Migration
16 18 private
17 19  
18 20 def self.fix_encoding(model, param)
19   - result = model.find(:all, :conditions => "#{param} LIKE '%!binary%'")
  21 + result = model.all
20 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 37 end
23 38  
24 39 def self.deep_fix(hash)
25 40 hash.each do |value|
26   - value.force_encoding('UTF-8') if value.is_a?(String) && !value.frozen? && value.encoding == Encoding::ASCII_8BIT
27 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 49 end
29 50 end
30 51  
... ...
db/migrate/20140724180943_add_index_to_blog_posts_sort.rb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +class AddIndexToBlogPostsSort < ActiveRecord::Migration
  2 + def self.up
  3 + %w[articles article_versions].each do |table|
  4 + add_index table.to_sym, [:published_at, :id]
  5 + end
  6 + end
  7 +
  8 + def self.down
  9 + %w[articles article_versions].each do |table|
  10 + remove_index table.to_sym, [:published_at, :id]
  11 + end
  12 + end
  13 +end
... ...
db/schema.rb
... ... @@ -95,12 +95,15 @@ ActiveRecord::Schema.define(:version =&gt; 20140827191326) do
95 95 t.integer "license_id"
96 96 t.integer "image_id"
97 97 t.integer "position"
98   - t.integer "created_by_id"
99 98 t.integer "spam_comments_count", :default => 0
100 99 t.integer "author_id"
  100 + t.integer "created_by_id"
101 101 end
102 102  
103 103 add_index "article_versions", ["article_id"], :name => "index_article_versions_on_article_id"
  104 + add_index "article_versions", ["path", "profile_id"], :name => "index_article_versions_on_path_and_profile_id"
  105 + add_index "article_versions", ["path"], :name => "index_article_versions_on_path"
  106 + add_index "article_versions", ["published_at", "id"], :name => "index_article_versions_on_published_at_and_id"
104 107  
105 108 create_table "articles", :force => true do |t|
106 109 t.string "name"
... ... @@ -143,9 +146,9 @@ ActiveRecord::Schema.define(:version =&gt; 20140827191326) do
143 146 t.integer "license_id"
144 147 t.integer "image_id"
145 148 t.integer "position"
146   - t.integer "created_by_id"
147 149 t.integer "spam_comments_count", :default => 0
148 150 t.integer "author_id"
  151 + t.integer "created_by_id"
149 152 end
150 153  
151 154 add_index "articles", ["comments_count"], :name => "index_articles_on_comments_count"
... ... @@ -153,9 +156,15 @@ ActiveRecord::Schema.define(:version =&gt; 20140827191326) do
153 156 add_index "articles", ["hits"], :name => "index_articles_on_hits"
154 157 add_index "articles", ["name"], :name => "index_articles_on_name"
155 158 add_index "articles", ["parent_id"], :name => "index_articles_on_parent_id"
  159 + add_index "articles", ["path", "profile_id"], :name => "index_articles_on_path_and_profile_id"
  160 + add_index "articles", ["path"], :name => "index_articles_on_path"
156 161 add_index "articles", ["profile_id"], :name => "index_articles_on_profile_id"
  162 + add_index "articles", ["published_at", "id"], :name => "index_articles_on_published_at_and_id"
157 163 add_index "articles", ["slug"], :name => "index_articles_on_slug"
158 164 add_index "articles", ["translation_of_id"], :name => "index_articles_on_translation_of_id"
  165 + add_index "articles", ["type", "parent_id"], :name => "index_articles_on_type_and_parent_id"
  166 + add_index "articles", ["type", "profile_id"], :name => "index_articles_on_type_and_profile_id"
  167 + add_index "articles", ["type"], :name => "index_articles_on_type"
159 168  
160 169 create_table "articles_categories", :id => false, :force => true do |t|
161 170 t.integer "article_id"
... ... @@ -278,6 +287,11 @@ ActiveRecord::Schema.define(:version =&gt; 20140827191326) do
278 287 t.string "google_maps_key"
279 288 end
280 289  
  290 + add_index "domains", ["is_default"], :name => "index_domains_on_is_default"
  291 + add_index "domains", ["name"], :name => "index_domains_on_name"
  292 + add_index "domains", ["owner_id", "owner_type", "is_default"], :name => "index_domains_on_owner_id_and_owner_type_and_is_default"
  293 + add_index "domains", ["owner_id", "owner_type"], :name => "index_domains_on_owner_id_and_owner_type"
  294 +
281 295 create_table "environments", :force => true do |t|
282 296 t.string "name"
283 297 t.string "contact_email"
... ...
debian/bundle/config
... ... @@ -1,3 +0,0 @@
1   ----
2   -BUNDLE_WITHOUT: test:cucumber
3   -
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 +
  7 +noosfero (1.0~rc3) wheezy-test; urgency=low
  8 +
  9 + * Third release candidate to Noosfero 1.0
  10 +
  11 + -- Antonio Terceiro <terceiro@debian.org> Fri, 12 Sep 2014 16:20:58 -0300
  12 +
  13 +noosfero (1.0~rc2) wheezy-test; urgency=low
  14 +
  15 + * Second 1.0 release candidate
  16 +
  17 + -- Antonio Terceiro <terceiro@debian.org> Fri, 12 Sep 2014 13:01:11 -0300
  18 +
1 19 noosfero (1.0~rc1) wheezy-test; urgency=low
2 20  
3 21 * First 1.0 release candidate
... ... @@ -10,6 +28,18 @@ noosfero (0.99.0~rc20140618202455) wheezy-test; urgency=low
10 28  
11 29 -- Rodrigo Souto <rodrigo@colivre.coop.br> Wed, 18 Jun 2014 20:25:01 +0000
12 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 +
  37 +noosfero (0.47.4) unstable; urgency=low
  38 +
  39 + * Bugfixes and performance optimizations
  40 +
  41 + -- Rodrigo Souto <rodrigo@colivre.coop.br> Thu, 21 Aug 2014 19:25:37 +0000
  42 +
13 43 noosfero (0.47.3) unstable; urgency=low
14 44  
15 45 * Bugfixes release
... ...
debian/control
... ... @@ -9,7 +9,7 @@ Build-Depends:
9 9 ruby-gettext,
10 10 ruby-sqlite3,
11 11 rake,
12   - rails3 (>= 3.2.6-1~),
  12 + rails3 (>= 3.2.19-1~),
13 13 ruby-rspec,
14 14 ruby-rspec-rails,
15 15 ruby-will-paginate,
... ... @@ -30,12 +30,14 @@ Vcs-Browser: http://git.colivre.coop.br/?p=noosfero.git
30 30  
31 31 Package: noosfero
32 32 Architecture: all
  33 +Pre-Depends: ruby1.8 (>= 1.8.7.358)
33 34 Depends:
34 35 rails3 (>= 3.2.6-1~),
35 36 ruby (>= 1:1.9.3),
36 37 rake,
37 38 ruby-dalli,
38 39 ruby-exception-notification,
  40 + ruby-gettext,
39 41 ruby-fast-gettext,
40 42 ruby-pg,
41 43 ruby-rmagick,
... ... @@ -49,6 +51,7 @@ Depends:
49 51 ruby-hpricot,
50 52 ruby-nokogiri,
51 53 ruby-acts-as-taggable-on,
  54 + ruby-progressbar,
52 55 ruby-prototype-rails,
53 56 ruby-rails-autolink,
54 57 memcached,
... ...
debian/filter-gemfile 0 → 100755
... ... @@ -0,0 +1,5 @@
  1 +#!/bin/sh
  2 +
  3 +set -e
  4 +
  5 +sed -e '/^group\s*:\(test\|cucumber\)/,/^end/ d' Gemfile
... ...
debian/noosfero.install
... ... @@ -7,10 +7,6 @@ util usr/share/noosfero
7 7 Rakefile usr/share/noosfero
8 8 vendor usr/share/noosfero
9 9  
10   -Gemfile usr/share/noosfero
11   -Gemfile.lock usr/share/noosfero
12   -debian/bundle/config usr/share/noosfero/.bundle
13   -
14 10 config/application.rb usr/share/noosfero/config
15 11 config/boot.rb usr/share/noosfero/config
16 12 config/environment.rb usr/share/noosfero/config
... ...
debian/noosfero.links
... ... @@ -15,3 +15,4 @@ var/lib/noosfero-data/public/thumbnails usr/share/noosfero/public/th
15 15 usr/share/noosfero/public/designs/themes/noosfero usr/share/noosfero/public/designs/themes/default
16 16 usr/share/noosfero/public/designs/icons/tango usr/share/noosfero/public/designs/icons/default
17 17 usr/share/noosfero/script/noosfero-plugins usr/sbin/noosfero-plugins
  18 +/dev/null usr/share/noosfero/Gemfile.lock
... ...
debian/rules
... ... @@ -20,6 +20,10 @@ override_dh_link:
20 20 dh_link usr/lib/noosfero/dbinstall usr/share/dbconfig-common/scripts/noosfero/install/$$db; \
21 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 27 override_dh_installinit:
24 28 dh_installinit -pnoosfero --onlyscripts
25 29  
... ...
etc/init.d/noosfero
... ... @@ -45,7 +45,7 @@ if [ -z &quot;$NOOSFERO_DIR&quot; ] || [ -z &quot;$NOOSFERO_USER&quot; ]; then
45 45 fi
46 46  
47 47 if test -x /usr/sbin/noosfero-check-dbconfig ; then
48   - if ! noosfero-check-dbconfig; then
  48 + if ! /usr/sbin/noosfero-check-dbconfig; then
49 49 echo "Noosfero database access not configured, service disabled."
50 50 exit 0
51 51 fi
... ...
etc/noosfero/varnish-accept-language.vcl
... ... @@ -6,7 +6,14 @@ C{
6 6 /*
7 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 23 #include <string.h>
17 24  
18 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 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 32 #define RETURN_LANG(x) { \
25 33 strncpy(lang, x, LANG_MAXLEN); \
26 34 return; \
... ... @@ -64,9 +72,8 @@ int is_supported(vcl_string *lang) {
64 72 strncat(match_str, lang, LANG_MAXLEN);
65 73 strncat(match_str, ":\0", 2);
66 74  
67   - if (strstr(supported_languages, match_str)) {
  75 + if (strstr(supported_languages, match_str))
68 76 is_supported = 1;
69   - }
70 77  
71 78 return is_supported;
72 79 }
... ... @@ -90,6 +97,7 @@ void select_language(const vcl_string *incoming_header, char *lang) {
90 97 vcl_string *lang_tok = NULL;
91 98 vcl_string root_lang[3];
92 99 vcl_string *header;
  100 + vcl_string header_copy[HDR_MAXLEN];
93 101 vcl_string *pos = NULL;
94 102 vcl_string *q_spec = NULL;
95 103 unsigned int curr_lang = 0, i = 0;
... ... @@ -106,7 +114,7 @@ void select_language(const vcl_string *incoming_header, char *lang) {
106 114 RETURN_DEFAULT_LANG;
107 115  
108 116 /* Tokenize Accept-Language */
109   - header = (vcl_string *) incoming_header;
  117 + header = strncpy(header_copy, incoming_header, sizeof(header_copy));
110 118  
111 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 145 header = NULL;
138 146  
139 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 152 /* Sort by priority */
... ... @@ -157,12 +166,11 @@ void vcl_rewrite_accept_language(const struct sess *sp) {
157 166 vcl_string *in_hdr;
158 167 vcl_string lang[LANG_MAXLEN];
159 168  
160   - memset(lang, 0, LANG_MAXLEN);
161   -
162 169 /* Get Accept-Language header from client */
163 170 in_hdr = VRT_GetHdr(sp, HDR_REQ, "\020Accept-Language:");
164 171  
165 172 /* Normalize and filter out by list of supported languages */
  173 + memset(lang, 0, sizeof(lang));
166 174 select_language(in_hdr, lang);
167 175  
168 176 /* By default, use a different header name: don't mess with backend logic */
... ... @@ -191,3 +199,4 @@ sub vcl_fetch {
191 199 set beresp.http.Vary = "X-Varnish-Accept-Language";
192 200 }
193 201 }
  202 +
... ...
features/change_organization_name.feature
... ... @@ -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   -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 27 And I press "Save"
28 28 Then I should not see "Birth date is invalid"
29 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"
... ...