Commit d35779c07490f70c33e688afa945036e075a90f2

Authored by Antonio Terceiro
2 parents 1420310b af89dbce

Merge branch 'master' into rails-2.3.5

Conflicts:
	app/controllers/admin_controller.rb
	app/controllers/application.rb
	app/controllers/public/account_controller.rb
	app/controllers/public/content_viewer_controller.rb
	lib/noosfero/i18n.rb
	test/functional/account_controller_test.rb
	test/functional/admin_controller_test.rb
	test/unit/contact_test.rb
	test/unit/profile_test.rb
Showing 842 changed files with 113986 additions and 21393 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 842 files displayed.

@@ -3,7 +3,8 @@ Antonio Terceiro <terceiro@colivre.coop.br> <terceiro@softwarelivre.org> @@ -3,7 +3,8 @@ Antonio Terceiro <terceiro@colivre.coop.br> <terceiro@softwarelivre.org>
3 Aurelio A. Heckert <aurelio@colivre.coop.br> <AurelioAHeckert@3f533792-8f58-4932-b0fe-aaf55b0a4547> 3 Aurelio A. Heckert <aurelio@colivre.coop.br> <AurelioAHeckert@3f533792-8f58-4932-b0fe-aaf55b0a4547>
4 Aurelio A. Heckert <aurelio@colivre.coop.br> <aurelio@colivre.coop.br> 4 Aurelio A. Heckert <aurelio@colivre.coop.br> <aurelio@colivre.coop.br>
5 Aurelio A. Heckert <aurelio@colivre.coop.br> <aurium@gmail.com> 5 Aurelio A. Heckert <aurelio@colivre.coop.br> <aurium@gmail.com>
6 -Caio SBA <caiosba@gmail.com> <caiosba@safernet.org.br> 6 +Caio SBA <caio@colivre.coop.br> <caiosba@gmail.com>
  7 +Caio SBA <caio@colivre.coop.br> <caiosba@safernet.org.br>
7 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br> <DanielaFeitosa@3f533792-8f58-4932-b0fe-aaf55b0a4547> 8 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br> <DanielaFeitosa@3f533792-8f58-4932-b0fe-aaf55b0a4547>
8 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br> <danielafeitosa@colivre.coop.br> 9 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br> <danielafeitosa@colivre.coop.br>
9 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br> <daniela@sede.colivre.coop.br> 10 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br> <daniela@sede.colivre.coop.br>
@@ -8,8 +8,9 @@ Developers @@ -8,8 +8,9 @@ Developers
8 8
9 Antonio Terceiro <terceiro@colivre.coop.br> 9 Antonio Terceiro <terceiro@colivre.coop.br>
10 Aurelio A. Heckert <aurelio@colivre.coop.br> 10 Aurelio A. Heckert <aurelio@colivre.coop.br>
  11 +Braulio Bhavamitra <brauliobo@gmail.com>
11 Bráulio Bhavamitra <brauliobo@gmail.com> 12 Bráulio Bhavamitra <brauliobo@gmail.com>
12 -Caio SBA <caiosba@gmail.com> 13 +Caio SBA <caio@colivre.coop.br>
13 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br> 14 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br>
14 Daniel Cunha <daniel@colivre.coop.br> 15 Daniel Cunha <daniel@colivre.coop.br>
15 Fernanda Lopes <nanda.listas+psl@gmail.com> 16 Fernanda Lopes <nanda.listas+psl@gmail.com>
@@ -23,6 +24,7 @@ LinguÁgil 2010 &lt;linguagil.bahia@gmail.com&gt; @@ -23,6 +24,7 @@ LinguÁgil 2010 &lt;linguagil.bahia@gmail.com&gt;
23 Martín Olivera <molivera@solar.org.ar> 24 Martín Olivera <molivera@solar.org.ar>
24 Moises Machado <moises@colivre.coop.br> 25 Moises Machado <moises@colivre.coop.br>
25 Nanda Lopes <nanda.listas+psl@gmail.com> 26 Nanda Lopes <nanda.listas+psl@gmail.com>
  27 +Rafael Gomes <rafaelgomes@techfree.com.br>
26 Raphaël Rousseau <raph@r4f.org> 28 Raphaël Rousseau <raph@r4f.org>
27 Raquel Lira <raquel.lira@gmail.com> 29 Raquel Lira <raquel.lira@gmail.com>
28 Rodrigo Souto <rodrigo@colivre.coop.br> 30 Rodrigo Souto <rodrigo@colivre.coop.br>
@@ -31,11 +31,13 @@ You can copy and paste the commands below into a terminal (please review the @@ -31,11 +31,13 @@ You can copy and paste the commands below into a terminal (please review the
31 commands and make sure you understand what you are doing): 31 commands and make sure you understand what you are doing):
32 32
33 # checkout the code from repository 33 # checkout the code from repository
34 - git clone git://git.colivre.coop.br/noosfero.git 34 + git clone git://gitorious.org/noosfero/noosfero.git
35 # enter the directory 35 # enter the directory
36 cd noosfero 36 cd noosfero
37 # copy a sample config file 37 # copy a sample config file
38 cp config/database.yml.sqlite3 config/database.yml 38 cp config/database.yml.sqlite3 config/database.yml
  39 + # create tmp directory if it doesn't exist
  40 + mkdir tmp
39 # create the development database 41 # create the development database
40 rake db:schema:load 42 rake db:schema:load
41 # run pending migrations 43 # run pending migrations
@@ -59,8 +61,8 @@ another port than 3000, you can use the -p option of ./script/server: @@ -59,8 +61,8 @@ another port than 3000, you can use the -p option of ./script/server:
59 61
60 The above command makes the server available at http://localhost:9999/ 62 The above command makes the server available at http://localhost:9999/
61 63
62 -The sample-data data scripts creates one administrator user with login "ze" and  
63 -password "test". 64 +The sample-data data scripts creates two administrator users with login "ze" and
  65 +password "test" and login "adminuser" and password "admin".
64 66
65 Note that some operations, like generating image thumbnails, sending e-mails, 67 Note that some operations, like generating image thumbnails, sending e-mails,
66 etc, are done in background in the context of a service independent from the 68 etc, are done in background in the context of a service independent from the
@@ -84,3 +86,7 @@ you want to enable it then you need to change some files: @@ -84,3 +86,7 @@ you want to enable it then you need to change some files:
84 86
85 3) Add in config/noosfero.yml at development section: 87 3) Add in config/noosfero.yml at development section:
86 exception_recipients: [admin@example.com] 88 exception_recipients: [admin@example.com]
  89 +
  90 +== Releasing and building Debian package
  91 +
  92 +See RELEASING file.
@@ -43,6 +43,9 @@ case will need do install hicolor-icon-theme as well bacause tango-icon-theme @@ -43,6 +43,9 @@ case will need do install hicolor-icon-theme as well bacause tango-icon-theme
43 depends on it. After that you can try the command line above again, but 43 depends on it. After that you can try the command line above again, but
44 without "tango-icon-theme". 44 without "tango-icon-theme".
45 45
  46 +More Informations to install the tango-icon-theme on Debian Lenny:
  47 +* http://packages.debian.org/en/lenny/all/tango-icon-theme/download
  48 +
46 If you manage to install Noosfero successfully on other systems than Debian, 49 If you manage to install Noosfero successfully on other systems than Debian,
47 please feel free to contact the Noosfero development mailing with the 50 please feel free to contact the Noosfero development mailing with the
48 instructions for doing so, and we'll include it here. 51 instructions for doing so, and we'll include it here.
@@ -98,7 +101,7 @@ downloading from git @@ -98,7 +101,7 @@ downloading from git
98 Here we are cloning the noosfero repository from git. Note: you will need to 101 Here we are cloning the noosfero repository from git. Note: you will need to
99 install git before. 102 install git before.
100 103
101 -$ git clone git://git.colivre.coop.br/noosfero.git current 104 +$ git clone git://gitorious.org/noosfero/noosfero.git current
102 $ cd current 105 $ cd current
103 $ git checkout -b stable origin/stable 106 $ git checkout -b stable origin/stable
104 107
@@ -221,16 +221,19 @@ Note: module proxy_http must be enabled: @@ -221,16 +221,19 @@ Note: module proxy_http must be enabled:
221 221
222 # a2enmod proxy_http 222 # a2enmod proxy_http
223 223
224 -  
225 8. DNS configuration 224 8. DNS configuration
226 225
227 - * /etc/bind/db.colivre: 226 +For this point, we assume you are using BIND as your DNS server. You need to
  227 +add the following entries to the DNS zone file corresponding to the domain
  228 +of your noosfero site:
228 229
229 _xmpp-client._tcp SRV 5 100 5222 master 230 _xmpp-client._tcp SRV 5 100 5222 master
230 -(...)  
231 conference CNAME master 231 conference CNAME master
232 _xmpp-client._tcp.conference SRV 5 100 5222 master 232 _xmpp-client._tcp.conference SRV 5 100 5222 master
233 233
  234 +If you are running a DNS server other than BIND, you will have to figure out
  235 +how to create equivalente rules for your zone file. Patches to this
  236 +documentation are welcome.
234 237
235 9. Testing this Setup 238 9. Testing this Setup
236 239
INSTALL.multitenancy 0 → 100644
@@ -0,0 +1,163 @@ @@ -0,0 +1,163 @@
  1 +== Multitenancy support
  2 +
  3 +Multitenancy refers to a principle in software architecture where a
  4 +single instance of the software runs on a server, serving multiple
  5 +client organizations (tenants). Multitenancy is contrasted with a
  6 +multi-instance architecture where separate software instances (or
  7 +hardware systems) are set up for different client organizations. With
  8 +a multitenant architecture, a software application is designed to
  9 +virtually partition its data and configuration, and each client
  10 +organization works with a customized virtual application instance.
  11 +
  12 +Today this feature is available only for PostgreSQL databases.
  13 +
  14 +This document assumes that you have a new fully PostgresSQL default Noosfero
  15 +installation as explained at the INSTALL file.
  16 +
  17 +== Separated data
  18 +
  19 +The items below are separated for each hosted environment:
  20 +
  21 +* Uploaded files
  22 +* Database
  23 +* Ferret index
  24 +* ActiveRecord#cache_key
  25 +* Feed updater
  26 +* Delayed Job Workers
  27 +
  28 +== Database configuration file
  29 +
  30 +The file config/database.yml must follow a structure in order to
  31 +achieve multitenancy support. In this example, we will set 3
  32 +different environments: env1, env2 and env3.
  33 +
  34 +Each "hosted" environment must have an entry like this:
  35 +
  36 +env1_production:
  37 + adapter: postgresql
  38 + encoding: unicode
  39 + database: noosfero
  40 + schema_search_path: public
  41 + username: noosfero
  42 + domains:
  43 + - env1.com
  44 + - env1.org
  45 +
  46 +env2_production:
  47 + adapter: postgresql
  48 + encoding: unicode
  49 + database: noosfero
  50 + schema_search_path: env2
  51 + username: noosfero
  52 + domains:
  53 + - env2.com
  54 + - env2.org
  55 +
  56 +env3_production:
  57 + adapter: postgresql
  58 + encoding: unicode
  59 + database: noosfero
  60 + schema_search_path: env3
  61 + username: noosfero
  62 + domains:
  63 + - env3.com
  64 + - env3.net
  65 +
  66 +The "hosted" environments define, besides the schema_search_path, a
  67 +list of domains that, when accessed, tells which database the
  68 +application should use. Also, the environment name must end with
  69 +'_hosting', where 'hosting' is the name of the hosting environment.
  70 +
  71 +You must also tell the application which is the default environment.
  72 +
  73 +production:
  74 + env1_production
  75 +
  76 +On the example above there are only three hosted environments, but it
  77 +can be more than three. The schemas 'env2' and 'env3' must already
  78 +exist in the same database of the hosting environment. As postgres
  79 +user, you can create them typing:
  80 +
  81 +$ psql database_name -c "CREATE SCHEMA env2 AUTHORIZATION database_user"
  82 +$ psql database_name -c "CREATE SCHEMA env3 AUTHORIZATION database_user"
  83 +
  84 +Replace database_name and database_user above with your stuff.
  85 +
  86 +So, yet on this same example, when a user accesses http://env2.com or
  87 +http://env2.org, the Noosfero application running on production will
  88 +turn the database schema to 'env2'. When the access is from domains
  89 +http://env3.com or http://env3.net, the schema to be loaded will be
  90 +'env3'.
  91 +
  92 +There is an example of this file in config/database.yml.multitenancy
  93 +
  94 +== Preparing the database
  95 +
  96 +Now create the environments:
  97 +
  98 +$ RAILS_ENV=production rake multitenancy:create
  99 +
  100 +This command above will create the hosted environment files equal to
  101 +their hosting environment, here called 'production'.
  102 +
  103 +Run db:schema:load for each other environment:
  104 +
  105 +$ RAILS_ENV=env2_production rake db:schema:load
  106 +$ RAILS_ENV=env3_production rake db:schema:load
  107 +
  108 +Then run the migrations for the hosting environment, and it will
  109 +run for each of its hosted environments:
  110 +
  111 +RAILS_ENV=production rake db:migrate
  112 +
  113 +== Start Noosfero
  114 +
  115 +Run Noosfero init file as root:
  116 +
  117 +# invoke-rc.d noosfero start
  118 +
  119 +== Ferret
  120 +
  121 +It's necessary to run only one instance of ferret_server. Don't worry
  122 +about this, Noosfero initializer had already done this for you.
  123 +
  124 +== Feed updater & Delayed job
  125 +
  126 +Just for your information, a daemon of feed-updater and delayed_job
  127 +must be running for each environment. Noosfero initializer do this,
  128 +relax.
  129 +
  130 +== Uploaded files
  131 +
  132 +When running with PostgreSQL, Noosfero uploads stuff to a folder named
  133 +the same way as the running schema. Inside the upload folder root, for
  134 +example, will be public/image_uploads/env2 and public/image_uploads/env3.
  135 +
  136 +== Adding multitenancy support to an existing Noosfero environment
  137 +
  138 +If you already have a Noosfero environment, you can turn it multitenant
  139 +by following the steps below in addition to the previous steps:
  140 +
  141 +1. Reindex your database
  142 +
  143 +Rebuild the Ferret index by running the following task just
  144 +for your hosting environment, do this as noosfero user:
  145 +
  146 +$ RAILS_ENV=production rake multitenancy:reindex
  147 +
  148 +2. Move the uploaded files to the right place
  149 +
  150 +Add a directory with the same name as your schema name (by default this
  151 +name is 'public') in the root of each upload directory, for example,
  152 +public/articles/0000 will be moved to public/articles/public/0000. Do this
  153 +with the directories public/image_uploads, public/articles and public/thumbnails.
  154 +
  155 +3. Fix paths on activities
  156 +
  157 +The profile activities store static paths to the images, so it's necessary to fix
  158 +these paths. You can do this easily by setting an alias on your webserver.
  159 +On Apache you can add the three rules below, where 'public' is the schema name:
  160 +
  161 + RewriteRule ^/articles(.+) /articles/public$1
  162 + RewriteRule ^/image_uploads(.+) /image_uploads/public$1
  163 + RewriteRule ^/thumbnails(.+) /thumbnails/public$1
INSTALL.varnish
@@ -50,14 +50,22 @@ apache-compatible format. You should change your statistics generation software @@ -50,14 +50,22 @@ apache-compatible format. You should change your statistics generation software
50 50
51 # invoke-rc.d varnish restart 51 # invoke-rc.d varnish restart
52 52
53 -6) Configure varnish to store separate caches for each language 53 +6) Configure varnish to fit noosfero
  54 +(assuming Noosfero is installed in /var/lib/noosfero)
54 55
55 -6a) Add the following line to your /etc/varnish/default.vcl file (assuming  
56 -Noosfero is installed in /var/lib/noosfero): 56 +6a) Configure noosfero to do specific routines to varnish
  57 +
  58 +Add the following line to your /etc/varnish/default.vcl file:
  59 +
  60 + include "/var/lib/noosfero/etc/noosfero/varnish-noosfero.vcl";
  61 +
  62 +6b) Configure varnish to store separate caches for each language
  63 +
  64 +Add the following line to your /etc/varnish/default.vcl file:
57 65
58 include "/var/lib/noosfero/etc/noosfero/varnish-accept-language.vcl"; 66 include "/var/lib/noosfero/etc/noosfero/varnish-accept-language.vcl";
59 67
60 -6b) Restart Varnish 68 +7) Restart Varnish
61 69
62 # invoke-rc.d varnish restart 70 # invoke-rc.d varnish restart
63 71
@@ -12,28 +12,28 @@ This file documents release-related activities. @@ -12,28 +12,28 @@ This file documents release-related activities.
12 12
13 == Releasing noosfero 13 == Releasing noosfero
14 14
  15 +Considering you are on a Debian GNU/Linux or Debian-based system
  16 + # apt-get install devscripts debhelper
  17 +
15 To prepare a release of noosfero, you must follow the steps below: 18 To prepare a release of noosfero, you must follow the steps below:
16 19
17 -* finish all requirements and bugs assigned to the to-be-released version  
18 -* make sure all tests pass  
19 -* write release notes at the version's wiki topic.  
20 -* generate package with <tt>rake package</tt>. Your tarball will be under the pkg/  
21 - directory, named as noosfero-${VERSION}.tar.gz  
22 -* test that the package contains everything that is needed: explode the tarball  
23 - in a temporary directory, copy config/database.yml.sqlite3 to  
24 - config/database.yml, and make <tt>rake db:migrate</tt> and <tt>rake test</tt>. If  
25 - everything is ok, you are done. If not, maybe some files are not going into  
26 - the tarball. See lib/tasks/package.rake, probably you'll need to change it.  
27 -* Go to the version's wiki topic and edit it to reflect the new reality.  
28 -* Attach the generated package to that topic. Before attaching calculate the md5 of the package (with mu5sum and paste the MD5 hash as comment in the attachment form) 20 +* Finish all requirements and bugs assigned to the to-be-released version
  21 +* Make sure all tests pass
  22 +* Change the version in lib/noosfero.rb and debian/changelog to the
  23 + to-be-released version (e.g. 0.2.0, 0.3.1)
  24 +* Write release notes at the version's wiki topic
  25 +* Generate packages with <tt>rake noosfero:release</tt>. Your tarball and deb
  26 + pkg will be under the pkg/ directory. This task will create a git tag too.
  27 +* Test that the tarball and deb package are ok
  28 +* Go to the version's wiki topic and edit it to reflect the new reality
  29 +* Edit the topic WebPreferences and update DEBIAN_REPOSITORY_TOPICS setting
  30 +* Attach the generated packages to that topic. Before attaching calculate the
  31 + sha1 of the package (with sha1sum and paste the SHA1 hash as comment in the
  32 + attachment form)
29 * Download the attached and verify the MD5 hash 33 * Download the attached and verify the MD5 hash
30 -* create a git tag for the released version with <tt>git tag</tt>.  
31 -* IMMEDIATELY change the version in lib/noosfero.rb to the next version. (e.g.  
32 - 0.2.0 -> 0.3.0)  
33 -* update an eventual demonstration version that you run.  
34 -* write an announcement e-mail to the relevant maimling lists pointing to the release notes, and maybe to the demonstration version. 34 +* Update an eventual demonstration version that you run.
  35 +* Write an announcement e-mail to the relevant mailing lists pointing to the
  36 + release notes, and maybe to the demonstration version.
35 37
36 If you had any problem during these steps, you can do <tt>rake clobber_package</tt> to 38 If you had any problem during these steps, you can do <tt>rake clobber_package</tt> to
37 completely delete the generated packages and start the process again. 39 completely delete the generated packages and start the process again.
38 -  
39 -  
app/controllers/admin/admin_panel_controller.rb
1 class AdminPanelController < AdminController 1 class AdminPanelController < AdminController
2 2
3 - before_filter :login_required  
4 -  
5 protect 'view_environment_admin_panel', :environment 3 protect 'view_environment_admin_panel', :environment
6 4
7 def boxes_holder 5 def boxes_holder
@@ -11,6 +9,7 @@ class AdminPanelController &lt; AdminController @@ -11,6 +9,7 @@ class AdminPanelController &lt; AdminController
11 def site_info 9 def site_info
12 if request.post? 10 if request.post?
13 if @environment.update_attributes(params[:environment]) 11 if @environment.update_attributes(params[:environment])
  12 + session[:notice] = _('Environment settings updated')
14 redirect_to :action => 'index' 13 redirect_to :action => 'index'
15 end 14 end
16 end 15 end
app/controllers/admin/categories_controller.rb
@@ -10,11 +10,16 @@ class CategoriesController &lt; AdminController @@ -10,11 +10,16 @@ class CategoriesController &lt; AdminController
10 @product_categories = environment.product_categories.find(:all, :conditions => {:parent_id => nil}) 10 @product_categories = environment.product_categories.find(:all, :conditions => {:parent_id => nil})
11 end 11 end
12 12
  13 + def get_children
  14 + children = Category.find(params[:id]).children
  15 + render :partial => 'category_children', :locals => {:children => children}
  16 + end
  17 +
13 ALLOWED_TYPES = CategoriesHelper::TYPES.map {|item| item[1] } 18 ALLOWED_TYPES = CategoriesHelper::TYPES.map {|item| item[1] }
14 19
15 # posts back 20 # posts back
16 def new 21 def new
17 - type = (params[:type] || 'Category') 22 + type = (params[:type] || params[:parent_type] || 'Category')
18 raise 'Type not allowed' unless ALLOWED_TYPES.include?(type) 23 raise 'Type not allowed' unless ALLOWED_TYPES.include?(type)
19 24
20 @category = type.constantize.new(params[:category]) 25 @category = type.constantize.new(params[:category])
app/controllers/admin/plugins_controller.rb
1 class PluginsController < AdminController 1 class PluginsController < AdminController
  2 + protect 'edit_environment_features', :environment
