Commit d0aadb3e84a74ebe9313dd04845088b95d2be2ac

Authored by Rodrigo Souto
2 parents 51314a6f f4012a36

Merge branch 'master' into custom-forms

Showing 331 changed files with 14300 additions and 8252 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 331 files displayed.

AUTHORS
... ... @@ -22,6 +22,7 @@ Diego Araújo <diegoamc90@gmail.com>
22 22 Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com>
23 23 Fernanda Lopes <nanda.listas+psl@gmail.com>
24 24 Grazieno Pellegrino <grazieno@gmail.com>
  25 +Isaac Canan <isaac@intelletto.com.br>
25 26 Italo Valcy <italo@dcc.ufba.br>
26 27 João da Silva <jaodsilv@linux.ime.usp.br>
27 28 João M. M. da Silva + Carlos Morais <jaodsilv@linux.ime.usp.br>
... ...
INSTALL.varnish
... ... @@ -15,6 +15,10 @@ Noosfero was tested with Varnish 2.x. If you are using a Debian Lenny (and you
15 15 should, unless Debian already released Squeeze by now), make sure you install
16 16 varnish from the lenny-backports suite.
17 17  
  18 +Install the RPAF apache module (or skip this step if not using apache):
  19 +
  20 + # apt-get install libapache2-mod-rpaf
  21 +
18 22 3) Enable varnish logging:
19 23  
20 24 3a) Edit /etc/default/varnishncsa and uncomment the line that contains:
... ...
app/controllers/admin/licenses_controller.rb 0 → 100644
... ... @@ -0,0 +1,50 @@
  1 +class LicensesController < AdminController
  2 + protect 'manage_environment_licenses', :environment
  3 +
  4 + def index
  5 + @licenses = environment.licenses
  6 + end
  7 +
  8 + def create
  9 + @license = License.new(params[:license])
  10 + if request.post?
  11 + begin
  12 + @license.environment = environment
  13 + @license.save!
  14 + session[:notice] = _('License created')
  15 + redirect_to :action => 'index'
  16 + rescue
  17 + session[:notice] = _('License could not be created')
  18 + end
  19 + end
  20 + end
  21 +
  22 + def edit
  23 + @license = environment.licenses.find(params[:license_id])
  24 + if request.post?
  25 + begin
  26 + @license.update_attributes!(params[:license])
  27 + session[:notice] = _('License updated')
  28 + redirect_to :action => 'index'
  29 + rescue
  30 + session[:notice] = _('License could not be updated')
  31 + end
  32 + end
  33 + end
  34 +
  35 + def remove
  36 + @license = environment.licenses.find(params[:license_id])
  37 + if request.post?
  38 + begin
  39 + @license.destroy
  40 + session[:notice] = _('License removed')
  41 + rescue
  42 + session[:notice] = _('License could not be removed')
  43 + end
  44 + else
  45 + session[:notice] = _('License could not be removed')
  46 + end
  47 + redirect_to :action => 'index'
  48 + end
  49 +
  50 +end
... ...
app/controllers/admin/templates_controller.rb 0 → 100644
... ... @@ -0,0 +1,52 @@
  1 +class TemplatesController < AdminController
  2 + protect 'manage_environment_templates', :environment
  3 +
  4 + def create_person_template
  5 + if request.post?
  6 + begin
  7 + identifier = params[:name].to_slug
  8 + password = Digest::MD5.hexdigest(rand.to_s)
  9 + template = User.new(:login => identifier, :email => identifier+'@templates.noo', :password => password, :password_confirmation => password, :person_data => {:name => params[:name], :is_template => true})
  10 + template.save!
  11 + session[:notice] = _('New template created')
  12 + redirect_to :action => 'index'
  13 + rescue
  14 + @error = _('Name has already been taken')
  15 + end
  16 + end
  17 + end
  18 +
  19 + def create_community_template
  20 + if request.post?
  21 + begin
  22 + create_organization_template(Community)
  23 + session[:notice] = _('New template created')
  24 + redirect_to :action => 'index'
  25 + rescue
  26 + @error = _('Name has already been taken')
  27 + end
  28 + end
  29 + end
  30 +
  31 + def create_enterprise_template
  32 + if request.post?
  33 + begin
  34 + create_organization_template(Enterprise)
  35 + session[:notice] = _('New template created')
  36 + redirect_to :action => 'index'
  37 + rescue
  38 + @error = _('Name has already been taken')
  39 + end
  40 + end
  41 + end
  42 +
  43 + private
  44 +
  45 + def create_organization_template(klass)
  46 + identifier = params[:name].to_slug
  47 + template = klass.new(:name => params[:name], :identifier => identifier, :is_template => true)
  48 + template.save!
  49 + end
  50 +
  51 +end
  52 +
... ...
app/controllers/application_controller.rb
1 1 class ApplicationController < ActionController::Base
2 2  
3 3 before_filter :setup_multitenancy
  4 + before_filter :detect_stuff_by_domain
  5 + before_filter :init_noosfero_plugins
4 6  
5 7 include ApplicationHelper
6 8 layout :get_layout
... ... @@ -51,8 +53,6 @@ class ApplicationController &lt; ActionController::Base
51 53  
52 54 include NeedsProfile
53 55  
54   - before_filter :detect_stuff_by_domain
55   - before_filter :init_noosfero_plugins
56 56 attr_reader :environment
57 57  
58 58 before_filter :load_terminology
... ...
app/controllers/public/content_viewer_controller.rb
... ... @@ -19,7 +19,7 @@ class ContentViewerController &lt; ApplicationController
19 19 unless @page
20 20 page_from_old_path = profile.articles.find_by_old_path(path)
21 21 if page_from_old_path
22   - redirect_to :profile => profile.identifier, :page => page_from_old_path.explode_path
  22 + redirect_to profile.url.merge(:page => page_from_old_path.explode_path)
23 23 return
24 24 end
25 25 end
... ... @@ -99,6 +99,14 @@ class ContentViewerController &lt; ApplicationController
99 99 @images = @images.paginate(:per_page => per_page, :page => params[:npage]) unless params[:slideshow]
100 100 end
101 101  
  102 + @unfollow_form = params[:unfollow] && params[:unfollow] == 'true'
  103 + if params[:unfollow] && params[:unfollow] == 'commit' && request.post?
  104 + @page.followers -= [params[:email]]
  105 + if @page.save
  106 + session[:notice] = _("Notification of new comments to '%s' was successfully canceled") % params[:email]
  107 + end
  108 + end
  109 +
102 110 @comments = @page.comments(true).as_thread
103 111 @comments_count = @page.comments.count
104 112 if params[:slideshow]
... ...
app/controllers/public/search_controller.rb
... ... @@ -4,10 +4,17 @@ class SearchController &lt; PublicController
4 4 include SearchHelper
5 5 include ActionView::Helpers::NumberHelper
6 6  
  7 + before_filter :redirect_asset_param, :except => [:facets_browse, :assets]
7 8 before_filter :load_category
8 9 before_filter :load_search_assets
9 10 before_filter :load_query
10 11  
  12 + # Backwards compatibility with old URLs
  13 + def redirect_asset_param
  14 + return unless params.has_key?(:asset)
  15 + redirect_to params.merge(:action => params.delete(:asset))
  16 + end
  17 +
11 18 no_design_blocks
12 19  
13 20 def facets_browse
... ... @@ -243,17 +250,16 @@ class SearchController &lt; PublicController
243 250 @searching = {}
244 251 @titles = {}
245 252 @enabled_searches.each do |key, name|
246   - @titles[key] = name
  253 + @titles[key] = _(name)
247 254 @searching[key] = params[:action] == 'index' || params[:action] == key.to_s
248 255 end
249 256 @names = @titles if @names.nil?
250 257 end
251 258  
252 259 def limit
253   - searching = @searching.values.select{ |v| v }
254   - if params[:display] == 'map'
  260 + if map_search?
255 261 MAP_SEARCH_LIMIT
256   - elsif searching.size <= 1
  262 + elsif !multiple_search?
257 263 if [:people, :communities].include? @asset
258 264 BLOCKS_SEARCH_LIMIT
259 265 elsif @asset == :enterprises and @empty_query
... ... @@ -267,31 +273,34 @@ class SearchController &lt; PublicController
267 273 end
268 274  
269 275 def paginate_options(page = params[:page])
  276 + page = 1 if multiple_search? or params[:display] == 'map'
270 277 { :per_page => limit, :page => page }
271 278 end
272 279  
273 280 def full_text_search(filters = [], options = {})
274 281 paginate_options = paginate_options(params[:page])
275 282 asset_class = asset_class(@asset)
276   -
277 283 solr_options = options
278   - if !@results_only and asset_class.respond_to? :facets
279   - solr_options.merge! asset_class.facets_find_options(params[:facet])
280   - solr_options[:all_facets] = true
281   - solr_options[:limit] = 0 if @facets_only
282   - end
283   - solr_options[:filter_queries] ||= []
284   - solr_options[:filter_queries] += filters
285   - solr_options[:filter_queries] << "environment_id:#{environment.id}"
286   - solr_options[:filter_queries] << asset_class.facet_category_query.call(@category) if @category
287   -
288   - solr_options[:boost_functions] ||= []
289   - params[:order_by] = nil if params[:order_by] == 'none'
290   - if params[:order_by]
291   - order = SortOptions[@asset][params[:order_by].to_sym]
292   - raise "Unknown order by" if order.nil?
293   - order[:solr_opts].each do |opt, value|
294   - solr_options[opt] = value.is_a?(Proc) ? instance_eval(&value) : value
  284 + pg_options = paginate_options(params[:page])
  285 +
  286 + if !multiple_search?
  287 + if !@results_only and asset_class.respond_to? :facets
  288 + solr_options.merge! asset_class.facets_find_options(params[:facet])
  289 + solr_options[:all_facets] = true
  290 + end
  291 + solr_options[:filter_queries] ||= []
  292 + solr_options[:filter_queries] += filters
  293 + solr_options[:filter_queries] << "environment_id:#{environment.id}"
  294 + solr_options[:filter_queries] << asset_class.facet_category_query.call(@category) if @category
  295 +
  296 + solr_options[:boost_functions] ||= []
  297 + params[:order_by] = nil if params[:order_by] == 'none'
  298 + if params[:order_by]
  299 + order = SortOptions[@asset][params[:order_by].to_sym]
  300 + raise "Unknown order by" if order.nil?
  301 + order[:solr_opts].each do |opt, value|
  302 + solr_options[opt] = value.is_a?(Proc) ? instance_eval(&value) : value
  303 + end
295 304 end
296 305 end
297 306  
... ...
app/helpers/application_helper.rb
... ... @@ -10,6 +10,8 @@ module ApplicationHelper
10 10  
11 11 include ThickboxHelper
12 12  
  13 + include ColorboxHelper
  14 +
13 15 include BoxesHelper
14 16  
15 17 include FormsHelper
... ... @@ -1076,24 +1078,24 @@ module ApplicationHelper
1076 1078  
1077 1079 def search_contents_menu
1078 1080 links = [
1079   - {s_('contents|More Recent') => {:href => url_for({:controller => 'search', :action => 'contents', :filter => 'more_recent'})}},
1080   - {s_('contents|More Viewed') => {:href => url_for({:controller => 'search', :action => 'contents', :filter => 'more_popular'})}},
1081   - {s_('contents|Most Commented') => {:href => url_for({:controller => 'search', :action => 'contents', :filter => 'more_comments'})}}
  1081 + {s_('contents|More recent') => {:href => url_for({:controller => 'search', :action => 'contents', :filter => 'more_recent'})}},
  1082 + {s_('contents|More viewed') => {:href => url_for({:controller => 'search', :action => 'contents', :filter => 'more_popular'})}},
  1083 + {s_('contents|Most commented') => {:href => url_for({:controller => 'search', :action => 'contents', :filter => 'more_comments'})}}
1082 1084 ]
1083 1085 if logged_in?
1084   - links.push(_('New Content') => lightbox_options({:href => url_for({:controller => 'cms', :action => 'new', :profile => current_user.login, :cms => true})}))
  1086 + links.push(_('New content') => colorbox_options({:href => url_for({:controller => 'cms', :action => 'new', :profile => current_user.login, :cms => true})}))
