Commit d35779c07490f70c33e688afa945036e075a90f2
Exists in
master
and in
22 other branches
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.
.mailmap
... | ... | @@ -3,7 +3,8 @@ Antonio Terceiro <terceiro@colivre.coop.br> <terceiro@softwarelivre.org> |
3 | 3 | Aurelio A. Heckert <aurelio@colivre.coop.br> <AurelioAHeckert@3f533792-8f58-4932-b0fe-aaf55b0a4547> |
4 | 4 | Aurelio A. Heckert <aurelio@colivre.coop.br> <aurelio@colivre.coop.br> |
5 | 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 | 8 | Daniela Soares Feitosa <danielafeitosa@colivre.coop.br> <DanielaFeitosa@3f533792-8f58-4932-b0fe-aaf55b0a4547> |
8 | 9 | Daniela Soares Feitosa <danielafeitosa@colivre.coop.br> <danielafeitosa@colivre.coop.br> |
9 | 10 | Daniela Soares Feitosa <danielafeitosa@colivre.coop.br> <daniela@sede.colivre.coop.br> | ... | ... |
AUTHORS
... | ... | @@ -8,8 +8,9 @@ Developers |
8 | 8 | |
9 | 9 | Antonio Terceiro <terceiro@colivre.coop.br> |
10 | 10 | Aurelio A. Heckert <aurelio@colivre.coop.br> |
11 | +Braulio Bhavamitra <brauliobo@gmail.com> | |
11 | 12 | Bráulio Bhavamitra <brauliobo@gmail.com> |
12 | -Caio SBA <caiosba@gmail.com> | |
13 | +Caio SBA <caio@colivre.coop.br> | |
13 | 14 | Daniela Soares Feitosa <danielafeitosa@colivre.coop.br> |
14 | 15 | Daniel Cunha <daniel@colivre.coop.br> |
15 | 16 | Fernanda Lopes <nanda.listas+psl@gmail.com> |
... | ... | @@ -23,6 +24,7 @@ LinguÁgil 2010 <linguagil.bahia@gmail.com> |
23 | 24 | Martín Olivera <molivera@solar.org.ar> |
24 | 25 | Moises Machado <moises@colivre.coop.br> |
25 | 26 | Nanda Lopes <nanda.listas+psl@gmail.com> |
27 | +Rafael Gomes <rafaelgomes@techfree.com.br> | |
26 | 28 | Raphaël Rousseau <raph@r4f.org> |
27 | 29 | Raquel Lira <raquel.lira@gmail.com> |
28 | 30 | Rodrigo Souto <rodrigo@colivre.coop.br> | ... | ... |
HACKING
... | ... | @@ -31,11 +31,13 @@ You can copy and paste the commands below into a terminal (please review the |
31 | 31 | commands and make sure you understand what you are doing): |
32 | 32 | |
33 | 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 | 35 | # enter the directory |
36 | 36 | cd noosfero |
37 | 37 | # copy a sample config file |
38 | 38 | cp config/database.yml.sqlite3 config/database.yml |
39 | + # create tmp directory if it doesn't exist | |
40 | + mkdir tmp | |
39 | 41 | # create the development database |
40 | 42 | rake db:schema:load |
41 | 43 | # run pending migrations |
... | ... | @@ -59,8 +61,8 @@ another port than 3000, you can use the -p option of ./script/server: |
59 | 61 | |
60 | 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 | 67 | Note that some operations, like generating image thumbnails, sending e-mails, |
66 | 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 | 86 | |
85 | 87 | 3) Add in config/noosfero.yml at development section: |
86 | 88 | exception_recipients: [admin@example.com] |
89 | + | |
90 | +== Releasing and building Debian package | |
91 | + | |
92 | +See RELEASING file. | ... | ... |
INSTALL
... | ... | @@ -43,6 +43,9 @@ case will need do install hicolor-icon-theme as well bacause tango-icon-theme |
43 | 43 | depends on it. After that you can try the command line above again, but |
44 | 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 | 49 | If you manage to install Noosfero successfully on other systems than Debian, |
47 | 50 | please feel free to contact the Noosfero development mailing with the |
48 | 51 | instructions for doing so, and we'll include it here. |
... | ... | @@ -98,7 +101,7 @@ downloading from git |
98 | 101 | Here we are cloning the noosfero repository from git. Note: you will need to |
99 | 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 | 105 | $ cd current |
103 | 106 | $ git checkout -b stable origin/stable |
104 | 107 | ... | ... |
INSTALL.chat
... | ... | @@ -221,16 +221,19 @@ Note: module proxy_http must be enabled: |
221 | 221 | |
222 | 222 | # a2enmod proxy_http |
223 | 223 | |
224 | - | |
225 | 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 | 230 | _xmpp-client._tcp SRV 5 100 5222 master |
230 | -(...) | |
231 | 231 | conference CNAME master |
232 | 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 | 238 | 9. Testing this Setup |
236 | 239 | ... | ... |
... | ... | @@ -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 | 50 | |
51 | 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 | 66 | include "/var/lib/noosfero/etc/noosfero/varnish-accept-language.vcl"; |
59 | 67 | |
60 | -6b) Restart Varnish | |
68 | +7) Restart Varnish | |
61 | 69 | |
62 | 70 | # invoke-rc.d varnish restart |
63 | 71 | ... | ... |
RELEASING
... | ... | @@ -12,28 +12,28 @@ This file documents release-related activities. |
12 | 12 | |
13 | 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 | 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 | 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 | 38 | If you had any problem during these steps, you can do <tt>rake clobber_package</tt> to |
37 | 39 | completely delete the generated packages and start the process again. |
38 | - | |
39 | - | ... | ... |
app/controllers/admin/admin_panel_controller.rb
1 | 1 | class AdminPanelController < AdminController |
2 | 2 | |
3 | - before_filter :login_required | |
4 | - | |
5 | 3 | protect 'view_environment_admin_panel', :environment |
6 | 4 | |
7 | 5 | def boxes_holder |
... | ... | @@ -11,6 +9,7 @@ class AdminPanelController < AdminController |
11 | 9 | def site_info |
12 | 10 | if request.post? |
13 | 11 | if @environment.update_attributes(params[:environment]) |
12 | + session[:notice] = _('Environment settings updated') | |
14 | 13 | redirect_to :action => 'index' |
15 | 14 | end |
16 | 15 | end | ... | ... |
app/controllers/admin/categories_controller.rb
... | ... | @@ -10,11 +10,16 @@ class CategoriesController < AdminController |
10 | 10 | @product_categories = environment.product_categories.find(:all, :conditions => {:parent_id => nil}) |
11 | 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 | 18 | ALLOWED_TYPES = CategoriesHelper::TYPES.map {|item| item[1] } |
14 | 19 | |
15 | 20 | # posts back |
16 | 21 | def new |
17 | - type = (params[:type] || 'Category') | |
22 | + type = (params[:type] || params[:parent_type] || 'Category') | |
18 | 23 | raise 'Type not allowed' unless ALLOWED_TYPES.include?(type) |
19 | 24 | |
20 | 25 | @category = type.constantize.new(params[:category]) | ... | ... |
app/controllers/admin/plugins_controller.rb
app/controllers/admin/role_controller.rb
... | ... | @@ -9,21 +9,6 @@ class RoleController < AdminController |
9 | 9 | @role = environment.roles.find(params[:id]) |
10 | 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 | 12 | def edit |
28 | 13 | @role = environment.roles.find(params[:id]) |
29 | 14 | end |
... | ... | @@ -38,13 +23,4 @@ class RoleController < AdminController |
38 | 23 | end |
39 | 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 | 26 | end | ... | ... |
app/controllers/admin_controller.rb
app/controllers/box_organizer_controller.rb
... | ... | @@ -82,7 +82,7 @@ class BoxOrganizerController < ApplicationController |
82 | 82 | def save |
83 | 83 | @block = boxes_holder.blocks.find(params[:id]) |
84 | 84 | @block.update_attributes(params[:block]) |
85 | - expire_timeout_fragment(@block.cache_keys) | |
85 | + expire_timeout_fragment(@block.cache_key) | |
86 | 86 | redirect_to :action => 'index' |
87 | 87 | end |
88 | 88 | |
... | ... | @@ -93,7 +93,7 @@ class BoxOrganizerController < ApplicationController |
93 | 93 | def remove |
94 | 94 | @block = Block.find(params[:id]) |
95 | 95 | if @block.destroy |
96 | - expire_timeout_fragment(@block.cache_keys) | |
96 | + expire_timeout_fragment(@block.cache_key) | |
97 | 97 | redirect_to :action => 'index' |
98 | 98 | else |
99 | 99 | session[:notice] = _('Failed to remove block') | ... | ... |
app/controllers/my_profile/cms_controller.rb
... | ... | @@ -43,6 +43,9 @@ class CmsController < MyProfileController |
43 | 43 | if @parent && @parent.blog? |
44 | 44 | articles -= Article.folder_types.map(&:constantize) |
45 | 45 | end |
46 | + if user.is_admin?(profile.environment) | |
47 | + articles << RawHTMLArticle | |
48 | + end | |
46 | 49 | articles |
47 | 50 | end |
48 | 51 | |
... | ... | @@ -168,8 +171,7 @@ class CmsController < MyProfileController |
168 | 171 | @article = @parent = check_parent(params[:parent_id]) |
169 | 172 | @target = @parent ? ('/%s/%s' % [profile.identifier, @parent.full_name]) : '/%s' % profile.identifier |
170 | 173 | @folders = Folder.find(:all, :conditions => { :profile_id => profile }) |
171 | - @media_listing = params[:media_listing] | |
172 | - if @article && !@media_listing | |
174 | + if @article | |
173 | 175 | record_coming |
174 | 176 | end |
175 | 177 | if request.post? && params[:uploaded_files] |
... | ... | @@ -178,26 +180,14 @@ class CmsController < MyProfileController |
178 | 180 | end |
179 | 181 | @errors = @uploaded_files.select { |f| f.errors.any? } |
180 | 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 | 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 | 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 | 191 | end |
202 | 192 | end |
203 | 193 | end |
... | ... | @@ -286,44 +276,28 @@ class CmsController < MyProfileController |
286 | 276 | @task = SuggestArticle.new(params[:task]) |
287 | 277 | if request.post? |
288 | 278 | @task.target = profile |
289 | - if @task.save | |
279 | + if verify_recaptcha(:model => @task, :message => _('Please type the words correctly')) && @task.save | |
290 | 280 | session[:notice] = _('Thanks for your suggestion. The community administrators were notified.') |
291 | 281 | redirect_to @back_to |
292 | 282 | end |
293 | 283 | end |
294 | 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 | 299 | end |
300 | + render :text => article_list_to_json(files_uploaded), :content_type => 'text/plain' | |
327 | 301 | end |
328 | 302 | |
329 | 303 | protected |
... | ... | @@ -353,7 +327,7 @@ class CmsController < MyProfileController |
353 | 327 | end |
354 | 328 | |
355 | 329 | def refuse_blocks |
356 | - if ['TinyMceArticle', 'Event', 'EnterpriseHomepage'].include?(@type) | |
330 | + if ['TinyMceArticle', 'TextileArticle', 'Event', 'EnterpriseHomepage'].include?(@type) | |
357 | 331 | @no_design_blocks = true |
358 | 332 | end |
359 | 333 | end |
... | ... | @@ -367,5 +341,21 @@ class CmsController < MyProfileController |
367 | 341 | @selected_locale = @article.language || FastGettext.locale |
368 | 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 | 360 | end |
371 | 361 | ... | ... |
app/controllers/my_profile/manage_products_controller.rb
... | ... | @@ -4,6 +4,7 @@ class ManageProductsController < ApplicationController |
4 | 4 | protect 'manage_products', :profile, :except => [:show] |
5 | 5 | before_filter :check_environment_feature |
6 | 6 | before_filter :login_required, :except => [:show] |
7 | + before_filter :create_product?, :only => [:new] | |
7 | 8 | |
8 | 9 | protected |
9 | 10 | |
... | ... | @@ -14,6 +15,13 @@ class ManageProductsController < ApplicationController |
14 | 15 | end |
15 | 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 | 25 | public |
18 | 26 | |
19 | 27 | def index |
... | ... | @@ -40,8 +48,8 @@ class ManageProductsController < ApplicationController |
40 | 48 | end |
41 | 49 | |
42 | 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 | 53 | @categories = ProductCategory.top_level_for(environment) |
46 | 54 | @level = 0 |
47 | 55 | if request.post? |
... | ... | @@ -50,7 +58,7 @@ class ManageProductsController < ApplicationController |
50 | 58 | render :partial => 'shared/redirect_via_javascript', |
51 | 59 | :locals => { :url => url_for(:controller => 'manage_products', :action => 'show', :id => @product) } |
52 | 60 | else |
53 | - render :partial => 'shared/dialog_error_messages', :locals => { :object_name => 'product' } | |
61 | + render_dialog_error_messages 'product' | |
54 | 62 | end |
55 | 63 | end |
56 | 64 | end |
... | ... | @@ -72,7 +80,7 @@ class ManageProductsController < ApplicationController |
72 | 80 | |
73 | 81 | def edit_category |
74 | 82 | @product = @profile.products.find(params[:id]) |
75 | - @category = @product.product_category | |
83 | + @category = @product.product_category || ProductCategory.first | |
76 | 84 | @categories = ProductCategory.top_level_for(environment) |
77 | 85 | @edit = true |
78 | 86 | @level = @category.level |
... | ... | @@ -81,7 +89,7 @@ class ManageProductsController < ApplicationController |
81 | 89 | render :partial => 'shared/redirect_via_javascript', |
82 | 90 | :locals => { :url => url_for(:controller => 'manage_products', :action => 'show', :id => @product) } |
83 | 91 | else |
84 | - render :partial => 'shared/dialog_error_messages', :locals => { :object_name => 'product' } | |
92 | + render_dialog_error_messages 'product' | |
85 | 93 | end |
86 | 94 | end |
87 | 95 | end |
... | ... | @@ -96,7 +104,7 @@ class ManageProductsController < ApplicationController |
96 | 104 | @inputs = @product.inputs |
97 | 105 | render :partial => 'display_inputs' |
98 | 106 | else |
99 | - render :partial => 'shared/dialog_error_messages', :locals => { :object_name => 'product' } | |
107 | + render_dialog_error_messages 'product' | |
100 | 108 | end |
101 | 109 | else |
102 | 110 | render :partial => 'add_input' |
... | ... | @@ -147,7 +155,7 @@ class ManageProductsController < ApplicationController |
147 | 155 | @inputs = @product.inputs |
148 | 156 | render :partial => 'display_inputs' |
149 | 157 | else |
150 | - render :partial => 'shared/dialog_error_messages', :locals => { :object_name => 'input' } | |
158 | + render_dialog_error_messages 'input' | |
151 | 159 | end |
152 | 160 | end |
153 | 161 | end | ... | ... |
app/controllers/my_profile/profile_design_controller.rb
... | ... | @@ -25,6 +25,7 @@ class ProfileDesignController < BoxOrganizerController |
25 | 25 | blocks << DisabledEnterpriseMessageBlock |
26 | 26 | blocks << HighlightsBlock |
27 | 27 | blocks << FeaturedProductsBlock |
28 | + blocks << FansBlock | |
28 | 29 | end |
29 | 30 | |
30 | 31 | # product block exclusive for enterprises in environments that permits it |
... | ... | @@ -37,6 +38,10 @@ class ProfileDesignController < BoxOrganizerController |
37 | 38 | blocks << BlogArchivesBlock |
38 | 39 | end |
39 | 40 | |
41 | + if user.is_admin?(profile.environment) | |
42 | + blocks << RawHTMLBlock | |
43 | + end | |
44 | + | |
40 | 45 | blocks |
41 | 46 | end |
42 | 47 | ... | ... |
app/controllers/my_profile/profile_editor_controller.rb
... | ... | @@ -4,7 +4,7 @@ class ProfileEditorController < MyProfileController |
4 | 4 | protect 'destroy_profile', :profile, :only => [:destroy_profile] |
5 | 5 | |
6 | 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 | 8 | end |
9 | 9 | |
10 | 10 | helper :profile | ... | ... |
app/controllers/my_profile/profile_members_controller.rb
1 | 1 | class ProfileMembersController < MyProfileController |
2 | 2 | protect 'manage_memberships', :profile |
3 | - no_design_blocks | |
4 | 3 | |
5 | 4 | def index |
6 | 5 | @members = profile.members |
... | ... | @@ -15,29 +14,25 @@ class ProfileMembersController < MyProfileController |
15 | 14 | rescue ActiveRecord::RecordNotFound |
16 | 15 | @person = nil |
17 | 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 | 22 | session[:notice] = _('Roles successfuly updated') |
23 | + redirect_to :controller => 'profile_editor' | |
23 | 24 | else |
24 | 25 | session[:notice] = _('Couldn\'t change the roles') |
26 | + redirect_to :action => 'index' | |
25 | 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 | 30 | end |
32 | 31 | end |
33 | - | |
32 | + | |
34 | 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 | 36 | end |
42 | 37 | |
43 | 38 | def add_role |
... | ... | @@ -90,6 +85,7 @@ class ProfileMembersController < MyProfileController |
90 | 85 | end |
91 | 86 | |
92 | 87 | def add_members |
88 | + @roles = Profile::Roles.organization_member_roles(environment.id) | |
93 | 89 | end |
94 | 90 | |
95 | 91 | def add_member |
... | ... | @@ -122,19 +118,42 @@ class ProfileMembersController < MyProfileController |
122 | 118 | render :layout => false |
123 | 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 | 156 | end |
137 | - render :layout => false | |
138 | 157 | end |
139 | 158 | |
140 | 159 | def send_mail | ... | ... |
app/controllers/my_profile/tasks_controller.rb
... | ... | @@ -3,12 +3,13 @@ class TasksController < MyProfileController |
3 | 3 | protect 'perform_task', :profile |
4 | 4 | |
5 | 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 | 8 | @failed = params ? params[:failed] : {} |
8 | 9 | end |
9 | 10 | |
10 | 11 | def processed |
11 | - @tasks = profile.all_finished_tasks.sort_by(&:created_at) | |
12 | + @tasks = Task.to(profile).finished.sort_by(&:created_at) | |
12 | 13 | end |
13 | 14 | |
14 | 15 | VALID_DECISIONS = [ 'finish', 'cancel', 'skip' ] | ... | ... |
app/controllers/public/account_controller.rb
... | ... | @@ -4,7 +4,6 @@ class AccountController < ApplicationController |
4 | 4 | |
5 | 5 | inverse_captcha :field => 'e_mail' |
6 | 6 | |
7 | - | |
8 | 7 | before_filter :login_required, :only => [:activation_question, :accept_terms, :activate_enterprise] |
9 | 8 | before_filter :redirect_if_logged_in, :only => [:login, :signup] |
10 | 9 | |
... | ... | @@ -15,6 +14,17 @@ class AccountController < ApplicationController |
15 | 14 | end |
16 | 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 | 28 | # action to perform login to the application |
19 | 29 | def login |
20 | 30 | @user = User.new |
... | ... | @@ -57,9 +67,8 @@ class AccountController < ApplicationController |
57 | 67 | @user.person_data = params[:profile_data] |
58 | 68 | @person = Person.new(params[:profile_data]) |
59 | 69 | @person.environment = @user.environment |
60 | - if request.post? && params[self.icaptcha_field].blank? | |
70 | + if request.post? | |
61 | 71 | @user.signup! |
62 | - self.current_user = @user | |
63 | 72 | owner_role = Role.find_by_name('owner') |
64 | 73 | @user.person.affiliate(@user.person, [owner_role]) if owner_role |
65 | 74 | invitation = Task.find_by_code(@invitation_code) |
... | ... | @@ -67,8 +76,7 @@ class AccountController < ApplicationController |
67 | 76 | invitation.update_attributes!({:friend => @user.person}) |
68 | 77 | invitation.finish |
69 | 78 | end |
70 | - session[:notice] = _("Thanks for signing up!") | |
71 | - go_to_initial_page if redirect? | |
79 | + @register_pending = true | |
72 | 80 | end |
73 | 81 | rescue ActiveRecord::RecordInvalid |
74 | 82 | @person.valid? |
... | ... | @@ -223,6 +231,8 @@ class AccountController < ApplicationController |
223 | 231 | session[:notice] = nil # consume the notice |
224 | 232 | end |
225 | 233 | |
234 | + @plugins.enabled_plugins.each { |plugin| user_data.merge!(plugin.user_data_extras) } | |
235 | + | |
226 | 236 | render :text => user_data.to_json, :layout => false, :content_type => "application/javascript" |
227 | 237 | end |
228 | 238 | ... | ... |
app/controllers/public/browse_controller.rb
... | ... | @@ -6,6 +6,8 @@ class BrowseController < PublicController |
6 | 6 | more_recent |
7 | 7 | more_active |
8 | 8 | more_popular |
9 | + more_comments | |
10 | + more_views | |
9 | 11 | ) |
10 | 12 | |
11 | 13 | def per_page |
... | ... | @@ -36,6 +38,18 @@ class BrowseController < PublicController |
36 | 38 | @results = @results.compact.paginate(:per_page => per_page, :page => params[:page]) |
37 | 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 | 53 | protected |
40 | 54 | |
41 | 55 | def filter |
... | ... | @@ -54,6 +68,9 @@ class BrowseController < PublicController |
54 | 68 | 'communities_more_recent' => _('More recent communities'), |
55 | 69 | 'communities_more_active' => _('More active communities'), |
56 | 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 | 74 | }[str] || str |
58 | 75 | end |
59 | 76 | ... | ... |
app/controllers/public/contact_controller.rb
... | ... | @@ -4,10 +4,9 @@ class ContactController < PublicController |
4 | 4 | |
5 | 5 | needs_profile |
6 | 6 | |
7 | - inverse_captcha :field => 'e_mail' | |
8 | 7 | def new |
9 | 8 | @contact |
10 | - if request.post? && params[self.icaptcha_field].blank? && params[:confirm] == 'true' | |
9 | + if request.post? && params[:confirm] == 'true' | |
11 | 10 | @contact = user.build_contact(profile, params[:contact]) |
12 | 11 | @contact.city = (!params[:city].blank? && City.exists?(params[:city])) ? City.find(params[:city]).name : nil |
13 | 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 < ApplicationController |
2 | 2 | |
3 | 3 | needs_profile |
4 | 4 | |
5 | - inverse_captcha :field => 'e_mail' | |
6 | - | |
7 | 5 | helper ProfileHelper |
8 | 6 | helper TagsHelper |
9 | 7 | |
... | ... | @@ -68,8 +66,13 @@ class ContentViewerController < ApplicationController |
68 | 66 | |
69 | 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 | 76 | end |
74 | 77 | |
75 | 78 | if request.post? && params[:remove_comment] |
... | ... | @@ -106,11 +109,10 @@ class ContentViewerController < ApplicationController |
106 | 109 | protected |
107 | 110 | |
108 | 111 | def add_comment |
109 | - @comment = Comment.new(params[:comment]) | |
110 | 112 | @comment.author = user if logged_in? |
111 | 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 | 116 | @comment = nil # clear the comment form |
115 | 117 | redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view] |
116 | 118 | else | ... | ... |
app/controllers/public/profile_controller.rb
... | ... | @@ -2,8 +2,8 @@ class ProfileController < PublicController |
2 | 2 | |
3 | 3 | needs_profile |
4 | 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 | 8 | helper TagsHelper |
9 | 9 | |
... | ... | @@ -44,7 +44,7 @@ class ProfileController < PublicController |
44 | 44 | tagged, |
45 | 45 | :title => _("%s's contents tagged with \"%s\"") % [profile.name, @tag], |
46 | 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 | 49 | render :text => data, :content_type => "text/xml" |
50 | 50 | end |
... | ... | @@ -71,6 +71,10 @@ class ProfileController < PublicController |
71 | 71 | end |
72 | 72 | end |
73 | 73 | |
74 | + def fans | |
75 | + @fans = profile.fans | |
76 | + end | |
77 | + | |
74 | 78 | def favorite_enterprises |
75 | 79 | @favorite_enterprises = profile.favorite_enterprises |
76 | 80 | end |
... | ... | @@ -96,7 +100,7 @@ class ProfileController < PublicController |
96 | 100 | if request.post? |
97 | 101 | profile.add_member(user) |
98 | 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 | 104 | else |
101 | 105 | if user.memberships.include?(profile) |
102 | 106 | session[:notice] = _('You are already a member of %s.') % profile.name |
... | ... | @@ -223,6 +227,52 @@ class ProfileController < PublicController |
223 | 227 | end |
224 | 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 | 276 | protected |
227 | 277 | |
228 | 278 | def check_access_to_profile |
... | ... | @@ -231,16 +281,16 @@ class ProfileController < PublicController |
231 | 281 | end |
232 | 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 | 287 | end |
238 | 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 | 292 | if back |
243 | - session[:before_join] = nil | |
293 | + session[:previous_location] = nil | |
244 | 294 | redirect_to back |
245 | 295 | else |
246 | 296 | redirect_to profile.url |
... | ... | @@ -259,7 +309,7 @@ class ProfileController < PublicController |
259 | 309 | end |
260 | 310 | |
261 | 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 | 313 | end |
264 | 314 | |
265 | 315 | def per_page | ... | ... |
app/helpers/application_helper.rb
... | ... | @@ -209,7 +209,11 @@ module ApplicationHelper |
209 | 209 | the_class << ' ' << html_options[:class] |
210 | 210 | end |
211 | 211 | the_title = html_options[:title] || label |
212 | - link_to(' '+content_tag('span', label), url, html_options.merge(:class => the_class, :title => the_title)) | |
212 | + if html_options[:disabled] | |
213 | + content_tag('a', ' '+content_tag('span', label), html_options.merge(:class => the_class, :title => the_title)) | |
214 | + else | |
215 | + link_to(' '+content_tag('span', label), url, html_options.merge(:class => the_class, :title => the_title)) | |
216 | + end | |
213 | 217 | end |
214 | 218 | |
215 | 219 | def button_to_function(type, label, js_code, html_options = {}, &block) |
... | ... | @@ -257,30 +261,59 @@ module ApplicationHelper |
257 | 261 | concat(content_tag('div', capture(&block) + tag('br', :style => 'clear: left;'), { :class => 'button-bar' }.merge(options))) |
258 | 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 | 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 | 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 | 281 | end |
282 | + | |
283 | + partial_for_class_in_view_path(klass.superclass, view_path) | |
271 | 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 | 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 | 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 | 314 | end |
315 | + | |
316 | + view_for_profile_actions(klass.superclass) | |
284 | 317 | end |
285 | 318 | |
286 | 319 | def user |
... | ... | @@ -556,17 +589,18 @@ module ApplicationHelper |
556 | 589 | |
557 | 590 | def gravatar_url_for(email, options = {}) |
558 | 591 | # Ta dando erro de roteamento |
592 | + default = theme_option['gravatar'] || NOOSFERO_CONF['gravatar'] || nil | |
559 | 593 | url_for( { :gravatar_id => Digest::MD5.hexdigest(email), |
560 | 594 | :host => 'www.gravatar.com', |
561 | 595 | :protocol => 'http://', |
562 | 596 | :only_path => false, |
563 | 597 | :controller => 'avatar.php', |
564 | - :d => NOOSFERO_CONF['gravatar'] ? NOOSFERO_CONF['gravatar'] : nil | |
598 | + :d => default | |
565 | 599 | }.merge(options) ) |
566 | 600 | end |
567 | 601 | |
568 | 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 | 604 | url = 'http://www.gravatar.com/avatar.php?gravatar_id=' + |
571 | 605 | Digest::MD5.hexdigest(email) |
572 | 606 | { |
... | ... | @@ -870,7 +904,7 @@ module ApplicationHelper |
870 | 904 | |
871 | 905 | def template_stylesheet_path |
872 | 906 | if profile.nil? |
873 | - '/designs/templates/default/stylesheets/style.css' | |
907 | + "/designs/templates/#{environment.layout_template}/stylesheets/style.css" | |
874 | 908 | else |
875 | 909 | "/designs/templates/#{profile.layout_template}/stylesheets/style.css" |
876 | 910 | end |
... | ... | @@ -947,8 +981,10 @@ module ApplicationHelper |
947 | 981 | 'thickbox', |
948 | 982 | 'lightbox', |
949 | 983 | 'colorpicker', |
984 | + colorbox_stylesheet_path, | |
950 | 985 | pngfix_stylesheet_path, |
951 | - ] | |
986 | + ] + | |
987 | + tokeninput_stylesheets | |
952 | 988 | end |
953 | 989 | |
954 | 990 | # DEPRECATED. Do not use this· |
... | ... | @@ -960,6 +996,14 @@ module ApplicationHelper |
960 | 996 | 'iepngfix/iepngfix.css' |
961 | 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 | 1007 | def noosfero_layout_features |
964 | 1008 | render :file => 'shared/noosfero_layout_features' |
965 | 1009 | end |
... | ... | @@ -975,7 +1019,10 @@ module ApplicationHelper |
975 | 1019 | def article_to_html(article, options = {}) |
976 | 1020 | options.merge!(:page => params[:npage]) |
977 | 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 | 1026 | content |
980 | 1027 | end |
981 | 1028 | |
... | ... | @@ -1083,6 +1130,17 @@ module ApplicationHelper |
1083 | 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 | 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 | 1144 | def pagination_links(collection, options={}) |
1087 | 1145 | options = {:prev_label => '« ' + _('Previous'), :next_label => _('Next') + ' »'}.merge(options) |
1088 | 1146 | will_paginate(collection, options) |
... | ... | @@ -1099,16 +1157,27 @@ module ApplicationHelper |
1099 | 1157 | result |
1100 | 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 | 1169 | def usermenu_logged_in |
1103 | 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 | 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 | 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 | 1181 | pending_tasks_count + |
1113 | 1182 | link_to('<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>', { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system")) |
1114 | 1183 | end |
... | ... | @@ -1206,4 +1275,39 @@ module ApplicationHelper |
1206 | 1275 | end |
1207 | 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 | 1313 | end | ... | ... |
app/helpers/boxes_helper.rb
... | ... | @@ -99,7 +99,9 @@ module BoxesHelper |
99 | 99 | unless block.visible? |
100 | 100 | options[:title] = _("This block is invisible. Your visitors will not see it.") |
101 | 101 | end |
102 | - | |
102 | + @controller.send(:content_editor?) || @plugins.enabled_plugins.each do |plugin| | |
103 | + result = plugin.parse_content(result) | |
104 | + end | |
103 | 105 | box_decorator.block_target(block.box, block) + |
104 | 106 | content_tag('div', |
105 | 107 | content_tag('div', | ... | ... |
app/helpers/catalog_helper.rb
... | ... | @@ -5,16 +5,24 @@ include ManageProductsHelper |
5 | 5 | |
6 | 6 | def display_products_list(profile, products) |
7 | 7 | data = '' |
8 | + extra_content = [] | |
9 | + extra_content_list = [] | |
8 | 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 | 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 | 15 | content_tag('h3', link_to_product(product)) + |
13 | 16 | content_tag('ul', |
14 | 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 | 26 | :class => 'product') |
19 | 27 | } |
20 | 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 | 22 | end |
23 | 23 | comments = '' |
24 | 24 | unless args[:no_comments] || !article.accept_comments |
25 | - comments = ("- %s") % link_to_comments(article) | |
25 | + comments = (" - %s") % link_to_comments(article) | |
26 | 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 | 33 | end |
29 | 34 | title |
30 | 35 | end |
... | ... | @@ -46,4 +51,21 @@ module ContentViewerHelper |
46 | 51 | end |
47 | 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 | 71 | end | ... | ... |
app/helpers/dates_helper.rb
... | ... | @@ -42,11 +42,11 @@ module DatesHelper |
42 | 42 | end |
43 | 43 | end |
44 | 44 | |
45 | - def show_period(date1, date2 = nil) | |
45 | + def show_period(date1, date2 = nil, use_numbers = false) | |
46 | 46 | if (date1 == date2) || (date2.nil?) |
47 | - show_date(date1) | |
47 | + show_date(date1, use_numbers) | |
48 | 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 | 50 | end |
51 | 51 | end |
52 | 52 | ... | ... |
app/helpers/display_helper.rb
... | ... | @@ -27,14 +27,18 @@ module DisplayHelper |
27 | 27 | end |
28 | 28 | |
29 | 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('​') | |
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('​') | |
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 | 42 | end |
39 | 43 | end |
40 | 44 | end | ... | ... |
app/helpers/events_helper.rb
... | ... | @@ -21,14 +21,13 @@ module EventsHelper |
21 | 21 | end |
22 | 22 | |
23 | 23 | def populate_calendar(selected_date, events) |
24 | + events.reject! {|event| !event.display_to?(user)} | |
24 | 25 | calendar = Event.date_range(selected_date.year, selected_date.month).map do |date| |
25 | 26 | [ |
26 | 27 | # the day itself |
27 | 28 | date, |
28 | 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 | 31 | # is this date in the current month? |
33 | 32 | true |
34 | 33 | ] | ... | ... |
app/helpers/profile_editor_helper.rb
... | ... | @@ -104,8 +104,8 @@ module ProfileEditorHelper |
104 | 104 | @country_helper ||= CountriesHelper.instance |
105 | 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 | 109 | end |
110 | 110 | |
111 | 111 | def select_schooling(object, method, options) | ... | ... |
app/helpers/sweeper_helper.rb
... | ... | @@ -22,7 +22,7 @@ module SweeperHelper |
22 | 22 | |
23 | 23 | # friends blocks |
24 | 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 | 26 | end |
27 | 27 | |
28 | 28 | def expire_communities(profile) |
... | ... | @@ -34,13 +34,13 @@ module SweeperHelper |
34 | 34 | |
35 | 35 | # communities block |
36 | 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 | 38 | end |
39 | 39 | |
40 | 40 | def expire_enterprises(profile) |
41 | 41 | # enterprises and favorite enterprises blocks |
42 | 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 | 44 | end |
45 | 45 | |
46 | 46 | def expire_profile_index(profile) | ... | ... |
app/helpers/tags_helper.rb
... | ... | @@ -28,7 +28,6 @@ module TagsHelper |
28 | 28 | # courtesy of Aurelio: http://www.colivre.coop.br/Aurium/Nuvem |
29 | 29 | # (pt_BR only). |
30 | 30 | def tag_cloud(tags, tagname_option, url, options = {}) |
31 | - | |
32 | 31 | |
33 | 32 | return content_tag('em', _('No tags yet.')) + |
34 | 33 | ' <a href="' + _('http://en.wikipedia.org/wiki/Tag_%28metadata%29') + |
... | ... | @@ -42,7 +41,7 @@ module TagsHelper |
42 | 41 | max = tags.values.max.to_f |
43 | 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 | 45 | if ( max == min ) |
47 | 46 | v = 0.5 |
48 | 47 | else | ... | ... |
... | ... | @@ -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 | ... | ... |
... | ... | @@ -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 < Task |
77 | 77 | true |
78 | 78 | end |
79 | 79 | |
80 | + def reject_details | |
81 | + true | |
82 | + end | |
83 | + | |
80 | 84 | def default_decision |
81 | 85 | if article |
82 | 86 | 'skip' |
... | ... | @@ -90,7 +94,11 @@ class ApproveArticle < Task |
90 | 94 | end |
91 | 95 | |
92 | 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 | 102 | end |
95 | 103 | |
96 | 104 | def target_notification_message |
... | ... | @@ -107,4 +115,11 @@ class ApproveArticle < Task |
107 | 115 | end |
108 | 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 | 125 | end | ... | ... |
app/models/article.rb
... | ... | @@ -188,6 +188,14 @@ class Article < ActiveRecord::Base |
188 | 188 | body || '' |
189 | 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 | 199 | # returns the data of the article. Must be overriden in each subclass to |
192 | 200 | # provide the correct content for the article. |
193 | 201 | def data |
... | ... | @@ -265,6 +273,10 @@ class Article < ActiveRecord::Base |
265 | 273 | false |
266 | 274 | end |
267 | 275 | |
276 | + def uploaded_file? | |
277 | + false | |
278 | + end | |
279 | + | |
268 | 280 | def has_posts? |
269 | 281 | false |
270 | 282 | end |
... | ... | @@ -343,11 +355,20 @@ class Article < ActiveRecord::Base |
343 | 355 | ['Folder', 'Blog', 'Forum', 'Gallery'] |
344 | 356 | end |
345 | 357 | |
358 | + def self.text_article_types | |
359 | + ['TextArticle', 'TextileArticle', 'TinyMceArticle'] | |
360 | + end | |
361 | + | |
346 | 362 | named_scope :published, :conditions => { :published => true } |
347 | 363 | named_scope :folders, :conditions => { :type => folder_types} |
348 | 364 | named_scope :no_folders, :conditions => ['type NOT IN (?)', folder_types] |
349 | 365 | named_scope :galleries, :conditions => { :type => 'Gallery' } |
350 | 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 | 373 | def self.display_filter(user, profile) |
353 | 374 | return {:conditions => ['published = ?', true]} if !user |
... | ... | @@ -509,6 +530,35 @@ class Article < ActiveRecord::Base |
509 | 530 | self.parent && self.parent.accept_uploads? |
510 | 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 | 562 | private |
513 | 563 | |
514 | 564 | def sanitize_tag_list | ... | ... |
app/models/block.rb
... | ... | @@ -34,6 +34,12 @@ class Block < ActiveRecord::Base |
34 | 34 | else |
35 | 35 | return context[:request_path] == '/' |
36 | 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 | 43 | end |
38 | 44 | end |
39 | 45 | true |
... | ... | @@ -45,6 +51,8 @@ class Block < ActiveRecord::Base |
45 | 51 | # * <tt>'never'</tt>: the block is hidden (it does not appear for visitors) |
46 | 52 | # * <tt>'home_page_only'</tt> the block is displayed only when viewing the |
47 | 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 | 56 | settings_items :display, :type => :string, :default => 'always' |
49 | 57 | |
50 | 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 < ActiveRecord::Base |
119 | 127 | true |
120 | 128 | end |
121 | 129 | |
122 | - def cache_keys | |
123 | - "block-id-#{id}" | |
124 | - end | |
125 | - | |
126 | 130 | def timeout |
127 | 131 | 4.hours |
128 | 132 | end | ... | ... |
app/models/blog.rb
app/models/comment.rb
... | ... | @@ -2,7 +2,7 @@ class Comment < ActiveRecord::Base |
2 | 2 | |
3 | 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 | 6 | belongs_to :article, :counter_cache => true |
7 | 7 | belongs_to :author, :class_name => 'Person', :foreign_key => 'author_id' |
8 | 8 | has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy |
... | ... | @@ -98,6 +98,16 @@ class Comment < ActiveRecord::Base |
98 | 98 | root |
99 | 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 | 111 | class Notifier < ActionMailer::Base |
102 | 112 | def mail(comment) |
103 | 113 | profile = comment.article.profile | ... | ... |
app/models/community.rb
app/models/contact.rb
... | ... | @@ -23,23 +23,26 @@ class Contact < ActiveRecord::Base #WithoutTable |
23 | 23 | |
24 | 24 | class Sender < ActionMailer::Base |
25 | 25 | def mail(contact) |
26 | + content_type 'text/html' | |
26 | 27 | emails = contact.dest.notification_emails |
27 | 28 | recipients emails |
28 | - from "#{contact.name} <#{contact.email}>" | |
29 | + from "#{contact.name} <#{contact.dest.environment.contact_email}>" | |
30 | + reply_to contact.email | |
29 | 31 | if contact.sender |
30 | 32 | headers 'X-Noosfero-Sender' => contact.sender.identifier |
31 | 33 | end |
32 | 34 | if contact.receive_a_copy |
33 | 35 | cc "#{contact.name} <#{contact.email}>" |
34 | 36 | end |
35 | - subject contact.subject | |
37 | + subject "[#{contact.dest.short_name(30)}] " + contact.subject | |
36 | 38 | body :name => contact.name, |
37 | 39 | :email => contact.email, |
38 | 40 | :city => contact.city, |
39 | 41 | :state => contact.state, |
40 | 42 | :message => contact.message, |
41 | 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 | 46 | end |
44 | 47 | end |
45 | 48 | ... | ... |
app/models/domain.rb
... | ... | @@ -10,7 +10,7 @@ class Domain < ActiveRecord::Base |
10 | 10 | |
11 | 11 | # <tt>name</tt> must be a sequence of word characters (a to z, plus 0 to 9, |
12 | 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 | 15 | # checks validations that could not be expressed using Rails' predefined |
16 | 16 | # validations. In particular: | ... | ... |
app/models/enterprise.rb
... | ... | @@ -7,6 +7,8 @@ class Enterprise < Organization |
7 | 7 | has_many :products, :dependent => :destroy, :order => 'name ASC' |
8 | 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 | 12 | extra_data_for_index :product_categories |
11 | 13 | |
12 | 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 < Organization |
145 | 147 | end |
146 | 148 | |
147 | 149 | before_create do |enterprise| |
150 | + enterprise.validated = enterprise.environment.enabled?('enterprises_are_validated_when_created') | |
148 | 151 | if enterprise.environment.enabled?('enterprises_are_disabled_when_created') |
149 | 152 | enterprise.enabled = false |
150 | 153 | end |
... | ... | @@ -165,4 +168,12 @@ class Enterprise < Organization |
165 | 168 | enable_contact_us |
166 | 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 | 179 | end | ... | ... |
app/models/environment.rb
... | ... | @@ -9,6 +9,13 @@ class Environment < ActiveRecord::Base |
9 | 9 | |
10 | 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 | 19 | PERMISSIONS['Environment'] = { |
13 | 20 | 'view_environment_admin_panel' => N_('View environment admin panel'), |
14 | 21 | 'edit_environment_features' => N_('Edit environment features'), |
... | ... | @@ -67,6 +74,10 @@ class Environment < ActiveRecord::Base |
67 | 74 | self.affiliate(user, Environment::Roles.admin(self.id)) |
68 | 75 | end |
69 | 76 | |
77 | + def remove_admin(user) | |
78 | + self.disaffiliate(user, Environment::Roles.admin(self.id)) | |
79 | + end | |
80 | + | |
70 | 81 | def admins |
71 | 82 | Person.members_of(self).all(:conditions => ['role_assignments.role_id = ?', Environment::Roles.admin(self).id]) |
72 | 83 | end |
... | ... | @@ -106,6 +117,7 @@ class Environment < ActiveRecord::Base |
106 | 117 | 'enable_organization_url_change' => _("Allow organizations to change their URL"), |
107 | 118 | 'admin_must_approve_new_communities' => _("Admin must approve creation of communities"), |
108 | 119 | 'enterprises_are_disabled_when_created' => __('Enterprises are disabled when created'), |
120 | + 'enterprises_are_validated_when_created' => __('Enterprises are validated when created'), | |
109 | 121 | 'show_balloon_with_profile_links_when_clicked' => _('Show a balloon with profile links when a profile image is clicked'), |
110 | 122 | 'xmpp_chat' => _('XMPP/Jabber based chat'), |
111 | 123 | 'show_zoom_button_on_article_images' => _('Show a zoom link on all article images') |
... | ... | @@ -218,7 +230,19 @@ class Environment < ActiveRecord::Base |
218 | 230 | settings_items :currency_separator, :type => String, :default => '.' |
219 | 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 | 247 | settings_items :enabled_plugins, :type => Array, :default => [] |
224 | 248 | |
... | ... | @@ -228,17 +252,28 @@ class Environment < ActiveRecord::Base |
228 | 252 | |
229 | 253 | # Enables a feature identified by its name |
230 | 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 | 262 | end |
233 | 263 | |
234 | 264 | # Disables a feature identified by its name |
235 | 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 | 272 | end |
238 | 273 | |
239 | 274 | # Tells if a feature, identified by its name, is enabled |
240 | 275 | def enabled?(feature) |
241 | - self.settings["#{feature}_enabled"] == true | |
276 | + self.settings["#{feature}_enabled".to_sym] == true | |
242 | 277 | end |
243 | 278 | |
244 | 279 | # enables the features identified by <tt>features</tt>, which is expected to |
... | ... | @@ -494,6 +529,7 @@ class Environment < ActiveRecord::Base |
494 | 529 | xss_terminate :only => [ :message_for_disabled_enterprise ], :with => 'white_list', :on => 'validation' |
495 | 530 | |
496 | 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 | 534 | include WhiteListFilter |
499 | 535 | filter_iframes :message_for_disabled_enterprise, :whitelist => lambda { trusted_sites_for_iframe } |
... | ... | @@ -517,12 +553,12 @@ class Environment < ActiveRecord::Base |
517 | 553 | # If #force_www is true, adds 'www.' at the beginning of the hostname. If the |
518 | 554 | # environment has not associated domains, returns 'localhost'. |
519 | 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 | 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 | 560 | end |
561 | + domain | |
526 | 562 | end |
527 | 563 | |
528 | 564 | def top_url |
... | ... | @@ -671,13 +707,14 @@ class Environment < ActiveRecord::Base |
671 | 707 | def create_templates |
672 | 708 | pre = self.name.to_slug + '_' |
673 | 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 | 711 | com_id = Community.create!(:name => 'Community template', :identifier => pre + 'community_template', :environment => self, :visible => false).id |
675 | 712 | pass = Digest::MD5.hexdigest rand.to_s |
676 | 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 | 715 | usr_id = user.id |
680 | 716 | self.settings[:enterprise_template_id] = ent_id |
717 | + self.inactive_enterprise_template = inactive_enterprise_tmpl | |
681 | 718 | self.settings[:community_template_id] = com_id |
682 | 719 | self.settings[:person_template_id] = usr_id |
683 | 720 | self.save! |
... | ... | @@ -685,7 +722,7 @@ class Environment < ActiveRecord::Base |
685 | 722 | |
686 | 723 | after_destroy :destroy_templates |
687 | 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 | 726 | template.destroy |
690 | 727 | end |
691 | 728 | end |
... | ... | @@ -701,6 +738,4 @@ class Environment < ActiveRecord::Base |
701 | 738 | def image_galleries |
702 | 739 | portal_community ? portal_community.image_galleries : [] |
703 | 740 | end |
704 | - | |
705 | 741 | end |
706 | - | ... | ... |
... | ... | @@ -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 < Article |
29 | 29 | def to_html(options = {}) |
30 | 30 | folder = self |
31 | 31 | lambda do |
32 | - render :file => 'content_viewer/folder', :locals => { :folder => folder } | |
32 | + render :file => 'content_viewer/folder', :locals => {:folder => folder} | |
33 | 33 | end |
34 | 34 | end |
35 | 35 | ... | ... |
app/models/image.rb
1 | 1 | class Image < ActiveRecord::Base |
2 | - belongs_to :owner, :polymorphic => true | |
3 | 2 | |
4 | 3 | def self.max_size |
5 | 4 | Image.attachment_options[:max_size] |
6 | 5 | end |
7 | 6 | |
7 | + sanitize_filename | |
8 | + | |
8 | 9 | has_attachment :content_type => :image, |
9 | 10 | :storage => :file_system, |
10 | 11 | :path_prefix => 'public/image_uploads', |
... | ... | @@ -20,4 +21,6 @@ class Image < ActiveRecord::Base |
20 | 21 | |
21 | 22 | delay_attachment_fu_thumbnails |
22 | 23 | |
24 | + postgresql_attachment_fu | |
25 | + | |
23 | 26 | end | ... | ... |
app/models/invitation.rb
app/models/invite_friend.rb
app/models/link_list_block.rb
... | ... | @@ -57,7 +57,7 @@ class LinkListBlock < Block |
57 | 57 | def link_html(link) |
58 | 58 | klass = 'icon-' + link[:icon] if link[:icon] |
59 | 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 | 62 | end |
63 | 63 | ... | ... |
app/models/organization.rb
... | ... | @@ -95,12 +95,12 @@ class Organization < Profile |
95 | 95 | [] |
96 | 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 | 101 | validates_format_of :foundation_year, :with => Noosfero::Constants::INTEGER_FORMAT |
102 | - | |
103 | 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 | 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 < Profile |
149 | 149 | false |
150 | 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 | 160 | end | ... | ... |
app/models/person.rb
... | ... | @@ -17,6 +17,8 @@ class Person < Profile |
17 | 17 | |
18 | 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 | 22 | has_many :mailings |
21 | 23 | |
22 | 24 | has_many :scraps_sent, :class_name => 'Scrap', :foreign_key => :sender_id, :dependent => :destroy |
... | ... | @@ -116,6 +118,8 @@ class Person < Profile |
116 | 118 | description |
117 | 119 | ] |
118 | 120 | |
121 | + validates_multiparameter_assignments | |
122 | + | |
119 | 123 | def self.fields |
120 | 124 | FIELDS |
121 | 125 | end |
... | ... | @@ -387,6 +391,21 @@ class Person < Profile |
387 | 391 | leave_hash.to_json |
388 | 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 | 409 | protected |
391 | 410 | |
392 | 411 | def followed_by?(profile) | ... | ... |
app/models/product.rb
... | ... | @@ -66,7 +66,7 @@ class Product < ActiveRecord::Base |
66 | 66 | end |
67 | 67 | |
68 | 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 | 70 | end |
71 | 71 | |
72 | 72 | def category_full_name |
... | ... | @@ -149,4 +149,8 @@ class Product < ActiveRecord::Base |
149 | 149 | unit.blank? ? name : "#{name} - #{unit.name.downcase}" |
150 | 150 | end |
151 | 151 | |
152 | + def display_supplier_on_search? | |
153 | + true | |
154 | + end | |
155 | + | |
152 | 156 | end | ... | ... |
app/models/products_block.rb
... | ... | @@ -20,7 +20,15 @@ class ProductsBlock < Block |
20 | 20 | block_title(title) + |
21 | 21 | content_tag( |
22 | 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 | 33 | end |
26 | 34 | ... | ... |
app/models/profile.rb
... | ... | @@ -52,8 +52,9 @@ class Profile < ActiveRecord::Base |
52 | 52 | acts_as_accessible |
53 | 53 | |
54 | 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 | 59 | def members |
59 | 60 | Person.members_of(self) |
... | ... | @@ -163,34 +164,19 @@ class Profile < ActiveRecord::Base |
163 | 164 | |
164 | 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 | 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 | 172 | end |
188 | - return nil | |
189 | 173 | end |
190 | 174 | |
191 | 175 | has_many :profile_categorizations, :conditions => [ 'categories_profiles.virtual = ?', false ] |
192 | 176 | has_many :categories, :through => :profile_categorizations |
193 | 177 | |
178 | + has_many :abuse_complaints, :foreign_key => 'requestor_id' | |
179 | + | |
194 | 180 | def interests |
195 | 181 | categories.select {|item| !item.is_a?(Region)} |
196 | 182 | end |
... | ... | @@ -564,9 +550,7 @@ private :generate_url, :url_options |
564 | 550 | if self.closed? && members_count > 0 |
565 | 551 | AddMember.create!(:person => person, :organization => self) unless self.already_request_membership?(person) |
566 | 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 | 554 | self.affiliate(person, Profile::Roles.member(environment.id)) |
571 | 555 | end |
572 | 556 | else |
... | ... | @@ -809,6 +793,34 @@ private :generate_url, :url_options |
809 | 793 | "#{jid(options)}/#{short_name}" |
810 | 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 | 824 | protected |
813 | 825 | |
814 | 826 | def followed_by?(person) | ... | ... |
app/models/profile_list_block.rb
1 | 1 | class ProfileListBlock < Block |
2 | 2 | |
3 | 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 | 6 | def self.description |
7 | 7 | _('Random profiles') |
... | ... | @@ -13,21 +13,21 @@ class ProfileListBlock < Block |
13 | 13 | end |
14 | 14 | |
15 | 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 | 25 | end |
18 | 26 | |
19 | 27 | def profile_count |
20 | 28 | profiles.visible.count('DISTINCT(profiles.id)') |
21 | 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 | 31 | # the title of the block. Probably will be overriden in subclasses. |
32 | 32 | def default_title |
33 | 33 | _('{#} People or Groups') | ... | ... |
app/models/suggest_article.rb
app/models/task.rb
... | ... | @@ -20,11 +20,14 @@ class Task < ActiveRecord::Base |
20 | 20 | # the status of a task that was cancelled. |
21 | 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 | 24 | FINISHED = 3 |
25 | 25 | |
26 | + # the status of a task that was created but is not displayed yet | |
27 | + HIDDEN = 4 | |
28 | + | |
26 | 29 | def self.names |
27 | - [nil, N_('Active'), N_('Cancelled'), N_('Finished')] | |
30 | + [nil, N_('Active'), N_('Cancelled'), N_('Finished'), N_('Hidden')] | |
28 | 31 | end |
29 | 32 | end |
30 | 33 | |
... | ... | @@ -38,7 +41,7 @@ class Task < ActiveRecord::Base |
38 | 41 | |
39 | 42 | def initialize(*args) |
40 | 43 | super |
41 | - self.status ||= Task::Status::ACTIVE | |
44 | + self.status = (args.first ? args.first[:status] : nil) || Task::Status::ACTIVE | |
42 | 45 | end |
43 | 46 | |
44 | 47 | attr_accessor :code_length |
... | ... | @@ -52,20 +55,26 @@ class Task < ActiveRecord::Base |
52 | 55 | end |
53 | 56 | |
54 | 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 | 71 | end |
67 | 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 | 78 | # this method finished the task. It calls #perform, which must be overriden |
70 | 79 | # by subclasses. At the end a message (as returned by #finish_message) is |
71 | 80 | # sent to the requestor with #notify_requestor. |
... | ... | @@ -175,6 +184,12 @@ class Task < ActiveRecord::Base |
175 | 184 | raise NotImplementedError, "#{self} does not implement #task_cancelled_message" |
176 | 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 | 193 | # The message that will be sent to the *target* of the task when it is |
179 | 194 | # created. The indent of this message is to notify the target about the |
180 | 195 | # request that was just created for him/her. |
... | ... | @@ -199,6 +214,23 @@ class Task < ActiveRecord::Base |
199 | 214 | self.target.environment unless self.target.nil? |
200 | 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 | 234 | protected |
203 | 235 | |
204 | 236 | # This method must be overrided in subclasses, and its implementation must do |
... | ... | @@ -232,6 +264,23 @@ class Task < ActiveRecord::Base |
232 | 264 | |
233 | 265 | named_scope :pending, :conditions => { :status => Task::Status::ACTIVE } |
234 | 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 | 285 | class << self |
237 | 286 | |
... | ... | @@ -254,6 +303,10 @@ class Task < ActiveRecord::Base |
254 | 303 | self.find(:first, :conditions => { :code => code, :status => Task::Status::ACTIVE }) |
255 | 304 | end |
256 | 305 | |
306 | + def per_page | |
307 | + 15 | |
308 | + end | |
309 | + | |
257 | 310 | end |
258 | 311 | |
259 | 312 | end | ... | ... |
app/models/text_article.rb
app/models/textile_article.rb
... | ... | @@ -9,11 +9,28 @@ class TextileArticle < TextArticle |
9 | 9 | end |
10 | 10 | |
11 | 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 | 21 | end |
14 | 22 | |
15 | 23 | def notifiable? |
16 | 24 | true |
17 | 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 | 36 | end | ... | ... |
app/models/thumbnail.rb
app/models/ticket.rb
app/models/uploaded_file.rb
... | ... | @@ -18,6 +18,8 @@ class UploadedFile < Article |
18 | 18 | |
19 | 19 | validates_size_of :title, :maximum => 60, :if => (lambda { |file| !file.title.blank? }) |
20 | 20 | |
21 | + sanitize_filename | |
22 | + | |
21 | 23 | before_create do |uploaded_file| |
22 | 24 | uploaded_file.is_image = true if uploaded_file.image? |
23 | 25 | end |
... | ... | @@ -52,6 +54,8 @@ class UploadedFile < Article |
52 | 54 | |
53 | 55 | delay_attachment_fu_thumbnails |
54 | 56 | |
57 | + postgresql_attachment_fu | |
58 | + | |
55 | 59 | def self.icon_name(article = nil) |
56 | 60 | if article |
57 | 61 | article.image? ? article.public_filename(:icon) : (article.mime_type ? article.mime_type.gsub(/[\/+.]/, '-') : 'upload-file') |
... | ... | @@ -132,4 +136,8 @@ class UploadedFile < Article |
132 | 136 | def gallery? |
133 | 137 | self.parent && self.parent.folder? && self.parent.gallery? |
134 | 138 | end |
139 | + | |
140 | + def uploaded_file? | |
141 | + true | |
142 | + end | |
135 | 143 | end | ... | ... |
app/models/user.rb
... | ... | @@ -21,6 +21,8 @@ class User < ActiveRecord::Base |
21 | 21 | end |
22 | 22 | end |
23 | 23 | |
24 | + before_create :make_activation_code | |
25 | + | |
24 | 26 | before_create do |user| |
25 | 27 | if user.environment.nil? |
26 | 28 | user.environment = Environment.default |
... | ... | @@ -31,8 +33,11 @@ class User < ActiveRecord::Base |
31 | 33 | user.person ||= Person.new |
32 | 34 | user.person.attributes = user.person_data.merge(:identifier => user.login, :user_id => user.id, :environment_id => user.environment_id) |
33 | 35 | user.person.name ||= user.login |
36 | + user.person.visible = false unless user.activated? | |
34 | 37 | user.person.save! |
35 | 38 | end |
39 | + after_create :deliver_activation_code | |
40 | + after_create :delay_activation_check | |
36 | 41 | |
37 | 42 | attr_writer :person_data |
38 | 43 | def person_data |
... | ... | @@ -55,6 +60,17 @@ class User < ActiveRecord::Base |
55 | 60 | :environment => user.environment.name, |
56 | 61 | :url => url_for(:host => user.environment.default_hostname, :controller => 'home') |
57 | 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 | 74 | end |
59 | 75 | |
60 | 76 | def signup! |
... | ... | @@ -67,6 +83,8 @@ class User < ActiveRecord::Base |
67 | 83 | has_one :person, :dependent => :destroy |
68 | 84 | belongs_to :environment |
69 | 85 | |
86 | + attr_protected :activated_at | |
87 | + | |
70 | 88 | # Virtual attribute for the unencrypted password |
71 | 89 | attr_accessor :password |
72 | 90 | |
... | ... | @@ -87,10 +105,22 @@ class User < ActiveRecord::Base |
87 | 105 | # Authenticates a user by their login name and unencrypted password. Returns the user or nil. |
88 | 106 | def self.authenticate(login, password, environment = nil) |
89 | 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 | 109 | u && u.authenticated?(password) ? u : nil |
92 | 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 | 124 | class UnsupportedEncryptionType < Exception; end |
95 | 125 | |
96 | 126 | def self.system_encryption_method |
... | ... | @@ -195,7 +225,7 @@ class User < ActiveRecord::Base |
195 | 225 | end |
196 | 226 | |
197 | 227 | def name |
198 | - person.name | |
228 | + person ? person.name : login | |
199 | 229 | end |
200 | 230 | |
201 | 231 | def enable_email! |
... | ... | @@ -253,4 +283,16 @@ class User < ActiveRecord::Base |
253 | 283 | def password_required? |
254 | 284 | crypted_password.blank? || !password.blank? |
255 | 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 | 298 | end | ... | ... |
app/sweepers/article_sweeper.rb
... | ... | @@ -21,7 +21,7 @@ protected |
21 | 21 | blocks = article.profile.blocks |
22 | 22 | blocks += article.profile.environment.blocks if article.profile.environment |
23 | 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 | 25 | env = article.profile.environment |
26 | 26 | if env && (env.portal_community == article.profile) |
27 | 27 | expire_fragment(env.portal_news_cache_key) | ... | ... |
app/sweepers/friendship_sweeper.rb
app/sweepers/profile_sweeper.rb
... | ... | @@ -23,12 +23,25 @@ protected |
23 | 23 | expire_profile_index(profile) if profile.person? |
24 | 24 | |
25 | 25 | profile.blocks.each do |block| |
26 | - expire_timeout_fragment(block.cache_keys) | |
26 | + expire_timeout_fragment(block.cache_key) | |
27 | 27 | end |
28 | + | |
29 | + expire_blogs(profile) if profile.organization? | |
28 | 30 | end |
29 | 31 | |
30 | 32 | def expire_statistics_block_cache(profile) |
31 | 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 | 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 | 47 | end | ... | ... |
app/sweepers/role_assignment_sweeper.rb
... | ... | @@ -25,7 +25,7 @@ protected |
25 | 25 | |
26 | 26 | profile.blocks_to_expire_cache.each { |block| |
27 | 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 | 30 | end |
31 | 31 | ... | ... |
app/views/account/_signup_form.rhtml
app/views/account/login.rhtml
... | ... | @@ -5,9 +5,11 @@ |
5 | 5 | <% @user ||= User.new %> |
6 | 6 | <% is_thickbox ||= false %> |
7 | 7 | |
8 | +<%= @message %> | |
9 | + | |
8 | 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 | 14 | <%= f.password_field :password %> |
13 | 15 | ... | ... |
app/views/account/signup.rhtml
1 | 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 | 1 | <h1><%= _('Edit Templates') %></h1> |
2 | 2 | |
3 | 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 | 10 | </ul> | ... | ... |
app/views/admin_panel/index.rhtml
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | <p><%= _('You, as an environment administrator, has the following options:')%></p> |
4 | 4 | |
5 | 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 | 7 | <tr><td><%= link_to __('Edit message for disabled enterprises'), :action => 'message_for_disabled_enterprise' %></td></tr> |
8 | 8 | <tr><td><%= link_to _('Enable/disable features'), :controller => 'features' %></td></tr> |
9 | 9 | <tr><td><%= link_to _('Enable/disable plugins'), :controller => 'plugins' %></td></tr> |
... | ... | @@ -16,4 +16,7 @@ |
16 | 16 | <tr><td><%= link_to _('Manage Fields'), :controller => 'features', :action => 'manage_fields' %></td></tr> |
17 | 17 | <tr><td><%= link_to _('Set Portal'), :action => 'set_portal_community' %></td></tr> |
18 | 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 | 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 | 10 | <%= labelled_form_field _('Homepage content'), text_area(:environment, :description, :cols => 40, :style => 'width: 90%', :class => 'mceEditor') %> |
10 | 11 | |
11 | 12 | <% button_bar do %> |
12 | - <%= submit_button(:save, _('Save')) %> | |
13 | - <%= button(:cancel, _('Cancel'), :action => 'index') %> | |
13 | + <%= submit_button(:save, _('Save'), :cancel => {:action => 'index'}) %> | |
14 | 14 | <% end %> |
15 | - | |
16 | 15 | <% end %> | ... | ... |
app/views/blocks/my_network.rhtml
... | ... | @@ -6,7 +6,7 @@ |
6 | 6 | <li><%= link_to(__('Homepage'), owner.url, :class => 'url') %></li> |
7 | 7 | <li><%= link_to(_('View profile'), owner.public_profile_url) %></li> |
8 | 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 | 10 | <% end %> |
11 | 11 | </ul> |
12 | 12 | ... | ... |
app/views/blocks/profile_image.rhtml
... | ... | @@ -20,5 +20,5 @@ |
20 | 20 | |
21 | 21 | </div><!-- end class="vcard" --> |
22 | 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 | 24 | </script> | ... | ... |
app/views/blocks/profile_info.rhtml
... | ... | @@ -41,5 +41,5 @@ |
41 | 41 | |
42 | 42 | </div><!-- end class="vcard" --> |
43 | 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 | 45 | </script> | ... | ... |
app/views/blocks/profile_info_actions/community.rhtml
1 | 1 | <ul> |
2 | 2 | <% if logged_in? %> |
3 | - | |
4 | 3 | <% if profile.members.include?(user) %> |
5 | 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 | 13 | </li> |
9 | 14 | <% else %> |
10 | 15 | <% unless profile.already_request_membership?(user) %> |
11 | 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 | 25 | </li> |
15 | 26 | <% end %> |
16 | 27 | <% end %> |
28 | + | |
17 | 29 | <% if profile.enable_contact? %> |
18 | 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 | 36 | </li> |
21 | 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 | 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 | 47 | </li> |
29 | - | |
30 | 48 | <% end %> |
31 | 49 | </ul> | ... | ... |
app/views/blocks/profile_info_actions/enterprise.rhtml
... | ... | @@ -7,4 +7,6 @@ |
7 | 7 | <% if profile.enable_contact? %> |
8 | 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 | 9 | <% end %> |
10 | + | |
11 | + <li><%= report_abuse(profile, :button) %></li> | |
10 | 12 | </ul> | ... | ... |
app/views/blocks/profile_info_actions/person.rhtml
... | ... | @@ -11,5 +11,6 @@ |
11 | 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 | 12 | <% end %> |
13 | 13 | |
14 | + <li><%= report_abuse(profile, :button) %></li> | |
14 | 15 | <% end %> |
15 | 16 | </ul> | ... | ... |
app/views/box_organizer/_article_block.rhtml
... | ... | @@ -5,6 +5,6 @@ |
5 | 5 | </p> |
6 | 6 | <% else %> |
7 | 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 | 9 | <% end %> |
10 | 10 | </div> | ... | ... |
app/views/box_organizer/edit.rhtml
... | ... | @@ -14,6 +14,9 @@ |
14 | 14 | <%= radio_button(:block, :display, 'home_page_only') %> |
15 | 15 | <%= label_tag('block_display_home_page_only', _('Only in the homepage')) %> |
16 | 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 | 20 | <%= radio_button(:block, :display, 'never') %> |
18 | 21 | <%= label_tag('block_display_never', _("Don't display")) %> |
19 | 22 | </div> | ... | ... |
... | ... | @@ -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 | 8 | <% end %> |
9 | 9 | <ul class='common-profile-list-block'> |
10 | 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 | 12 | <% end %> |
13 | 13 | </ul> |
14 | 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/categories/_category.rhtml
... | ... | @@ -2,12 +2,12 @@ |
2 | 2 | <div class='treeitem'> |
3 | 3 | <%= display_color_for_category(category) %> |
4 | 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 | 12 | <div> |
13 | 13 | <%= link_to _('Add subcategory'), :action => 'new', :parent_id => category %> |
... | ... | @@ -16,12 +16,6 @@ |
16 | 16 | </div> |
17 | 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 | 21 | </li> | ... | ... |
app/views/categories/index.rhtml
app/views/cms/_blog.rhtml
... | ... | @@ -50,7 +50,7 @@ |
50 | 50 | %> |
51 | 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 | 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 | -<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/_image_thumb.rhtml
... | ... | @@ -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