2 3
3 def index 4 def index
4 @active_plugins = Noosfero::Plugin.all.map {|plugin_name| plugin_name.constantize }.compact 5 @active_plugins = Noosfero::Plugin.all.map {|plugin_name| plugin_name.constantize }.compact
app/controllers/admin/role_controller.rb
@@ -9,21 +9,6 @@ class RoleController &lt; AdminController @@ -9,21 +9,6 @@ class RoleController &lt; AdminController
9 @role = environment.roles.find(params[:id]) 9 @role = environment.roles.find(params[:id])
10 end 10 end
11 11
12 - def new  
13 - @role = Role.new  
14 - end  
15 -  
16 - def create  
17 - @role = Role.new(params[:role])  
18 - @role.environment = environment  
19 - if @role.save  
20 - redirect_to :action => 'show', :id => @role  
21 - else  
22 - session[:notice] = _('Failed to create role')  
23 - render :action => 'new'  
24 - end  
25 - end  
26 -  
27 def edit 12 def edit
28 @role = environment.roles.find(params[:id]) 13 @role = environment.roles.find(params[:id])
29 end 14 end
@@ -38,13 +23,4 @@ class RoleController &lt; AdminController @@ -38,13 +23,4 @@ class RoleController &lt; AdminController
38 end 23 end
39 end 24 end
40 25
41 - def destroy  
42 - @role = environment.roles.find(params[:id])  
43 - if @role.destroy  
44 - redirect_to :action => 'index'  
45 - else  
46 - session[:notice] = _('Failed to edit role')  
47 - redirect_to :action => 'index'  
48 - end  
49 - end  
50 end 26 end
app/controllers/admin_controller.rb
1 class AdminController < ApplicationController 1 class AdminController < ApplicationController
  2 + before_filter :login_required
2 end 3 end
app/controllers/box_organizer_controller.rb
@@ -82,7 +82,7 @@ class BoxOrganizerController &lt; ApplicationController @@ -82,7 +82,7 @@ class BoxOrganizerController &lt; ApplicationController
82 def save 82 def save
83 @block = boxes_holder.blocks.find(params[:id]) 83 @block = boxes_holder.blocks.find(params[:id])
84 @block.update_attributes(params[:block]) 84 @block.update_attributes(params[:block])
85 - expire_timeout_fragment(@block.cache_keys) 85 + expire_timeout_fragment(@block.cache_key)
86 redirect_to :action => 'index' 86 redirect_to :action => 'index'
87 end 87 end
88 88
@@ -93,7 +93,7 @@ class BoxOrganizerController &lt; ApplicationController @@ -93,7 +93,7 @@ class BoxOrganizerController &lt; ApplicationController
93 def remove 93 def remove
94 @block = Block.find(params[:id]) 94 @block = Block.find(params[:id])
95 if @block.destroy 95 if @block.destroy
96 - expire_timeout_fragment(@block.cache_keys) 96 + expire_timeout_fragment(@block.cache_key)
97 redirect_to :action => 'index' 97 redirect_to :action => 'index'
98 else 98 else
99 session[:notice] = _('Failed to remove block') 99 session[:notice] = _('Failed to remove block')
app/controllers/my_profile/cms_controller.rb
@@ -43,6 +43,9 @@ class CmsController &lt; MyProfileController @@ -43,6 +43,9 @@ class CmsController &lt; MyProfileController
43 if @parent && @parent.blog? 43 if @parent && @parent.blog?
44 articles -= Article.folder_types.map(&:constantize) 44 articles -= Article.folder_types.map(&:constantize)
45 end 45 end
  46 + if user.is_admin?(profile.environment)
  47 + articles << RawHTMLArticle
  48 + end
46 articles 49 articles
47 end 50 end
48 51
@@ -168,8 +171,7 @@ class CmsController &lt; MyProfileController @@ -168,8 +171,7 @@ class CmsController &lt; MyProfileController
168 @article = @parent = check_parent(params[:parent_id]) 171 @article = @parent = check_parent(params[:parent_id])
169 @target = @parent ? ('/%s/%s' % [profile.identifier, @parent.full_name]) : '/%s' % profile.identifier 172 @target = @parent ? ('/%s/%s' % [profile.identifier, @parent.full_name]) : '/%s' % profile.identifier
170 @folders = Folder.find(:all, :conditions => { :profile_id => profile }) 173 @folders = Folder.find(:all, :conditions => { :profile_id => profile })
171 - @media_listing = params[:media_listing]  
172 - if @article && !@media_listing 174 + if @article
173 record_coming 175 record_coming
174 end 176 end
175 if request.post? && params[:uploaded_files] 177 if request.post? && params[:uploaded_files]
@@ -178,26 +180,14 @@ class CmsController &lt; MyProfileController @@ -178,26 +180,14 @@ class CmsController &lt; MyProfileController
178 end 180 end
179 @errors = @uploaded_files.select { |f| f.errors.any? } 181 @errors = @uploaded_files.select { |f| f.errors.any? }
180 if @errors.any? 182 if @errors.any?
181 - if @media_listing  
182 - flash[:notice] = _('Could not upload all files')  
183 - redirect_to :action => 'media_listing'  
184 - else  
185 - render :action => 'upload_files', :parent_id => @parent_id  
186 - end 183 + render :action => 'upload_files', :parent_id => @parent_id
187 else 184 else
188 - if @media_listing  
189 - flash[:notice] = _('All files were uploaded successfully')  
190 - redirect_to :action => 'media_listing' 185 + if @back_to
  186 + redirect_to @back_to
  187 + elsif @parent
  188 + redirect_to :action => 'view', :id => @parent.id
191 else 189 else
192 - if @back_to  
193 - redirect_to @back_to  
194 - else  
195 - redirect_to( if @parent  
196 - {:action => 'view', :id => @parent.id}  
197 - else  
198 - {:action => 'index'}  
199 - end)  
200 - end 190 + redirect_to :action => 'index'
201 end 191 end
202 end 192 end
203 end 193 end
@@ -286,44 +276,28 @@ class CmsController &lt; MyProfileController @@ -286,44 +276,28 @@ class CmsController &lt; MyProfileController
286 @task = SuggestArticle.new(params[:task]) 276 @task = SuggestArticle.new(params[:task])
287 if request.post? 277 if request.post?
288 @task.target = profile 278 @task.target = profile
289 - if @task.save 279 + if verify_recaptcha(:model => @task, :message => _('Please type the words correctly')) && @task.save
290 session[:notice] = _('Thanks for your suggestion. The community administrators were notified.') 280 session[:notice] = _('Thanks for your suggestion. The community administrators were notified.')
291 redirect_to @back_to 281 redirect_to @back_to
292 end 282 end
293 end 283 end
294 end 284 end
295 285
296 - def media_listing  
297 - if params[:image_folder_id]  
298 - folder = profile.articles.find(params[:image_folder_id]) if !params[:image_folder_id].blank?  
299 - @images = (folder ? folder.children : profile.top_level_articles).images  
300 - elsif params[:document_folder_id]  
301 - folder = profile.articles.find(params[:document_folder_id]) if !params[:document_folder_id].blank?  
302 - @documents = (folder ? folder.children : profile.top_level_articles)  
303 - else  
304 - @documents = profile.articles  
305 - @images = @documents.images  
306 - @documents -= @images  
307 - end  
308 -  
309 - @images = @images.paginate(:per_page => per_page, :page => params[:ipage], :order => "updated_at desc") if @images  
310 - @documents = @documents.paginate(:per_page => per_page, :page => params[:dpage], :order => "updated_at desc", :conditions => {:is_image => false}) if @documents  
311 -  
312 - @folders = profile.folders  
313 - @image_folders = @folders.select {|f| f.children.any? {|c| c.image?} }  
314 - @document_folders = @folders.select {|f| f.children.any? {|c| !c.image? && c.kind_of?(UploadedFile) } }  
315 -  
316 - @media_listing = true  
317 -  
318 - respond_to do |format|  
319 - format.html { render :layout => false}  
320 - format.js {  
321 - render :update do |page|  
322 - page.replace_html 'media-listing-folder-images', :partial => 'image_thumb', :locals => {:images => @images } if !@images.blank?  
323 - page.replace_html 'media-listing-folder-documents', :partial => 'document_link', :locals => {:documents => @documents } if !@documents.blank?  
324 - end  
325 - } 286 + def search
  287 + query = params[:q]
  288 + results = query.blank? ? [] : profile.articles.published.find_by_contents(query)
  289 + render :text => article_list_to_json(results), :content_type => 'application/json'
  290 + end
  291 + def media_upload
  292 + files_uploaded = []
  293 + parent = check_parent(params[:parent_id])
  294 + files = [:file1,:file2, :file3].map { |f| params[f] }.compact
  295 + if request.post?
  296 + files.each do |file|
  297 + files_uploaded << UploadedFile.create(:uploaded_data => file, :profile => profile, :parent => parent) unless file == ''
  298 + end
326 end 299 end
  300 + render :text => article_list_to_json(files_uploaded), :content_type => 'text/plain'
327 end 301 end
328 302
329 protected 303 protected
@@ -353,7 +327,7 @@ class CmsController &lt; MyProfileController @@ -353,7 +327,7 @@ class CmsController &lt; MyProfileController
353 end 327 end
354 328
355 def refuse_blocks 329 def refuse_blocks
356 - if ['TinyMceArticle', 'Event', 'EnterpriseHomepage'].include?(@type) 330 + if ['TinyMceArticle', 'TextileArticle', 'Event', 'EnterpriseHomepage'].include?(@type)
357 @no_design_blocks = true 331 @no_design_blocks = true
358 end 332 end
359 end 333 end
@@ -367,5 +341,21 @@ class CmsController &lt; MyProfileController @@ -367,5 +341,21 @@ class CmsController &lt; MyProfileController
367 @selected_locale = @article.language || FastGettext.locale 341 @selected_locale = @article.language || FastGettext.locale
368 end 342 end
369 343
  344 + def article_list_to_json(list)
  345 + list.map do |item|
  346 + {
  347 + 'title' => item.title,
  348 + 'url' => item.image? ? item.public_filename(:uploaded) : url_for(item.url),
  349 + :icon => icon_for_article(item),
  350 + :content_type => item.mime_type,
  351 + :error => item.errors.any? ? _('%s could not be uploaded') % item.title : nil,
  352 + }
  353 + end.to_json
  354 + end
  355 +
  356 + def content_editor?
  357 + true
  358 + end
  359 +
370 end 360 end
371 361
app/controllers/my_profile/manage_products_controller.rb
@@ -4,6 +4,7 @@ class ManageProductsController &lt; ApplicationController @@ -4,6 +4,7 @@ class ManageProductsController &lt; ApplicationController
4 protect 'manage_products', :profile, :except => [:show] 4 protect 'manage_products', :profile, :except => [:show]
5 before_filter :check_environment_feature 5 before_filter :check_environment_feature
6 before_filter :login_required, :except => [:show] 6 before_filter :login_required, :except => [:show]
  7 + before_filter :create_product?, :only => [:new]
7 8
8 protected 9 protected
9 10
@@ -14,6 +15,13 @@ class ManageProductsController &lt; ApplicationController @@ -14,6 +15,13 @@ class ManageProductsController &lt; ApplicationController
14 end 15 end
15 end 16 end
16 17
  18 + def create_product?
  19 + if !profile.create_product?
  20 + render_access_denied
  21 + return
  22 + end
  23 + end
  24 +
17 public 25 public
18 26
19 def index 27 def index
@@ -40,8 +48,8 @@ class ManageProductsController &lt; ApplicationController @@ -40,8 +48,8 @@ class ManageProductsController &lt; ApplicationController
40 end 48 end
41 49
42 def new 50 def new
43 - @product = @profile.products.build(:product_category_id => params[:selected_category_id])  
44 - @category = @product.product_category 51 + @category = params[:selected_category_id] ? Category.find(params[:selected_category_id]) : nil
  52 + @product = @profile.products.build(:product_category => @category)
45 @categories = ProductCategory.top_level_for(environment) 53 @categories = ProductCategory.top_level_for(environment)
46 @level = 0 54 @level = 0
47 if request.post? 55 if request.post?
@@ -50,7 +58,7 @@ class ManageProductsController &lt; ApplicationController @@ -50,7 +58,7 @@ class ManageProductsController &lt; ApplicationController
50 render :partial => 'shared/redirect_via_javascript', 58 render :partial => 'shared/redirect_via_javascript',
51 :locals => { :url => url_for(:controller => 'manage_products', :action => 'show', :id => @product) } 59 :locals => { :url => url_for(:controller => 'manage_products', :action => 'show', :id => @product) }
52 else 60 else
53 - render :partial => 'shared/dialog_error_messages', :locals => { :object_name => 'product' } 61 + render_dialog_error_messages 'product'
54 end 62 end
55 end 63 end
56 end 64 end
@@ -72,7 +80,7 @@ class ManageProductsController &lt; ApplicationController @@ -72,7 +80,7 @@ class ManageProductsController &lt; ApplicationController
72 80
73 def edit_category 81 def edit_category
74 @product = @profile.products.find(params[:id]) 82 @product = @profile.products.find(params[:id])
75 - @category = @product.product_category 83 + @category = @product.product_category || ProductCategory.first
76 @categories = ProductCategory.top_level_for(environment) 84 @categories = ProductCategory.top_level_for(environment)
77 @edit = true 85 @edit = true
78 @level = @category.level 86 @level = @category.level
@@ -81,7 +89,7 @@ class ManageProductsController &lt; ApplicationController @@ -81,7 +89,7 @@ class ManageProductsController &lt; ApplicationController
81 render :partial => 'shared/redirect_via_javascript', 89 render :partial => 'shared/redirect_via_javascript',
82 :locals => { :url => url_for(:controller => 'manage_products', :action => 'show', :id => @product) } 90 :locals => { :url => url_for(:controller => 'manage_products', :action => 'show', :id => @product) }
83 else 91 else
84 - render :partial => 'shared/dialog_error_messages', :locals => { :object_name => 'product' } 92 + render_dialog_error_messages 'product'
85 end 93 end
86 end 94 end
87 end 95 end
@@ -96,7 +104,7 @@ class ManageProductsController &lt; ApplicationController @@ -96,7 +104,7 @@ class ManageProductsController &lt; ApplicationController
96 @inputs = @product.inputs 104 @inputs = @product.inputs
97 render :partial => 'display_inputs' 105 render :partial => 'display_inputs'
98 else 106 else
99 - render :partial => 'shared/dialog_error_messages', :locals => { :object_name => 'product' } 107 + render_dialog_error_messages 'product'
100 end 108 end
101 else 109 else
102 render :partial => 'add_input' 110 render :partial => 'add_input'
@@ -147,7 +155,7 @@ class ManageProductsController &lt; ApplicationController @@ -147,7 +155,7 @@ class ManageProductsController &lt; ApplicationController
147 @inputs = @product.inputs 155 @inputs = @product.inputs
148 render :partial => 'display_inputs' 156 render :partial => 'display_inputs'
149 else 157 else
150 - render :partial => 'shared/dialog_error_messages', :locals => { :object_name => 'input' } 158 + render_dialog_error_messages 'input'
151 end 159 end
152 end 160 end
153 end 161 end
app/controllers/my_profile/profile_design_controller.rb
@@ -25,6 +25,7 @@ class ProfileDesignController &lt; BoxOrganizerController @@ -25,6 +25,7 @@ class ProfileDesignController &lt; BoxOrganizerController
25 blocks << DisabledEnterpriseMessageBlock 25 blocks << DisabledEnterpriseMessageBlock
26 blocks << HighlightsBlock 26 blocks << HighlightsBlock
27 blocks << FeaturedProductsBlock 27 blocks << FeaturedProductsBlock
  28 + blocks << FansBlock
28 end 29 end
29 30
30 # product block exclusive for enterprises in environments that permits it 31 # product block exclusive for enterprises in environments that permits it
@@ -37,6 +38,10 @@ class ProfileDesignController &lt; BoxOrganizerController @@ -37,6 +38,10 @@ class ProfileDesignController &lt; BoxOrganizerController
37 blocks << BlogArchivesBlock 38 blocks << BlogArchivesBlock
38 end 39 end
39 40
  41 + if user.is_admin?(profile.environment)
  42 + blocks << RawHTMLBlock
  43 + end
  44 +
40 blocks 45 blocks
41 end 46 end
42 47
app/controllers/my_profile/profile_editor_controller.rb
@@ -4,7 +4,7 @@ class ProfileEditorController &lt; MyProfileController @@ -4,7 +4,7 @@ class ProfileEditorController &lt; MyProfileController
4 protect 'destroy_profile', :profile, :only => [:destroy_profile] 4 protect 'destroy_profile', :profile, :only => [:destroy_profile]
5 5
6 def index 6 def index
7 - @pending_tasks = profile.all_pending_tasks.select{|i| user.has_permission?(i.permission, profile)} 7 + @pending_tasks = Task.to(profile).pending.select{|i| user.has_permission?(i.permission, profile)}
8 end 8 end
9 9
10 helper :profile 10 helper :profile
app/controllers/my_profile/profile_members_controller.rb
1 class ProfileMembersController < MyProfileController 1 class ProfileMembersController < MyProfileController
2 protect 'manage_memberships', :profile 2 protect 'manage_memberships', :profile
3 - no_design_blocks  
4 3
5 def index 4 def index
6 @members = profile.members 5 @members = profile.members
@@ -15,29 +14,25 @@ class ProfileMembersController &lt; MyProfileController @@ -15,29 +14,25 @@ class ProfileMembersController &lt; MyProfileController
15 rescue ActiveRecord::RecordNotFound 14 rescue ActiveRecord::RecordNotFound
16 @person = nil 15 @person = nil
17 end 16 end
18 - if !params[:confirmation] && @person && @person.is_last_admin_leaving?(profile, @roles)  
19 - redirect_to :action => :last_admin, :roles => params[:roles], :person => @person  
20 - else  
21 - if @person && @person.define_roles(@roles, profile) 17 +
  18 + if @person
  19 + if@person.is_last_admin_leaving?(profile, @roles)
  20 + redirect_to :action => :last_admin
  21 + elsif @person.define_roles(@roles, profile)
22 session[:notice] = _('Roles successfuly updated') 22 session[:notice] = _('Roles successfuly updated')
  23 + redirect_to :controller => 'profile_editor'
23 else 24 else
24 session[:notice] = _('Couldn\'t change the roles') 25 session[:notice] = _('Couldn\'t change the roles')
  26 + redirect_to :action => 'index'
25 end 27 end
26 - if params[:confirmation]  
27 - redirect_to profile.url  
28 - else  
29 - redirect_to :action => :index  
30 - end 28 + else
  29 + redirect_to :action => 'index'
31 end 30 end
32 end 31 end
33 - 32 +
34 def last_admin 33 def last_admin
35 - @person = params[:person]  
36 - @roles = params[:roles] || []  
37 - @members = profile.members.select {|member| !profile.admins.include?(member)}  
38 - @title = _('Current admins')  
39 - @collection = :profile_admins  
40 - @remove_action = {:action => 'remove_admin'} 34 + @roles = [Profile::Roles.admin(environment.id)]
  35 + @pre_population = [].to_json
41 end 36 end
42 37
43 def add_role 38 def add_role
@@ -90,6 +85,7 @@ class ProfileMembersController &lt; MyProfileController @@ -90,6 +85,7 @@ class ProfileMembersController &lt; MyProfileController
90 end 85 end
91 86
92 def add_members 87 def add_members
  88 + @roles = Profile::Roles.organization_member_roles(environment.id)
93 end 89 end
94 90
95 def add_member 91 def add_member
@@ -122,19 +118,42 @@ class ProfileMembersController &lt; MyProfileController @@ -122,19 +118,42 @@ class ProfileMembersController &lt; MyProfileController
122 render :layout => false 118 render :layout => false
123 end 119 end
124 120
125 - def find_users  
126 - if !params[:query] || params[:query].length <= 2  
127 - @users_found = []  
128 - elsif params[:scope] == 'all_users'  
129 - @users_found = Person.find_by_contents(params[:query] + '*').select {|user| !profile.members.include?(user)}  
130 - @button_alt = _('Add member')  
131 - @add_action = {:action => 'add_member'}  
132 - elsif params[:scope] == 'new_admins'  
133 - @users_found = Person.find_by_contents(params[:query] + '*').select {|user| profile.members.include?(user) && !profile.admins.include?(user)}  
134 - @button_alt = _('Add member')  
135 - @add_action = {:action => 'add_admin'} 121 + def search_user
  122 + role = Role.find(params[:role])
  123 + render :text => environment.people.find(:all, :conditions => ['LOWER(name) LIKE ? OR LOWER(identifier) LIKE ?', "%#{params['q_'+role.key]}%", "%#{params['q_'+role.key]}%"]).
  124 + select { |person| !profile.members_by_role(role).include?(person) }.
  125 + map {|person| {:id => person.id, :name => person.name} }.
  126 + to_json
  127 + end
  128 +
  129 + def save_associations
  130 + error = false
  131 + roles = Profile::Roles.organization_member_roles(environment.id)
  132 + roles.select { |role| params['q_'+role.key] }.each do |role|
  133 + people = [Person.find(params['q_'+role.key].split(','))].flatten
  134 + to_remove = profile.members_by_role(role) - people
  135 + to_add = people - profile.members_by_role(role)
  136 +
  137 + begin
  138 + to_remove.each { |person| profile.disaffiliate(person, role) }
  139 + to_add.each { |person| profile.affiliate(person, role) }
  140 + rescue Exception => ex
  141 + logger.info ex
  142 + error = true
  143 + end
  144 + end
  145 +
  146 + if error
  147 + session[:notice] = _('The members list couldn\'t be updated. Please contact the administrator.')
  148 + redirect_to :action => 'add_members'
  149 + else
  150 + if profile.admins.blank? && !params[:last_admin]
  151 + redirect_to :action => 'last_admin'
  152 + else
  153 + session[:notice] = _('The members list was updated.')
  154 + redirect_to :controller => 'profile_editor'
  155 + end
136 end 156 end
137 - render :layout => false  
138 end 157 end
139 158
140 def send_mail 159 def send_mail
app/controllers/my_profile/tasks_controller.rb
@@ -3,12 +3,13 @@ class TasksController &lt; MyProfileController @@ -3,12 +3,13 @@ class TasksController &lt; MyProfileController
3 protect 'perform_task', :profile 3 protect 'perform_task', :profile
4 4
5 def index 5 def index
6 - @tasks = profile.all_pending_tasks.sort_by(&:created_at) 6 + @filter = params[:filter_type].blank? ? nil : params[:filter_type]
  7 + @tasks = Task.to(profile).pending.of(@filter).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page])