1085 1087 end
1086 1088  
1087 1089 link_to(content_tag(:span, _('Contents'), :class => 'icon-menu-articles'), {:controller => "search", :action => 'contents', :category_path => ''}, :id => 'submenu-contents') +
1088   - link_to(content_tag(:span, _('Contents Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-contents-trigger')
  1090 + link_to(content_tag(:span, _('Contents menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-contents-trigger')
1089 1091 end
1090 1092 alias :browse_contents_menu :search_contents_menu
1091 1093  
1092 1094 def search_people_menu
1093 1095 links = [
1094   - {s_('people|More Recent') => {:href => url_for({:controller => 'search', :action => 'people', :filter => 'more_recent'})}},
1095   - {s_('people|More Active') => {:href => url_for({:controller => 'search', :action => 'people', :filter => 'more_active'})}},
1096   - {s_('people|More Popular') => {:href => url_for({:controller => 'search', :action => 'people', :filter => 'more_popular'})}}
  1096 + {s_('people|More recent') => {:href => url_for({:controller => 'search', :action => 'people', :filter => 'more_recent'})}},
  1097 + {s_('people|More active') => {:href => url_for({:controller => 'search', :action => 'people', :filter => 'more_active'})}},
  1098 + {s_('people|More popular') => {:href => url_for({:controller => 'search', :action => 'people', :filter => 'more_popular'})}}
1097 1099 ]
1098 1100 if logged_in?
1099 1101 links.push(_('My friends') => {:href => url_for({:profile => current_user.login, :controller => 'friends'})})
... ... @@ -1101,15 +1103,15 @@ module ApplicationHelper
1101 1103 end
1102 1104  
1103 1105 link_to(content_tag(:span, _('People'), :class => 'icon-menu-people'), {:controller => "search", :action => 'people', :category_path => ''}, :id => 'submenu-people') +
1104   - link_to(content_tag(:span, _('People Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-people-trigger')
  1106 + link_to(content_tag(:span, _('People menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-people-trigger')
1105 1107 end
1106 1108 alias :browse_people_menu :search_people_menu
1107 1109  
1108 1110 def search_communities_menu
1109 1111 links = [
1110   - {s_('communities|More Recent') => {:href => url_for({:controller => 'search', :action => 'communities', :filter => 'more_recent'})}},
1111   - {s_('communities|More Active') => {:href => url_for({:controller => 'search', :action => 'communities', :filter => 'more_active'})}},
1112   - {s_('communities|More Popular') => {:href => url_for({:controller => 'search', :action => 'communities', :filter => 'more_popular'})}}
  1112 + {s_('communities|More recent') => {:href => url_for({:controller => 'search', :action => 'communities', :filter => 'more_recent'})}},
  1113 + {s_('communities|More active') => {:href => url_for({:controller => 'search', :action => 'communities', :filter => 'more_active'})}},
  1114 + {s_('communities|More popular') => {:href => url_for({:controller => 'search', :action => 'communities', :filter => 'more_popular'})}}
1113 1115 ]
1114 1116 if logged_in?
1115 1117 links.push(_('My communities') => {:href => url_for({:profile => current_user.login, :controller => 'memberships'})})
... ... @@ -1117,7 +1119,7 @@ module ApplicationHelper
1117 1119 end
1118 1120  
1119 1121 link_to(content_tag(:span, _('Communities'), :class => 'icon-menu-community'), {:controller => "search", :action => 'communities'}, :id => 'submenu-communities') +
1120   - link_to(content_tag(:span, _('Communities Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-communities-trigger')
  1122 + link_to(content_tag(:span, _('Communities menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-communities-trigger')
1121 1123 end
1122 1124 alias :browse_communities_menu :search_communities_menu
1123 1125  
... ... @@ -1170,6 +1172,10 @@ module ApplicationHelper
1170 1172 ], :class => 'limited-text-area')
1171 1173 end
1172 1174  
  1175 + def expandable_text_area(object_name, method, text_area_id, options = {})
  1176 + text_area(object_name, method, { :id => text_area_id, :onkeyup => "grow_text_area('#{text_area_id}')" }.merge(options))
  1177 + end
  1178 +
1173 1179 def pluralize_without_count(count, singular, plural = nil)
1174 1180 count == 1 ? singular : (plural || singular.pluralize)
1175 1181 end
... ... @@ -1318,4 +1324,70 @@ module ApplicationHelper
1318 1324 _("Are you sure that you want to remove the item \"#{article.name}\"?")
1319 1325 end
1320 1326 end
  1327 +
  1328 + def template_options(klass, field_name)
  1329 + return '' if klass.templates.count == 0
  1330 + return hidden_field_tag("#{field_name}[template_id]", klass.templates.first.id) if klass.templates.count == 1
  1331 +
  1332 + counter = 0
  1333 + radios = klass.templates.map do |template|
  1334 + counter += 1
  1335 + content_tag('li', labelled_radio_button(template.name, "#{field_name}[template_id]", template.id, counter==1))
  1336 + end.join("\n")
  1337 +
  1338 + content_tag('div', content_tag('span', _('Template:')) +
  1339 + content_tag('ul', radios, :style => 'list-style: none; padding-left: 0; margin-top: 0.5em;'),
  1340 + :id => 'template-options',
  1341 + :style => 'margin-top: 1em'
  1342 + )
  1343 + end
  1344 +
  1345 + def token_input_field_tag(name, element_id, search_action, options = {}, text_field_options = {}, html_options = {})
  1346 + options[:min_chars] ||= 3
  1347 + options[:hint_text] ||= _("Type in a search term")
  1348 + options[:no_results_text] ||= _("No results")
  1349 + options[:searching_text] ||= _("Searching...")
  1350 + options[:search_delay] ||= 1000
  1351 + options[:prevent_duplicates] ||= true
  1352 + options[:backspace_delete_item] ||= false
  1353 + options[:focus] ||= false
  1354 + options[:avoid_enter] ||= true
  1355 + options[:on_result] ||= 'null'
  1356 + options[:on_add] ||= 'null'
  1357 + options[:on_delete] ||= 'null'
  1358 + options[:on_ready] ||= 'null'
  1359 +
  1360 + result = text_field_tag(name, nil, text_field_options.merge(html_options.merge({:id => element_id})))
  1361 + result +=
  1362 + "
  1363 + <script type='text/javascript'>
  1364 + jQuery('##{element_id}')
  1365 + .tokenInput('#{url_for(search_action)}', {
  1366 + minChars: #{options[:min_chars].to_json},
  1367 + prePopulate: #{options[:pre_populate].to_json},
  1368 + hintText: #{options[:hint_text].to_json},
  1369 + noResultsText: #{options[:no_results_text].to_json},
  1370 + searchingText: #{options[:searching_text].to_json},
  1371 + searchDelay: #{options[:serach_delay].to_json},
  1372 + preventDuplicates: #{options[:prevent_duplicates].to_json},
  1373 + backspaceDeleteItem: #{options[:backspace_delete_item].to_json},
  1374 + queryParam: #{name.to_json},
  1375 + tokenLimit: #{options[:token_limit].to_json},
  1376 + onResult: #{options[:on_result]},
  1377 + onAdd: #{options[:on_add]},
  1378 + onDelete: #{options[:on_delete]},
  1379 + onReady: #{options[:on_ready]},
  1380 + })
  1381 + "
  1382 + result += options[:focus] ? ".focus();" : ";"
  1383 + if options[:avoid_enter]
  1384 + result += "jQuery('#token-input-#{element_id}')
  1385 + .live('keydown', function(event){
  1386 + if(event.keyCode == '13') return false;
  1387 + });"
  1388 + end
  1389 + result += "</script>"
  1390 + result
  1391 + end
  1392 +
1321 1393 end
... ...
app/helpers/colorbox_helper.rb 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +module ColorboxHelper
  2 +
  3 + def colorbox_close_button(text, options = {})
  4 + button(:close, text, '#', colorbox_options(options, :close))
  5 + end
  6 +
  7 + def colorbox_button(type, label, url, options = {})
  8 + button(type, label, url, colorbox_options(options))
  9 + end
  10 +
  11 + # options must be an HTML options hash as passed to link_to etc.
  12 + #
  13 + # returns a new hash with colorbox class added. Keeps existing classes.
  14 + def colorbox_options(options, type=nil)
  15 + the_class = 'colorbox'
  16 + the_class += "-#{type.to_s}" unless type.nil?
  17 + the_class << " #{options[:class]}" if options.has_key?(:class)
  18 + options.merge(:class => the_class)
  19 + end
  20 +
  21 +end
... ...
app/helpers/search_helper.rb
... ... @@ -18,7 +18,7 @@ module SearchHelper
18 18  
19 19 SortOptions = {
20 20 :products => ActiveSupport::OrderedHash[ :none, {:label => _('Relevance')},
21   - :more_recent, {:label => _('More Recent'), :solr_opts => {:sort => 'updated_at desc, score desc'}},
  21 + :more_recent, {:label => _('More recent'), :solr_opts => {:sort => 'updated_at desc, score desc'}},
22 22 :name, {:label => _('Name'), :solr_opts => {:sort => 'name_sortable asc'}},
23 23 :closest, {:label => _('Closest to me'), :if => proc{ logged_in? && (profile=current_user.person).lat && profile.lng },
24 24 :solr_opts => {:sort => "geodist() asc",
... ... @@ -45,6 +45,14 @@ module SearchHelper
45 45 # FIXME remove it after search_controler refactored
46 46 include EventsHelper
47 47  
  48 + def multiple_search?
  49 + ['index', 'category_index'].include?(params[:action]) or @results.size > 1
  50 + end
  51 +
  52 + def map_search?
  53 + !@query.blank? and !multiple_search? and params[:display] == 'map'
  54 + end
  55 +
48 56 def search_page_title(title, category = nil)
49 57 title = "<h1>" + title
50 58 title += '<small>' + category.name + '</small>' if category
... ... @@ -58,8 +66,8 @@ module SearchHelper
58 66 :align => 'center', :class => 'search-category-context') if category
59 67 end
60 68  
61   - def display_results(use_map = false)
62   - if params[:display] == 'map' && use_map
  69 + def display_results(map_capable = false)
  70 + if map_capable and map_search?
63 71 partial = 'google_maps'
64 72 klass = 'map'
65 73 else
... ...
app/models/article.rb
... ... @@ -34,9 +34,12 @@ class Article &lt; ActiveRecord::Base
34 34 settings_items :display_hits, :type => :boolean, :default => true
35 35 settings_items :author_name, :type => :string, :default => ""
36 36 settings_items :allow_members_to_edit, :type => :boolean, :default => false
  37 + settings_items :followers, :type => Array, :default => []
37 38  
38 39 belongs_to :reference_article, :class_name => "Article", :foreign_key => 'reference_article_id'
39 40  
  41 + belongs_to :license
  42 +
40 43 has_many :translations, :class_name => 'Article', :foreign_key => :translation_of_id
41 44 belongs_to :translation_of, :class_name => 'Article', :foreign_key => :translation_of_id
42 45 before_destroy :rotate_translations
... ... @@ -51,6 +54,11 @@ class Article &lt; ActiveRecord::Base
51 54 end
52 55 end
53 56  
  57 + after_destroy :destroy_activity
  58 + def destroy_activity
  59 + self.activity.destroy if self.activity
  60 + end
  61 +
54 62 xss_terminate :only => [ :name ], :on => 'validation', :with => 'white_list'
55 63  
56 64 named_scope :in_category, lambda { |category|
... ...
app/models/comment.rb
... ... @@ -75,11 +75,30 @@ class Comment &lt; ActiveRecord::Base
75 75 article.comments_updated if article.kind_of?(Article)
76 76 end
77 77  
78   - after_create do |comment|
79   - if comment.source.kind_of?(Article) && comment.article.notify_comments? && !comment.article.profile.notification_emails.empty?
80   - Comment::Notifier.deliver_mail(comment)
  78 + after_create :new_follower
  79 + def new_follower
  80 + if source.kind_of?(Article)
  81 + article.followers += [author_email]
  82 + article.followers -= article.profile.notification_emails
  83 + article.followers.uniq!
  84 + article.save
  85 + end
  86 + end
  87 +
  88 + after_create :notify_by_mail
  89 + def notify_by_mail
  90 + if source.kind_of?(Article) && article.notify_comments?
  91 + if !article.profile.notification_emails.empty?
  92 + Comment::Notifier.deliver_mail(self)
  93 + end
  94 + emails = article.followers - [author_email]
  95 + if !emails.empty?
  96 + Comment::Notifier.deliver_mail_to_followers(self, emails)
  97 + end
81 98 end
  99 + end
82 100  
  101 + after_create do |comment|
83 102 if comment.source.kind_of?(Article)
84 103 comment.article.create_activity if comment.article.activity.nil?
85 104 if comment.article.activity
... ... @@ -138,6 +157,22 @@ class Comment &lt; ActiveRecord::Base
138 157 :environment => profile.environment.name,
139 158 :url => profile.environment.top_url
140 159 end
  160 + def mail_to_followers(comment, emails)
  161 + profile = comment.article.profile
  162 + bcc emails
  163 + from "#{profile.environment.name} <#{profile.environment.contact_email}>"
  164 + subject _("[%s] %s commented on a content of %s") % [profile.environment.name, comment.author_name, profile.short_name]
  165 + body :recipient => profile.nickname || profile.name,
  166 + :sender => comment.author_name,
  167 + :sender_link => comment.author_link,
  168 + :article_title => comment.article.name,
  169 + :comment_url => comment.url,
  170 + :unsubscribe_url => comment.article.view_url.merge({:unfollow => true}),
  171 + :comment_title => comment.title,
  172 + :comment_body => comment.body,
  173 + :environment => profile.environment.name,
  174 + :url => profile.environment.top_url
  175 + end
141 176 end
142 177  
143 178 def rejected?
... ...
app/models/community.rb
... ... @@ -61,10 +61,10 @@ class Community &lt; Organization
61 61  
62 62 def name=(value)
63 63 super(value)
64   - self.identifier = value.to_slug
  64 + self.identifier ||= value.to_slug
65 65 end
66 66  
67   - def template
  67 + def default_template
68 68 environment.community_template
69 69 end
70 70  
... ... @@ -88,7 +88,7 @@ class Community &lt; Organization
88 88 end
89 89  
90 90 def activities
91   - Scrap.find_by_sql("SELECT id, updated_at, '#{Scrap.to_s}' AS klass FROM #{Scrap.table_name} WHERE scraps.receiver_id = #{self.id} AND scraps.scrap_id IS NULL UNION SELECT id, updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} WHERE action_tracker.target_id = #{self.id} UNION SELECT at.id, at.updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} at INNER JOIN articles a ON at.target_id = a.id WHERE a.profile_id = #{self.id} AND at.target_type = 'Article' ORDER BY updated_at DESC")
  91 + Scrap.find_by_sql("SELECT id, updated_at, '#{Scrap.to_s}' AS klass FROM #{Scrap.table_name} WHERE scraps.receiver_id = #{self.id} AND scraps.scrap_id IS NULL UNION SELECT id, updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} WHERE action_tracker.target_id = #{self.id} and action_tracker.verb != 'join_community' and action_tracker.verb != 'leave_scrap' UNION SELECT at.id, at.updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} at INNER JOIN articles a ON at.target_id = a.id WHERE a.profile_id = #{self.id} AND at.target_type = 'Article' ORDER BY updated_at DESC")
92 92 end
93 93  
94 94 end
... ...
app/models/enterprise.rb
... ... @@ -154,13 +154,14 @@ class Enterprise &lt; Organization
154 154 true
155 155 end
156 156  
157   - def template
158   - if enabled?
159   - environment.enterprise_template
160   - else
161   - environment.inactive_enterprise_template
162   - end
  157 + def default_template
  158 + environment.enterprise_template
  159 + end
  160 +
  161 + def template_with_inactive_enterprise
  162 + !enabled? ? environment.inactive_enterprise_template : template_without_inactive_enterprise
163 163 end
  164 + alias_method_chain :template, :inactive_enterprise
164 165  
165 166 def control_panel_settings_button
166 167 {:title => __('Enterprise Info and settings'), :icon => 'edit-profile-enterprise'}
... ...
app/models/environment.rb
... ... @@ -24,6 +24,8 @@ class Environment &lt; ActiveRecord::Base
24 24 'manage_environment_roles' => N_('Manage environment roles'),
25 25 'manage_environment_validators' => N_('Manage environment validators'),
26 26 'manage_environment_users' => N_('Manage environment users'),
  27 + 'manage_environment_templates' => N_('Manage environment templates'),
  28 + 'manage_environment_licenses' => N_('Manage environment licenses'),
27 29 }
28 30  
29 31 module Roles
... ... @@ -158,6 +160,7 @@ class Environment &lt; ActiveRecord::Base
158 160 has_many :products, :through => :enterprises
159 161 has_many :people
160 162 has_many :communities
  163 + has_many :licenses
161 164  
162 165 has_many :categories
163 166 has_many :display_categories, :class_name => 'Category', :conditions => 'display_color is not null and parent_id is null', :order => 'display_color'
... ... @@ -719,12 +722,12 @@ class Environment &lt; ActiveRecord::Base
719 722  
720 723 def create_templates
721 724 pre = self.name.to_slug + '_'
722   - ent_id = Enterprise.create!(:name => 'Enterprise template', :identifier => pre + 'enterprise_template', :environment => self, :visible => false).id
723   - inactive_enterprise_tmpl = Enterprise.create!(:name => 'Inactive Enterprise template', :identifier => pre + 'inactive_enterprise_template', :environment => self, :visible => false)
724   - com_id = Community.create!(:name => 'Community template', :identifier => pre + 'community_template', :environment => self, :visible => false).id
  725 + ent_id = Enterprise.create!(:name => 'Enterprise template', :identifier => pre + 'enterprise_template', :environment => self, :visible => false, :is_template => true).id
  726 + inactive_enterprise_tmpl = Enterprise.create!(:name => 'Inactive Enterprise template', :identifier => pre + 'inactive_enterprise_template', :environment => self, :visible => false, :is_template => true)
  727 + com_id = Community.create!(:name => 'Community template', :identifier => pre + 'community_template', :environment => self, :visible => false, :is_template => true).id
725 728 pass = Digest::MD5.hexdigest rand.to_s
726 729 user = User.create!(:login => (pre + 'person_template'), :email => (pre + 'template@template.noo'), :password => pass, :password_confirmation => pass, :environment => self).person
727   - user.update_attributes(:visible => false, :name => "Person template")
  730 + user.update_attributes(:visible => false, :name => "Person template", :is_template => true)
728 731 usr_id = user.id
729 732 self.settings[:enterprise_template_id] = ent_id
730 733 self.inactive_enterprise_template = inactive_enterprise_tmpl
... ... @@ -740,6 +743,18 @@ class Environment &lt; ActiveRecord::Base
740 743 end
741 744 end
742 745  
  746 + after_create :create_default_licenses
  747 + def create_default_licenses
  748 + License.create!(:name => 'CC (by)', :url => 'http://creativecommons.org/licenses/by/3.0/legalcode', :environment => self)
  749 + License.create!(:name => 'CC (by-nd)', :url => 'http://creativecommons.org/licenses/by-nd/3.0/legalcode', :environment => self)
  750 + License.create!(:name => 'CC (by-sa)', :url => 'http://creativecommons.org/licenses/by-sa/3.0/legalcode', :environment => self)
  751 + License.create!(:name => 'CC (by-nc)', :url => 'http://creativecommons.org/licenses/by-nc/3.0/legalcode', :environment => self)
  752 + License.create!(:name => 'CC (by-nc-nd)', :url => 'http://creativecommons.org/licenses/by-nc-nd/3.0/legalcode', :environment => self)
  753 + License.create!(:name => 'CC (by-nc-sa)', :url => 'http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode', :environment => self)
  754 + License.create!(:name => 'Free Art', :url => 'http://artlibre.org/licence/lal/en', :environment => self)
  755 + License.create!(:name => 'GNU FDL', :url => 'http://www.gnu.org/licenses/fdl-1.3.txt', :environment => self)
  756 + end
  757 +
743 758 def highlighted_products_with_image(options = {})
744 759 Product.find(:all, {:conditions => {:highlighted => true, :enterprise_id => self.enterprises.find(:all, :select => :id) }, :joins => :image}.merge(options))
745 760 end
... ...
app/models/input.rb
... ... @@ -9,6 +9,8 @@ class Input &lt; ActiveRecord::Base
9 9  
10 10 belongs_to :unit
11 11  
  12 + named_scope :relevant_to_price, :conditions => { :relevant_to_price => true }
  13 +
12 14 include FloatHelper
13 15  
14 16 def price_per_unit=(value)
... ...
app/models/license.rb 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +class License < ActiveRecord::Base
  2 + belongs_to :environment
  3 + has_many :content, :class_name => 'Article', :foreign_key => 'license_id'
  4 +
  5 + validates_presence_of :name, :environment
  6 + validates_presence_of :slug, :if => lambda {|license| license.name.present?}
  7 + validates_uniqueness_of :slug, :scope => :environment_id
  8 +
  9 + before_validation do |license|
  10 + license.slug ||= license.name.to_slug if license.name.present?
  11 + end
  12 +end
... ...
app/models/location_block.rb
1 1 class LocationBlock < Block
2 2  
3   - settings_items :zoom, :type => :integer , :default => 4
4   - settings_items :map_type, :type => :string , :default => 'roadmap'
  3 + settings_items :zoom, :type => :integer, :default => 4
  4 + settings_items :map_type, :type => :string, :default => 'roadmap'
5 5  
6 6 def self.description
7 7 _('Location map')
... ... @@ -12,18 +12,10 @@ class LocationBlock &lt; Block
12 12 end
13 13  
14 14 def content(args={})
  15 + block = self
15 16 profile = self.owner
16   - title = self.title
17   - if profile.lat
18   - block_title(title) +
19   - content_tag('div',
20   - '<img src="http://maps.google.com/maps/api/staticmap?center=' + profile.lat.to_s() +
21   - ',' + profile.lng.to_s() + '&zoom=' + zoom.to_s() +
22   - '&size=190x250&maptype=' + map_type + '&markers=' + profile.lat.to_s() + ',' +
23   - profile.lng.to_s() + ',green' + '&sensor=false"/>',
24   - :class => 'the-localization-map' )
25   - else
26   - content_tag('i', _('This profile has no geographical position registered.'))
  17 + lambda do
  18 + render :file => 'blocks/location', :locals => {:block => block, :profile => profile}
27 19 end
28 20 end
29 21  
... ...
app/models/mailing.rb
... ... @@ -9,7 +9,11 @@ class Mailing &lt; ActiveRecord::Base
9 9 xss_terminate :only => [ :subject, :body ], :with => 'white_list', :on => 'validation'
10 10  
11 11 after_create do |mailing|
12   - Delayed::Job.enqueue MailingJob.new(mailing.id)
  12 + mailing.schedule
  13 + end
  14 +
  15 + def schedule
  16 + Delayed::Job.enqueue MailingJob.new(self.id)
13 17 end
14 18  
15 19 def generate_from
... ... @@ -30,8 +34,14 @@ class Mailing &lt; ActiveRecord::Base
30 34  
31 35 def deliver
32 36 each_recipient do |recipient|
33   - Mailing::Sender.deliver_mail(self, recipient.email)
34   - self.mailing_sents.create(:person => recipient)
  37 + begin
  38 + Mailing::Sender.deliver_mail(self, recipient.email)
  39 + self.mailing_sents.create(:person => recipient)
  40 + rescue Exception
  41 + # FIXME should not discard errors silently. An idea is to collect all
  42 + # errors and generate a task (notification) for the +source+
  43 + # (environment/organization) listing these errors.
  44 + end
35 45 end
36 46 end
37 47  
... ...
app/models/organization.rb
... ... @@ -77,6 +77,7 @@ class Organization &lt; Profile
77 77 state
78 78 country
79 79 tag_list
  80 + template_id
80 81 ]
81 82  
82 83 def self.fields
... ...
app/models/person.rb
... ... @@ -22,7 +22,22 @@ class Person &lt; Profile
22 22 super
23 23 end
24 24  
25   - named_scope :members_of, lambda { |resource| { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => ['role_assignments.resource_type = ? AND role_assignments.resource_id = ?', resource.class.base_class.name, resource.id ] } }
  25 + acts_as_having_hotspots
  26 +
  27 + named_scope :members_of, lambda { |resources|
  28 + resources = [resources] if !resources.kind_of?(Array)
  29 + conditions = resources.map {|resource| "role_assignments.resource_type = '#{resource.class.base_class.name}' AND role_assignments.resource_id = #{resource.id || -1}"}.join(' OR ')
  30 + { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => [conditions] }
  31 + }
  32 +
  33 + def has_permission_with_plugins?(permission, profile)
  34 + permissions = [has_permission_without_plugins?(permission, profile)]
  35 + permissions += enabled_plugins.map do |plugin|
  36 + plugin.has_permission?(self, permission, profile)
  37 + end
  38 + permissions.include?(true)
  39 + end
  40 + alias_method_chain :has_permission?, :plugins
26 41  
27 42 def memberships
28 43 Profile.memberships_of(self)
... ... @@ -285,7 +300,7 @@ class Person &lt; Profile
285 300 end
286 301 end
287 302  
288   - def template
  303 + def default_template
289 304 environment.person_template
290 305 end
291 306  
... ... @@ -443,7 +458,7 @@ class Person &lt; Profile
443 458 end
444 459  
445 460 def activities
446   - Scrap.find_by_sql("SELECT id, updated_at, '#{Scrap.to_s}' AS klass FROM #{Scrap.table_name} WHERE scraps.receiver_id = #{self.id} AND scraps.scrap_id IS NULL UNION SELECT id, updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} WHERE action_tracker.user_id = #{self.id} ORDER BY updated_at DESC")
  461 + Scrap.find_by_sql("SELECT id, updated_at, '#{Scrap.to_s}' AS klass FROM #{Scrap.table_name} WHERE scraps.receiver_id = #{self.id} AND scraps.scrap_id IS NULL UNION SELECT id, updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} WHERE action_tracker.user_id = #{self.id} and action_tracker.verb != 'leave_scrap_to_self' and action_tracker.verb != 'add_member_in_community' ORDER BY updated_at DESC")
447 462 end
448 463  
449 464 protected
... ...
app/models/price_detail.rb
... ... @@ -4,9 +4,13 @@ class PriceDetail &lt; ActiveRecord::Base
4 4 validates_presence_of :product_id
5 5  
6 6 belongs_to :production_cost
7   - validates_presence_of :production_cost_id
  7 + validates_presence_of :production_cost
8 8 validates_uniqueness_of :production_cost_id, :scope => :product_id
9 9  
  10 + def name
  11 + production_cost.name
  12 + end
  13 +
10 14 def price
11 15 self[:price] || 0
12 16 end
... ...
app/models/product.rb
... ... @@ -158,7 +158,7 @@ class Product &lt; ActiveRecord::Base
158 158  
159 159 def inputs_cost
160 160 return 0 if inputs.empty?
161   - inputs.map(&:cost).inject { |sum,price| sum + price }
  161 + inputs.relevant_to_price.map(&:cost).inject { |sum,price| sum + price }
162 162 end
163 163  
164 164 def total_production_cost
... ... @@ -201,6 +201,7 @@ class Product &lt; ActiveRecord::Base
201 201 self.inputs(true).each{ |i| t_i += 1; se_i += 1 if i.is_from_solidarity_economy }
202 202 t_i = 1 if t_i == 0 # avoid division by 0
203 203 p = case (se_i.to_f/t_i)*100
  204 + when 0 then [0, '']
204 205 when 0..24.999 then [0, _("0%")];
205 206 when 25..49.999 then [25, _("25%")];
206 207 when 50..74.999 then [50, _("50%")];
... ...
app/models/production_cost.rb
... ... @@ -5,4 +5,5 @@ class ProductionCost &lt; ActiveRecord::Base
5 5 validates_presence_of :name
6 6 validates_length_of :name, :maximum => 30, :allow_blank => true
7 7 validates_uniqueness_of :name, :scope => [:owner_id, :owner_type]
  8 +
8 9 end
... ...
app/models/profile.rb
... ... @@ -60,20 +60,33 @@ class Profile &lt; ActiveRecord::Base
60 60 }
61 61  
62 62 acts_as_accessible
  63 + acts_as_having_hotspots
63 64  
64 65 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 ] } }
65 66 #FIXME: these will work only if the subclass is already loaded
66 67 named_scope :enterprises, lambda { {:conditions => (Enterprise.send(:subclasses).map(&:name) << 'Enterprise').map { |klass| "profiles.type = '#{klass}'"}.join(" OR ")} }
67 68 named_scope :communities, lambda { {:conditions => (Community.send(:subclasses).map(&:name) << 'Community').map { |klass| "profiles.type = '#{klass}'"}.join(" OR ")} }
  69 + named_scope :templates, :conditions => {:is_template => true}
68 70  
69 71 def members
70   - Person.members_of(self)
  72 + scopes = dispatch_scopes(:organization_members, self)
  73 + scopes << Person.members_of(self)
  74 + scopes.size == 1 ? scopes.first : Person.or_scope(scopes)
71 75 end
72 76  
73 77 def members_count
74   - members.count('DISTINCT(profiles.id)')
  78 + members.count
75 79 end
76 80  
  81 + class << self
  82 + def count_with_distinct(*args)
  83 + options = args.last || {}
  84 + count_without_distinct(:id, {:distinct => true}.merge(options))
  85 + end
  86 + alias_method_chain :count, :distinct
  87 + end
  88 +
  89 +
77 90 def members_by_role(role)
78 91 Person.members_of(self).all(:conditions => ['role_assignments.role_id = ?', role.id])
79 92 end
... ... @@ -98,6 +111,7 @@ class Profile &lt; ActiveRecord::Base
98 111 has_many :action_tracker_notifications, :foreign_key => 'profile_id'
99 112 has_many :tracked_notifications, :through => :action_tracker_notifications, :source => :action_tracker, :order => 'updated_at DESC'
100 113 has_many :scraps_received, :class_name => 'Scrap', :foreign_key => :receiver_id, :order => "updated_at DESC", :dependent => :destroy
  114 + belongs_to :template, :class_name => 'Profile', :foreign_key => 'template_id'
101 115  
102 116 # FIXME ugly workaround
103 117 def self.human_attribute_name(attrib)
... ... @@ -204,7 +218,7 @@ class Profile &lt; ActiveRecord::Base
204 218 end
205 219  
206 220 belongs_to :region
207   -
  221 +
208 222 def location(separator = ' - ')
209 223 myregion = self.region
210 224 if myregion
... ... @@ -274,8 +288,14 @@ class Profile &lt; ActiveRecord::Base
274 288 validates_format_of :identifier, :with => IDENTIFIER_FORMAT, :if => lambda { |profile| !profile.identifier.blank? }
275 289 validates_exclusion_of :identifier, :in => RESERVED_IDENTIFIERS
276 290 validates_uniqueness_of :identifier, :scope => :environment_id
277   -
278 291 validates_length_of :nickname, :maximum => 16, :allow_nil => true
  292 + validate :valid_template
  293 +
  294 + def valid_template
  295 + if template_id.present? and !template.is_template
  296 + errors.add(:template, _('is not a template.'))
  297 + end
  298 + end
279 299  
280 300 before_create :set_default_environment
281 301 def set_default_environment
... ... @@ -285,12 +305,12 @@ class Profile &lt; ActiveRecord::Base
285 305 true
286 306 end
287 307  
288   - # registar callback for creating boxes after the object is created.
  308 + # registar callback for creating boxes after the object is created.
289 309 after_create :create_default_set_of_boxes
290 310  
291 311 # creates the initial set of boxes when the profile is created. Can be
292 312 # overriden for each subclass to create a custom set of boxes for its
293   - # instances.
  313 + # instances.
294 314 def create_default_set_of_boxes
295 315 if template
296 316 apply_template(template, :copy_articles => false)
... ... @@ -322,10 +342,15 @@ class Profile &lt; ActiveRecord::Base
322 342 end
323 343  
324 344 # this method should be overwritten to provide the correct template
325   - def template
  345 + def default_template
326 346 nil
327 347 end
328 348  
  349 + def template_with_default
  350 + template_without_default || default_template
  351 + end
  352 + alias_method_chain :template, :default
  353 +
329 354 def apply_template(template, options = {:copy_articles => true})
330 355 copy_blocks_from(template)
331 356 copy_articles_from(template) if options[:copy_articles]
... ... @@ -405,7 +430,7 @@ class Profile &lt; ActiveRecord::Base
405 430  
406 431 # returns +false+
407 432 def person?
408   - self.kind_of?(Person)
  433 + self.kind_of?(Person)
409 434 end
410 435  
411 436 def enterprise?
... ... @@ -513,7 +538,7 @@ private :generate_url, :url_options
513 538  
514 539 after_create :insert_default_article_set
515 540 def insert_default_article_set
516   - if template
  541 + if template
517 542 copy_articles_from template
518 543 else
519 544 default_set_of_articles.each do |article|
... ... @@ -583,7 +608,7 @@ private :generate_url, :url_options
583 608 raise _("%s can't have members") % self.class.name
584 609 end
585 610 end
586   -
  611 +
587 612 def remove_member(person)
588 613 self.disaffiliate(person, Profile::Roles.all_roles(environment.id))
589 614 end
... ... @@ -880,7 +905,7 @@ private :generate_url, :url_options
880 905  
881 906 def self.f_enabled_proc(enabled)
882 907 enabled = enabled == "true" ? true : false
883   - enabled ? _('Enabled') : _('Not enabled')
  908 + enabled ? s_('facets|Enabled') : s_('facets|Not enabled')
884 909 end
885 910 def f_enabled
886 911 self.enabled
... ... @@ -909,7 +934,7 @@ private :generate_url, :url_options
909 934 acts_as_searchable :fields => facets_fields_for_solr + [:extra_data_for_index,
910 935 # searched fields
911 936 {:name => {:type => :text, :boost => 2.0}},
912   - {:identifier => :text}, {:address => :text}, {:nickname => :text},
  937 + {:identifier => :text}, {:nickname => :text},
913 938 # filtered fields
914 939 {:public => :boolean}, {:environment_id => :integer},
915 940 {:category_filter => :integer},
... ... @@ -929,7 +954,7 @@ private :generate_url, :url_options
929 954  
930 955 def control_panel_settings_button
931 956 {:title => _('Profile Info and settings'), :icon => 'edit-profile'}
932   - end
  957 + end
933 958  
934 959 def followed_by?(person)
935 960 person.is_member_of?(self)
... ...
app/models/profile_list_block.rb
... ... @@ -25,7 +25,7 @@ class ProfileListBlock &lt; Block
25 25 end
26 26  
27 27 def profile_count
28   - profiles.visible.count('DISTINCT(profiles.id)')
  28 + profiles.visible.count
29 29 end
30 30  
31 31 # the title of the block. Probably will be overriden in subclasses.
... ...
app/models/uploaded_file.rb
... ... @@ -8,7 +8,7 @@ class UploadedFile &lt; Article
8 8 _('File')
9 9 end
10 10  
11   - track_actions :upload_image, :after_create, :keep_params => ["view_url", "thumbnail_path", "parent.url", "parent.name"], :if => Proc.new { |a| a.published? && a.image? && !a.parent.nil? && a.parent.gallery? }, :custom_target => :action_tracker_target
  11 + track_actions :upload_image, :after_create, :keep_params => ["view_url", "thumbnail_path", "parent.url", "parent.name"], :if => Proc.new { |a| a.published? && a.image? && !a.parent.nil? && a.parent.gallery? }, :custom_target => :parent
12 12  
13 13 include ShortFilename
14 14  
... ... @@ -144,9 +144,4 @@ class UploadedFile &lt; Article
144 144 def uploaded_file?
145 145 true
146 146 end
147   -
148   - def action_tracker_target
149   - self
150   - end
151   -
152 147 end
... ...
app/models/user.rb
... ... @@ -21,12 +21,11 @@ class User &lt; ActiveRecord::Base
21 21 end
22 22 end
23 23  
24   - before_create :make_activation_code
25   -
26 24 before_create do |user|
27 25 if user.environment.nil?
28 26 user.environment = Environment.default
29 27 end
  28 + user.send(:make_activation_code) unless user.environment.enabled?('skip_new_user_email_confirmation')
30 29 end
31 30  
32 31 after_create do |user|
... ... @@ -35,7 +34,7 @@ class User &lt; ActiveRecord::Base
35 34 user.person.name ||= user.login
36 35 user.person.visible = false unless user.activated?
37 36 user.person.save!
38   - if user.environment && user.environment.enabled?('skip_new_user_email_confirmation')
  37 + if user.environment.enabled?('skip_new_user_email_confirmation')
39 38 user.activate
40 39 end
41 40 end
... ... @@ -114,10 +113,11 @@ class User &lt; ActiveRecord::Base
114 113  
115 114 # Activates the user in the database.
116 115 def activate
  116 + return false unless self.person
117 117 self.activated_at = Time.now.utc
118 118 self.activation_code = nil
119 119 self.person.visible = true
120   - self.person.save! && self.save
  120 + self.person.save! && self.save!
121 121 end
122 122  
123 123 def activated?
... ...
app/views/account/_signup_form.rhtml
... ... @@ -69,6 +69,8 @@
69 69  
70 70 <div id="signup-form-profile">
71 71  
  72 + <%= template_options(Person, 'profile_data') %>
  73 +
72 74 <% labelled_fields_for :profile_data, @person do |f| %>
73 75 <%= render :partial => 'profile_editor/person_form', :locals => {:f => f} %>
74 76 <% end %>
... ...
app/views/admin_panel/edit_templates.rhtml
... ... @@ -1,10 +0,0 @@
1   -<h1><%= _('Edit Templates') %></h1>
2   -
3   -<ul>
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 %>
10   -</ul>
app/views/admin_panel/index.rhtml
... ... @@ -12,9 +12,10 @@
12 12 <tr><td><%= link_to _('Manage User roles'), :controller => 'role' %></td></tr>
13 13 <tr><td><%= link_to _('Manage users'), :controller => 'users' %></td></tr>
14 14 <tr><td><%= link_to _('Manage Validators by region'), :controller => 'region_validators' %></td></tr>
15   - <tr><td><%= link_to _('Edit Templates'), :action => 'edit_templates' %></td></tr>
  15 + <tr><td><%= link_to _('Edit Templates'), :controller => 'templates' %></td></tr>
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 + <tr><td><%= link_to _('Manage Licenses'), :controller =>'licenses' %></td></tr>
18 19 <% @plugins.dispatch(:admin_panel_links).each do |link| %>
19 20 <tr><td><%= link_to link[:title], link[:url] %></td></tr>
20 21 <% end %>
... ...
app/views/blocks/location.html.erb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +<% if profile.lat %>
  2 + <%= block_title block.title %>
  3 + <div class='the-localization-map'>
  4 + <img src="http://maps.google.com/maps/api/staticmap?center=<%=profile.lat%>,<%=profile.lng%>&zoom=<%=block.zoom%>&size=190x250&maptype=<%=block.map_type%>&markers=<%=profile.lat%>,<%=profile.lng%>&sensor=false"/>
  5 + </div>
  6 +</div>
  7 +<% else %>
  8 + <i><%= _('This profile has no geographical position registered.') %></i>
  9 +<% end %>
... ...
app/views/catalog/index.rhtml
... ... @@ -56,7 +56,7 @@
56 56 <div>
57 57 <div class="arrow"></div>
58 58 <div class="content" id="product-price-composition">
59   - <% product.inputs.each do |i| %>
  59 + <% product.inputs.relevant_to_price.each do |i| %>
60 60 <div class="search-product-input-dots-to-price">
61 61 <div class="search-product-input-name"><%= i.product_category.name %></div>
62 62 <%= price_span i.cost, :class => 'search-product-input-price' %>
... ...
app/views/cms/_blog.rhtml
... ... @@ -6,6 +6,8 @@
6 6  
7 7 <%= required f.text_field(:name, :size => '64', :onchange => "updateUrlField(this, 'article_slug')") %>
8 8  
  9 +<%= render :partial => 'general_fields' %>
  10 +
9 11 <script type="text/javascript">
10 12 function submit_button(index) {
11 13 return $("article_slug").form.select("input.submit")[index];
... ...
app/views/cms/_event.rhtml
... ... @@ -5,6 +5,7 @@
5 5  
6 6 <%= required f.text_field('name', :size => '64') %>
7 7  
  8 +<%= render :partial => 'general_fields' %>
8 9 <%= render :partial => 'translatable' %>
9 10  
10 11 <%= labelled_form_field(_('Start date'), pick_date(:article, :start_date)) %>
... ...
app/views/cms/_folder.rhtml
1 1 <%= required_fields_message %>
2 2  
3 3 <%= required f.text_field('name', :size => '64') %>
  4 +<%= render :partial => 'general_fields' %>
4 5  
5 6 <%= labelled_form_field(_('Description:'), text_area(:article, :body, :rows => 3, :cols => 64)) %>
... ...
app/views/cms/_forum.rhtml
... ... @@ -6,6 +6,8 @@
6 6  
7 7 <%= required f.text_field(:name, :size => '64', :onchange => "updateUrlField(this, 'article_slug')") %>
8 8  
  9 +<%= render :partial => 'general_fields' %>
  10 +
9 11 <%= labelled_form_field(_('Description:'), text_area(:article, :body, :cols => 64, :rows => 10)) %>
10 12  
11 13 <%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, [5, 10, 20, 50, 100])) %>
... ...
app/views/cms/_gallery.rhtml
... ... @@ -2,4 +2,6 @@
2 2  
3 3 <%= required f.text_field('name', :size => '64') %>
4 4  
  5 +<%= render :partial => 'general_fields' %>
  6 +
5 7 <%= labelled_form_field(_('Description:'), text_area(:article, :body, :rows => 3, :cols => 64)) %>
... ...
app/views/cms/_general_fields.html.erb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= labelled_form_field(_('License'), select(:article, :license_id, options_for_select_with_title([[_('None'), nil]] + profile.environment.licenses.map {|license| [license.name, license.id]}, @article.license ? @article.license.id : nil))) %>
... ...
app/views/cms/_published_article.rhtml
1 1 <%= f.text_field 'name', :size => '64' %>
  2 +<%= render :partial => 'general_fields' %>
2 3  
3 4 <p><%= _('This is a republication of "%s", by %s.') % [link_to(h(@article.reference_article.name), @article.reference_article.url), @article.reference_article.profile.name] %></p>
... ...
app/views/cms/_raw_html_article.rhtml
... ... @@ -2,5 +2,6 @@
2 2  
3 3 <%= required labelled_form_field(_('Title'), text_field(:article, 'name', :size => '64')) %>
4 4  
  5 +<%= render :partial => 'general_fields' %>
5 6 <%= render :partial => 'translatable' %>
6 7 <%= render :partial => 'shared/lead_and_body' %>
... ...
app/views/cms/_rss_feed.rhtml
... ... @@ -2,6 +2,8 @@
2 2  
3 3 <%= required f.text_field(:name) %>
4 4  
  5 +<%= render :partial => 'general_fields' %>
  6 +
5 7 <%= required labelled_form_field(_('Limit of articles'), text_field(:article, :limit)) %>
6 8  
7 9 <%= labelled_form_field(_('Include in RSS Feed only posts from language:'), f.select(:language, [[_('All'), nil ]] + Noosfero.locales.map { |k,v| [v, k]})) %>
... ...
app/views/cms/_textile_article.rhtml
... ... @@ -4,5 +4,6 @@
4 4  
5 5 <%= required labelled_form_field(_('Title'), text_field(:article, 'name', :size => '72')) %>
6 6  
  7 +<%= render :partial => 'general_fields' %>
7 8 <%= render :partial => 'translatable' %>
8 9 <%= render :partial => 'shared/lead_and_body' %>
... ...
app/views/cms/_tiny_mce_article.rhtml
... ... @@ -5,6 +5,7 @@
5 5 <div>
6 6 <%= required labelled_form_field(_('Title'), text_field(:article, 'name', :size => '64')) %>
7 7  
  8 + <%= render :partial => 'general_fields' %>
8 9 <%= render :partial => 'translatable' %>
9 10 <%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true} %>
10 11 </div>
... ...
app/views/cms/select_article_type.rhtml
... ... @@ -13,4 +13,4 @@
13 13 </ul>
14 14 <br style="clear:both" />
15 15  
16   -<%= lightbox_close_button(_('Cancel')) %>
  16 +<%= colorbox_close_button(_('Cancel')) %>
... ...
app/views/cms/view.rhtml
... ... @@ -5,7 +5,7 @@
5 5 <% button_bar(:style => 'margin-bottom: 1em;') do %>
6 6 <% parent_id = ((@article && @article.allow_children?) ? @article : nil) %>
7 7  
8   - <%= lightbox_button('new', _('New content'), :action => 'new', :parent_id => parent_id, :cms => true) %>
  8 + <%= colorbox_button('new', _('New content'), :action => 'new', :parent_id => parent_id, :cms => true) %>
9 9 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor', :action => "index") %>
10 10 <% end %>
11 11  
... ...
app/views/comment/notifier/mail_to_followers.rhtml 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +<%= _('Hi!') %>
  2 +
  3 +<%= word_wrap(_('%{sender} (%{sender_link}) commented on the content "%{article_title}".') % { :sender => @sender, :sender_link => url_for(@sender_link), :article_title => @article_title }) %>
  4 +
  5 +<%= word_wrap(_('Title: %s') % @comment_title) if @comment_title %>
  6 +
  7 +<%= _("Comment:") %>
  8 +-------------------------------------------------------------------------------
  9 +<%= word_wrap(@comment_body) %>
  10 +-------------------------------------------------------------------------------
  11 +
  12 +<%= _('Click on the address below to view this comment:') %>
  13 +<%= url_for @comment_url %>
  14 +
  15 +<%= _('Click on the address below to cancel the notification of new comments:') %>
  16 +<%= url_for @unsubscribe_url %>
  17 +
  18 +<%= _("Greetings,") %>
  19 +
  20 +--
  21 +<%= _('%s team.') % @environment %>
  22 +<%= url_for @url %>
... ...
app/views/content_viewer/_article_toolbar.rhtml
... ... @@ -33,7 +33,7 @@
33 33 :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)),
34 34 :type => @page.type, :article => { :translation_of_id => @page.native_translation.id }),
35 35 :class => 'button with-text icon-locale' if @page.translatable? && !@page.native_translation.language.blank? %>
36   - <%= lightbox_remote_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) %>
  36 + <%= colorbox_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) %>
37 37 <% end %>
38 38  
39 39 <% if @page.accept_uploads? && @page.allow_create?(user) %>
... ...
app/views/content_viewer/_confirm_unfollow.rhtml 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +<% if @unfollow_form %>
  2 +<div class='unfollow-article'>
  3 + <h1><%= _('Cancel notification of new comments') %></h1>
  4 + <p><%= _("Fill in the following field with your e-mail if you don't want to be notified when this content receives new comments anymore.") %></p>
  5 + <% form_tag(@page.view_url.merge({:only_path => true}), {:method => 'post', :class => 'comment_form'}) do %>
  6 + <%= hidden_field_tag(:unfollow, 'commit') %>
  7 + <%= labelled_form_field(_('Enter your e-Mail'), text_field_tag(:email, nil, {:size => 40})) %>
  8 + <% button_bar do %>
  9 + <%= submit_button(:ok, _('Cancel notifications for e-mail above') ) %>
  10 + <% end %>
  11 + <% end %>
  12 +</div>
  13 +<% end %>
... ...
app/views/content_viewer/view_page.rhtml
... ... @@ -6,12 +6,30 @@
6 6  
7 7 <div id="article" class="<%= @page.css_class_name %>">
8 8  
  9 +<%= render :partial => 'confirm_unfollow' %>
  10 +
9 11 <div id="article-toolbar"></div>
10 12  
11 13 <script type="text/javascript">
12   - <%= remote_function :update => "article-toolbar", :url => @page.url.merge({ :toolbar => true, :only_path => true }), :complete => "$$('#article-toolbar .remote-lbOn').each(function(link) { new lightbox(link); }); jQuery('#article-toolbar .simplemenu-trigger').click(function(e) { e.stopPropagation(); })" %>
  14 + <%= remote_function :update => "article-toolbar", :url => @page.url.merge({ :toolbar => true, :only_path => true }) %>
13 15 </script>
14 16  
  17 +<% if @page.display_hits? || @page.license.present? %>
  18 + <div id='article-sub-header'>
  19 + <% if @page.display_hits? %>
  20 + <div id="article-hits">
  21 + <%= n_('Viewed one time', 'Viewed %{num} times', @page.hits) % { :num => @page.hits } %>
  22 + </div>
  23 + <% end %>
  24 +
  25 + <% if @page.license.present? %>
  26 + <div id="article-license">
  27 + <%= _('Licensed under %s') % (@page.license.url.present? ? link_to(@page.license.name, @page.license.url, :target => '_blank') : @page.license.name) %>
  28 + </div>
  29 + <% end %>
  30 + </div>
  31 +<% end %>
  32 +
15 33 <% if !@page.tags.empty? %>
16 34 <div id="article-tags">
17 35 <%= _("This article's tags:") %>
... ... @@ -19,12 +37,6 @@
19 37 </div>
20 38 <% end %>
21 39  
22   -<% if @page.display_hits? %>
23   - <div id="article-hits">
24   - <%= n_('Viewed one time', 'Viewed %{num} times', @page.hits) % { :num => @page.hits } %>
25   - </div>
26   -<% end %>
27   -
28 40 <% if @page.parent && !@page.parent.path.blank? %>
29 41 <div id="article-parent">
30 42 <%= button(:back, _('Go back to %s') % @page.parent.short_title, @page.parent.url) %>
... ...
app/views/edit_template/index.rhtml
... ... @@ -1,14 +0,0 @@
1   -mexendo o contedudo para ver como fica a parada toda
2   -mexendo o contedudo para ver como fica a parada toda
3   -mexendo o contedudo para ver como fica a parada toda
4   -mexendo o contedudo para ver como fica a parada toda
5   -mexendo o contedudo para ver como fica a parada toda
6   -mexendo o contedudo para ver como fica a parada toda
7   -mexendo o contedudo para ver como fica a parada toda
8   -mexendo o contedudo para ver como fica a parada toda
9   -mexendo o contedudo para ver como fica a parada toda
10   -mexendo o contedudo para ver como fica a parada toda
11   -mexendo o contedudo para ver como fica a parada toda
12   -mexendo o contedudo para ver como fica a parada toda
13   -mexendo o contedudo para ver como fica a parada toda
14   -
app/views/enterprise_registration/basic_information.rhtml
... ... @@ -28,6 +28,14 @@
28 28 <%= hidden_field_tag 'create_enterprise[target_id]', environment.id %>
29 29 <% end %>
30 30  
  31 + <% @plugins.dispatch(:enterprise_registration_hidden_fields).each do |field| %>
  32 + <% field.each do |key, value| %>
  33 + <%= f.hidden_field(key, :value => value) %>
  34 + <% end %>
  35 + <% end %>
  36 +
  37 + <%= template_options(Enterprise, 'create_enterprise')%>
  38 +
31 39 <% button_bar do %>
32 40 <%= submit_button('next', _('Next'), :cancel => {:profile => current_user.person.identifier, :action=>"enterprises", :controller=>"profile"}) %>
33 41 <% end %>
... ...
app/views/licenses/_form.html.erb 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +<%= error_messages_for :license %>
  2 +
  3 +<% form_for :license, @license do |f| %>
  4 + <%= hidden_field_tag(:license_id, params[:license_id]) %>
  5 + <%= required labelled_form_field(_('Name'), f.text_field(:name)) %>
  6 + <%= labelled_form_field(_('License url'), f.text_field(:url)) %>
  7 +
  8 + <% button_bar do %>
  9 + <%= submit_button('save', _('Save'))%>
  10 + <%= button('cancel', _('Cancel'), {:action => 'index'})%>
  11 + <% end %>
  12 +<% end %>
... ...
app/views/licenses/create.html.erb 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +<h1><%= _('New license') %></h1>
  2 +<%= render :partial => 'form' %>
... ...
app/views/licenses/edit.html.erb 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +<h1><%= _('Edit license') %></h1>
  2 +<%= render :partial => 'form' %>
... ...
app/views/licenses/index.html.erb 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +<h1><%= _('Manage licenses') %></h1>
  2 +<table style='overflow: hidden;'>
  3 + <tr>
  4 + <th style='width: 25%'><%= _('Name') %></th>
  5 + <th style='width: 60%'><%= _('Url reference') %></th>
  6 + <th style='width: 15%'><%= _('Actions') %></th>
  7 + </tr>
  8 + <% @licenses.each do |license| %>
  9 + <tr>
  10 + <td title="<%= license.name%>"><%= truncate(license.name, :length => 19) %></td>
  11 + <td title="<%= license.url %>"><%= license.url.present? ? link_to(truncate(license.url, :length => 60), license.url, :target => '_blank') : '' %></td>
  12 + <td style='white-space: nowrap;'>
  13 + <%= button_without_text :edit, _('Edit'), :action => 'edit', :license_id => license.id %>
  14 + <%= button_without_text :remove, _('Remove'), {:action => 'remove', :license_id => license.id}, :method => 'post', :confirm => _('Are you sure you want to remove this license?') %></td>
  15 + </tr>
  16 + <% end %>
  17 +</table>
  18 +
  19 +<% button_bar do %>
  20 + <%= button(:add, _('Add a new license'), :action => 'create')%>
  21 + <%= button :back, _('Back to admin panel'), :controller => 'admin_panel' %>
  22 +<% end %>
... ...
app/views/maps/_google_map.js.erb
... ... @@ -5,27 +5,113 @@ var marker;
5 5 var center;
6 6 var move = true;
7 7 var previousCenter;
  8 +var mapZoom = 15;
  9 +var delay_autocomplete = 500;
8 10  
9   -function getAddress(latlng) {
  11 +function pointToAddress(latlng) {
10 12 $('location-fields').addClassName("loading");
11 13  
12   - if (latlng != null) {
13   - geocoder.geocode( {'latLng': latlng}, showAddress);
14   - }
  14 + if (latlng == null)
  15 + return;
  16 +
  17 + geocoder.geocode( {'latLng': latlng}, function(results, status) {
  18 + if (status != google.maps.GeocoderStatus.OK) {
  19 + alert("<%=_("Address not found, reason:")%>" + statusErrorMessage(status));
  20 + return;
  21 + }
  22 +
  23 + var place = results[0];
  24 +
  25 + $('location-fields').removeClassName("loading");
  26 +
  27 + var position = marker.getPosition();
  28 + $('profile_data_lat').value = position.lat();
  29 + $('profile_data_lng').value = position.lng();
  30 +
  31 + form = jQuery('#location-form')[0];
  32 + form.lat = marker.getPosition().lat();
  33 + form.lng = marker.getPosition().lng();
  34 +
  35 + var components_len = place.address_components.size();
  36 + if (components_len < 2)
  37 + return;
  38 +
  39 + var country_code = "";
  40 + var state = "";
  41 + var city = "";
  42 + var zip_code = "";
  43 + var route = "";
  44 + var number = "";
  45 + var sublocality = "";
  46 + var address = "";
  47 +
  48 + var i;
  49 + var has_postal_code = false;
  50 + for (i=0; i < components_len; i++) {
  51 + type = place.address_components[i].types[0];
  52 + if (type == 'postal_code')
  53 + has_postal_code = true;
  54 + }
  55 +
  56 + for (i=0; i < components_len; i++) {
  57 + type = place.address_components[i].types[0];
  58 + value = place.address_components[i];
  59 +
  60 + if (type == 'country')
  61 + country_code = value.short_name;
  62 + else if (type == 'administrative_area_level_1')
  63 + state = value.long_name;
  64 + else if (type == 'locality')
  65 + city = value.long_name;
  66 + else if (type == 'postal_code')
  67 + zip_code = value.short_name;
  68 + if (has_postal_code) {
  69 + if (type == "route")
  70 + route = value.long_name;
  71 + else if (type == "street_number")
  72 + number = value.short_name;
  73 + else if (type == 'sublocality')
  74 + sublocality = value.long_name;
  75 + }
  76 + }
  77 +
  78 + // build address
  79 + if (route) {
  80 + address = route;
  81 + if (number)
  82 + address = address + ', ' + number;
  83 + if (sublocality && sublocality != city)
  84 + address = address + ', ' + sublocality;
  85 + }
  86 +
  87 + if (country_code)
  88 + $('profile_data_country').value = country_code;
  89 + if (state)
  90 + $('profile_data_state').value = state;
  91 + if (city)
  92 + $('profile_data_city').value = city;
  93 + if (zip_code)
  94 + $('profile_data_zip_code').value = zip_code;
  95 + if (address)
  96 + $('profile_data_address').value = address;
  97 +
  98 + map.setCenter(marker.getPosition());
  99 + });
15 100 }
16 101  
17   -function codeAddress() {
  102 +function addressToPoint() {
18 103 $('location-fields').addClassName("loading");
19 104  
20 105 var country_option = $('profile_data_country').value;
21   - var address = $('profile_data_address').value + "-" + $('profile_data_zip_code').value + "," + $('profile_data_city').value+ "-" + $('profile_data_state').value + "," + country_option;
  106 + var address = $('profile_data_address').value + ", " + $('profile_data_zip_code').value + ", "
  107 + + $('profile_data_city').value+ ", " + $('profile_data_state').value + ", " + country_option;
22 108  
23 109 if (geocoder) {
24   - geocoder.geocode( { 'address': address}, function(results, status) {
  110 + geocoder.geocode({ 'address': address}, function(results, status) {
25 111 if (status == google.maps.GeocoderStatus.OK) {
26 112 map.setCenter(results[0].geometry.location);
27 113 marker.setPosition(results[0].geometry.location);
28   - getAddress(marker.getPosition());
  114 + pointToAddress(marker.getPosition());
29 115  
30 116 $('profile_data_lat').value = results[0].geometry.location.lat();
31 117 $('profile_data_lng').value = results[0].geometry.location.lng();
... ... @@ -33,17 +119,15 @@ function codeAddress() {
33 119 enable_save();
34 120 } else {
35 121 $('location-fields').removeClassName("loading");
36   - alert('<%=_("Address not found, reason:")%>' + translate_status(status));
  122 + alert('<%=_("Address not found, reason:")%>' + statusErrorMessage(status));
37 123 }
38 124 });
39 125 }
40 126  
41   - map.setZoom(11);
42   -
43 127 return false;
44 128 }
45 129  
46   -function translate_status(status)
  130 +function statusErrorMessage(status)
47 131 {
48 132 var translated_status = '';
49 133  
... ... @@ -59,136 +143,42 @@ function translate_status(status)
59 143 return translated_status;
60 144 }
61 145  
62   -function getAddressData() {
63   - var text = '';
64   - var fields = [
65   - 'profile_data_country',
66   - 'profile_data_state',
67   - 'profile_data_city',
68   - 'profile_data_address',
69   - 'profile_data_zip_code'
70   - ];
71   - for (var i = 0; i < fields.length; i++) {
72   - var field = fields[i];
73   - if ($(field)) {
74   - text += $(field).value + " ";
75   - }
76   - }
77   - return text;
78   -}
79   -
80   -function showAddress(results, status) {
81   -
82   - if (status == google.maps.GeocoderStatus.OK) {
83   - map.setCenter(results[0].geometry.location);
84   - updateFields(results[0]);
85   -
86   - } else {
87   - alert("<%=_("Address not found, reason:")%>" + translate_status(status));
88   - }
89   -
90   -}
91   -
92   -function updateFields(place) {
93   - var position = marker.getPosition();
94   - $('profile_data_lat').value = position.lat();
95   - $('profile_data_lng').value = position.lng();
96   - $('location-fields').removeClassName("loading");
97   -
98   - form = jQuery('#location-form')[0];
99   - form.lat = marker.getPosition().lat();
100   - form.lng = marker.getPosition().lng();
101   -
102   - var components_len = place.address_components.size();
103   -
104   - if(components_len < 2)
105   - {
106   - return false;
107   - }
108   -
109   - var components = place.address_components;
110   - var address = "";
111   - var zip_code = "";
112   - var city = "";
113   - var state = "";
114   - var country_code = "";
115   - var i = 0;
116   -
117   - for( i =0 ; i < components_len; i ++)
118   - {
119   -
120   - if (components[i].types[0] == 'country')
121   - country_code = components[i].short_name;
122   - else if (components[i].types[0] == 'administrative_area_level_1')
123   - state = components[i].long_name;
124   - else if (components[i].types[0] == 'locality')
125   - city = components[i].long_name;
126   - else if (components[i].types[0] == 'sublocality')
127   - address = components[i].long_name + "-" + address;
128   - else if (components[i].types[0] == "route")
129   - address = components[i].long_name + address;
130   - else if (components[i].types[0] == "street_number")
131   - address = address + "," + components[i].short_name ;
132   - else if (components[i].types[0] == 'postal_code')
133   - zip_code = components[i].short_name;
134   - }
135   -
136   - $('profile_data_country').value = country_code;
137   - $('profile_data_state').value = state;
138   - $('profile_data_address').value = address;
139   - $('profile_data_city').value = city;
140   - $('profile_data_zip_code').value = zip_code;
141   -}
142   -
143   -
144   -function initialize_map() {
  146 +function initializeMap() {
145 147 geocoder = new google.maps.Geocoder();
146 148  
147 149 var lat = <%= profile.lat || 'false' %>;
148 150 var lng = <%= profile.lng || 'false' %>;
149   -
150 151 if ( !(lat && lng) ) {
151 152 lat = -15.7605361485013;
152 153 lng = -47.933349609375;
153 154 }
154 155  
155   - var latlng = new google.maps.LatLng(lat,lng);
156   -
157   - var myOptions = {
158   - zoom: 8,
159   - center: latlng,
160   - mapTypeId: google.maps.MapTypeId.ROADMAP
161   - }
162   -
163   - center = latlng;
164   -
165   - map = new google.maps.Map(document.getElementById("location-map"), myOptions);
166   -
167   - continueLoadMapV3()
168   -}
169   -
170   -function continueLoadMapV3() {
  156 + var center = new google.maps.LatLng(lat,lng);;
  157 + map = new google.maps.Map(document.getElementById("location-map"), {
  158 + zoom: mapZoom,
  159 + center: center,
  160 + mapTypeId: google.maps.MapTypeId.HYBRID
  161 + });
171 162  
172   - marker = new google.maps.Marker({
173   - position: center,
174   - map: map,
175   - draggable: true
176   - });
  163 + marker = new google.maps.Marker({
  164 + position: center,
  165 + map: map,
  166 + draggable: true
  167 + });
177 168  
178   - google.maps.event.addListener(marker, "dragend", function() {
179   - move = false;
180   - getAddress(marker.getPosition());
181   - enable_save();
182   - });
  169 + google.maps.event.addListener(marker, "dragend", function() {
  170 + move = false;
  171 + pointToAddress(marker.getPosition());
  172 + map.setCenter(marker.getPosition());
  173 + enable_save();
  174 + });
183 175  
184 176 }
185 177  
186   -window.onload = initialize_map;
187   -
188   -var delay_autocomplete = 500;
189   -
190 178 jQuery.noConflict();
191   -jQuery(document).ready(function (){
  179 +jQuery(document).ready(function () {
  180 +
  181 + initializeMap();
192 182  
193 183 jQuery.widget( "custom.catcomplete",jQuery.ui.autocomplete, {
194 184 _renderMenu: function( ul, items ) {
... ... @@ -204,7 +194,6 @@ jQuery(document).ready(function (){
204 194 }
205 195 });
206 196  
207   -
208 197 jQuery("#profile_data_city").catcomplete({
209 198 source: "../maps/search_city",
210 199 minLength: 3,
... ... @@ -219,21 +208,13 @@ jQuery(document).ready(function (){
219 208 });
220 209  
221 210 jQuery("#profile_data_city").keyup(function(){
222   -
223 211 disable_save();
224   -
225 212 });
226   -
227 213 jQuery("#profile_data_state").keyup(function(){
228   -
229 214 disable_save();
230   -
231 215 });
232   -
233 216 jQuery("#profile_data_country").change(function(){
234   -
235 217 disable_save();
236   -
237 218 });
238 219  
239 220 });
... ...
app/views/maps/edit_location.rhtml
... ... @@ -12,7 +12,7 @@
12 12 <%= labelled_form_field _('ZIP code'), text_field(:profile_data, :zip_code) %>
13 13 <%= labelled_form_field _('Address (street and number)'), text_field(:profile_data, :address) %>
14 14 <% button_bar do %>
15   - <%= button_to_function :search, _('Locate in the map'), "codeAddress()", :title => _("Locate the address informed above in the map below (note that you'll probably need to adjust the marker to get a precise position)") %>
  15 + <%= button_to_function :search, _('Locate in the map'), "addressToPoint()", :title => _("Locate the address informed above in the map below (note that you'll probably need to adjust the marker to get a precise position)") %>
16 16 <%= submit_button 'save', _('Save') %>
17 17 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>
18 18 <% end %>
... ...
app/views/memberships/index.rhtml
... ... @@ -8,30 +8,6 @@
8 8 <%= button :back, _('Go back'), :controller => 'profile_editor' %>
9 9 <% end %>
10 10  
11   -<ul>
12   -<% for membership in @memberships %>
13   - <li>
14   - <div class='common-profile-list-block'>
15   - <%= profile_image_link(membership, :portrait, 'div') %>
16   - </div>
17   - <span class='profile-details'>
18   - <strong><%= membership.name %></strong><br/>
19   - <%= _('Role: %s') % rolename_for(profile, membership) %> <br/>
20   - <%= _('Type: %s') % getterm(membership.class.identification) %> <br/>
21   - <%= _('Description: %s') % membership.description + '<br/>' if membership.community? %>
22   - <%= _('Members: %s') % membership.members_count.to_s %> <br/>
23   - <%= _('Created at: %s') % show_date(membership.created_at) unless membership.enterprise? %> <br/>
24   - <% button_bar do %>
25   - <%= button 'menu-ctrl-panel', _('Control panel of this group'), membership.admin_url %>
26   - <%= button 'menu-logout', _('Leave community'), membership.leave_url(true), :class => 'leave-community' %>
27   - <% if (membership.community? && user.has_permission?(:destroy_profile, membership)) %>
28   - <%= button 'delete', _('Remove'), { :controller => 'profile_editor', :action => 'destroy_profile', :profile => membership.identifier } %>
29   - <% end %>
30   - <% end %>
31   - </span>
32   - <br class="may-clear" />
33   - </li>
34   -<% end %>
35   -</ul>
  11 +<%= render :partial => 'shared/list_groups', :locals => {:groups => @memberships} %>
36 12  
37 13 </div>
... ...
app/views/memberships/new_community.rhtml
... ... @@ -16,6 +16,12 @@
16 16  
17 17 <%= required f.text_field(:name) %>
18 18  
  19 + <% @plugins.dispatch(:new_community_hidden_fields).each do |field| %>
  20 + <% field.each do |key, value| %>
  21 + <%= f.hidden_field(key, :value => value) %>
  22 + <% end %>
  23 + <% end %>
  24 +
19 25 <%= render :partial => 'shared/organization_custom_fields', :locals => { :f => f, :object_name => 'community', :profile => @community } %>
20 26  
21 27 <% f.fields_for :image_builder, @community.image do |i| %>
... ... @@ -38,6 +44,8 @@
38 44 </div>
39 45 </div>
40 46  
  47 + <%= template_options(Community, 'community')%>
  48 +
41 49 <% button_bar do %>
42 50 <%= submit_button(:save, _('Create')) %>
43 51 <%= button(:cancel, _('Cancel'), :action => 'index') %>
... ...
app/views/profile/_profile_comment_form.rhtml
... ... @@ -3,15 +3,17 @@
3 3 <p class='profile-wall-reply'>
4 4 <% update_area = tab_action == 'wall' ? 'profile_activities' : 'network-activities' %>
5 5 <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_comment_on_activity', :tab_action => tab_action}, :html => { :class => 'profile-wall-reply-form', 'data-update' => update_area } do %>
6   - <%= text_area :comment, :body, {:id => "reply_content_#{activity.id}",
7   - :cols => 50,
8   - :rows => 1,
9   - :class => 'submit-with-keypress',
10   - :title => _('Leave your comment'),
11   - :onfocus => ('if(this.value==this.title){this.value="";this.style.color="#000"};this.style.backgroundImage="url(' + profile_icon(current_person, :icon, false) + ')"' if logged_in?),
12   - :onblur => ('if(this.value==""){this.value=this.title;this.style.color="#ccc"};this.style.backgroundImage="none"' if logged_in?),
13   - :value => _('Leave your comment'),
14   - :style => 'color: #ccc' } %>
  6 + <%= expandable_text_area :comment,
  7 + :body,
  8 + "reply_content_#{activity.id}",
  9 + :cols => 50,
  10 + :rows => 1,
  11 + :class => 'submit-with-keypress',
  12 + :title => _('Leave your comment'),
  13 + :onfocus => ('if(this.value==this.title){this.value="";this.style.color="#000"};this.style.backgroundImage="url(' + profile_icon(current_person, :icon, false) + ')"' if logged_in?),
  14 + :onblur => ('if(this.value==""){this.value=this.title;this.style.color="#ccc"};this.style.backgroundImage="none"' if logged_in?),
  15 + :value => _('Leave your comment'),
  16 + :style => 'color: #ccc' %>
15 17 <%= hidden_field_tag :source_id, activity.id, :id => "activity_id_#{activity.id}" %>
16 18 <% end %>
17 19 </p>
... ...
app/views/profile/_profile_scrap_reply_form.rhtml
... ... @@ -2,15 +2,16 @@
2 2 <div id='profile-wall-reply-form-<%= scrap.id%>' style='display:none'>
3 3 <p class='profile-wall-reply'>
4 4 <% form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap'}, :update => "profile_activities", :html => { :class => 'profile-wall-reply-form'} do %>
5   - <%= text_area :scrap, :content, { :id => "reply_content_#{scrap.id}",
6   - :cols => 50,
7   - :rows => 1,
8   - :class => 'submit-with-keypress',
9   - :title => _('Leave your comment'),
10   - :onfocus => ('if(this.value==this.title){this.value="";this.style.color="#000"};this.style.backgroundImage="url(' + profile_icon(current_person, :icon, false) + ')"' if logged_in?),
11   - :onblur => ('if(this.value==""){this.value=this.title;this.style.color="#ccc"};this.style.backgroundImage="none"' if logged_in?),
12   - :value => _('Leave your comment')
13   - } %>
  5 + <%= expandable_text_area :scrap,
  6 + :content,
  7 + "reply_content_#{scrap.id}",
  8 + :cols => 50,
  9 + :rows => 1,
  10 + :class => 'submit-with-keypress',
  11 + :title => _('Leave your comment'),
  12 + :onfocus => ('if(this.value==this.title){this.value="";this.style.color="#000"};this.style.backgroundImage="url(' + profile_icon(current_person, :icon, false) + ')"' if logged_in?),
  13 + :onblur => ('if(this.value==""){this.value=this.title;this.style.color="#ccc"};this.style.backgroundImage="none"' if logged_in?),
  14 + :value => _('Leave your comment') %>
14 15 <%= hidden_field_tag 'scrap[scrap_id]', scrap.id %>
15 16 <%= hidden_field_tag 'receiver_id', scrap.sender.id %>
16 17 <% end %>
... ...
app/views/profile/_upload_image.rhtml
... ... @@ -6,15 +6,9 @@
6 6 <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
7 7 <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
8 8 <div class='profile-wall-actions'>
9   - <%= link_to(s_('profile|Comment'), '#', { :class => 'focus-on-comment'}) unless activity.get_view_url.size == 1 %>
10 9 <%= link_to_remote(content_tag(:span, _('Remove')), :confirm => _('Are you sure?'), :url =>{:action => 'remove_activity', :activity_id => activity.id}, :update => "profile-activity-item-#{activity.id}") if logged_in? && current_person == @profile %>
11 10 </div>
12 11 </div>
13 12 </div>
14 13 <div title='<%= activity.target.class.short_description %>' class='profile-activity-icon icon-new icon-newgallery'></div>
15   -
16   -<% if activity.get_view_url.size == 1 %>
17   - <%= render :partial => 'profile_comments', :locals => { :activity => activity, :tab_action => tab_action } %>
18   -<% end %>
19   -
20 14 <br/>
... ...
app/views/profile/index.rhtml
... ... @@ -29,7 +29,6 @@
29 29 <% if logged_in? && current_person.follows?(@profile) %>
30 30 <% tabs << {:title => _('Wall'), :id => 'profile-wall', :content => (render :partial => 'profile_wall')} %>
31 31 <% end %>
32   - <% tabs << {:title => _('What\'s new'), :id => 'profile-network', :content => (render :partial => 'profile_network')} %>
33 32 <% elsif @profile.person? %>
34 33 <% tabs << {:title => _('Profile'), :id => 'person-profile', :content => (render :partial => 'person_profile')} %>
35 34 <% if logged_in? && current_person.follows?(@profile) %>
... ...
app/views/profile_editor/edit.rhtml
... ... @@ -4,6 +4,12 @@
4 4  
5 5 <% labelled_form_for :profile_data, @profile, :html => { :id => 'profile-data', :multipart => true } do |f| %>
6 6  
  7 + <% if user.has_permission?('manage_environment_templates', profile.environment) %>
  8 + <div id="profile-is-template">
  9 + <%= labelled_check_box(_('This profile is a template'), 'profile_data[is_template]', true, @profile.is_template) %>
  10 + </div>
  11 + <% end %>
  12 +
7 13 <%= render :partial => partial_for_class(@profile.class), :locals => { :f => f } %>
8 14  
9 15 <% unless @profile.person? && @environment.active_person_fields.include?('image') %>
... ...
app/views/search/_display_results.rhtml
1   -<div id="search-results" class="<%= @results.size == 1 ? 'only-one-result-box' : 'multiple-results-boxes' %>">
  1 +<div id="search-results" class="<%= !multiple_search? ? 'only-one-result-box' : 'multiple-results-boxes' %>">
2 2 <% @order.each do |name| %>
3 3 <% results = @results[name] %>
4 4 <% empty = results.nil? || results.empty? %>
... ... @@ -7,7 +7,7 @@
7 7 <% if not empty %>
8 8 <% partial = partial_for_class(results.first.class.class_name.constantize) %>
9 9  
10   - <% if @results.size > 1 %>
  10 + <% if multiple_search? %>
11 11 <h3><%= @names[name] %></h3>
12 12 <% if results.total_entries > SearchController::MULTIPLE_SEARCH_LIMIT %>
13 13 <%= link_to(_('see all (%d)') % results.total_entries, params.merge(:action => name), :class => 'see-more' ) %>
... ... @@ -22,9 +22,10 @@
22 22 </ul>
23 23 </div>
24 24 <% else %>
25   - <% if @results.size > 1 %>
  25 + <% if multiple_search? %>
26 26 <h3><%= @names[name] %></h3>
27 27 <% end %>
  28 +
28 29 <div class="search-results-innerbox search-results-type-empty">
29 30 <div> <%= _('None') %> </div>
30 31 </div>
... ...
app/views/search/_product.rhtml
... ... @@ -27,9 +27,9 @@
27 27 <% end %>
28 28  
29 29 <% if product.price_described? %>
30   - <% title = (product.inputs + product.price_details).map{ |i|
  30 + <% title = (product.inputs.relevant_to_price + product.price_details).map{ |i|
31 31 '<div class="search-product-input-dots-to-price">' +
32   - '<div class="search-product-input-name">' + i.product_category.name + '</div>' +
  32 + '<div class="search-product-input-name">' + i.name + '</div>' +
33 33 price_span(i.price, :class => 'search-product-input-price') +
34 34 '</div>' }.join('') %>
35 35 <%= link_to_function _("Open Price"), '', :title => title, :class => "search-product-price-details" %>
... ...
app/views/search/_profile.rhtml
1 1 <li class="search-profile-item">
2   -<% if @empty_query or @results.size > 1 or !profile.enterprise? %>
  2 +<% if @empty_query or multiple_search? or !profile.enterprise? %>
3 3 <%= profile_image_link profile, :portrait, 'div',
4 4 @filter == 'more_recent' ? profile.send(@filter + '_label') + show_date(profile.created_at) : profile.send(@filter + '_label') %>
5 5 <% else %>
... ...
app/views/shared/_list_groups.html.erb 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +<ul id="groups-list">
  2 +<% for group in groups %>
  3 + <li>
  4 + <div class='common-profile-list-block'>
  5 + <%= profile_image_link(group, :portrait, 'div') %>
  6 + </div>
  7 + <span class='profile-details'>
  8 + <strong><%= group.name %></strong><br/>
  9 + <%= _('Role: %s') % rolename_for(profile, group) + '<br/>' if profile.role_assignments.find_by_resource_id(group.id) %>
  10 + <%= _('Type: %s') % getterm(group.class.identification) %> <br/>
  11 + <%= _('Description: %s') % group.description + '<br/>' if group.community? %>
  12 + <%= _('Members: %s') % group.members_count.to_s %> <br/>
  13 + <%= _('Created at: %s') % show_date(group.created_at) unless group.enterprise? %> <br/>
  14 + <% button_bar do %>
  15 + <%= button 'menu-ctrl-panel', _('Control panel of this group'), group.admin_url %>
  16 + <%= button 'menu-logout', _('Leave community'), group.leave_url(true), :class => 'leave-community' %>
  17 + <% if (group.community? && user.has_permission?(:destroy_profile, group)) %>
  18 + <%= button 'delete', _('Remove'), { :controller => 'profile_editor', :action => 'destroy_profile', :profile => group.identifier } %>
  19 + <% end %>
  20 + <% end %>
  21 + </span>
  22 + <br class="may-clear" />
  23 + </li>
  24 +<% end %>
  25 +</ul>
  26 +
... ...
app/views/tasks/processed.rhtml
... ... @@ -7,7 +7,7 @@
7 7 <ul>
8 8 <% @tasks.each do |item| %>
9 9 <li>
10   - <strong><%= item.information %></strong> <br/>
  10 + <strong><%= task_information(item) %></strong> <br/>
11 11 <small>
12 12 <%= _('Created:') +' '+ show_date(item.created_at) %>
13 13 &nbsp; &#151; &nbsp;
... ...
app/views/templates/_create_template_form.html.erb 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +<% if @error %>
  2 + <div class="errorExplanation" id="errorExplanation">
  3 + <h2><%= _('The template could not be saved') %></h2>
  4 + <p><%= _('There were problems with the following fields:') %> </p>
  5 + <ul>
  6 + <li><%= @error %></li>
  7 + </ul>
  8 + </div>
  9 +<% end %>
  10 +
  11 +<% form_tag do %>
  12 + <%= labelled_text_field(_('Name')+': ', :name)%>
  13 +
  14 + <% button_bar do %>
  15 + <%= submit_button('save', _('Save'))%>
  16 + <%= button('cancel', _('Cancel'), {:action => 'index'})%>
  17 + <% end %>
  18 +<% end %>
  19 +
... ...
app/views/templates/create_community_template.html.erb 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +<% title = case @kind
  2 + when 'person'
  3 +
  4 + when 'community'
  5 +
  6 + when 'enterprise'
  7 + _('Create enterprise template')
  8 +end %>
  9 +
  10 +<h1><%= _('Create community template') %></h1>
  11 +
  12 +<%= render :partial => 'create_template_form' %>
... ...
app/views/templates/create_enterprise_template.html.erb 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +<h1><%= _('Create enterprise template') %></h1>
  2 +
  3 +<%= render :partial => 'create_template_form' %>
... ...
app/views/templates/create_person_template.html.erb 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +<% title = case @kind
  2 + when 'person'
  3 +
  4 + when 'community'
  5 + _('Create community template')
  6 + when 'enterprise'
  7 + _('Create enterprise template')
  8 +end %>
  9 +
  10 +<h1><%= _('Create person template') %></h1>
  11 +
  12 +<%= render :partial => 'create_template_form' %>
... ...
app/views/templates/index.html.erb 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +<h1><%= _('Edit Templates') %></h1>
  2 +
  3 +<%= _('Manage the templates used on creation of profiles') %>
  4 +
  5 +<% list_of_templates = [[_('Person') , Person.templates , 'person' ],
  6 + [_('Community') , Community.templates , 'community' ],
  7 + [_('Enterprise'), Enterprise.templates, 'enterprise']] %>
  8 +
  9 +<% list_of_templates.each do |title, templates, kind|%>
  10 + <div class='template-kind'>
  11 + <h2><%= title %></h2>
  12 + <%= button :add, _('New...'), {:action => "create_#{kind}_template"}, :title => _("Create a new template for %s") % title.downcase %>
  13 + <ul>
  14 + <% templates.each do |template| %>
  15 + <li>
  16 + <%= image_tag "icons-app/#{kind}-icon.png" %>
  17 + <%= link_to(template.name, {:controller => 'profile_editor', :profile => template.identifier}, :title => _('Edit template "%s"') % template.name ) %>
  18 + </li>
  19 + <% end %>
  20 + </ul>
  21 + </div>
  22 +<% end %>
  23 +
  24 +<% button_bar do %>
  25 + <%= button :back, _('Back to admin panel'), :controller => 'admin_panel' %>
  26 +<% end %>
... ...
config/initializers/action_tracker.rb
... ... @@ -23,7 +23,28 @@ ActionTrackerConfig.verbs = {
23 23 },
24 24  
25 25 :upload_image => {
26   - :description => lambda { n_('uploaded 1 image<br />%{thumbnails}<br style="clear: both;" />', 'uploaded %{num} images<br />%{thumbnails}<br style="clear: both;" />', get_view_url.size) % { :num => get_view_url.size, :thumbnails => '{{ta.collect_group_with_index(:thumbnail_path){ |t,i| content_tag(:span, link_to(image_tag(t), ta.get_view_url[i]))}.last(3).join}}' } },
  26 + :description => lambda do
  27 + total = get_view_url.size
  28 + n_('uploaded 1 image', 'uploaded %d images', total) % total +
  29 + '<br />{{'+
  30 + 'ta.collect_group_with_index(:thumbnail_path) { |t,i|' +
  31 + " if ( #{total} == 1 );" +
  32 + ' link_to( image_tag(t), ta.get_view_url[i], :class => \'upimg\' );' +
  33 + ' else;' +
  34 + " pos = #{total}-i;" +
  35 + ' morethen2 = pos>2 ? \'morethen2\' : \'\';' +
  36 + ' morethen5 = pos>5 ? \'morethen5\' : \'\';' +
  37 + ' t = t.gsub(/(.*)(display)(.*)/, \'\\1thumb\\3\');' +
  38 + ' link_to( \'&nbsp;\', ta.get_view_url[i],' +
  39 + ' :style => "background-image:url(#{t})",' +
  40 + ' :class => "upimg pos#{pos} #{morethen2} #{morethen5}" );' +
  41 + ' end' +
  42 + '}.reverse.join}}' +
  43 + ( total > 5 ?
  44 + '<span class="more" onclick="this.parentNode.className+=\' show-all\'">' +
  45 + '&hellip;</span>' : '' ) +
  46 + '<br style="clear: both;" />'
  47 + end,
27 48 :type => :groupable
28 49 },
29 50  
... ...
config/initializers/plugins.rb
1 1 require 'noosfero/plugin'
  2 +require 'noosfero/plugin/acts_as_having_hotspots'
2 3 require 'noosfero/plugin/manager'
3 4 require 'noosfero/plugin/context'
4 5 require 'noosfero/plugin/active_record'
... ...
db/migrate/20120710033223_add_template_and_is_template_fields.rb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +class AddTemplateAndIsTemplateFields < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :profiles, :is_template, :boolean, :default => false
  4 + add_column :profiles, :template_id, :integer
  5 + end
  6 +
  7 + def self.down
  8 + remove_column :profiles, :is_template
  9 + remove_column :profiles, :template_id
  10 + end
  11 +end
... ...
db/migrate/20120710062802_fill_is_template_field_on_basic_templates.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class FillIsTemplateFieldOnBasicTemplates < ActiveRecord::Migration
  2 + def self.up
  3 + update("update profiles set is_template = (1=1) where identifier like '%_template'")
  4 + end
  5 +
  6 + def self.down
  7 + say('This migration can\'t be reverted.')
  8 + end
  9 +end
... ...
db/migrate/20120713073641_create_licenses.rb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +class CreateLicenses < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :licenses do |t|
  4 + t.string :name, :null => false
  5 + t.string :slug, :null => false
  6 + t.string :url
  7 + t.references :environment, :null => false
  8 + end
  9 + end
  10 +
  11 + def self.down
  12 + drop_table :licenses
  13 + end
  14 +end
... ...
db/migrate/20120713082741_add_license_to_article.rb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +class AddLicenseToArticle < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :articles, :license_id, :integer
  4 + add_column :article_versions, :license_id, :integer
  5 + end
  6 +
  7 + def self.down
  8 + remove_column :articles, :license_id
  9 + remove_column :article_versions, :license_id
  10 + end
  11 +end
... ...
db/migrate/20120716161506_add_manage_environment_license_to_admin_role.rb 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +class AddManageEnvironmentLicenseToAdminRole < ActiveRecord::Migration
  2 + def self.up
  3 + Environment.all.map(&:id).each do |id|
  4 + role = Environment::Roles.admin(id)
  5 + role.permissions << 'manage_environment_licenses'
  6 + role.save!
  7 + end
  8 + end
  9 +
  10 + def self.down
  11 + Environment.all.map(&:id).each do |id|
  12 + role = Environment::Roles.admin(id)
  13 + role.permissions -= ['manage_environment_licenses']
  14 + role.save!
  15 + end
  16 + end
  17 +end
... ...
db/migrate/20120718145131_add_manage_environment_templates_to_admin_role.rb 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +class AddManageEnvironmentTemplatesToAdminRole < ActiveRecord::Migration
  2 + def self.up
  3 + Environment.all.map(&:id).each do |id|
  4 + role = Environment::Roles.admin(id)
  5 + role.permissions << 'manage_environment_templates'
  6 + role.save!
  7 + end
  8 + end
  9 +
  10 + def self.down
  11 + Environment.all.map(&:id).each do |id|
  12 + role = Environment::Roles.admin(id)
  13 + role.permissions -= ['manage_environment_templates']
  14 + role.save!
  15 + end
  16 + end
  17 +end
... ...
db/migrate/20120718162001_create_default_licenses.rb 0 → 100644
... ... @@ -0,0 +1,27 @@
  1 +class CreateDefaultLicenses < ActiveRecord::Migration
  2 + def self.up
  3 + Environment.all.each do |environment|
  4 + License.create!(:name => 'CC (by)', :url => 'http://creativecommons.org/licenses/by/3.0/legalcode', :environment => environment)
  5 + License.create!(:name => 'CC (by-nd)', :url => 'http://creativecommons.org/licenses/by-nd/3.0/legalcode', :environment => environment)
  6 + License.create!(:name => 'CC (by-sa)', :url => 'http://creativecommons.org/licenses/by-sa/3.0/legalcode', :environment => environment)
  7 + License.create!(:name => 'CC (by-nc)', :url => 'http://creativecommons.org/licenses/by-nc/3.0/legalcode', :environment => environment)
  8 + License.create!(:name => 'CC (by-nc-nd)', :url => 'http://creativecommons.org/licenses/by-nc-nd/3.0/legalcode', :environment => environment)
  9 + License.create!(:name => 'CC (by-nc-sa)', :url => 'http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode', :environment => environment)
  10 + License.create!(:name => 'Free Art', :url => 'http://artlibre.org/licence/lal/en', :environment => environment)
  11 + License.create!(:name => 'GNU FDL', :url => 'http://www.gnu.org/licenses/fdl-1.3.txt', :environment => environment)
  12 + end
  13 + end
  14 +
  15 + def self.down
  16 + licenses = []
  17 + licenses += License.find(:all, :conditions => {:name => 'CC (by)'})
  18 + licenses += License.find(:all, :conditions => {:name => 'CC (by-nd)'})
  19 + licenses += License.find(:all, :conditions => {:name => 'CC (by-sa)'})
  20 + licenses += License.find(:all, :conditions => {:name => 'CC (by-nc)'})
  21 + licenses += License.find(:all, :conditions => {:name => 'CC (by-nc-nd)'})
  22 + licenses += License.find(:all, :conditions => {:name => 'CC (by-nc-sa)'})
  23 + licenses += License.find(:all, :conditions => {:name => 'Free Art'})
  24 + licenses += License.find(:all, :conditions => {:name => 'GNU FDL'})
  25 + licenses.compact.map(&:destroy)
  26 + end
  27 +end
... ...
db/migrate/20120813163139_set_activation_code_to_nil_if_already_activated.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class SetActivationCodeToNilIfAlreadyActivated < ActiveRecord::Migration
  2 + def self.up
  3 + update("UPDATE users SET activation_code = null WHERE activated_at IS NOT NULL")
  4 + end
  5 +
  6 + def self.down
  7 + say('Can not be reverted.')
  8 + end
  9 +end
... ...
db/migrate/20120818030329_remove_action_tracker_with_target_nil.rb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +class RemoveActionTrackerWithTargetNil < ActiveRecord::Migration
  2 + def self.up
  3 + select_all("SELECT id FROM action_tracker").each do |tracker|
  4 + activity = ActionTracker::Record.find_by_id(tracker['id'])
  5 + if activity && activity.target.nil?
  6 + activity.destroy
  7 + end
  8 + end
  9 + end
  10 +
  11 + def self.down
  12 + say "this migration can't be reverted"
  13 + end
  14 +end
... ...
db/schema.rb
... ... @@ -9,7 +9,7 @@
9 9 #
10 10 # It's strongly recommended to check this file into your version control system.
11 11  
12   -ActiveRecord::Schema.define(:version => 20120411132751) do
  12 +ActiveRecord::Schema.define(:version => 20120818030329) do
13 13  
14 14 create_table "abuse_reports", :force => true do |t|
15 15 t.integer "reporter_id"
... ... @@ -85,6 +85,7 @@ ActiveRecord::Schema.define(:version =&gt; 20120411132751) do
85 85 t.integer "translation_of_id"
86 86 t.string "language"
87 87 t.string "source_name"
  88 + t.integer "license_id"
88 89 end
89 90  
90 91 create_table "articles", :force => true do |t|
... ... @@ -125,6 +126,7 @@ ActiveRecord::Schema.define(:version =&gt; 20120411132751) do
125 126 t.integer "translation_of_id"
126 127 t.string "language"
127 128 t.string "source_name"
  129 + t.integer "license_id"
128 130 end
129 131  
130 132 add_index "articles", ["translation_of_id"], :name => "index_articles_on_translation_of_id"
... ... @@ -314,6 +316,13 @@ ActiveRecord::Schema.define(:version =&gt; 20120411132751) do
314 316 add_index "inputs", ["product_category_id"], :name => "index_inputs_on_product_category_id"
315 317 add_index "inputs", ["product_id"], :name => "index_inputs_on_product_id"
316 318  
  319 + create_table "licenses", :force => true do |t|
  320 + t.string "name", :null => false
  321 + t.string "slug", :null => false
  322 + t.string "url"
  323 + t.integer "environment_id", :null => false
  324 + end
  325 +
317 326 create_table "mailing_sents", :force => true do |t|
318 327 t.integer "mailing_id"
319 328 t.integer "person_id"
... ... @@ -425,6 +434,8 @@ ActiveRecord::Schema.define(:version =&gt; 20120411132751) do
425 434 t.boolean "validated", :default => true
426 435 t.string "cnpj"
427 436 t.string "national_region_code"
  437 + t.boolean "is_template", :default => false
  438 + t.integer "template_id"
428 439 end
429 440  
430 441 add_index "profiles", ["environment_id"], :name => "index_profiles_on_environment_id"
... ...
debian/changelog
  1 +noosfero (0.38.2) unstable; urgency=low
  2 +
  3 + * Bugfixes release
  4 +
  5 + -- Antonio Terceiro <terceiro@colivre.coop.br> Wed, 05 Sep 2012 10:07:58 -0300
  6 +
  7 +noosfero (0.38.1) unstable; urgency=low
  8 +
  9 + * Bugfixes release
  10 +
  11 + -- Daniela Soares Feitosa <daniela@colivre.coop.br> Sat, 18 Aug 2012 07:49:59 -0300
  12 +
  13 +noosfero (0.38.0) unstable; urgency=low
  14 +
  15 + * Features version release
  16 +
  17 + -- Daniela Soares Feitosa <daniela@colivre.coop.br> Tue, 31 Jul 2012 19:51:43 -0300
  18 +
1 19 noosfero (0.37.0) unstable; urgency=low
2 20  
3 21 * Features version release
... ...
debian/control
... ... @@ -47,11 +47,12 @@ Depends:
47 47 memcached,
48 48 debconf,
49 49 dbconfig-common,
50   - postgresql,
51 50 adduser,
52 51 exim4 | mail-transport-agent,
53 52 ${misc:Depends}
54   -Recommends: postgresql-client
  53 +Recommends:
  54 + postgresql,
  55 + postgresql-client
55 56 Description: free web-based platform for social networks
56 57 Noosfero is a web platform for social and solidarity economy networks with
57 58 blog, e-Porfolios, CMS, RSS, thematic discussion, events agenda and collective
... ... @@ -61,8 +62,7 @@ Description: free web-based platform for social networks
61 62  
62 63 Package: noosfero-apache
63 64 Architecture: all
64   -Depends: apache2, debconf
65   -Suggests: noosfero
  65 +Depends: apache2, debconf, noosfero
66 66 Description: free web-based platform for social networks (apache frontend)
67 67 Noosfero is a web platform for social and solidarity economy networks with
68 68 blog, e-Porfolios, CMS, RSS, thematic discussion, events agenda and collective
... ...
debian/thin.yml
... ... @@ -2,7 +2,7 @@
2 2 pid: tmp/pids/thin.pid
3 3 address: 127.0.0.1
4 4 user: noosfero
5   -timeout: 30
  5 +timeout: 0
6 6 port: 50000
7 7 log: log/thin.log
8 8 max_conns: 1024
... ...
etc/logrotate.d/noosfero
1   -/var/log/noosfero/*.log /home/noosfero/current/log/*.log {
  1 +/var/log/noosfero/*.log {
2 2 daily
3 3 missingok
4 4 rotate 30
... ...
etc/noosfero/varnish-noosfero.vcl
1 1 sub vcl_recv {
  2 + if (req.request == "GET" || req.request == "HEAD") {
2 3 if (req.http.Cookie) {
3   - # We only care about the "_noosfero_session.*" cookie, used for
4   - # authentication.
5   - if (req.http.Cookie ~ "_noosfero_session.*" ) {
6   - return (pass);
7   - }
8   - # Else strip all cookies
  4 + # We only care about the "_noosfero_session.*" cookie, used for
  5 + # authentication.
  6 + if (req.http.Cookie !~ "_noosfero_session.*" ) {
  7 + # strip all cookies
9 8 unset req.http.Cookie;
  9 + }
10 10 }
  11 + }
11 12 }
12 13  
13 14 sub vcl_error {
... ...
features/edit_environment_templates.feature
1 1 Feature: edit environment templates
2 2 As an administrator
3   - I want edit templates
  3 + I want to edit templates
4 4  
5 5 Background:
6 6 Given that the default environment have all profile templates
... ... @@ -9,37 +9,37 @@ Feature: edit environment templates
9 9 Given I am logged in as admin
10 10 When I follow "Administration"
11 11 And I follow "Edit Templates"
12   - Then I should see "Edit Person Template" link
13   - And I should see "Edit Community Template" link
14   - And I should see "Edit Enterprise Template" link
15   - And I should see "Edit Inactive Enterprise Template" link
  12 + Then I should see "Person template" link
  13 + And I should see "Community template" link
  14 + And I should see "Enterprise template" link
  15 + And I should see "Inactive Enterprise template" link
16 16  
17 17 Scenario: Go to control panel of person template
18 18 Given I am logged in as admin
19 19 When I follow "Administration"
20 20 And I follow "Edit Templates"
21   - And I follow "Edit Person Template"
  21 + And I follow "Person template"
22 22 Then I should be on Person template's control panel
23 23  
24 24 Scenario: Go to control panel of enterprise template
25 25 Given I am logged in as admin
26 26 When I follow "Administration"
27 27 And I follow "Edit Templates"
28   - And I follow "Edit Enterprise Template"
  28 + And I follow "Enterprise template"
29 29 Then I should be on Enterprise template's control panel
30 30  
31 31 Scenario: Go to control panel of inactive enterprise template
32 32 Given I am logged in as admin
33 33 When I follow "Administration"
34 34 And I follow "Edit Templates"
35   - And I follow "Edit Inactive Enterprise Template"
  35 + And I follow "Inactive enterprise template"
36 36 Then I should be on Inactive Enterprise template's control panel
37 37  
38 38 Scenario: Go to control panel of community template
39 39 Given I am logged in as admin
40 40 When I follow "Administration"
41 41 And I follow "Edit Templates"
42   - And I follow "Edit Community Template"
  42 + And I follow "Community template"
43 43 Then I should be on Community template's control panel
44 44  
45 45 Scenario: Not see link to edit an unexistent template
... ... @@ -47,7 +47,7 @@ Feature: edit environment templates
47 47 And I am logged in as admin
48 48 When I follow "Administration"
49 49 And I follow "Edit Templates"
50   - Then I should see "Edit Person Template" link
51   - And I should see "Edit Community Template" link
52   - And I should see "Edit Enterprise Template" link
53   - And I should not see "Edit Inactive Enterprise Template" link
  50 + Then I should see "Person template" link
  51 + And I should see "Community template" link
  52 + And I should see "Enterprise template" link
  53 + And I should not see "Inactive enterprise template" link
... ...
features/private_profile.feature
... ... @@ -30,16 +30,6 @@ Feature: private profiles
30 30 When I go to shygirl's homepage
31 31 Then I should not see "Add friend"
32 32  
33   - Scenario: viewing a private community profile shouldn't show the news if not logged or not a member
34   - Given I am on Safernet's homepage
35   - Then I should not see "What's new"
36   - And I am logged in as "joao"
37   - When I am on Safernet's homepage
38   - Then I should not see "What's new"
39   - And "joao" is a member of "Safernet"
40   - When I am on Safernet's homepage
41   - Then I should see "What's new"
42   -
43 33 Scenario: person private profiles should not display sensible information
44 34 Given I am logged in as "joao"
45 35 When I go to shygirl's homepage
... ...
features/step_definitions/mezuro_steps.rb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +Then /^I directly delete content with name "([^\"]*)" for testing purposes$/ do |content_name|
  2 + Article.find_by_name(content_name).destroy
  3 +end
  4 +
  5 +Then /^I should be at the url "([^\"]*)"$/ do |url|
  6 + if response.class.to_s == 'Webrat::SeleniumResponse'
  7 + URI.parse(response.selenium.get_location).path.should == url
  8 + else
  9 + URI.parse(current_url).path.should == url
  10 + end
  11 +end
  12 +
  13 +Then /^I don't fill anything$/ do
  14 +end
... ...
lib/noosfero.rb
... ... @@ -2,7 +2,7 @@ require &#39;fast_gettext&#39;
2 2  
3 3 module Noosfero
4 4 PROJECT = 'noosfero'
5   - VERSION = '0.37.0'
  5 + VERSION = '0.38.2'
6 6  
7 7 def self.pattern_for_controllers_in_directory(dir)
8 8 disjunction = controllers_in_directory(dir).join('|')
... ...
lib/noosfero/plugin.rb
... ... @@ -256,4 +256,29 @@ class Noosfero::Plugin
256 256 nil
257 257 end
258 258  
  259 + # -> Extends organization list of members
  260 + # returns = An instance of ActiveRecord::NamedScope::Scope retrieved through
  261 + # Person.members_of method.
  262 + def organization_members(organization)
  263 + nil
  264 + end
  265 +
  266 + # -> Extends person permission access
  267 + # returns = boolean
  268 + def has_permission?(person, permission, target)
  269 + nil
  270 + end
  271 +
  272 + # -> Adds hidden_fields to the new community view
  273 + # returns = {key => value}
  274 + def new_community_hidden_fields
  275 + nil
  276 + end
  277 +
  278 + # -> Adds hidden_fields to the enterprise registration view
  279 + # returns = {key => value}
  280 + def enterprise_registration_hidden_fields
  281 + nil
  282 + end
  283 +
259 284 end
... ...
lib/noosfero/plugin/acts_as_having_hotspots.rb 0 → 100644
... ... @@ -0,0 +1,44 @@
  1 +module ActsAsHavingHotspots
  2 + module ClassMethods
  3 + # Adding this feature to a class demands that it defines an instance method
  4 + # 'environment' that returns the environment associated with the instance.
  5 + def acts_as_having_hotspots
  6 + send :include, InstanceMethods
  7 + end
  8 +
  9 + module InstanceMethods
  10 + # Dispatches +event+ to each enabled plugin and collect the results.
  11 + #
  12 + # Returns an Array containing the objects returned by the event method in
  13 + # each plugin. This array is compacted (i.e. nils are removed) and flattened
  14 + # (i.e. elements of arrays are added to the resulting array). For example, if
  15 + # the enabled plugins return 1, 0, nil, and [1,2,3], then this method will
  16 + # return [1,0,1,2,3]
  17 + #
  18 + def dispatch(event, *args)
  19 + enabled_plugins.map { |plugin| plugin.send(event, *args) }.compact.flatten
  20 + end
  21 +
  22 + # Dispatch without flatten since scopes are executed if you run flatten on them
  23 + def dispatch_scopes(event, *args)
  24 + enabled_plugins.map { |plugin| plugin.send(event, *args) }.compact
  25 + end
  26 +
  27 + def enabled_plugins
  28 + Thread.current[:enabled_plugins] ||= (Noosfero::Plugin.all & environment.enabled_plugins).map do |plugin_name|
  29 + plugin = plugin_name.constantize.new
  30 + plugin.context = context
  31 + plugin
  32 + end
  33 + end
  34 +
  35 + if !method_defined?(:context)
  36 + define_method(:context) do
  37 + Noosfero::Plugin::Context.new
  38 + end
  39 + end
  40 + end
  41 + end
  42 +end
  43 +
  44 +ActiveRecord::Base.send(:extend, ActsAsHavingHotspots::ClassMethods)
... ...
lib/noosfero/plugin/context.rb
... ... @@ -2,7 +2,7 @@
2 2 # controller that can be accessed by plugins
3 3 class Noosfero::Plugin::Context
4 4  
5   - def initialize(controller)
  5 + def initialize(controller = ApplicationController.new)
6 6 @controller = controller
7 7 end
8 8  
... ...
lib/noosfero/plugin/manager.rb
1 1 class Noosfero::Plugin::Manager
2 2  
3   - attr_reader :context
  3 + extend ActsAsHavingHotspots::ClassMethods
  4 + acts_as_having_hotspots
4 5  
5   - def initialize(controller)
6   - @context = Noosfero::Plugin::Context.new(controller)
7   - end
  6 + attr_reader :context
8 7  
  8 + delegate :environment, :to => :context
9 9 delegate :each, :to => :enabled_plugins
10 10 include Enumerable
11 11  
12   - # Dispatches +event+ to each enabled plugin and collect the results.
13   - #
14   - # Returns an Array containing the objects returned by the event method in
15   - # each plugin. This array is compacted (i.e. nils are removed) and flattened
16   - # (i.e. elements of arrays are added to the resulting array). For example, if
17   - # the enabled plugins return 1, 0, nil, and [1,2,3], then this method will
18   - # return [1,0,1,2,3]
19   - #
20   - def dispatch(event, *args)
21   - map { |plugin| plugin.send(event, *args) }.compact.flatten
22   - end
23   -
24   - def enabled_plugins
25   - @enabled_plugins ||= (Noosfero::Plugin.all & context.environment.enabled_plugins).map do |plugin|
26   - p = plugin.constantize.new
27   - p.context = context
28   - p
  12 + def initialize(controller)
  13 + @context = Noosfero::Plugin::Context.new(controller)
  14 + Thread.current[:enabled_plugins] = (Noosfero::Plugin.all & environment.enabled_plugins).map do |plugin_name|
  15 + plugin = plugin_name.constantize.new
  16 + plugin.context = context
  17 + plugin
29 18 end
30 19 end
31 20  
... ...