7 @failed = params ? params[:failed] : {} 8 @failed = params ? params[:failed] : {}
8 end 9 end
9 10
10 def processed 11 def processed
11 - @tasks = profile.all_finished_tasks.sort_by(&:created_at) 12 + @tasks = Task.to(profile).finished.sort_by(&:created_at)
12 end 13 end
13 14
14 VALID_DECISIONS = [ 'finish', 'cancel', 'skip' ] 15 VALID_DECISIONS = [ 'finish', 'cancel', 'skip' ]
app/controllers/public/account_controller.rb
@@ -4,7 +4,6 @@ class AccountController &lt; ApplicationController @@ -4,7 +4,6 @@ class AccountController &lt; ApplicationController
4 4
5 inverse_captcha :field => 'e_mail' 5 inverse_captcha :field => 'e_mail'
6 6
7 -  
8 before_filter :login_required, :only => [:activation_question, :accept_terms, :activate_enterprise] 7 before_filter :login_required, :only => [:activation_question, :accept_terms, :activate_enterprise]
9 before_filter :redirect_if_logged_in, :only => [:login, :signup] 8 before_filter :redirect_if_logged_in, :only => [:login, :signup]
10 9
@@ -15,6 +14,17 @@ class AccountController &lt; ApplicationController @@ -15,6 +14,17 @@ class AccountController &lt; ApplicationController
15 end 14 end
16 end 15 end
17 16
  17 + def activate
  18 + @user = User.find_by_activation_code(params[:activation_code]) if params[:activation_code]
  19 + if @user and @user.activate
  20 + @message = _("Your account has been activated, now you can log in!")
  21 + render :action => 'login', :userlogin => @user.login
  22 + else
  23 + session[:notice] = _("It looks like you're trying to activate an account. Perhaps have already activated this account?")
  24 + redirect_to :controller => :home
  25 + end
  26 + end
  27 +
18 # action to perform login to the application 28 # action to perform login to the application
19 def login 29 def login
20 @user = User.new 30 @user = User.new
@@ -57,9 +67,8 @@ class AccountController &lt; ApplicationController @@ -57,9 +67,8 @@ class AccountController &lt; ApplicationController
57 @user.person_data = params[:profile_data] 67 @user.person_data = params[:profile_data]
58 @person = Person.new(params[:profile_data]) 68 @person = Person.new(params[:profile_data])
59 @person.environment = @user.environment 69 @person.environment = @user.environment
60 - if request.post? && params[self.icaptcha_field].blank? 70 + if request.post?
61 @user.signup! 71 @user.signup!
62 - self.current_user = @user  
63 owner_role = Role.find_by_name('owner') 72 owner_role = Role.find_by_name('owner')
64 @user.person.affiliate(@user.person, [owner_role]) if owner_role 73 @user.person.affiliate(@user.person, [owner_role]) if owner_role
65 invitation = Task.find_by_code(@invitation_code) 74 invitation = Task.find_by_code(@invitation_code)
@@ -67,8 +76,7 @@ class AccountController &lt; ApplicationController @@ -67,8 +76,7 @@ class AccountController &lt; ApplicationController
67 invitation.update_attributes!({:friend => @user.person}) 76 invitation.update_attributes!({:friend => @user.person})
68 invitation.finish 77 invitation.finish
69 end 78 end
70 - session[:notice] = _("Thanks for signing up!")  
71 - go_to_initial_page if redirect? 79 + @register_pending = true
72 end 80 end
73 rescue ActiveRecord::RecordInvalid 81 rescue ActiveRecord::RecordInvalid
74 @person.valid? 82 @person.valid?
@@ -223,6 +231,8 @@ class AccountController &lt; ApplicationController @@ -223,6 +231,8 @@ class AccountController &lt; ApplicationController
223 session[:notice] = nil # consume the notice 231 session[:notice] = nil # consume the notice
224 end 232 end
225 233
  234 + @plugins.enabled_plugins.each { |plugin| user_data.merge!(plugin.user_data_extras) }
  235 +
226 render :text => user_data.to_json, :layout => false, :content_type => "application/javascript" 236 render :text => user_data.to_json, :layout => false, :content_type => "application/javascript"
227 end 237 end
228 238
app/controllers/public/browse_controller.rb
@@ -6,6 +6,8 @@ class BrowseController &lt; PublicController @@ -6,6 +6,8 @@ class BrowseController &lt; PublicController
6 more_recent 6 more_recent
7 more_active 7 more_active
8 more_popular 8 more_popular
  9 + more_comments
  10 + more_views
9 ) 11 )
10 12
11 def per_page 13 def per_page
@@ -36,6 +38,18 @@ class BrowseController &lt; PublicController @@ -36,6 +38,18 @@ class BrowseController &lt; PublicController
36 @results = @results.compact.paginate(:per_page => per_page, :page => params[:page]) 38 @results = @results.compact.paginate(:per_page => per_page, :page => params[:page])
37 end 39 end
38 40
  41 + def contents
  42 + @filter = filter
  43 + @title = self.filter_description(params[:action] + '_' + @filter )
  44 +
  45 + @results = @environment.articles.published.text_articles.send(@filter)
  46 +
  47 + if !params[:query].blank?
  48 + @results = @results.find_by_contents(params[:query])
  49 + end
  50 + @results = @results.compact.paginate(:per_page => per_page, :page => params[:page])
  51 + end
  52 +
39 protected 53 protected
40 54
41 def filter 55 def filter
@@ -54,6 +68,9 @@ class BrowseController &lt; PublicController @@ -54,6 +68,9 @@ class BrowseController &lt; PublicController
54 'communities_more_recent' => _('More recent communities'), 68 'communities_more_recent' => _('More recent communities'),
55 'communities_more_active' => _('More active communities'), 69 'communities_more_active' => _('More active communities'),
56 'communities_more_popular' => _('More popular communities'), 70 'communities_more_popular' => _('More popular communities'),
  71 + 'contents_more_recent' => _('More recent contents'),
  72 + 'contents_more_views' => _('Most viewed contents'),
  73 + 'contents_more_comments' => _('Most commented contents'),
57 }[str] || str 74 }[str] || str
58 end 75 end
59 76
app/controllers/public/contact_controller.rb
@@ -4,10 +4,9 @@ class ContactController &lt; PublicController @@ -4,10 +4,9 @@ class ContactController &lt; PublicController
4 4
5 needs_profile 5 needs_profile
6 6
7 - inverse_captcha :field => 'e_mail'  
8 def new 7 def new
9 @contact 8 @contact
10 - if request.post? && params[self.icaptcha_field].blank? && params[:confirm] == 'true' 9 + if request.post? && params[:confirm] == 'true'
11 @contact = user.build_contact(profile, params[:contact]) 10 @contact = user.build_contact(profile, params[:contact])
12 @contact.city = (!params[:city].blank? && City.exists?(params[:city])) ? City.find(params[:city]).name : nil 11 @contact.city = (!params[:city].blank? && City.exists?(params[:city])) ? City.find(params[:city]).name : nil
13 @contact.state = (!params[:state].blank? && State.exists?(params[:state])) ? State.find(params[:state]).name : nil 12 @contact.state = (!params[:state].blank? && State.exists?(params[:state])) ? State.find(params[:state]).name : nil
app/controllers/public/content_viewer_controller.rb
@@ -2,8 +2,6 @@ class ContentViewerController &lt; ApplicationController @@ -2,8 +2,6 @@ class ContentViewerController &lt; ApplicationController
2 2
3 needs_profile 3 needs_profile
4 4
5 - inverse_captcha :field => 'e_mail'  
6 -  
7 helper ProfileHelper 5 helper ProfileHelper
8 helper TagsHelper 6 helper TagsHelper
9 7
@@ -68,8 +66,13 @@ class ContentViewerController &lt; ApplicationController @@ -68,8 +66,13 @@ class ContentViewerController &lt; ApplicationController
68 66
69 @form_div = params[:form] 67 @form_div = params[:form]
70 68
71 - if request.post? && params[:comment] && params[self.icaptcha_field].blank? && params[:confirm] == 'true' && @page.accept_comments?  
72 - add_comment 69 + if params[:comment] && params[:confirm] == 'true'
  70 + @comment = Comment.new(params[:comment])
  71 + if request.post? && @page.accept_comments?
  72 + add_comment
  73 + end
  74 + else
  75 + @comment = Comment.new
73 end 76 end
74 77
75 if request.post? && params[:remove_comment] 78 if request.post? && params[:remove_comment]
@@ -106,11 +109,10 @@ class ContentViewerController &lt; ApplicationController @@ -106,11 +109,10 @@ class ContentViewerController &lt; ApplicationController
106 protected 109 protected
107 110
108 def add_comment 111 def add_comment
109 - @comment = Comment.new(params[:comment])  
110 @comment.author = user if logged_in? 112 @comment.author = user if logged_in?
111 @comment.article = @page 113 @comment.article = @page
112 - if @comment.save  
113 - @page.update_attribute(:updated_at, Time.now) 114 + if (logged_in? || verify_recaptcha(:model => @comment, :message => _('Please type the words correctly'))) && @comment.save
  115 + @page.touch
114 @comment = nil # clear the comment form 116 @comment = nil # clear the comment form
115 redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view] 117 redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view]
116 else 118 else
app/controllers/public/profile_controller.rb
@@ -2,8 +2,8 @@ class ProfileController &lt; PublicController @@ -2,8 +2,8 @@ class ProfileController &lt; PublicController
2 2
3 needs_profile 3 needs_profile
4 before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add] 4 before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add]
5 - before_filter :store_before_join, :only => [:join, :join_not_logged]  
6 - before_filter :login_required, :only => [:add, :join, :join_not_logged, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_scraps, :view_more_activities, :view_more_network_activities] 5 + before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse]
  6 + before_filter :login_required, :only => [:add, :join, :join_not_logged, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_scraps, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report]
7 7
8 helper TagsHelper 8 helper TagsHelper
9 9
@@ -44,7 +44,7 @@ class ProfileController &lt; PublicController @@ -44,7 +44,7 @@ class ProfileController &lt; PublicController
44 tagged, 44 tagged,
45 :title => _("%s's contents tagged with \"%s\"") % [profile.name, @tag], 45 :title => _("%s's contents tagged with \"%s\"") % [profile.name, @tag],
46 :description => _("%s's contents tagged with \"%s\"") % [profile.name, @tag], 46 :description => _("%s's contents tagged with \"%s\"") % [profile.name, @tag],
47 - :link => url_for(:action => 'tags') 47 + :link => url_for(profile.url)
48 ) 48 )
49 render :text => data, :content_type => "text/xml" 49 render :text => data, :content_type => "text/xml"
50 end 50 end
@@ -71,6 +71,10 @@ class ProfileController &lt; PublicController @@ -71,6 +71,10 @@ class ProfileController &lt; PublicController
71 end 71 end
72 end 72 end
73 73
  74 + def fans
  75 + @fans = profile.fans
  76 + end
  77 +
74 def favorite_enterprises 78 def favorite_enterprises
75 @favorite_enterprises = profile.favorite_enterprises 79 @favorite_enterprises = profile.favorite_enterprises
76 end 80 end
@@ -96,7 +100,7 @@ class ProfileController &lt; PublicController @@ -96,7 +100,7 @@ class ProfileController &lt; PublicController
96 if request.post? 100 if request.post?
97 profile.add_member(user) 101 profile.add_member(user)
98 session[:notice] = _('%s administrator still needs to accept you as member.') % profile.name if profile.closed? 102 session[:notice] = _('%s administrator still needs to accept you as member.') % profile.name if profile.closed?
99 - redirect_to_before_join 103 + redirect_to_previous_location
100 else 104 else
101 if user.memberships.include?(profile) 105 if user.memberships.include?(profile)
102 session[:notice] = _('You are already a member of %s.') % profile.name 106 session[:notice] = _('You are already a member of %s.') % profile.name
@@ -223,6 +227,52 @@ class ProfileController &lt; PublicController @@ -223,6 +227,52 @@ class ProfileController &lt; PublicController
223 end 227 end
224 end 228 end
225 229
  230 + def report_abuse
  231 + @abuse_report = AbuseReport.new
  232 + render :layout => false
  233 + end
  234 +
  235 + def register_report
  236 + if !verify_recaptcha
  237 + render :text => {
  238 + :ok => false,
  239 + :error => {
  240 + :code => 1,
  241 + :message => _('You could not answer the captcha.')
  242 + }
  243 + }.to_json
  244 + else
  245 + begin
  246 + abuse_report = AbuseReport.new(params[:abuse_report])
  247 + if !params[:content_type].blank?
  248 + article = params[:content_type].constantize.find(params[:content_id])
  249 + abuse_report.content = instance_eval(&article.reported_version)
  250 + end
  251 +
  252 + user.register_report(abuse_report, profile)
  253 +
  254 + if !params[:content_type].blank?
  255 + abuse_report = AbuseReport.find_by_reporter_id_and_abuse_complaint_id(user.id, profile.opened_abuse_complaint.id)
  256 + Delayed::Job.enqueue DownloadReportedImagesJob.new(abuse_report, article)
  257 + end
  258 +
  259 + render :text => {
  260 + :ok => true,
  261 + :message => _('Your abuse report was registered. The administrators are reviewing your report.'),
  262 + }.to_json
  263 + rescue Exception => exception
  264 + logger.error(exception.to_s)
  265 + render :text => {
  266 + :ok => false,
  267 + :error => {
  268 + :code => 2,
  269 + :message => _('Your report couldn\'t be saved due to some problem. Please contact the administrator.')
  270 + }
  271 + }.to_json
  272 + end
  273 + end
  274 + end
  275 +
226 protected 276 protected
227 277
228 def check_access_to_profile 278 def check_access_to_profile
@@ -231,16 +281,16 @@ class ProfileController &lt; PublicController @@ -231,16 +281,16 @@ class ProfileController &lt; PublicController
231 end 281 end
232 end 282 end
233 283
234 - def store_before_join  
235 - if session[:before_join].nil?  
236 - session[:before_join] = request.referer 284 + def store_location
  285 + if session[:previous_location].nil?
  286 + session[:previous_location] = request.referer
237 end 287 end
238 end 288 end
239 289
240 - def redirect_to_before_join  
241 - back = session[:before_join] 290 + def redirect_to_previous_location
  291 + back = session[:previous_location]
242 if back 292 if back
243 - session[:before_join] = nil 293 + session[:previous_location] = nil
244 redirect_to back 294 redirect_to back
245 else 295 else
246 redirect_to profile.url 296 redirect_to profile.url
@@ -259,7 +309,7 @@ class ProfileController &lt; PublicController @@ -259,7 +309,7 @@ class ProfileController &lt; PublicController
259 end 309 end
260 310
261 def invisible_profile 311 def invisible_profile
262 - render_access_denied(_("Sorry, this profile was defined as private by its owner. You'll not be able to view content here unless the profile owner adds adds you."), _("Oops ... you cannot go ahead here")) 312 + render_access_denied(_("This profile is inaccessible. You don't have the permission to view the content here."), _("Oops ... you cannot go ahead here"))
263 end 313 end
264 314
265 def per_page 315 def per_page
app/helpers/application_helper.rb
@@ -209,7 +209,11 @@ module ApplicationHelper @@ -209,7 +209,11 @@ module ApplicationHelper
209 the_class << ' ' << html_options[:class] 209 the_class << ' ' << html_options[:class]
210 end 210 end
211 the_title = html_options[:title] || label 211 the_title = html_options[:title] || label
212 - link_to('&nbsp;'+content_tag('span', label), url, html_options.merge(:class => the_class, :title => the_title)) 212 + if html_options[:disabled]
  213 + content_tag('a', '&nbsp;'+content_tag('span', label), html_options.merge(:class => the_class, :title => the_title))
  214 + else
  215 + link_to('&nbsp;'+content_tag('span', label), url, html_options.merge(:class => the_class, :title => the_title))
  216 + end
213 end 217 end
214 218
215 def button_to_function(type, label, js_code, html_options = {}, &block) 219 def button_to_function(type, label, js_code, html_options = {}, &block)
@@ -257,30 +261,59 @@ module ApplicationHelper @@ -257,30 +261,59 @@ module ApplicationHelper
257 concat(content_tag('div', capture(&block) + tag('br', :style => 'clear: left;'), { :class => 'button-bar' }.merge(options))) 261 concat(content_tag('div', capture(&block) + tag('br', :style => 'clear: left;'), { :class => 'button-bar' }.merge(options)))
258 end 262 end
259 263
260 - def partial_for_class(klass)  
261 - if klass.nil?  
262 - raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?'  
263 - end 264 + VIEW_EXTENSIONS = %w[.rhtml .html.erb]
264 265
  266 + def partial_for_class_in_view_path(klass, view_path)
  267 + return nil if klass.nil?
265 name = klass.name.underscore 268 name = klass.name.underscore
266 - if File.exists?(File.join(RAILS_ROOT, 'app', 'views', params[:controller], "_#{name}.rhtml"))  
267 - name 269 +
  270 + search_name = String.new(name)
  271 + if search_name.include?("/")
  272 + search_name.gsub!(/(\/)([^\/]*)$/,'\1_\2')
  273 + name = File.join(params[:controller], name) if defined?(params) && params[:controller]
268 else 274 else
269 - partial_for_class(klass.superclass) 275 + search_name = "_" + search_name
  276 + end
  277 +
  278 + VIEW_EXTENSIONS.each do |ext|
  279 + path = defined?(params) && params[:controller] ? File.join(view_path, params[:controller], search_name+ext) : File.join(view_path, search_name+ext)
  280 + return name if File.exists?(File.join(path))
270 end 281 end
  282 +
  283 + partial_for_class_in_view_path(klass.superclass, view_path)
271 end 284 end
272 285
273 - def partial_for_task_class(klass, action)  
274 - if klass.nil?  
275 - raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' 286 + def partial_for_class(klass)
  287 + raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil?
  288 + name = klass.name.underscore
  289 + @controller.view_paths.each do |view_path|
  290 + partial = partial_for_class_in_view_path(klass, view_path)
  291 + return partial if partial
276 end 292 end
277 293
  294 + raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?'
  295 + end
  296 +
  297 + def partial_for_task_class(klass, action)
  298 + raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil?
  299 +
278 name = "#{klass.name.underscore}_#{action.to_s}" 300 name = "#{klass.name.underscore}_#{action.to_s}"
279 - if File.exists?(File.join(RAILS_ROOT, 'app', 'views', params[:controller], "_#{name}.rhtml"))  
280 - name  
281 - else  
282 - partial_for_task_class(klass.superclass, action) 301 + VIEW_EXTENSIONS.each do |ext|
  302 + return name if File.exists?(File.join(RAILS_ROOT, 'app', 'views', params[:controller], '_'+name+ext))
  303 + end
  304 +
  305 + partial_for_task_class(klass.superclass, action)
  306 + end
  307 +
  308 + def view_for_profile_actions(klass)
  309 + raise ArgumentError, 'No profile actions view for this class.' if klass.nil?
  310 +
  311 + name = klass.name.underscore
  312 + VIEW_EXTENSIONS.each do |ext|
  313 + return "blocks/profile_info_actions/"+name+ext if File.exists?(File.join(RAILS_ROOT, 'app', 'views', 'blocks', 'profile_info_actions', name+ext))
283 end 314 end
  315 +
  316 + view_for_profile_actions(klass.superclass)
284 end 317 end
285 318
286 def user 319 def user
@@ -556,17 +589,18 @@ module ApplicationHelper @@ -556,17 +589,18 @@ module ApplicationHelper
556 589
557 def gravatar_url_for(email, options = {}) 590 def gravatar_url_for(email, options = {})
558 # Ta dando erro de roteamento 591 # Ta dando erro de roteamento
  592 + default = theme_option['gravatar'] || NOOSFERO_CONF['gravatar'] || nil
559 url_for( { :gravatar_id => Digest::MD5.hexdigest(email), 593 url_for( { :gravatar_id => Digest::MD5.hexdigest(email),
560 :host => 'www.gravatar.com', 594 :host => 'www.gravatar.com',
561 :protocol => 'http://', 595 :protocol => 'http://',
562 :only_path => false, 596 :only_path => false,
563 :controller => 'avatar.php', 597 :controller => 'avatar.php',
564 - :d => NOOSFERO_CONF['gravatar'] ? NOOSFERO_CONF['gravatar'] : nil 598 + :d => default
565 }.merge(options) ) 599 }.merge(options) )
566 end 600 end
567 601
568 def str_gravatar_url_for(email, options = {}) 602 def str_gravatar_url_for(email, options = {})
569 - default = NOOSFERO_CONF['gravatar'] ? NOOSFERO_CONF['gravatar'] : nil 603 + default = theme_option['gravatar'] || NOOSFERO_CONF['gravatar'] || nil
570 url = 'http://www.gravatar.com/avatar.php?gravatar_id=' + 604 url = 'http://www.gravatar.com/avatar.php?gravatar_id=' +
571 Digest::MD5.hexdigest(email) 605 Digest::MD5.hexdigest(email)
572 { 606 {
@@ -870,7 +904,7 @@ module ApplicationHelper @@ -870,7 +904,7 @@ module ApplicationHelper
870 904
871 def template_stylesheet_path 905 def template_stylesheet_path
872 if profile.nil? 906 if profile.nil?
873 - '/designs/templates/default/stylesheets/style.css' 907 + "/designs/templates/#{environment.layout_template}/stylesheets/style.css"
874 else 908 else
875 "/designs/templates/#{profile.layout_template}/stylesheets/style.css" 909 "/designs/templates/#{profile.layout_template}/stylesheets/style.css"
876 end 910 end
@@ -947,8 +981,10 @@ module ApplicationHelper @@ -947,8 +981,10 @@ module ApplicationHelper
947 'thickbox', 981 'thickbox',
948 'lightbox', 982 'lightbox',
949 'colorpicker', 983 'colorpicker',
  984 + colorbox_stylesheet_path,
950 pngfix_stylesheet_path, 985 pngfix_stylesheet_path,
951 - ] 986 + ] +
  987 + tokeninput_stylesheets
952 end 988 end
953 989
954 # DEPRECATED. Do not use this· 990 # DEPRECATED. Do not use this·
@@ -960,6 +996,14 @@ module ApplicationHelper @@ -960,6 +996,14 @@ module ApplicationHelper
960 'iepngfix/iepngfix.css' 996 'iepngfix/iepngfix.css'
961 end 997 end
962 998
  999 + def colorbox_stylesheet_path
  1000 + 'colorbox/colorbox.css'
  1001 + end
  1002 +
  1003 + def tokeninput_stylesheets
  1004 + ['token-input', 'token-input-facebook', 'token-input-mac']
  1005 + end
  1006 +
963 def noosfero_layout_features 1007 def noosfero_layout_features
964 render :file => 'shared/noosfero_layout_features' 1008 render :file => 'shared/noosfero_layout_features'
965 end 1009 end
@@ -975,7 +1019,10 @@ module ApplicationHelper @@ -975,7 +1019,10 @@ module ApplicationHelper
975 def article_to_html(article, options = {}) 1019 def article_to_html(article, options = {})
976 options.merge!(:page => params[:npage]) 1020 options.merge!(:page => params[:npage])
977 content = article.to_html(options) 1021 content = article.to_html(options)
978 - return self.instance_eval(&content) if content.kind_of?(Proc) 1022 + content = content.kind_of?(Proc) ? self.instance_eval(&content) : content
  1023 + @plugins && @plugins.enabled_plugins.each do |plugin|
  1024 + content = plugin.parse_content(content)
  1025 + end
979 content 1026 content
980 end 1027 end
981 1028
@@ -1083,6 +1130,17 @@ module ApplicationHelper @@ -1083,6 +1130,17 @@ module ApplicationHelper
1083 link_to(content_tag(:span, _('Communities Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-communities-trigger') 1130 link_to(content_tag(:span, _('Communities Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-communities-trigger')
1084 end 1131 end
1085 1132
  1133 + def browse_contents_menu
  1134 + links = [
  1135 + {s_('contents|More Comments') => {:href => url_for({:controller => 'browse', :action => 'contents', :filter => 'more_comments'})}},
  1136 + {s_('contents|More Views') => {:href => url_for({:controller => 'browse', :action => 'contents', :filter => 'more_views'})}},
  1137 + {s_('contents|More Recent') => {:href => url_for({:controller => 'browse', :action => 'contents', :filter => 'more_recent'})}}
  1138 + ]
  1139 +
  1140 + link_to(content_tag(:span, _('Contents'), :class => 'icon-blog'), {:controller => "browse", :action => 'contents'}, :id => 'submenu-contents') +
  1141 + link_to(content_tag(:span, _('Contents Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-contents-trigger')
  1142 + end
  1143 +
1086 def pagination_links(collection, options={}) 1144 def pagination_links(collection, options={})
1087 options = {:prev_label => '&laquo; ' + _('Previous'), :next_label => _('Next') + ' &raquo;'}.merge(options) 1145 options = {:prev_label => '&laquo; ' + _('Previous'), :next_label => _('Next') + ' &raquo;'}.merge(options)
1088 will_paginate(collection, options) 1146 will_paginate(collection, options)
@@ -1099,16 +1157,27 @@ module ApplicationHelper @@ -1099,16 +1157,27 @@ module ApplicationHelper
1099 result 1157 result
1100 end 1158 end
1101 1159
  1160 + def manage_enterprises
  1161 + if user && !user.enterprises.empty?
  1162 + enterprises_link = user.enterprises.map do |enterprise|
  1163 + link_to(content_tag('strong', [_('<span>Manage</span> %s') % enterprise.short_name(25)]), @environment.top_url + "/myprofile/#{enterprise.identifier}", :class => "icon-menu-"+enterprise.class.identification.underscore, :title => [_('Manage %s') % enterprise.short_name])
  1164 + end
  1165 + render :partial => 'shared/manage_enterprises', :locals => {:enterprises_link => enterprises_link}
  1166 + end
  1167 + end
  1168 +
1102 def usermenu_logged_in 1169 def usermenu_logged_in
1103 pending_tasks_count = '' 1170 pending_tasks_count = ''
1104 - if user && user.all_pending_tasks.count > 0  
1105 - pending_tasks_count = link_to(user.all_pending_tasks.count.to_s, '/myprofile/{login}/tasks', :id => 'pending-tasks-count', :title => _("Manage your pending tasks")) 1171 + count = user ? Task.to(user).pending.count : -1
  1172 + if count > 0
  1173 + pending_tasks_count = link_to(count.to_s, @environment.top_url + '/myprofile/{login}/tasks', :id => 'pending-tasks-count', :title => _("Manage your pending tasks"))
1106 end 1174 end
1107 1175
1108 - (_('Welcome, %s') % link_to('<i></i><strong>{login}</strong>', '/{login}', :id => "homepage-link", :title => _('Go to your homepage'))) + 1176 + (_("<span class='welcome'>Welcome,</span> %s") % link_to('<i></i><strong>{login}</strong>', @environment.top_url + '/{login}', :id => "homepage-link", :title => _('Go to your homepage'))) +
1109 render_environment_features(:usermenu) + 1177 render_environment_features(:usermenu) +
1110 - link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', { :controller => 'admin_panel', :action => 'index' }, :id => "controlpanel", :title => _("Configure the environment"), :class => 'admin-link', :style => 'display: none') +  
1111 - link_to('<i class="icon-menu-ctrl-panel"></i><strong>' + _('Control panel') + '</strong>', '/myprofile/{login}', :id => "controlpanel", :title => _("Configure your personal account and content")) + 1178 + link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', @environment.top_url + '/admin', :id => "controlpanel", :title => _("Configure the environment"), :class => 'admin-link', :style => 'display: none') +
  1179 + manage_enterprises.to_s +
  1180 + link_to('<i class="icon-menu-ctrl-panel"></i><strong>' + _('Control panel') + '</strong>', @environment.top_url + '/myprofile/{login}', :id => "controlpanel", :title => _("Configure your personal account and content")) +
1112 pending_tasks_count + 1181 pending_tasks_count +
1113 link_to('<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>', { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system")) 1182 link_to('<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>', { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system"))
1114 end 1183 end
@@ -1206,4 +1275,39 @@ module ApplicationHelper @@ -1206,4 +1275,39 @@ module ApplicationHelper
1206 end 1275 end
1207 end 1276 end
1208 1277
  1278 + def render_dialog_error_messages(instance_name)
  1279 + render :partial => 'shared/dialog_error_messages', :locals => { :object_name => instance_name }
  1280 + end
  1281 +
  1282 + def report_abuse(profile, type, content=nil)
  1283 + return if !user || user == profile
  1284 +
  1285 + url = { :controller => 'profile',
  1286 + :action => 'report_abuse',
  1287 + :profile => profile.identifier }
  1288 + url.merge!({:content_type => content.class.name, :content_id => content.id}) if content
  1289 + text = content_tag('span', _('Report abuse'))
  1290 + klass = 'report-abuse-action'
  1291 + already_reported_message = _('You already reported this profile.')
  1292 + report_profile_message = _('Report this profile for abusive behaviour')
  1293 +
  1294 + if type == :button
  1295 + if user.already_reported?(profile)
  1296 + button(:alert, text, url, :class => klass+' disabled', :disabled => true, :title => already_reported_message)
  1297 + else
  1298 + button(:alert, text, url, :class => klass, :title => report_profile_message)
  1299 + end
  1300 + elsif type == :link
  1301 + if user.already_reported?(profile)
  1302 + content_tag('a', text, :class => klass + ' disabled button with-text icon-alert', :title => already_reported_message)
  1303 + else
  1304 + link_to(text, url, :class => klass + ' button with-text icon-alert', :title => report_profile_message)
  1305 + end
  1306 + elsif type == :comment_link
  1307 + (user.already_reported?(profile) ?
  1308 + content_tag('a', text, :class => klass + ' disabled comment-footer comment-footer-link', :title => already_reported_message) :
  1309 + link_to(text, url, :class => klass + ' comment-footer comment-footer-link', :title => report_profile_message)
  1310 + ) + content_tag('span', ' | ', :class => 'comment-footer comment-footer-hide')
  1311 + end
  1312 + end
1209 end 1313 end
app/helpers/boxes_helper.rb
@@ -99,7 +99,9 @@ module BoxesHelper @@ -99,7 +99,9 @@ module BoxesHelper
99 unless block.visible? 99 unless block.visible?
100 options[:title] = _("This block is invisible. Your visitors will not see it.") 100 options[:title] = _("This block is invisible. Your visitors will not see it.")
101 end 101 end
102 - 102 + @controller.send(:content_editor?) || @plugins.enabled_plugins.each do |plugin|
  103 + result = plugin.parse_content(result)
  104 + end
103 box_decorator.block_target(block.box, block) + 105 box_decorator.block_target(block.box, block) +
104 content_tag('div', 106 content_tag('div',
105 content_tag('div', 107 content_tag('div',
app/helpers/catalog_helper.rb
@@ -5,16 +5,24 @@ include ManageProductsHelper @@ -5,16 +5,24 @@ include ManageProductsHelper
5 5
6 def display_products_list(profile, products) 6 def display_products_list(profile, products)
7 data = '' 7 data = ''
  8 + extra_content = []
  9 + extra_content_list = []
8 products.each { |product| 10 products.each { |product|
9 - 11 + extra_content = @plugins.map(:catalog_item_extras, product).collect { |content| instance_eval(&content) } if @plugins
  12 + extra_content_list = @plugins.map(:catalog_list_item_extras, product).collect { |content| instance_eval(&content) } if @plugins
10 data << content_tag('li', 13 data << content_tag('li',
11 - link_to_product(product, :class => 'product-pic', :style => 'background-image:url(%s)' % ( product.image ? product.image.public_filename(:portrait) : '/images/icons-app/product-default-pic-portrait.png' )) + 14 + link_to_product(product, :class => 'product-pic', :style => 'background-image:url(%s)' % product.default_image(:portrait) ) +
12 content_tag('h3', link_to_product(product)) + 15 content_tag('h3', link_to_product(product)) +
13 content_tag('ul', 16 content_tag('ul',
14 (product.price ? content_tag('li', _('Price: %s') % ( "%.2f" % product.price), :class => 'product_price') : '') + 17 (product.price ? content_tag('li', _('Price: %s') % ( "%.2f" % product.price), :class => 'product_price') : '') +
15 - content_tag('li', product_category_name(profile, product.product_category), :class => 'product_category') 18 + content_tag('li', product_category_name(profile, product.product_category), :class => 'product_category') +
  19 + extra_content_list.map { |content| content_tag('li', content)}.join("\n")
16 ) + 20 ) +
17 - (product.description ? content_tag('div', txt2html(product.description), :class => 'description') : tag('br', :style => 'clear:both')), 21 + (product.description ? content_tag('div',
  22 + txt2html(product.description),
  23 + :class => 'description') : tag('br',
  24 + :style => 'clear:both')) +
  25 + extra_content.join("\n"),
18 :class => 'product') 26 :class => 'product')
19 } 27 }
20 content_tag('h1', _('Products/Services')) + content_tag('ul', data, :id => 'product_list') 28 content_tag('h1', _('Products/Services')) + content_tag('ul', data, :id => 'product_list')
app/helpers/content_viewer_helper.rb
@@ -22,9 +22,14 @@ module ContentViewerHelper @@ -22,9 +22,14 @@ module ContentViewerHelper
22 end 22 end
23 comments = '' 23 comments = ''
24 unless args[:no_comments] || !article.accept_comments 24 unless args[:no_comments] || !article.accept_comments
25 - comments = ("- %s") % link_to_comments(article) 25 + comments = (" - %s") % link_to_comments(article)
26 end 26 end
27 - title << content_tag('span', _("%s, by %s %s") % [show_date(article.published_at), link_to(article.author_name, article.author.url), comments], :class => 'created-at') 27 + title << content_tag('span',
  28 + content_tag('span', show_date(article.published_at), :class => 'date') +
  29 + content_tag('span', [_(", by %s") % link_to(article.author_name, article.author.url)], :class => 'author') +
  30 + content_tag('span', comments, :class => 'comments'),
  31 + :class => 'created-at'
  32 + )
28 end 33 end
29 title 34 title
30 end 35 end
@@ -46,4 +51,21 @@ module ContentViewerHelper @@ -46,4 +51,21 @@ module ContentViewerHelper
46 end 51 end
47 end 52 end
48 53
  54 + def addthis_facebook_url(article)
  55 + "http://www.facebook.com/sharer.php?s=100&p[title]=%{title}&p[summary]=%{summary}&p[url]=%{url}&p[images][0]=%{image}" % {
  56 + :title => CGI.escape(article.title),
  57 + :url => CGI.escape(url_for(article.url)),
  58 + :summary => CGI.escape(truncate(strip_tags(article.body.to_s), 300)),
  59 + :image => CGI.escape(article.body_images_paths.first.to_s)
  60 + }
  61 + end
  62 +
  63 + def addthis_image_tag
  64 + if File.exists?(File.join(Rails.root, 'public', theme_path, 'images', 'addthis.gif'))
  65 + image_tag(File.join(theme_path, 'images', 'addthis.gif'), :border => 0, :alt => '')
  66 + else
  67 + image_tag("/images/bt-bookmark.gif", :width => 53, :height => 16, :border => 0, :alt => '')
  68 + end
  69 + end
  70 +
49 end 71 end
app/helpers/dates_helper.rb
@@ -42,11 +42,11 @@ module DatesHelper @@ -42,11 +42,11 @@ module DatesHelper
42 end 42 end
43 end 43 end
44 44
45 - def show_period(date1, date2 = nil) 45 + def show_period(date1, date2 = nil, use_numbers = false)
46 if (date1 == date2) || (date2.nil?) 46 if (date1 == date2) || (date2.nil?)
47 - show_date(date1) 47 + show_date(date1, use_numbers)
48 else 48 else
49 - _('from %{date1} to %{date2}') % {:date1 => show_date(date1), :date2 => show_date(date2)} 49 + _('from %{date1} to %{date2}') % {:date1 => show_date(date1, use_numbers), :date2 => show_date(date2, use_numbers)}
50 end 50 end
51 end 51 end
52 52
app/helpers/display_helper.rb
@@ -27,14 +27,18 @@ module DisplayHelper @@ -27,14 +27,18 @@ module DisplayHelper
27 end 27 end
28 28
29 def txt2html(txt) 29 def txt2html(txt)
30 - txt.  
31 - gsub( /\n\s*\n/, ' <p/> ' ).  
32 - gsub( /\n/, ' <br/> ' ).  
33 - gsub( /(^|\s)(www\.[^\s])/, '\1http://\2' ).  
34 - gsub( /(https?:\/\/([^\s]+))/ ) do  
35 - href, content = $1, $2.scan(/.{4}/).join('&#x200B;')  
36 - content_tag(:a, content, :href => href, :target => '_blank', :rel => 'nofolow',  
37 - :onclick => "return confirm('%s')" % escape_javascript(_('Are you sure you want to visit this web site?'))) 30 + txt.strip.
  31 + gsub( /\s*\n\s*\n\s*/, "\r<p/>\r" ).
  32 + gsub( /\s*\n\s*/, "\n<br/>\n" ).
  33 + gsub( /\r/, "\n" ).
  34 + gsub( /(^|\s)(www\.[^\s]+|https?:\/\/[^\s]+)/ ) do
  35 + pre_char, href = $1, $2
  36 + href = 'http://'+href if ! href.match /^https?:/
  37 + content = href.gsub(/^https?:\/\//, '').scan(/.{1,4}/).join('&#x200B;')
  38 + pre_char +
  39 + content_tag(:a, content, :href => href, :target => '_blank',
  40 + :rel => 'nofolow', :onclick => "return confirm('%s')" %
  41 + _('Are you sure you want to visit this web site?'))
38 end 42 end
39 end 43 end
40 end 44 end
app/helpers/events_helper.rb
@@ -21,14 +21,13 @@ module EventsHelper @@ -21,14 +21,13 @@ module EventsHelper
21 end 21 end
22 22
23 def populate_calendar(selected_date, events) 23 def populate_calendar(selected_date, events)
  24 + events.reject! {|event| !event.display_to?(user)}
24 calendar = Event.date_range(selected_date.year, selected_date.month).map do |date| 25 calendar = Event.date_range(selected_date.year, selected_date.month).map do |date|
25 [ 26 [
26 # the day itself 27 # the day itself
27 date, 28 date,
28 # is there any events in this date? 29 # is there any events in this date?
29 - events.select {|event| event.display_to?(user)}.any? do |event|  
30 - event.date_range.include?(date)  
31 - end, 30 + events.any? {|event| event.date_range.include?(date)},
32 # is this date in the current month? 31 # is this date in the current month?
33 true 32 true
34 ] 33 ]
app/helpers/profile_editor_helper.rb
@@ -104,8 +104,8 @@ module ProfileEditorHelper @@ -104,8 +104,8 @@ module ProfileEditorHelper
104 @country_helper ||= CountriesHelper.instance 104 @country_helper ||= CountriesHelper.instance
105 end 105 end
106 106
107 - def select_country(title, object, method, options)  
108 - labelled_form_field(title, select(object, method, [[_('[Select ...]'), nil]] + country_helper.countries, {}, options)) 107 + def select_country(title, object, method, html_options = {}, options = {})
  108 + labelled_form_field(title, select(object, method, [[_('[Select ...]'), nil]] + country_helper.countries, options, html_options))
109 end 109 end
110 110
111 def select_schooling(object, method, options) 111 def select_schooling(object, method, options)
app/helpers/sweeper_helper.rb
@@ -22,7 +22,7 @@ module SweeperHelper @@ -22,7 +22,7 @@ module SweeperHelper
22 22
23 # friends blocks 23 # friends blocks
24 blocks = profile.blocks.select{|b| b.kind_of?(FriendsBlock)} 24 blocks = profile.blocks.select{|b| b.kind_of?(FriendsBlock)}
25 - blocks.map(&:cache_keys).each{|ck|expire_timeout_fragment(ck)} 25 + blocks.map(&:cache_key).each{|ck|expire_timeout_fragment(ck)}
26 end 26 end
27 27
28 def expire_communities(profile) 28 def expire_communities(profile)
@@ -34,13 +34,13 @@ module SweeperHelper @@ -34,13 +34,13 @@ module SweeperHelper
34 34
35 # communities block 35 # communities block
36 blocks = profile.blocks.select{|b| b.kind_of?(CommunitiesBlock)} 36 blocks = profile.blocks.select{|b| b.kind_of?(CommunitiesBlock)}
37 - blocks.map(&:cache_keys).each{|ck|expire_timeout_fragment(ck)} 37 + blocks.map(&:cache_key).each{|ck|expire_timeout_fragment(ck)}
38 end 38 end
39 39
40 def expire_enterprises(profile) 40 def expire_enterprises(profile)
41 # enterprises and favorite enterprises blocks 41 # enterprises and favorite enterprises blocks
42 blocks = profile.blocks.select {|b| [EnterprisesBlock, FavoriteEnterprisesBlock].any?{|klass| b.kind_of?(klass)} } 42 blocks = profile.blocks.select {|b| [EnterprisesBlock, FavoriteEnterprisesBlock].any?{|klass| b.kind_of?(klass)} }
43 - blocks.map(&:cache_keys).each{|ck|expire_timeout_fragment(ck)} 43 + blocks.map(&:cache_key).each{|ck|expire_timeout_fragment(ck)}
44 end 44 end
45 45
46 def expire_profile_index(profile) 46 def expire_profile_index(profile)
app/helpers/tags_helper.rb
@@ -28,7 +28,6 @@ module TagsHelper @@ -28,7 +28,6 @@ module TagsHelper
28 # courtesy of Aurelio: http://www.colivre.coop.br/Aurium/Nuvem 28 # courtesy of Aurelio: http://www.colivre.coop.br/Aurium/Nuvem
29 # (pt_BR only). 29 # (pt_BR only).
30 def tag_cloud(tags, tagname_option, url, options = {}) 30 def tag_cloud(tags, tagname_option, url, options = {})
31 -  
32 31
33 return content_tag('em', _('No tags yet.')) + 32 return content_tag('em', _('No tags yet.')) +
34 ' <a href="' + _('http://en.wikipedia.org/wiki/Tag_%28metadata%29') + 33 ' <a href="' + _('http://en.wikipedia.org/wiki/Tag_%28metadata%29') +
@@ -42,7 +41,7 @@ module TagsHelper @@ -42,7 +41,7 @@ module TagsHelper
42 max = tags.values.max.to_f 41 max = tags.values.max.to_f
43 min = tags.values.min.to_f 42 min = tags.values.min.to_f
44 43
45 - tags.map do |tag,count| 44 + tags.sort_by{ |k,v| k.downcase }.map do |tag,count|
46 if ( max == min ) 45 if ( max == min )
47 v = 0.5 46 v = 0.5
48 else 47 else
app/models/abuse_complaint.rb 0 → 100644
@@ -0,0 +1,75 @@ @@ -0,0 +1,75 @@
  1 +class AbuseComplaint < Task
  2 + has_many :abuse_reports, :dependent => :destroy
  3 + belongs_to :reported, :class_name => "Profile", :foreign_key => "requestor_id"
  4 +
  5 + validates_presence_of :reported
  6 + alias :requestor :reported
  7 +
  8 + def initialize(*args)
  9 + super
  10 + self.status = (args.first ? args.first[:status] : nil) || Task::Status::HIDDEN
  11 + end
  12 +
  13 + after_update do |abuse_complaint|
  14 + if abuse_complaint.reported.environment.reports_lower_bound < abuse_complaint.abuse_reports.count && abuse_complaint.status == Task::Status::HIDDEN
  15 + abuse_complaint.activate
  16 + end
  17 + end
  18 +
  19 + def target
  20 + reported.environment
  21 + end
  22 +
  23 + def environment
  24 + target
  25 + end
  26 +
  27 + def title
  28 + abuse_reports.count > 1 ? (_('Abuse complaint (%s)') % abuse_reports.count) :_('Abuse complaint')
  29 + end
  30 +
  31 + def linked_subject
  32 + {:text => reported.name, :url => reported.url}
  33 + end
  34 +
  35 + def information
  36 + {:message => _('%{linked_subject} was reported due to inappropriate behavior.')}
  37 + end
  38 +
  39 + def accept_details
  40 + true
  41 + end
  42 +
  43 + def reject_details
  44 + true
  45 + end
  46 +
  47 + def icon
  48 + {:type => :profile_image, :profile => reported, :url => reported.url}
  49 + end
  50 +
  51 + def default_decision
  52 + 'skip'
  53 + end
  54 +
  55 + def perform
  56 + reported.disable
  57 + end
  58 +
  59 + def task_activated_message
  60 + _('Your profile was reported by the users of %s due to inappropriate behavior. The administrators of the environment are now reviewing the report. To solve this misunderstanding, please contact the administrators.') % environment.name
  61 + end
  62 +
  63 + def task_finished_message
  64 + _('Your profile was disabled by the administrators of %s due to inappropriate behavior. To solve this misunderstanding please contact them.') % environment.name
  65 + end
  66 +
  67 + def target_notification_description
  68 + _('%s was reported due to inappropriate behavior.') % reported.name
  69 + end
  70 +
  71 + def target_notification_message
  72 + _('The users of %{environment} reported %{reported} due to inappropriate behavior. A task was created with all the reports including the reasons and contents reported by these users. Please verify the reports and decide whether this profile must be disabled or not.') % {:environment => environment.name, :reported => reported.name}
  73 + end
  74 +
  75 +end
app/models/abuse_report.rb 0 → 100644
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +class AbuseReport < ActiveRecord::Base
  2 +
  3 + belongs_to :reporter, :class_name => 'Person'
  4 + belongs_to :abuse_complaint
  5 + has_many :reported_images, :dependent => :destroy
  6 +
  7 + validates_presence_of :reporter, :abuse_complaint, :reason
  8 + validates_uniqueness_of :reporter_id, :scope => :abuse_complaint_id
  9 +
  10 + xss_terminate :sanitize => [:reason]
  11 +
  12 + after_create do |abuse_report|
  13 + abuse_report.abuse_complaint.save!
  14 + end
  15 +end
app/models/approve_article.rb
@@ -77,6 +77,10 @@ class ApproveArticle &lt; Task @@ -77,6 +77,10 @@ class ApproveArticle &lt; Task
77 true 77 true
78 end 78 end
79 79
  80 + def reject_details
  81 + true
  82 + end
  83 +
80 def default_decision 84 def default_decision
81 if article 85 if article
82 'skip' 86 'skip'
@@ -90,7 +94,11 @@ class ApproveArticle &lt; Task @@ -90,7 +94,11 @@ class ApproveArticle &lt; Task
90 end 94 end
91 95
92 def target_notification_description 96 def target_notification_description
93 - _('%{requestor} wants to publish the article: %{article}.') % {:requestor => requestor.name, :article => article.name} 97 + if article
  98 + _('%{requestor} wants to publish the article: %{article}.') % {:requestor => requestor.name, :article => article.name}
  99 + else
  100 + _('%{requestor} wanted to publish an article but it was removed.') % {:requestor => requestor.name}
  101 + end
94 end 102 end
95 103
96 def target_notification_message 104 def target_notification_message
@@ -107,4 +115,11 @@ class ApproveArticle &lt; Task @@ -107,4 +115,11 @@ class ApproveArticle &lt; Task
107 end 115 end
108 end 116 end
109 117
  118 + def task_cancelled_message
  119 + message = _('Your request for publishing the article "{article}" was rejected.')
  120 + if !reject_explanation.blank?
  121 + message += " " + _("Here is the reject explanation left by the administrator who rejected your article: \n\n%{reject_explanation}") % {:reject_explanation => reject_explanation}
  122 + end
  123 + end
  124 +
110 end 125 end
app/models/article.rb
@@ -188,6 +188,14 @@ class Article &lt; ActiveRecord::Base @@ -188,6 +188,14 @@ class Article &lt; ActiveRecord::Base
188 body || '' 188 body || ''
189 end 189 end
190 190
  191 + include ApplicationHelper
  192 + def reported_version(options = {})
  193 + article = self
  194 + search_path = File.join(Rails.root, 'app', 'views', 'shared', 'reported_versions')
  195 + partial_path = File.join('shared', 'reported_versions', partial_for_class_in_view_path(article.class, search_path))
  196 + lambda { render_to_string(:partial => partial_path, :locals => {:article => article}) }
  197 + end
  198 +
191 # returns the data of the article. Must be overriden in each subclass to 199 # returns the data of the article. Must be overriden in each subclass to
192 # provide the correct content for the article. 200 # provide the correct content for the article.
193 def data 201 def data
@@ -265,6 +273,10 @@ class Article &lt; ActiveRecord::Base @@ -265,6 +273,10 @@ class Article &lt; ActiveRecord::Base
265 false 273 false
266 end 274 end
267 275
  276 + def uploaded_file?
  277 + false
  278 + end
  279 +
268 def has_posts? 280 def has_posts?
269 false 281 false
270 end 282 end
@@ -343,11 +355,20 @@ class Article &lt; ActiveRecord::Base @@ -343,11 +355,20 @@ class Article &lt; ActiveRecord::Base
343 ['Folder', 'Blog', 'Forum', 'Gallery'] 355 ['Folder', 'Blog', 'Forum', 'Gallery']
344 end 356 end
345 357
  358 + def self.text_article_types
  359 + ['TextArticle', 'TextileArticle', 'TinyMceArticle']
  360 + end
  361 +
346 named_scope :published, :conditions => { :published => true } 362 named_scope :published, :conditions => { :published => true }
347 named_scope :folders, :conditions => { :type => folder_types} 363 named_scope :folders, :conditions => { :type => folder_types}
348 named_scope :no_folders, :conditions => ['type NOT IN (?)', folder_types] 364 named_scope :no_folders, :conditions => ['type NOT IN (?)', folder_types]
349 named_scope :galleries, :conditions => { :type => 'Gallery' } 365 named_scope :galleries, :conditions => { :type => 'Gallery' }
350 named_scope :images, :conditions => { :is_image => true } 366 named_scope :images, :conditions => { :is_image => true }
  367 + named_scope :text_articles, :conditions => [ 'articles.type IN (?)', text_article_types ]
  368 +
  369 + named_scope :more_comments, :order => "comments_count DESC"
  370 + named_scope :more_views, :order => "hits DESC"
  371 + named_scope :more_recent, :order => "created_at DESC"
351 372
352 def self.display_filter(user, profile) 373 def self.display_filter(user, profile)
353 return {:conditions => ['published = ?', true]} if !user 374 return {:conditions => ['published = ?', true]} if !user
@@ -509,6 +530,35 @@ class Article &lt; ActiveRecord::Base @@ -509,6 +530,35 @@ class Article &lt; ActiveRecord::Base
509 self.parent && self.parent.accept_uploads? 530 self.parent && self.parent.accept_uploads?
510 end 531 end
511 532
  533 + def body_images_paths
  534 + require 'uri'
  535 + Hpricot(self.body.to_s).search('img[@src]').collect do |i|
  536 + (self.profile && self.profile.environment) ? URI.join(self.profile.environment.top_url, URI.escape(i.attributes['src'])).to_s : i.attributes['src']
  537 + end
  538 + end
  539 +
  540 + def more_comments_label
  541 + amount = self.comments_count
  542 + {
  543 + 0 => _('no comments'),
  544 + 1 => _('one comment')
  545 + }[amount] || _("%s comments") % amount
  546 +
  547 + end
  548 +
  549 + def more_views_label
  550 + amount = self.hits
  551 + {
  552 + 0 => _('no views'),
  553 + 1 => _('one view')
  554 + }[amount] || _("%s views") % amount
  555 +
  556 + end
  557 +
  558 + def more_recent_label
  559 + _('Created at: ')
  560 + end
  561 +
512 private 562 private
513 563
514 def sanitize_tag_list 564 def sanitize_tag_list
app/models/block.rb
@@ -34,6 +34,12 @@ class Block &lt; ActiveRecord::Base @@ -34,6 +34,12 @@ class Block &lt; ActiveRecord::Base
34 else 34 else
35 return context[:request_path] == '/' 35 return context[:request_path] == '/'
36 end 36 end
  37 + elsif display == 'except_home_page'
  38 + if context[:article]
  39 + return context[:article] != owner.home_page
  40 + else
  41 + return context[:request_path] != '/' + owner.identifier
  42 + end
37 end 43 end
38 end 44 end
39 true 45 true
@@ -45,6 +51,8 @@ class Block &lt; ActiveRecord::Base @@ -45,6 +51,8 @@ class Block &lt; ActiveRecord::Base
45 # * <tt>'never'</tt>: the block is hidden (it does not appear for visitors) 51 # * <tt>'never'</tt>: the block is hidden (it does not appear for visitors)
46 # * <tt>'home_page_only'</tt> the block is displayed only when viewing the 52 # * <tt>'home_page_only'</tt> the block is displayed only when viewing the
47 # homepage of its owner. 53 # homepage of its owner.
  54 + # * <tt>'except_home_page'</tt> the block is displayed only when viewing
  55 + # the homepage of its owner.
48 settings_items :display, :type => :string, :default => 'always' 56 settings_items :display, :type => :string, :default => 'always'
49 57
50 # The block can be configured to be displayed in all languages or in just one language. It can assume any locale of the environment: 58 # The block can be configured to be displayed in all languages or in just one language. It can assume any locale of the environment:
@@ -119,10 +127,6 @@ class Block &lt; ActiveRecord::Base @@ -119,10 +127,6 @@ class Block &lt; ActiveRecord::Base
119 true 127 true
120 end 128 end
121 129
122 - def cache_keys  
123 - "block-id-#{id}"  
124 - end  
125 -  
126 def timeout 130 def timeout
127 4.hours 131 4.hours
128 end 132 end
app/models/blog.rb
@@ -72,4 +72,8 @@ class Blog &lt; Folder @@ -72,4 +72,8 @@ class Blog &lt; Folder
72 72
73 alias :display_posts_in_current_language? :display_posts_in_current_language 73 alias :display_posts_in_current_language? :display_posts_in_current_language
74 74
  75 + def empty?
  76 + posts.empty?
  77 + end
  78 +
75 end 79 end
app/models/comment.rb
@@ -2,7 +2,7 @@ class Comment &lt; ActiveRecord::Base @@ -2,7 +2,7 @@ class Comment &lt; ActiveRecord::Base
2 2
3 track_actions :leave_comment, :after_create, :keep_params => ["article.title", "article.url", "title", "url", "body"], :custom_target => :action_tracker_target 3 track_actions :leave_comment, :after_create, :keep_params => ["article.title", "article.url", "title", "url", "body"], :custom_target => :action_tracker_target
4 4
5 - validates_presence_of :title, :body 5 + validates_presence_of :body
6 belongs_to :article, :counter_cache => true 6 belongs_to :article, :counter_cache => true
7 belongs_to :author, :class_name => 'Person', :foreign_key => 'author_id' 7 belongs_to :author, :class_name => 'Person', :foreign_key => 'author_id'
8 has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy 8 has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy
@@ -98,6 +98,16 @@ class Comment &lt; ActiveRecord::Base @@ -98,6 +98,16 @@ class Comment &lt; ActiveRecord::Base
98 root 98 root
99 end 99 end
100 100
  101 + include ApplicationHelper
  102 + def reported_version(options = {})
  103 + comment = self
  104 + lambda { render_to_string(:partial => 'shared/reported_versions/comment', :locals => {:comment => comment}) }
  105 + end
  106 +
  107 + def to_html(option={})
  108 + body || ''
  109 + end
  110 +
101 class Notifier < ActionMailer::Base 111 class Notifier < ActionMailer::Base
102 def mail(comment) 112 def mail(comment)
103 profile = comment.article.profile 113 profile = comment.article.profile
app/models/community.rb
@@ -75,4 +75,8 @@ class Community &lt; Organization @@ -75,4 +75,8 @@ class Community &lt; Organization
75 end 75 end
76 end 76 end
77 77
  78 + def control_panel_settings_button
  79 + {:title => __('Community Info and settings'), :icon => 'edit-profile-group'}
  80 + end
  81 +
78 end 82 end
app/models/contact.rb
@@ -23,23 +23,26 @@ class Contact &lt; ActiveRecord::Base #WithoutTable @@ -23,23 +23,26 @@ class Contact &lt; ActiveRecord::Base #WithoutTable
23 23
24 class Sender < ActionMailer::Base 24 class Sender < ActionMailer::Base
25 def mail(contact) 25 def mail(contact)
  26 + content_type 'text/html'
26 emails = contact.dest.notification_emails 27 emails = contact.dest.notification_emails
27 recipients emails 28 recipients emails
28 - from "#{contact.name} <#{contact.email}>" 29 + from "#{contact.name} <#{contact.dest.environment.contact_email}>"
  30 + reply_to contact.email
29 if contact.sender 31 if contact.sender
30 headers 'X-Noosfero-Sender' => contact.sender.identifier 32 headers 'X-Noosfero-Sender' => contact.sender.identifier
31 end 33 end
32 if contact.receive_a_copy 34 if contact.receive_a_copy
33 cc "#{contact.name} <#{contact.email}>" 35 cc "#{contact.name} <#{contact.email}>"
34 end 36 end
35 - subject contact.subject 37 + subject "[#{contact.dest.short_name(30)}] " + contact.subject
36 body :name => contact.name, 38 body :name => contact.name,
37 :email => contact.email, 39 :email => contact.email,
38 :city => contact.city, 40 :city => contact.city,
39 :state => contact.state, 41 :state => contact.state,
40 :message => contact.message, 42 :message => contact.message,
41 :environment => contact.dest.environment.name, 43 :environment => contact.dest.environment.name,
42 - :url => url_for(:host => contact.dest.environment.default_hostname, :controller => 'home') 44 + :url => url_for(:host => contact.dest.environment.default_hostname, :controller => 'home'),
  45 + :target => contact.dest.name
43 end 46 end
44 end 47 end
45 48
app/models/domain.rb
@@ -10,7 +10,7 @@ class Domain &lt; ActiveRecord::Base @@ -10,7 +10,7 @@ class Domain &lt; ActiveRecord::Base
10 10
11 # <tt>name</tt> must be a sequence of word characters (a to z, plus 0 to 9, 11 # <tt>name</tt> must be a sequence of word characters (a to z, plus 0 to 9,
12 # plus '_'). Letters must be lowercase 12 # plus '_'). Letters must be lowercase
13 - validates_format_of :name, :with => /^([a-z0-9_]+\.)+[a-z0-9_]+$/, :message => N_('%{fn} must be composed only of lowercase latters (a to z), numbers (0 to 9) and "_"') 13 + validates_format_of :name, :with => /^([a-z0-9_-]+\.)+[a-z0-9_-]+$/, :message => N_('%{fn} must be composed only of lowercase latters (a to z), numbers (0 to 9), "_" and "-"')
14 14
15 # checks validations that could not be expressed using Rails' predefined 15 # checks validations that could not be expressed using Rails' predefined
16 # validations. In particular: 16 # validations. In particular:
app/models/enterprise.rb
@@ -7,6 +7,8 @@ class Enterprise &lt; Organization @@ -7,6 +7,8 @@ class Enterprise &lt; Organization
7 has_many :products, :dependent => :destroy, :order => 'name ASC' 7 has_many :products, :dependent => :destroy, :order => 'name ASC'
8 has_many :inputs, :through => :products 8 has_many :inputs, :through => :products
9 9
  10 + has_and_belongs_to_many :fans, :class_name => 'Person', :join_table => 'favorite_enteprises_people'
  11 +
10 extra_data_for_index :product_categories 12 extra_data_for_index :product_categories
11 13
12 N_('Organization website'); N_('Historic and current context'); N_('Activities short description'); N_('City'); N_('State'); N_('Country'); N_('ZIP code') 14 N_('Organization website'); N_('Historic and current context'); N_('Activities short description'); N_('City'); N_('State'); N_('Country'); N_('ZIP code')
@@ -145,6 +147,7 @@ class Enterprise &lt; Organization @@ -145,6 +147,7 @@ class Enterprise &lt; Organization
145 end 147 end
146 148
147 before_create do |enterprise| 149 before_create do |enterprise|
  150 + enterprise.validated = enterprise.environment.enabled?('enterprises_are_validated_when_created')
148 if enterprise.environment.enabled?('enterprises_are_disabled_when_created') 151 if enterprise.environment.enabled?('enterprises_are_disabled_when_created')
149 enterprise.enabled = false 152 enterprise.enabled = false
150 end 153 end
@@ -165,4 +168,12 @@ class Enterprise &lt; Organization @@ -165,4 +168,12 @@ class Enterprise &lt; Organization
165 enable_contact_us 168 enable_contact_us
166 end 169 end
167 170
  171 + def control_panel_settings_button
  172 + {:title => __('Enterprise Info and settings'), :icon => 'edit-profile-enterprise'}
  173 + end
  174 +
  175 + def create_product?
  176 + true
  177 + end
  178 +
168 end 179 end
app/models/environment.rb
@@ -9,6 +9,13 @@ class Environment &lt; ActiveRecord::Base @@ -9,6 +9,13 @@ class Environment &lt; ActiveRecord::Base
9 9
10 has_many :tasks, :dependent => :destroy, :as => 'target' 10 has_many :tasks, :dependent => :destroy, :as => 'target'
11 11
  12 + IDENTIFY_SCRIPTS = /(php[0-9s]?|[sp]htm[l]?|pl|py|cgi|rb)/
  13 +
  14 + def self.verify_filename(filename)
  15 + filename += '.txt' if File.extname(filename) =~ IDENTIFY_SCRIPTS
  16 + filename
  17 + end
  18 +
12 PERMISSIONS['Environment'] = { 19 PERMISSIONS['Environment'] = {
13 'view_environment_admin_panel' => N_('View environment admin panel'), 20 'view_environment_admin_panel' => N_('View environment admin panel'),
14 'edit_environment_features' => N_('Edit environment features'), 21 'edit_environment_features' => N_('Edit environment features'),
@@ -67,6 +74,10 @@ class Environment &lt; ActiveRecord::Base @@ -67,6 +74,10 @@ class Environment &lt; ActiveRecord::Base
67 self.affiliate(user, Environment::Roles.admin(self.id)) 74 self.affiliate(user, Environment::Roles.admin(self.id))
68 end 75 end
69 76
  77 + def remove_admin(user)
  78 + self.disaffiliate(user, Environment::Roles.admin(self.id))
  79 + end
  80 +
70 def admins 81 def admins
71 Person.members_of(self).all(:conditions => ['role_assignments.role_id = ?', Environment::Roles.admin(self).id]) 82 Person.members_of(self).all(:conditions => ['role_assignments.role_id = ?', Environment::Roles.admin(self).id])
72 end 83 end
@@ -106,6 +117,7 @@ class Environment &lt; ActiveRecord::Base @@ -106,6 +117,7 @@ class Environment &lt; ActiveRecord::Base
106 'enable_organization_url_change' => _("Allow organizations to change their URL"), 117 'enable_organization_url_change' => _("Allow organizations to change their URL"),
107 'admin_must_approve_new_communities' => _("Admin must approve creation of communities"), 118 'admin_must_approve_new_communities' => _("Admin must approve creation of communities"),
108 'enterprises_are_disabled_when_created' => __('Enterprises are disabled when created'), 119 'enterprises_are_disabled_when_created' => __('Enterprises are disabled when created'),
  120 + 'enterprises_are_validated_when_created' => __('Enterprises are validated when created'),
109 'show_balloon_with_profile_links_when_clicked' => _('Show a balloon with profile links when a profile image is clicked'), 121 'show_balloon_with_profile_links_when_clicked' => _('Show a balloon with profile links when a profile image is clicked'),
110 'xmpp_chat' => _('XMPP/Jabber based chat'), 122 'xmpp_chat' => _('XMPP/Jabber based chat'),
111 'show_zoom_button_on_article_images' => _('Show a zoom link on all article images') 123 'show_zoom_button_on_article_images' => _('Show a zoom link on all article images')
@@ -218,7 +230,19 @@ class Environment &lt; ActiveRecord::Base @@ -218,7 +230,19 @@ class Environment &lt; ActiveRecord::Base
218 settings_items :currency_separator, :type => String, :default => '.' 230 settings_items :currency_separator, :type => String, :default => '.'
219 settings_items :currency_delimiter, :type => String, :default => ',' 231 settings_items :currency_delimiter, :type => String, :default => ','
220 232
221 - settings_items :trusted_sites_for_iframe, :type => Array, :default => ['itheora.org', 'tv.softwarelivre.org', 'stream.softwarelivre.org'] 233 + settings_items :trusted_sites_for_iframe, :type => Array, :default => %w[
  234 + developer.myspace.com
  235 + itheora.org
  236 + maps.google.com
  237 + platform.twitter.com
  238 + player.vimeo.com
  239 + stream.softwarelivre.org
  240 + tv.softwarelivre.org
  241 + www.facebook.com
  242 + www.flickr.com
  243 + www.gmodules.com
  244 + www.youtube.com
  245 + ] + ('a' .. 'z').map{|i| "#{i}.yimg.com"}
222 246
223 settings_items :enabled_plugins, :type => Array, :default => [] 247 settings_items :enabled_plugins, :type => Array, :default => []
224 248
@@ -228,17 +252,28 @@ class Environment &lt; ActiveRecord::Base @@ -228,17 +252,28 @@ class Environment &lt; ActiveRecord::Base
228 252
229 # Enables a feature identified by its name 253 # Enables a feature identified by its name
230 def enable(feature) 254 def enable(feature)
231 - self.settings["#{feature}_enabled"] = true 255 + self.settings["#{feature}_enabled".to_sym] = true
  256 + end
  257 +
  258 + def enable_plugin(plugin)
  259 + self.enabled_plugins += [plugin]
  260 + self.enabled_plugins.uniq!
  261 + self.save!
232 end 262 end
233 263
234 # Disables a feature identified by its name 264 # Disables a feature identified by its name
235 def disable(feature) 265 def disable(feature)
236 - self.settings["#{feature}_enabled"] = false 266 + self.settings["#{feature}_enabled".to_sym] = false
  267 + end
  268 +
  269 + def disable_plugin(plugin)
  270 + self.enabled_plugins.delete(plugin)
  271 + self.save!
237 end 272 end
238 273
239 # Tells if a feature, identified by its name, is enabled 274 # Tells if a feature, identified by its name, is enabled
240 def enabled?(feature) 275 def enabled?(feature)
241 - self.settings["#{feature}_enabled"] == true 276 + self.settings["#{feature}_enabled".to_sym] == true
242 end 277 end
243 278
244 # enables the features identified by <tt>features</tt>, which is expected to 279 # enables the features identified by <tt>features</tt>, which is expected to
@@ -494,6 +529,7 @@ class Environment &lt; ActiveRecord::Base @@ -494,6 +529,7 @@ class Environment &lt; ActiveRecord::Base
494 xss_terminate :only => [ :message_for_disabled_enterprise ], :with => 'white_list', :on => 'validation' 529 xss_terminate :only => [ :message_for_disabled_enterprise ], :with => 'white_list', :on => 'validation'
495 530
496 validates_presence_of :theme 531 validates_presence_of :theme
  532 + validates_numericality_of :reports_lower_bound, :allow_nil => false, :only_integer => true, :greater_than_or_equal_to => 0
497 533
498 include WhiteListFilter 534 include WhiteListFilter
499 filter_iframes :message_for_disabled_enterprise, :whitelist => lambda { trusted_sites_for_iframe } 535 filter_iframes :message_for_disabled_enterprise, :whitelist => lambda { trusted_sites_for_iframe }
@@ -517,12 +553,12 @@ class Environment &lt; ActiveRecord::Base @@ -517,12 +553,12 @@ class Environment &lt; ActiveRecord::Base
517 # If #force_www is true, adds 'www.' at the beginning of the hostname. If the 553 # If #force_www is true, adds 'www.' at the beginning of the hostname. If the
518 # environment has not associated domains, returns 'localhost'. 554 # environment has not associated domains, returns 'localhost'.
519 def default_hostname(email_hostname = false) 555 def default_hostname(email_hostname = false)
520 - if self.domains(true).empty?  
521 - 'localhost'  
522 - else 556 + domain = 'localhost'
  557 + unless self.domains(true).empty?
523 domain = (self.domains.find_by_is_default(true) || self.domains.find(:first, :order => 'id')).name 558 domain = (self.domains.find_by_is_default(true) || self.domains.find(:first, :order => 'id')).name
524 - email_hostname ? domain : (force_www ? ('www.' + domain) : domain) 559 + domain = email_hostname ? domain : (force_www ? ('www.' + domain) : domain)
525 end 560 end
  561 + domain
526 end 562 end
527 563
528 def top_url 564 def top_url
@@ -671,13 +707,14 @@ class Environment &lt; ActiveRecord::Base @@ -671,13 +707,14 @@ class Environment &lt; ActiveRecord::Base
671 def create_templates 707 def create_templates
672 pre = self.name.to_slug + '_' 708 pre = self.name.to_slug + '_'
673 ent_id = Enterprise.create!(:name => 'Enterprise template', :identifier => pre + 'enterprise_template', :environment => self, :visible => false).id 709 ent_id = Enterprise.create!(:name => 'Enterprise template', :identifier => pre + 'enterprise_template', :environment => self, :visible => false).id
  710 + inactive_enterprise_tmpl = Enterprise.create!(:name => 'Inactive Enterprise template', :identifier => pre + 'inactive_enterprise_template', :environment => self, :visible => false)
674 com_id = Community.create!(:name => 'Community template', :identifier => pre + 'community_template', :environment => self, :visible => false).id 711 com_id = Community.create!(:name => 'Community template', :identifier => pre + 'community_template', :environment => self, :visible => false).id
675 pass = Digest::MD5.hexdigest rand.to_s 712 pass = Digest::MD5.hexdigest rand.to_s
676 user = User.create!(:login => (pre + 'person_template'), :email => (pre + 'template@template.noo'), :password => pass, :password_confirmation => pass, :environment => self).person 713 user = User.create!(:login => (pre + 'person_template'), :email => (pre + 'template@template.noo'), :password => pass, :password_confirmation => pass, :environment => self).person
677 - user.visible = false  
678 - user.save! 714 + user.update_attributes(:visible => false, :name => "Person template")
679 usr_id = user.id 715 usr_id = user.id
680 self.settings[:enterprise_template_id] = ent_id 716 self.settings[:enterprise_template_id] = ent_id
  717 + self.inactive_enterprise_template = inactive_enterprise_tmpl
681 self.settings[:community_template_id] = com_id 718 self.settings[:community_template_id] = com_id
682 self.settings[:person_template_id] = usr_id 719 self.settings[:person_template_id] = usr_id
683 self.save! 720 self.save!
@@ -685,7 +722,7 @@ class Environment &lt; ActiveRecord::Base @@ -685,7 +722,7 @@ class Environment &lt; ActiveRecord::Base
685 722
686 after_destroy :destroy_templates 723 after_destroy :destroy_templates
687 def destroy_templates 724 def destroy_templates
688 - [enterprise_template, community_template, person_template].compact.each do |template| 725 + [enterprise_template, inactive_enterprise_template, community_template, person_template].compact.each do |template|
689 template.destroy 726 template.destroy
690 end 727 end
691 end 728 end
@@ -701,6 +738,4 @@ class Environment &lt; ActiveRecord::Base @@ -701,6 +738,4 @@ class Environment &lt; ActiveRecord::Base
701 def image_galleries 738 def image_galleries
702 portal_community ? portal_community.image_galleries : [] 739 portal_community ? portal_community.image_galleries : []
703 end 740 end
704 -  
705 end 741 end
706 -  
app/models/fans_block.rb 0 → 100644
@@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
  1 +class FansBlock < ProfileListBlock
  2 +
  3 + def self.description
  4 + _('Displays the people who like the enterprise')
  5 + end
  6 +
  7 + def default_title
  8 + n__('{#} fan', '{#} fans', profile_count)
  9 + end
  10 +
  11 + def help
  12 + _('This block presents the fans of an enterprise.')
  13 + end
  14 +
  15 + def footer
  16 + profile = self.owner
  17 + lambda do
  18 + link_to _('View all'), :profile => profile.identifier, :controller =>
  19 + 'profile', :action => 'fans'
  20 + end
  21 + end
  22 +
  23 + def profiles
  24 + owner.fans
  25 + end
  26 +
  27 + def profile_count
  28 + profiles.visible.count
  29 + end
  30 +
  31 +end
app/models/folder.rb
@@ -29,7 +29,7 @@ class Folder &lt; Article @@ -29,7 +29,7 @@ class Folder &lt; Article
29 def to_html(options = {}) 29 def to_html(options = {})
30 folder = self 30 folder = self
31 lambda do 31 lambda do
32 - render :file => 'content_viewer/folder', :locals => { :folder => folder } 32 + render :file => 'content_viewer/folder', :locals => {:folder => folder}
33 end 33 end
34 end 34 end
35 35
app/models/image.rb
1 class Image < ActiveRecord::Base 1 class Image < ActiveRecord::Base
2 - belongs_to :owner, :polymorphic => true  
3 2
4 def self.max_size 3 def self.max_size
5 Image.attachment_options[:max_size] 4 Image.attachment_options[:max_size]
6 end 5 end
7 6
  7 + sanitize_filename
  8 +
8 has_attachment :content_type => :image, 9 has_attachment :content_type => :image,
9 :storage => :file_system, 10 :storage => :file_system,
10 :path_prefix => 'public/image_uploads', 11 :path_prefix => 'public/image_uploads',
@@ -20,4 +21,6 @@ class Image &lt; ActiveRecord::Base @@ -20,4 +21,6 @@ class Image &lt; ActiveRecord::Base
20 21
21 delay_attachment_fu_thumbnails 22 delay_attachment_fu_thumbnails
22 23
  24 + postgresql_attachment_fu
  25 +
23 end 26 end
app/models/invitation.rb
@@ -27,6 +27,10 @@ class Invitation &lt; Task @@ -27,6 +27,10 @@ class Invitation &lt; Task
27 TaskMailer.deliver_invitation_notification(task) unless task.friend 27 TaskMailer.deliver_invitation_notification(task) unless task.friend
28 end 28 end
29 29
  30 + def title
  31 + _('Invitation')
  32 + end
  33 +
30 def validate 34 def validate
31 super 35 super
32 email = friend ? friend.user.email : friend_email 36 email = friend ? friend.user.email : friend_email
app/models/invite_friend.rb
@@ -8,7 +8,7 @@ class InviteFriend &lt; Invitation @@ -8,7 +8,7 @@ class InviteFriend &lt; Invitation
8 end 8 end
9 9
10 def title 10 def title
11 - _("New friend") 11 + _("Friend invitation")
12 end 12 end
13 13
14 def information 14 def information
app/models/link_list_block.rb
@@ -57,7 +57,7 @@ class LinkListBlock &lt; Block @@ -57,7 +57,7 @@ class LinkListBlock &lt; Block
57 def link_html(link) 57 def link_html(link)
58 klass = 'icon-' + link[:icon] if link[:icon] 58 klass = 'icon-' + link[:icon] if link[:icon]
59 sanitize_link( 59 sanitize_link(
60 - link_to(_(link[:name]), expand_address(link[:address]), :class => klass) 60 + link_to(link[:name], expand_address(link[:address]), :class => klass)
61 ) 61 )
62 end 62 end
63 63
app/models/organization.rb
@@ -95,12 +95,12 @@ class Organization &lt; Profile @@ -95,12 +95,12 @@ class Organization &lt; Profile
95 [] 95 []
96 end 96 end
97 97
98 - N_('Display name'); N_('Description'); N_('Contact person'); N_('Contact email'); N_('Acronym'); N_('Foundation year'); N_('Legal form'); N_('Economic activity'); N_('Management information'); N_('Validated'); N_('Tag list')  
99 - settings_items :display_name, :description, :contact_person, :contact_email, :acronym, :foundation_year, :legal_form, :economic_activity, :management_information, :validated, :cnpj 98 + N_('Display name'); N_('Description'); N_('Contact person'); N_('Contact email'); N_('Acronym'); N_('Foundation year'); N_('Legal form'); N_('Economic activity'); N_('Management information'); N_('Tag list')
  99 + settings_items :display_name, :description, :contact_person, :contact_email, :acronym, :foundation_year, :legal_form, :economic_activity, :management_information
100 100
101 validates_format_of :foundation_year, :with => Noosfero::Constants::INTEGER_FORMAT 101 validates_format_of :foundation_year, :with => Noosfero::Constants::INTEGER_FORMAT
102 -  
103 validates_format_of :contact_email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda { |org| !org.contact_email.blank? }) 102 validates_format_of :contact_email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda { |org| !org.contact_email.blank? })
  103 + validates_as_cnpj :cnpj
104 104
105 xss_terminate :only => [ :acronym, :contact_person, :contact_email, :legal_form, :economic_activity, :management_information ], :on => 'validation' 105 xss_terminate :only => [ :acronym, :contact_person, :contact_email, :legal_form, :economic_activity, :management_information ], :on => 'validation'
106 106
@@ -149,4 +149,12 @@ class Organization &lt; Profile @@ -149,4 +149,12 @@ class Organization &lt; Profile
149 false 149 false
150 end 150 end
151 151
  152 + def members_to_json
  153 + members.map { |member| {:id => member.id, :name => member.name} }.to_json
  154 + end
  155 +
  156 + def members_by_role_to_json(role)
  157 + members_by_role(role).map { |member| {:id => member.id, :name => member.name} }.to_json
  158 + end
  159 +
152 end 160 end
app/models/person.rb
@@ -17,6 +17,8 @@ class Person &lt; Profile @@ -17,6 +17,8 @@ class Person &lt; Profile
17 17
18 has_many :requested_tasks, :class_name => 'Task', :foreign_key => :requestor_id, :dependent => :destroy 18 has_many :requested_tasks, :class_name => 'Task', :foreign_key => :requestor_id, :dependent => :destroy
19 19
  20 + has_many :abuse_reports, :foreign_key => 'reporter_id', :dependent => :destroy
  21 +
20 has_many :mailings 22 has_many :mailings
21 23
22 has_many :scraps_sent, :class_name => 'Scrap', :foreign_key => :sender_id, :dependent => :destroy 24 has_many :scraps_sent, :class_name => 'Scrap', :foreign_key => :sender_id, :dependent => :destroy
@@ -116,6 +118,8 @@ class Person &lt; Profile @@ -116,6 +118,8 @@ class Person &lt; Profile
116 description 118 description
117 ] 119 ]
118 120
  121 + validates_multiparameter_assignments
  122 +
119 def self.fields 123 def self.fields
120 FIELDS 124 FIELDS
121 end 125 end
@@ -387,6 +391,21 @@ class Person &lt; Profile @@ -387,6 +391,21 @@ class Person &lt; Profile
387 leave_hash.to_json 391 leave_hash.to_json
388 end 392 end
389 393
  394 + def already_reported?(profile)
  395 + abuse_reports.any? { |report| report.abuse_complaint.reported == profile && report.abuse_complaint.opened? }
  396 + end
  397 +
  398 + def register_report(abuse_report, profile)
  399 + AbuseComplaint.create!(:reported => profile, :target => profile.environment) if !profile.opened_abuse_complaint
  400 + abuse_report.abuse_complaint = profile.opened_abuse_complaint
  401 + abuse_report.reporter = self
  402 + abuse_report.save!
  403 + end
  404 +
  405 + def control_panel_settings_button
  406 + {:title => _('Profile Info and settings'), :icon => 'edit-profile'}
  407 + end
  408 +
390 protected 409 protected
391 410
392 def followed_by?(profile) 411 def followed_by?(profile)
app/models/product.rb
@@ -66,7 +66,7 @@ class Product &lt; ActiveRecord::Base @@ -66,7 +66,7 @@ class Product &lt; ActiveRecord::Base
66 end 66 end
67 67
68 def default_image(size='thumb') 68 def default_image(size='thumb')
69 - '/images/icons-app/product-default-pic-%s.png' % size 69 + image ? image.public_filename(size) : '/images/icons-app/product-default-pic-%s.png' % size
70 end 70 end
71 71
72 def category_full_name 72 def category_full_name
@@ -149,4 +149,8 @@ class Product &lt; ActiveRecord::Base @@ -149,4 +149,8 @@ class Product &lt; ActiveRecord::Base
149 unit.blank? ? name : "#{name} - #{unit.name.downcase}" 149 unit.blank? ? name : "#{name} - #{unit.name.downcase}"
150 end 150 end
151 151
  152 + def display_supplier_on_search?
  153 + true
  154 + end
  155 +
152 end 156 end
app/models/products_block.rb
@@ -20,7 +20,15 @@ class ProductsBlock &lt; Block @@ -20,7 +20,15 @@ class ProductsBlock &lt; Block
20 block_title(title) + 20 block_title(title) +
21 content_tag( 21 content_tag(
22 'ul', 22 'ul',
23 - products.map {|product| content_tag('li', link_to(product.name, product.url, :style => 'background-image:url(%s)' % ( product.image ? product.image.public_filename(:minor) : product.default_image('minor'))), :class => 'product' )} 23 + products.map {|product|
  24 + content_tag('li',
  25 + link_to( product.name,
  26 + product.url,
  27 + :style => 'background-image:url(%s)' % product.default_image('minor')
  28 + ),
  29 + :class => 'product'
  30 + )
  31 + }
24 ) 32 )
25 end 33 end
26 34
app/models/profile.rb
@@ -52,8 +52,9 @@ class Profile &lt; ActiveRecord::Base @@ -52,8 +52,9 @@ class Profile &lt; ActiveRecord::Base
52 acts_as_accessible 52 acts_as_accessible
53 53
54 named_scope :memberships_of, lambda { |person| { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => ['role_assignments.accessor_type = ? AND role_assignments.accessor_id = ?', person.class.base_class.name, person.id ] } } 54 named_scope :memberships_of, lambda { |person| { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => ['role_assignments.accessor_type = ? AND role_assignments.accessor_id = ?', person.class.base_class.name, person.id ] } }
55 - named_scope :enterprises, :conditions => "profiles.type = 'Enterprise'"  
56 - named_scope :communities, :conditions => "profiles.type = 'Community'" 55 + #FIXME: these will work only if the subclass is already loaded
  56 + named_scope :enterprises, lambda { {:conditions => (Enterprise.send(:subclasses).map(&:name) << 'Enterprise').map { |klass| "profiles.type = '#{klass}'"}.join(" OR ")} }
  57 + named_scope :communities, lambda { {:conditions => (Community.send(:subclasses).map(&:name) << 'Community').map { |klass| "profiles.type = '#{klass}'"}.join(" OR ")} }
57 58
58 def members 59 def members
59 Person.members_of(self) 60 Person.members_of(self)
@@ -163,34 +164,19 @@ class Profile &lt; ActiveRecord::Base @@ -163,34 +164,19 @@ class Profile &lt; ActiveRecord::Base
163 164
164 has_many :events, :source => 'articles', :class_name => 'Event', :order => 'name' 165 has_many :events, :source => 'articles', :class_name => 'Event', :order => 'name'
165 166
166 - %w[ pending finished ].each do |status|  
167 - class_eval <<-CODE  
168 - def all_#{status}_tasks  
169 - env_tasks = []  
170 - if self.person?  
171 - env_tasks = Environment.find(:all).select{ |env| self.is_admin?(env) }.map{ |env| env.tasks.#{status} }.flatten  
172 - end  
173 - tasks.#{status} + env_tasks  
174 - end  
175 - CODE  
176 - end  
177 -  
178 def find_in_all_tasks(task_id) 167 def find_in_all_tasks(task_id)
179 - if tasks.exists?(task_id)  
180 - return tasks.find(task_id)  
181 - else  
182 - if self.person?  
183 - environments_admin = Environment.find(:all).select{ |env| self.is_admin?(env) }  
184 - task = environments_admin.select{ |env| env.tasks.exists?(task_id) }.map{ |i| i.tasks.find(task_id) }  
185 - return task.first unless task.empty?  
186 - end 168 + begin
  169 + Task.to(self).find(task_id)
  170 + rescue
  171 + nil
187 end 172 end
188 - return nil  
189 end 173 end
190 174
191 has_many :profile_categorizations, :conditions => [ 'categories_profiles.virtual = ?', false ] 175 has_many :profile_categorizations, :conditions => [ 'categories_profiles.virtual = ?', false ]
192 has_many :categories, :through => :profile_categorizations 176 has_many :categories, :through => :profile_categorizations
193 177
  178 + has_many :abuse_complaints, :foreign_key => 'requestor_id'
  179 +
194 def interests 180 def interests
195 categories.select {|item| !item.is_a?(Region)} 181 categories.select {|item| !item.is_a?(Region)}
196 end 182 end
@@ -564,9 +550,7 @@ private :generate_url, :url_options @@ -564,9 +550,7 @@ private :generate_url, :url_options
564 if self.closed? && members_count > 0 550 if self.closed? && members_count > 0
565 AddMember.create!(:person => person, :organization => self) unless self.already_request_membership?(person) 551 AddMember.create!(:person => person, :organization => self) unless self.already_request_membership?(person)
566 else 552 else
567 - if members_count == 0  
568 - self.affiliate(person, Profile::Roles.admin(environment.id))  
569 - end 553 + self.affiliate(person, Profile::Roles.admin(environment.id)) if members_count == 0
570 self.affiliate(person, Profile::Roles.member(environment.id)) 554 self.affiliate(person, Profile::Roles.member(environment.id))
571 end 555 end
572 else 556 else
@@ -809,6 +793,34 @@ private :generate_url, :url_options @@ -809,6 +793,34 @@ private :generate_url, :url_options
809 "#{jid(options)}/#{short_name}" 793 "#{jid(options)}/#{short_name}"
810 end 794 end
811 795
  796 + def is_on_homepage?(url, page=nil)
  797 + if page
  798 + page == self.home_page
  799 + else
  800 + url == '/' + self.identifier
  801 + end
  802 + end
  803 +
  804 + def opened_abuse_complaint
  805 + abuse_complaints.opened.first
  806 + end
  807 +
  808 + def disable
  809 + self.visible = false
  810 + user.password = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{identifier}--")
  811 + user.password_confirmation = user.password
  812 + save!
  813 + user.save!
  814 + end
  815 +
  816 + def control_panel_settings_button
  817 + {:title => _('Profile Info and settings'), :icon => 'edit-profile'}
  818 + end
  819 +
  820 + def self.identification
  821 + name
  822 + end
  823 +
812 protected 824 protected
813 825
814 def followed_by?(person) 826 def followed_by?(person)
app/models/profile_list_block.rb
1 class ProfileListBlock < Block 1 class ProfileListBlock < Block
2 2
3 settings_items :limit, :type => :integer, :default => 6 3 settings_items :limit, :type => :integer, :default => 6
4 - settings_items :prioritize_profiles_with_image, :type => :boolean, :default => false 4 + settings_items :prioritize_profiles_with_image, :type => :boolean, :default => true
5 5
6 def self.description 6 def self.description
7 _('Random profiles') 7 _('Random profiles')
@@ -13,21 +13,21 @@ class ProfileListBlock &lt; Block @@ -13,21 +13,21 @@ class ProfileListBlock &lt; Block
13 end 13 end
14 14
15 def profile_list 15 def profile_list
16 - profiles.visible.all(:limit => limit, :select => 'DISTINCT profiles.*, ' + image_prioritizer + randomizer, :joins => "LEFT OUTER JOIN images ON images.owner_id = profiles.id", :order => image_prioritizer + randomizer) 16 + result = nil
  17 + if !prioritize_profiles_with_image
  18 + result = profiles.visible.all(:limit => limit, :order => 'updated_at DESC').sort_by{ rand }
  19 + elsif profiles.visible.with_image.count >= limit
  20 + result = profiles.visible.with_image.all(:limit => limit * 5, :order => 'updated_at DESC').sort_by{ rand }
  21 + else
  22 + result = profiles.visible.with_image.sort_by{ rand } + profiles.visible.without_image.all(:limit => limit * 5, :order => 'updated_at DESC').sort_by{ rand }
  23 + end
  24 + result.slice(0..limit-1)
17 end 25 end
18 26
19 def profile_count 27 def profile_count
20 profiles.visible.count('DISTINCT(profiles.id)') 28 profiles.visible.count('DISTINCT(profiles.id)')
21 end 29 end
22 30
23 - def randomizer  
24 - @randomizer ||= "(profiles.id % #{rand(profile_count) + 1})"  
25 - end  
26 -  
27 - def image_prioritizer  
28 - prioritize_profiles_with_image ? '(images.id is null),' : ''  
29 - end  
30 -  
31 # the title of the block. Probably will be overriden in subclasses. 31 # the title of the block. Probably will be overriden in subclasses.
32 def default_title 32 def default_title
33 _('{#} People or Groups') 33 _('{#} People or Groups')
app/models/raw_html_article.rb 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +class RawHTMLArticle < TextArticle
  2 +
  3 + def self.short_description
  4 + _('Raw HTML text article.')
  5 + end
  6 +
  7 + def self.description
  8 + _('Allows HTML without filter (only for admins)')
  9 + end
  10 +
  11 + xss_terminate :only => [ ]
  12 +
  13 +end
app/models/reported_image.rb 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +class ReportedImage < ActiveRecord::Base
  2 + belongs_to :abuse_report
  3 +
  4 + validates_presence_of :abuse_report
  5 +
  6 + has_attachment :content_type => :image,
  7 + :storage => :file_system,
  8 + :max_size => 5.megabytes
  9 +
  10 +end
app/models/suggest_article.rb
1 class SuggestArticle < Task 1 class SuggestArticle < Task
2 2
3 - has_captcha  
4 -  
5 validates_presence_of :target_id, :article_name, :email, :name, :article_body 3 validates_presence_of :target_id, :article_name, :email, :name, :article_body
6 4
7 settings_items :email, :type => String 5 settings_items :email, :type => String
app/models/task.rb
@@ -20,11 +20,14 @@ class Task &lt; ActiveRecord::Base @@ -20,11 +20,14 @@ class Task &lt; ActiveRecord::Base
20 # the status of a task that was cancelled. 20 # the status of a task that was cancelled.
21 CANCELLED = 2 21 CANCELLED = 2
22 22
23 - # the status os a task that was successfully finished 23 + # the status of a task that was successfully finished
24 FINISHED = 3 24 FINISHED = 3
25 25
  26 + # the status of a task that was created but is not displayed yet
  27 + HIDDEN = 4
  28 +
26 def self.names 29 def self.names
27 - [nil, N_('Active'), N_('Cancelled'), N_('Finished')] 30 + [nil, N_('Active'), N_('Cancelled'), N_('Finished'), N_('Hidden')]
28 end 31 end
29 end 32 end
30 33
@@ -38,7 +41,7 @@ class Task &lt; ActiveRecord::Base @@ -38,7 +41,7 @@ class Task &lt; ActiveRecord::Base
38 41
39 def initialize(*args) 42 def initialize(*args)
40 super 43 super
41 - self.status ||= Task::Status::ACTIVE 44 + self.status = (args.first ? args.first[:status] : nil) || Task::Status::ACTIVE
42 end 45 end
43 46
44 attr_accessor :code_length 47 attr_accessor :code_length
@@ -52,20 +55,26 @@ class Task &lt; ActiveRecord::Base @@ -52,20 +55,26 @@ class Task &lt; ActiveRecord::Base
52 end 55 end
53 56
54 after_create do |task| 57 after_create do |task|
55 - begin  
56 - task.send(:send_notification, :created)  
57 - rescue NotImplementedError => ex  
58 - RAILS_DEFAULT_LOGGER.info ex.to_s  
59 - end  
60 -  
61 - begin  
62 - target_msg = task.target_notification_message  
63 - TaskMailer.deliver_target_notification(task, target_msg) if target_msg  
64 - rescue NotImplementedError => ex  
65 - RAILS_DEFAULT_LOGGER.info ex.to_s 58 + unless task.status == Task::Status::HIDDEN
  59 + begin
  60 + task.send(:send_notification, :created)
  61 + rescue NotImplementedError => ex
  62 + RAILS_DEFAULT_LOGGER.info ex.to_s
  63 + end
  64 +
  65 + begin
  66 + target_msg = task.target_notification_message
  67 + TaskMailer.deliver_target_notification(task, target_msg) if target_msg
  68 + rescue NotImplementedError => ex
  69 + RAILS_DEFAULT_LOGGER.info ex.to_s
  70 + end
66 end 71 end
67 end 72 end
68 73
  74 + def self.all_types
  75 + %w[Invitation EnterpriseActivation AddMember Ticket SuggestArticle AddFriend CreateCommunity AbuseComplaint ApproveArticle CreateEnterprise ChangePassword EmailActivation InviteFriend InviteMember]
  76 + end
  77 +
69 # this method finished the task. It calls #perform, which must be overriden 78 # this method finished the task. It calls #perform, which must be overriden
70 # by subclasses. At the end a message (as returned by #finish_message) is 79 # by subclasses. At the end a message (as returned by #finish_message) is
71 # sent to the requestor with #notify_requestor. 80 # sent to the requestor with #notify_requestor.
@@ -175,6 +184,12 @@ class Task &lt; ActiveRecord::Base @@ -175,6 +184,12 @@ class Task &lt; ActiveRecord::Base
175 raise NotImplementedError, "#{self} does not implement #task_cancelled_message" 184 raise NotImplementedError, "#{self} does not implement #task_cancelled_message"
176 end 185 end
177 186
  187 + # The message that will be sent to the requestor of the task when its
  188 + # activated.
  189 + def task_activated_message
  190 + raise NotImplementedError, "#{self} does not implement #task_cancelled_message"
  191 + end
  192 +
178 # The message that will be sent to the *target* of the task when it is 193 # The message that will be sent to the *target* of the task when it is
179 # created. The indent of this message is to notify the target about the 194 # created. The indent of this message is to notify the target about the
180 # request that was just created for him/her. 195 # request that was just created for him/her.
@@ -199,6 +214,23 @@ class Task &lt; ActiveRecord::Base @@ -199,6 +214,23 @@ class Task &lt; ActiveRecord::Base
199 self.target.environment unless self.target.nil? 214 self.target.environment unless self.target.nil?
200 end 215 end
201 216
  217 + def activate
  218 + self.status = Task::Status::ACTIVE
  219 + save!
  220 + begin
  221 + self.send(:send_notification, :activated)
  222 + rescue NotImplementedError => ex
  223 + RAILS_DEFAULT_LOGGER.info ex.to_s
  224 + end
  225 +
  226 + begin
  227 + target_msg = target_notification_message
  228 + TaskMailer.deliver_target_notification(self, target_msg) if target_msg
  229 + rescue NotImplementedError => ex
  230 + RAILS_DEFAULT_LOGGER.info ex.to_s
  231 + end
  232 + end
  233 +
202 protected 234 protected
203 235
204 # This method must be overrided in subclasses, and its implementation must do 236 # This method must be overrided in subclasses, and its implementation must do
@@ -232,6 +264,23 @@ class Task &lt; ActiveRecord::Base @@ -232,6 +264,23 @@ class Task &lt; ActiveRecord::Base
232 264
233 named_scope :pending, :conditions => { :status => Task::Status::ACTIVE } 265 named_scope :pending, :conditions => { :status => Task::Status::ACTIVE }
234 named_scope :finished, :conditions => { :status => [Task::Status::CANCELLED, Task::Status::FINISHED] } 266 named_scope :finished, :conditions => { :status => [Task::Status::CANCELLED, Task::Status::FINISHED] }
  267 + named_scope :opened, :conditions => { :status => [Task::Status::ACTIVE, Task::Status::HIDDEN] }
  268 + named_scope :of, lambda { |type| conditions = type ? "type LIKE '#{type}'" : "1=1"; {:conditions => [conditions]} }
  269 + named_scope :order_by, lambda { |attribute, ord| {:order => "#{attribute} #{ord}"} }
  270 +
  271 + named_scope :to, lambda { |profile|
  272 + environment_condition = nil
  273 + if profile.person?
  274 + envs_ids = Environment.find(:all).select{ |env| profile.is_admin?(env) }.map { |env| "target_id = #{env.id}"}.join(' OR ')
  275 + environment_condition = envs_ids.blank? ? nil : "(target_type = 'Environment' AND (#{envs_ids}))"
  276 + end
  277 + profile_condition = "(target_type = 'Profile' AND target_id = #{profile.id})"
  278 + { :conditions => [environment_condition, profile_condition].compact.join(' OR ') }
  279 + }
  280 +
  281 + def opened?
  282 + status == Task::Status::ACTIVE || status == Task::Status::HIDDEN
  283 + end
235 284
236 class << self 285 class << self
237 286
@@ -254,6 +303,10 @@ class Task &lt; ActiveRecord::Base @@ -254,6 +303,10 @@ class Task &lt; ActiveRecord::Base
254 self.find(:first, :conditions => { :code => code, :status => Task::Status::ACTIVE }) 303 self.find(:first, :conditions => { :code => code, :status => Task::Status::ACTIVE })
255 end 304 end
256 305
  306 + def per_page
  307 + 15
  308 + end
  309 +
257 end 310 end
258 311
259 end 312 end
app/models/text_article.rb
1 # a base class for all text article types. 1 # a base class for all text article types.
2 class TextArticle < Article 2 class TextArticle < Article
3 3
4 - xss_terminate :only => [ :name, :abstract, :body ], :on => 'validation' 4 + xss_terminate :only => [ :name ], :on => 'validation'
5 5
6 include Noosfero::TranslatableContent 6 include Noosfero::TranslatableContent
7 7
app/models/textile_article.rb
@@ -9,11 +9,28 @@ class TextileArticle &lt; TextArticle @@ -9,11 +9,28 @@ class TextileArticle &lt; TextArticle
9 end 9 end
10 10
11 def to_html(options ={}) 11 def to_html(options ={})
12 - RedCloth.new(self.body|| '').to_html 12 + convert_to_html(body)
  13 + end
  14 +
  15 + def lead
  16 + if abstract.blank?
  17 + super
  18 + else
  19 + convert_to_html(abstract)
  20 + end
13 end 21 end
14 22
15 def notifiable? 23 def notifiable?
16 true 24 true
17 end 25 end
18 26
  27 + protected
  28 +
  29 + def convert_to_html(textile)
  30 + @@sanitizer ||= HTML::WhiteListSanitizer.new
  31 + converter = RedCloth.new(textile|| '')
  32 + converter.hard_breaks = false
  33 + @@sanitizer.sanitize(converter.to_html)
  34 + end
  35 +
19 end 36 end
app/models/thumbnail.rb
@@ -2,4 +2,8 @@ class Thumbnail &lt; ActiveRecord::Base @@ -2,4 +2,8 @@ class Thumbnail &lt; ActiveRecord::Base
2 has_attachment :storage => :file_system, 2 has_attachment :storage => :file_system,
3 :content_type => :image, :max_size => 5.megabytes 3 :content_type => :image, :max_size => 5.megabytes
4 validates_as_attachment 4 validates_as_attachment
  5 +
  6 + sanitize_filename
  7 +
  8 + postgresql_attachment_fu
5 end 9 end
app/models/ticket.rb
1 class Ticket < Task 1 class Ticket < Task
2 - settings_items :title, :message 2 + settings_items :name, :message
  3 +
  4 + def title
  5 + _('Ticket') + (name ? ': '+name : '')
  6 + end
3 end 7 end
app/models/uploaded_file.rb
@@ -18,6 +18,8 @@ class UploadedFile &lt; Article @@ -18,6 +18,8 @@ class UploadedFile &lt; Article
18 18
19 validates_size_of :title, :maximum => 60, :if => (lambda { |file| !file.title.blank? }) 19 validates_size_of :title, :maximum => 60, :if => (lambda { |file| !file.title.blank? })
20 20
  21 + sanitize_filename
  22 +
21 before_create do |uploaded_file| 23 before_create do |uploaded_file|
22 uploaded_file.is_image = true if uploaded_file.image? 24 uploaded_file.is_image = true if uploaded_file.image?
23 end 25 end
@@ -52,6 +54,8 @@ class UploadedFile &lt; Article @@ -52,6 +54,8 @@ class UploadedFile &lt; Article
52 54
53 delay_attachment_fu_thumbnails 55 delay_attachment_fu_thumbnails
54 56
  57 + postgresql_attachment_fu
  58 +
55 def self.icon_name(article = nil) 59 def self.icon_name(article = nil)
56 if article 60 if article
57 article.image? ? article.public_filename(:icon) : (article.mime_type ? article.mime_type.gsub(/[\/+.]/, '-') : 'upload-file') 61 article.image? ? article.public_filename(:icon) : (article.mime_type ? article.mime_type.gsub(/[\/+.]/, '-') : 'upload-file')
@@ -132,4 +136,8 @@ class UploadedFile &lt; Article @@ -132,4 +136,8 @@ class UploadedFile &lt; Article
132 def gallery? 136 def gallery?
133 self.parent && self.parent.folder? && self.parent.gallery? 137 self.parent && self.parent.folder? && self.parent.gallery?
134 end 138 end
  139 +
  140 + def uploaded_file?
  141 + true
  142 + end
135 end 143 end
app/models/user.rb
@@ -21,6 +21,8 @@ class User &lt; ActiveRecord::Base @@ -21,6 +21,8 @@ class User &lt; ActiveRecord::Base
21 end 21 end
22 end 22 end
23 23
  24 + before_create :make_activation_code
  25 +
24 before_create do |user| 26 before_create do |user|
25 if user.environment.nil? 27 if user.environment.nil?
26 user.environment = Environment.default 28 user.environment = Environment.default
@@ -31,8 +33,11 @@ class User &lt; ActiveRecord::Base @@ -31,8 +33,11 @@ class User &lt; ActiveRecord::Base
31 user.person ||= Person.new 33 user.person ||= Person.new
32 user.person.attributes = user.person_data.merge(:identifier => user.login, :user_id => user.id, :environment_id => user.environment_id) 34 user.person.attributes = user.person_data.merge(:identifier => user.login, :user_id => user.id, :environment_id => user.environment_id)
33 user.person.name ||= user.login 35 user.person.name ||= user.login
  36 + user.person.visible = false unless user.activated?
34 user.person.save! 37 user.person.save!
35 end 38 end
  39 + after_create :deliver_activation_code
  40 + after_create :delay_activation_check
36 41
37 attr_writer :person_data 42 attr_writer :person_data
38 def person_data 43 def person_data
@@ -55,6 +60,17 @@ class User &lt; ActiveRecord::Base @@ -55,6 +60,17 @@ class User &lt; ActiveRecord::Base
55 :environment => user.environment.name, 60 :environment => user.environment.name,
56 :url => url_for(:host => user.environment.default_hostname, :controller => 'home') 61 :url => url_for(:host => user.environment.default_hostname, :controller => 'home')
57 end 62 end
  63 +
  64 + def activation_code(user)
  65 + recipients user.email
  66 +
  67 + from "#{user.environment.name} <#{user.environment.contact_email}>"
  68 + subject _("[%s] Activate your account") % [user.environment.name]
  69 + body :recipient => user.name,
  70 + :activation_code => user.activation_code,
  71 + :environment => user.environment.name,
  72 + :url => user.environment.top_url
  73 + end
58 end 74 end
59 75
60 def signup! 76 def signup!
@@ -67,6 +83,8 @@ class User &lt; ActiveRecord::Base @@ -67,6 +83,8 @@ class User &lt; ActiveRecord::Base
67 has_one :person, :dependent => :destroy 83 has_one :person, :dependent => :destroy
68 belongs_to :environment 84 belongs_to :environment
69 85
  86 + attr_protected :activated_at
  87 +
70 # Virtual attribute for the unencrypted password 88 # Virtual attribute for the unencrypted password
71 attr_accessor :password 89 attr_accessor :password
72 90
@@ -87,10 +105,22 @@ class User &lt; ActiveRecord::Base @@ -87,10 +105,22 @@ class User &lt; ActiveRecord::Base
87 # Authenticates a user by their login name and unencrypted password. Returns the user or nil. 105 # Authenticates a user by their login name and unencrypted password. Returns the user or nil.
88 def self.authenticate(login, password, environment = nil) 106 def self.authenticate(login, password, environment = nil)
89 environment ||= Environment.default 107 environment ||= Environment.default
90 - u = find_by_login_and_environment_id(login, environment.id) # need to get the salt 108 + u = first :conditions => ['login = ? AND environment_id = ? AND activated_at IS NOT NULL', login, environment.id] # need to get the salt
91 u && u.authenticated?(password) ? u : nil 109 u && u.authenticated?(password) ? u : nil
92 end 110 end
93 111
  112 + # Activates the user in the database.
  113 + def activate
  114 + self.activated_at = Time.now.utc
  115 + self.activation_code = nil
  116 + self.person.visible = true
  117 + self.person.save! && self.save
  118 + end
  119 +
  120 + def activated?
  121 + self.activation_code.nil? && !self.activated_at.nil?
  122 + end
  123 +
94 class UnsupportedEncryptionType < Exception; end 124 class UnsupportedEncryptionType < Exception; end
95 125
96 def self.system_encryption_method 126 def self.system_encryption_method
@@ -195,7 +225,7 @@ class User &lt; ActiveRecord::Base @@ -195,7 +225,7 @@ class User &lt; ActiveRecord::Base
195 end 225 end
196 226
197 def name 227 def name
198 - person.name 228 + person ? person.name : login
199 end 229 end
200 230
201 def enable_email! 231 def enable_email!
@@ -253,4 +283,16 @@ class User &lt; ActiveRecord::Base @@ -253,4 +283,16 @@ class User &lt; ActiveRecord::Base
253 def password_required? 283 def password_required?
254 crypted_password.blank? || !password.blank? 284 crypted_password.blank? || !password.blank?
255 end 285 end
  286 +
  287 + def make_activation_code
  288 + self.activation_code = Digest::SHA1.hexdigest(Time.now.to_s.split(//).sort_by{rand}.join)
  289 + end
  290 +
  291 + def deliver_activation_code
  292 + User::Mailer.deliver_activation_code(self) unless self.activation_code.blank?
  293 + end
  294 +
  295 + def delay_activation_check
  296 + Delayed::Job.enqueue(UserActivationJob.new(self.id), 0, 72.hours.from_now)
  297 + end
256 end 298 end
app/sweepers/article_sweeper.rb
@@ -21,7 +21,7 @@ protected @@ -21,7 +21,7 @@ protected
21 blocks = article.profile.blocks 21 blocks = article.profile.blocks
22 blocks += article.profile.environment.blocks if article.profile.environment 22 blocks += article.profile.environment.blocks if article.profile.environment
23 blocks = blocks.select{|b|[RecentDocumentsBlock, BlogArchivesBlock].any?{|c| b.kind_of?(c)}} 23 blocks = blocks.select{|b|[RecentDocumentsBlock, BlogArchivesBlock].any?{|c| b.kind_of?(c)}}
24 - blocks.map(&:cache_keys).each{|ck|expire_timeout_fragment(ck)} 24 + blocks.map(&:cache_key).each{|ck|expire_timeout_fragment(ck)}
25 env = article.profile.environment 25 env = article.profile.environment
26 if env && (env.portal_community == article.profile) 26 if env && (env.portal_community == article.profile)
27 expire_fragment(env.portal_news_cache_key) 27 expire_fragment(env.portal_news_cache_key)
app/sweepers/friendship_sweeper.rb
@@ -35,7 +35,7 @@ protected @@ -35,7 +35,7 @@ protected
35 end 35 end
36 36
37 blocks = profile.blocks.select{|b| b.kind_of?(FriendsBlock)} 37 blocks = profile.blocks.select{|b| b.kind_of?(FriendsBlock)}
38 - blocks.map(&:cache_keys).each{|ck|expire_timeout_fragment(ck)} 38 + blocks.map(&:cache_key).each{|ck|expire_timeout_fragment(ck)}
39 end 39 end
40 40
41 end 41 end
app/sweepers/profile_sweeper.rb
@@ -23,12 +23,25 @@ protected @@ -23,12 +23,25 @@ protected
23 expire_profile_index(profile) if profile.person? 23 expire_profile_index(profile) if profile.person?
24 24
25 profile.blocks.each do |block| 25 profile.blocks.each do |block|
26 - expire_timeout_fragment(block.cache_keys) 26 + expire_timeout_fragment(block.cache_key)
27 end 27 end
  28 +
  29 + expire_blogs(profile) if profile.organization?
28 end 30 end
29 31
30 def expire_statistics_block_cache(profile) 32 def expire_statistics_block_cache(profile)
31 blocks = profile.environment.blocks.select { |b| b.kind_of?(EnvironmentStatisticsBlock) } 33 blocks = profile.environment.blocks.select { |b| b.kind_of?(EnvironmentStatisticsBlock) }
32 - blocks.map(&:cache_keys).each{|ck|expire_timeout_fragment(ck)} 34 + blocks.map(&:cache_key).each{|ck|expire_timeout_fragment(ck)}
33 end 35 end
  36 +
  37 + def expire_blogs(profile)
  38 + profile.blogs.select{|b| !b.empty?}.each do |blog|
  39 + pages = blog.posts.count / blog.posts_per_page + 1
  40 + ([nil] + (1..pages).to_a).each do |i|
  41 + expire_timeout_fragment(blog.cache_key({:npage => i}))
  42 + expire_timeout_fragment(blog.cache_key({:npage => i}, profile))
  43 + end
  44 + end
  45 + end
  46 +
34 end 47 end
app/sweepers/role_assignment_sweeper.rb
@@ -25,7 +25,7 @@ protected @@ -25,7 +25,7 @@ protected
25 25
26 profile.blocks_to_expire_cache.each { |block| 26 profile.blocks_to_expire_cache.each { |block|
27 blocks = profile.blocks.select{|b| b.kind_of?(block)} 27 blocks = profile.blocks.select{|b| b.kind_of?(block)}
28 - blocks.map(&:cache_keys).each{|ck|expire_timeout_fragment(ck)} 28 + blocks.map(&:cache_key).each{|ck|expire_timeout_fragment(ck)}
29 } 29 }
30 end 30 end
31 31
app/views/account/_signup_form.rhtml
@@ -7,8 +7,7 @@ @@ -7,8 +7,7 @@
7 </div> 7 </div>
8 <% end %> 8 <% end %>
9 9
10 -<% labelled_form_for :user, @user do |f| %>  
11 -<%= icaptcha_field() %> 10 +<% labelled_form_for :user, @user, :html => { :multipart => true } do |f| %>
12 11
13 <%= hidden_field_tag :invitation_code, @invitation_code %> 12 <%= hidden_field_tag :invitation_code, @invitation_code %>
14 13
app/views/account/login.rhtml
@@ -5,9 +5,11 @@ @@ -5,9 +5,11 @@
5 <% @user ||= User.new %> 5 <% @user ||= User.new %>
6 <% is_thickbox ||= false %> 6 <% is_thickbox ||= false %>
7 7
  8 +<%= @message %>
  9 +
8 <% labelled_form_for :user, @user, :url => login_url do |f| %> 10 <% labelled_form_for :user, @user, :url => login_url do |f| %>
9 11
10 - <%= f.text_field :login, :id => 'main_user_login', :onchange => 'this.value = convToValidLogin( this.value )' %> 12 + <%= f.text_field :login, :id => 'main_user_login', :onchange => 'this.value = convToValidLogin( this.value )', :value => params[:userlogin] %>
11 13
12 <%= f.password_field :password %> 14 <%= f.password_field :password %>
13 15
app/views/account/signup.rhtml
1 <h1><%= _('Signup') %></h1> 1 <h1><%= _('Signup') %></h1>
2 -<%= render :partial => 'signup_form' %> 2 +<% if @register_pending %>
  3 + <%= _('Thanks for signing up! Now check your e-mail to activate your account!') %>
  4 + <p style="text-align: center"><%= link_to(_('Go to the homepage'), '/') %></p>
  5 +<% else %>
  6 + <%= render :partial => 'signup_form' %>
  7 +<% end %>
app/views/admin_panel/edit_templates.rhtml
1 <h1><%= _('Edit Templates') %></h1> 1 <h1><%= _('Edit Templates') %></h1>
2 2
3 <ul> 3 <ul>
4 -<li><%= link_to _('Edit Person Template'), :controller => 'profile_editor', :profile => environment.person_template.identifier %></li>  
5 -<li><%= link_to _('Edit Community Template'), :controller => 'profile_editor', :profile => environment.community_template.identifier %></li>  
6 -<li><%= link_to __('Edit Enterprise Template'), :controller => 'profile_editor', :profile => environment.enterprise_template.identifier %></li> 4 +<% [[_('Edit Person Template'), environment.person_template],
  5 + [_('Edit Community Template'), environment.community_template],
  6 + [__('Edit Enterprise Template'), environment.enterprise_template],
  7 + [__('Edit Inactive Enterprise Template'), environment.inactive_enterprise_template]].select{|i| i[1]}.each do |row| %>
  8 +<li><%= link_to row[0], :controller => 'profile_editor', :profile => row[1].identifier %></li>
  9 +<% end %>
7 </ul> 10 </ul>
app/views/admin_panel/index.rhtml
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 <p><%= _('You, as an environment administrator, has the following options:')%></p> 3 <p><%= _('You, as an environment administrator, has the following options:')%></p>
4 4
5 <table> 5 <table>
6 - <tr><td><%= link_to _('Edit site info'), :action => 'site_info' %></td></tr> 6 + <tr><td><%= link_to _('Edit environment settings'), :action => 'site_info' %></td></tr>
7 <tr><td><%= link_to __('Edit message for disabled enterprises'), :action => 'message_for_disabled_enterprise' %></td></tr> 7 <tr><td><%= link_to __('Edit message for disabled enterprises'), :action => 'message_for_disabled_enterprise' %></td></tr>
8 <tr><td><%= link_to _('Enable/disable features'), :controller => 'features' %></td></tr> 8 <tr><td><%= link_to _('Enable/disable features'), :controller => 'features' %></td></tr>
9 <tr><td><%= link_to _('Enable/disable plugins'), :controller => 'plugins' %></td></tr> 9 <tr><td><%= link_to _('Enable/disable plugins'), :controller => 'plugins' %></td></tr>
@@ -16,4 +16,7 @@ @@ -16,4 +16,7 @@
16 <tr><td><%= link_to _('Manage Fields'), :controller => 'features', :action => 'manage_fields' %></td></tr> 16 <tr><td><%= link_to _('Manage Fields'), :controller => 'features', :action => 'manage_fields' %></td></tr>
17 <tr><td><%= link_to _('Set Portal'), :action => 'set_portal_community' %></td></tr> 17 <tr><td><%= link_to _('Set Portal'), :action => 'set_portal_community' %></td></tr>
18 <tr><td><%= link_to _('Terms of use'), :action => 'terms_of_use' %></td></tr> 18 <tr><td><%= link_to _('Terms of use'), :action => 'terms_of_use' %></td></tr>
  19 + <% @plugins.map(:admin_panel_links).each do |link| %>
  20 + <tr><td><%= link_to link[:title], link[:url] %></td></tr>
  21 + <% end %>
19 </table> 22 </table>
app/views/admin_panel/site_info.rhtml
1 -<h2><%= _('Site info') %></h2> 1 +<h2><%= _('Environment settings') %></h2>
2 2
3 -<%= render :file => 'shared/tiny_mce' %>  
4 -  
5 -<% labelled_form_for :environment, @environment do |f| %> 3 +<%= error_messages_for :environment %>
6 4
7 - <%= labelled_form_field(_('Site name'), text_field(:environment, :name)) %> 5 +<%= render :file => 'shared/tiny_mce' %>
8 6
  7 +<% labelled_form_for :environment, @environment, :url => {:host => @environment.default_hostname} do |f| %>
  8 + <%= required labelled_form_field(_('Site name'), text_field(:environment, :name)) %>
  9 + <%= required f.text_field(:reports_lower_bound, :size => 3) %>
9 <%= labelled_form_field _('Homepage content'), text_area(:environment, :description, :cols => 40, :style => 'width: 90%', :class => 'mceEditor') %> 10 <%= labelled_form_field _('Homepage content'), text_area(:environment, :description, :cols => 40, :style => 'width: 90%', :class => 'mceEditor') %>
10 11
11 <% button_bar do %> 12 <% button_bar do %>
12 - <%= submit_button(:save, _('Save')) %>  
13 - <%= button(:cancel, _('Cancel'), :action => 'index') %> 13 + <%= submit_button(:save, _('Save'), :cancel => {:action => 'index'}) %>
14 <% end %> 14 <% end %>
15 -  
16 <% end %> 15 <% end %>
app/views/blocks/my_network.rhtml
@@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
6 <li><%= link_to(__('Homepage'), owner.url, :class => 'url') %></li> 6 <li><%= link_to(__('Homepage'), owner.url, :class => 'url') %></li>
7 <li><%= link_to(_('View profile'), owner.public_profile_url) %></li> 7 <li><%= link_to(_('View profile'), owner.public_profile_url) %></li>
8 <% if !user.nil? and owner.organization? and user.has_permission?('edit_profile', profile) %> 8 <% if !user.nil? and owner.organization? and user.has_permission?('edit_profile', profile) %>
9 - <li><%= link_to _('Control panel'), :controller => 'profile_editor' %></li> 9 + <li><%= link_to _('Control panel'), :controller => 'profile_editor', :profile => profile.identifier %></li>
10 <% end %> 10 <% end %>
11 </ul> 11 </ul>
12 12
app/views/blocks/profile_image.rhtml
@@ -20,5 +20,5 @@ @@ -20,5 +20,5 @@
20 20
21 </div><!-- end class="vcard" --> 21 </div><!-- end class="vcard" -->
22 <script type="text/javascript"> 22 <script type="text/javascript">
23 - <%= remote_function :url => { :controller => 'profile', :action => 'profile_info', :block_id => block.id } %> 23 + <%= remote_function :url => { :controller => 'profile', :profile => profile.identifier, :action => 'profile_info', :block_id => block.id } %>
24 </script> 24 </script>
app/views/blocks/profile_info.rhtml
@@ -41,5 +41,5 @@ @@ -41,5 +41,5 @@
41 41
42 </div><!-- end class="vcard" --> 42 </div><!-- end class="vcard" -->
43 <script type="text/javascript"> 43 <script type="text/javascript">
44 - <%= remote_function :url => { :controller => 'profile', :action => 'profile_info', :block_id => block.id } %> 44 + <%= remote_function :url => { :controller => 'profile', :profile => profile.identifier, :action => 'profile_info', :block_id => block.id } %>
45 </script> 45 </script>
app/views/blocks/profile_info_actions/community.rhtml
1 <ul> 1 <ul>
2 <% if logged_in? %> 2 <% if logged_in? %>
3 -  
4 <% if profile.members.include?(user) %> 3 <% if profile.members.include?(user) %>
5 <li> 4 <li>
6 - <%= button(:delete, content_tag('span', __('Leave')), profile.leave_url, :class => 'leave-community', :title => _("Leave community"), :style => 'position: relative;') %>  
7 - <%= button(:add, content_tag('span', __('Join')), profile.join_url, :class => 'join-community', :title => _("Join community"), :style => 'position: relative; display: none;') %> 5 + <%= button(:delete, content_tag('span', __('Leave')), profile.leave_url,
  6 + :class => 'leave-community',
  7 + :title => _("Leave community"),
  8 + :style => 'position: relative;') %>
  9 + <%= button(:add, content_tag('span', __('Join')), profile.join_url,
  10 + :class => 'join-community',
  11 + :title => _("Join community"),
  12 + :style => 'position: relative; display: none;') %>
8 </li> 13 </li>
9 <% else %> 14 <% else %>
10 <% unless profile.already_request_membership?(user) %> 15 <% unless profile.already_request_membership?(user) %>
11 <li> 16 <li>
12 - <%= button(:delete, content_tag('span', __('Leave')), profile.leave_url, :class => 'leave-community', :title => _("Leave community"), :style => 'position: relative; display: none;') %>  
13 - <%= button(:add, content_tag('span', __('Join')), profile.join_url, :class => 'join-community', :title => _("Join community"), :style => 'position: relative;') %> 17 + <%= button(:delete, content_tag('span', __('Leave')), profile.leave_url,
  18 + :class => 'leave-community',
  19 + :title => _("Leave community"),
  20 + :style => 'position: relative; display: none;') %>
  21 + <%= button(:add, content_tag('span', __('Join')), profile.join_url,
  22 + :class => 'join-community',
  23 + :title => _("Join community"),
  24 + :style => 'position: relative;') %>
14 </li> 25 </li>
15 <% end %> 26 <% end %>
16 <% end %> 27 <% end %>
  28 +
17 <% if profile.enable_contact? %> 29 <% if profile.enable_contact? %>
18 <li> 30 <li>
19 - <%= link_to content_tag('span', _('Send an e-mail')), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}, :class => 'button with-text icon-menu-mail' %> 31 + <%= link_to content_tag('span', _('Send an e-mail')),
  32 + { :profile => profile.identifier,
  33 + :controller => 'contact',
  34 + :action => 'new' },
  35 + :class => 'button with-text icon-menu-mail' %>
20 </li> 36 </li>
21 <% end %> 37 <% end %>
22 - <%= render_environment_features(:profile_actions) %>  
23 38
24 - <% else %> 39 + <li><%= report_abuse(profile, :button) %></li>
25 40
  41 + <%= render_environment_features(:profile_actions) %>
  42 + <% else %>
26 <li> 43 <li>
27 - <%= link_to content_tag('span', _('Join')), profile.join_not_logged_url, :class => 'button with-text icon-add', :title => _('Join this community') %> 44 + <%= link_to content_tag('span', _('Join')), profile.join_not_logged_url,
  45 + :class => 'button with-text icon-add',
  46 + :title => _('Join this community') %>
28 </li> 47 </li>
29 -  
30 <% end %> 48 <% end %>
31 </ul> 49 </ul>
app/views/blocks/profile_info_actions/enterprise.rhtml
@@ -7,4 +7,6 @@ @@ -7,4 +7,6 @@
7 <% if profile.enable_contact? %> 7 <% if profile.enable_contact? %>
8 <li> <%= link_to content_tag('span', _('Send an e-mail')), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}, {:id => 'enterprise-contact-button', :class => 'button with-text icon-menu-mail'} %> </li> 8 <li> <%= link_to content_tag('span', _('Send an e-mail')), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}, {:id => 'enterprise-contact-button', :class => 'button with-text icon-menu-mail'} %> </li>
9 <% end %> 9 <% end %>
  10 +
  11 + <li><%= report_abuse(profile, :button) %></li>
10 </ul> 12 </ul>
app/views/blocks/profile_info_actions/person.rhtml
@@ -11,5 +11,6 @@ @@ -11,5 +11,6 @@
11 <li> <%= link_to content_tag('span', _('Send an e-mail')), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}, :class => 'button with-text icon-menu-mail' %> </li> 11 <li> <%= link_to content_tag('span', _('Send an e-mail')), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}, :class => 'button with-text icon-menu-mail' %> </li>
12 <% end %> 12 <% end %>
13 13
  14 + <li><%= report_abuse(profile, :button) %></li>
14 <% end %> 15 <% end %>
15 </ul> 16 </ul>
app/views/box_organizer/_article_block.rhtml
@@ -5,6 +5,6 @@ @@ -5,6 +5,6 @@
5 </p> 5 </p>
6 <% else %> 6 <% else %>
7 <% articles = @block.available_articles.select {|article| !article.folder? } %> 7 <% articles = @block.available_articles.select {|article| !article.folder? } %>
8 - <%= select_tag('block[article_id]', options_for_select_with_title(articles.map {|item| [item.path, item.id]})) %> 8 + <%= select_tag('block[article_id]', options_for_select_with_title(articles.map {|item| [item.path, item.id]}, @block.article ? @block.article.id : nil)) %>
9 <% end %> 9 <% end %>
10 </div> 10 </div>
app/views/box_organizer/edit.rhtml
@@ -14,6 +14,9 @@ @@ -14,6 +14,9 @@
14 <%= radio_button(:block, :display, 'home_page_only') %> 14 <%= radio_button(:block, :display, 'home_page_only') %>
15 <%= label_tag('block_display_home_page_only', _('Only in the homepage')) %> 15 <%= label_tag('block_display_home_page_only', _('Only in the homepage')) %>
16 <br/> 16 <br/>
  17 + <%= radio_button(:block, :display, 'except_home_page') %>
  18 + <%= label_tag('block_display_except_home_page', _('In all pages, except in the homepage')) %>
  19 + <br/>
17 <%= radio_button(:block, :display, 'never') %> 20 <%= radio_button(:block, :display, 'never') %>
18 <%= label_tag('block_display_never', _("Don't display")) %> 21 <%= label_tag('block_display_never', _("Don't display")) %>
19 </div> 22 </div>
app/views/browse/_article.rhtml 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +<li class="<%= 'browse-results-type-content ' + icon_for_article(result) %>">
  2 + <strong><%= link_to(result.title, result.view_url) %></strong>
  3 + <div class="item_meta">
  4 + <span class="item_by">
  5 + <%= _('by %s') % link_to(result.author.name, result.author.url) %>
  6 + </span>
  7 + <span class="extra-info">
  8 + <%= (@filter == 'more_recent' ? result.send(@filter + '_label') + show_date(result.created_at) : result.send(@filter + '_label')) %>
  9 + </span>
  10 + </div>
  11 +</li>
app/views/browse/_display_results.rhtml
@@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
8 <% end %> 8 <% end %>
9 <ul class='common-profile-list-block'> 9 <ul class='common-profile-list-block'>
10 <% @results.each do |result| %> 10 <% @results.each do |result| %>
11 - <%= render :partial => partial_for_class(result.class), :locals => {:profile => result} %> 11 + <%= render :partial => partial_for_class(result.class), :locals => {:result => result} %>
12 <% end %> 12 <% end %>
13 </ul> 13 </ul>
14 <br style='clear: both;'> 14 <br style='clear: both;'>
app/views/browse/_person.rhtml
1 -<%= profile_image_link profile, :portrait, 'li',  
2 - "<span class='adr'>#{profile.city}</span>" +  
3 - (@filter == 'more_recent' ? profile.send(@filter + '_label') + show_date(profile.created_at) : profile.send(@filter + '_label')) %> 1 +<%= profile_image_link result, :portrait, 'li',
  2 + "<span class='adr'>#{result.city}</span>" +
  3 + (@filter == 'more_recent' ? result.send(@filter + '_label') + show_date(result.created_at) : result.send(@filter + '_label')) %>
app/views/browse/_profile.rhtml
1 -<%= profile_image_link profile, :portrait, 'li', @filter == 'more_recent' ? profile.send(@filter + '_label') + show_date(profile.created_at) : profile.send(@filter + '_label') %> 1 +<%= profile_image_link result, :portrait, 'li', @filter == 'more_recent' ? result.send(@filter + '_label') + show_date(result.created_at) : result.send(@filter + '_label') %>
app/views/browse/contents.rhtml 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +<%= search_page_title( @title, { :query => @query} ) %>
  2 +
  3 +<%= render :partial => 'search_form', :locals => {:action => 'contents'} %>
  4 +
  5 +<%= render :partial => 'display_results' %>
  6 +
  7 +<%= pagination_links @results %>
  8 +
  9 +<br style="clear:both" />
app/views/categories/_category.rhtml
@@ -2,12 +2,12 @@ @@ -2,12 +2,12 @@
2 <div class='treeitem'> 2 <div class='treeitem'>
3 <%= display_color_for_category(category) %> 3 <%= display_color_for_category(category) %>
4 <%= category.name %> 4 <%= category.name %>
5 - <div class='button' id="show_button_<%= category.id %>">  
6 - <%= link_to_function(_('Show'), "['category_#{category.id}','hide_button_#{category.id}'].each(Element.show); Element.hide('show_button_#{category.id}');") unless category.children.empty? %>  
7 - </div>  
8 - <div class='button' id="hide_button_<%= category.id %>" style='display:none;'>  
9 - <%= link_to_function(_('Hide'), "['category_#{category.id}','hide_button_#{category.id}'].each(Element.hide); Element.show('show_button_#{category.id}') ") %>  
10 - </div> 5 + <% if category.children.count > 0 %>
  6 + <div class='button' id="category-loading-<%= category.id %>" style="position: relative;">
  7 + <a href="#" id="show-button-<%= category.id %>" class="show-button" onclick="return false;" data-category="<%= category.id %>"><%= _('Show') %></a>
  8 + </div>
  9 + <a href="#" id="hide-button-<%= category.id %>" class="hide-button" onclick="return false;" data-category="<%= category.id %>" style="display: none;"><%= _('Hide') %></a>
  10 + <% end %>
11 11
12 <div> 12 <div>
13 <%= link_to _('Add subcategory'), :action => 'new', :parent_id => category %> 13 <%= link_to _('Add subcategory'), :action => 'new', :parent_id => category %>
@@ -16,12 +16,6 @@ @@ -16,12 +16,6 @@
16 </div> 16 </div>
17 </div> 17 </div>
18 18
19 - <div id="category_<%= category.id %>" style='display:none;'>  
20 - <% unless category.children.empty? %>  
21 - <ul class='tree'>  
22 - <%= render :partial => 'category', :collection => category.children %>  
23 - </ul>  
24 - <% end %>  
25 - </div> 19 +<ul id="category-sub-items-<%= category.id %>" class="tree" style='display:none;'></ul>
26 20
27 </li> 21 </li>
app/views/categories/_category_children.rhtml 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<% children.each do |category| %>
  2 + <%= render :partial => 'category', :locals => {:category => category} %>
  3 +<% end %>
app/views/categories/index.rhtml
@@ -25,3 +25,4 @@ @@ -25,3 +25,4 @@
25 <%= link_to _('New category'), :action => 'new', :type => 'Region' %> 25 <%= link_to _('New category'), :action => 'new', :type => 'Region' %>
26 </div> 26 </div>
27 27
  28 +<%= javascript_include_tag 'manage-categories' %>
app/views/cms/_blog.rhtml
@@ -50,7 +50,7 @@ @@ -50,7 +50,7 @@
50 %> 50 %>
51 </div> 51 </div>
52 52
53 -<%= labelled_form_field(_('Description:'), text_area(:article, :body, :cols => 64, :rows => 10)) %> 53 +<%= labelled_form_field(_('Description:'), text_area(:article, :body, :rows => 10)) %>
54 54
55 <%= labelled_form_field(_('How to display posts:'), f.select(:visualization_format, [ [ _('Full post'), 'full'], [ _('First paragraph'), 'short'] ])) %> 55 <%= labelled_form_field(_('How to display posts:'), f.select(:visualization_format, [ [ _('Full post'), 'full'], [ _('First paragraph'), 'short'] ])) %>
56 56
app/views/cms/_document_link.rhtml
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -<div id='media-listing-folder-documents' >  
2 - <ul>  
3 - <% documents.each do |document| %>  
4 - <li><%= link_to(document.name, document.view_url, :class => icon_for_article(document)) %></li>  
5 - <% end %>  
6 - </ul>  
7 - <div id='pagination-documents'>  
8 - <%= pagination_links documents, :param_name => 'dpage', :params => {:document_folder_id => params[:document_folder_id]} %>  
9 - </div>  
10 -</div>  
app/views/cms/_drag_and_drop_note.rhtml 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +<p>
  2 +<em><%= _('Drag images to add them to the text.') unless @article.is_a?(TextileArticle) %>
  3 +<%= _('Drag item names to the text to add links.') %></em>
  4 +</p>
app/views/cms/_image_thumb.rhtml
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -<div id='media-listing-folder-images' >  
2 - <ul>  
3 - <% images.each do |image| %>  
4 - <li><%= image_tag image.public_filename %></li>  
5 - <% end %>  
6 - </ul>  
7 - <div id='pagination-images'>  
8 - <%= pagination_links images, :param_name => 'ipage', :params => {:image_folder_id => params[:image_folder_id]} %>  
9 - </div>  
10 -</div>  
app/views/cms/_media_listing.rhtml
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -<iframe id='media-listing-iframe' src="<%= url_for(:controller => 'cms', :action => 'media_listing', :profile => profile.identifier, :type => @type) %>">  
2 - <p><%= _('Your browser does not support iframes.') %></p>  
3 -</iframe>