Commit 1c541c6f1431c436ece9fae60635390778647eea

Authored by Leandro Santos
2 parents a6c2ec9e e41d1f06

Merge branch 'serpro-context' of gitlab.com:participa/noosfero into serpro-context

Showing 366 changed files with 22696 additions and 8215 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 366 files displayed.

INSTALL.chat.md
1   -XMPP/Chat Setup
2   -===============
  1 +Automatic XMPP/Chat Setup
  2 +=========================
  3 +
  4 +Since Noosfero 1.2, the XMPP/Chat can be installed via `noosfero-chat` Debian
  5 +package. So you don't need to follow the manual instructions here if you
  6 +already have it installed on your system.
  7 +
  8 +But if you are going to install the `noosfero-chat` package on a system that
  9 +already has `noosfero` older 1.2 installed then you need to check if apache's
  10 +configuration file `/etc/apache2/sites-available/noosfero` has this line below:
  11 +
  12 + Include /usr/share/noosfero/util/chat/apache/xmpp.conf
  13 +
  14 +Manual XMPP/Chat Setup
  15 +======================
3 16  
4 17 The samples of config file to configure a XMPP/BOSH server with ejabberd,
5 18 postgresql and apache2 can be found at util/chat directory.
... ... @@ -8,7 +21,7 @@ This setup supposes that you are using Noosfero installed via Debian package
8 21 in a production environment.
9 22  
10 23 Steps
11   -=====
  24 +-----
12 25  
13 26 This is a step-by-step guide to get a XMPP service working, in a Debian system.
14 27  
... ... @@ -144,15 +157,8 @@ You should see a page with a message like that:
144 157  
145 158 ## 9. Test chat session
146 159  
147   -Open Noosfero console and execute:
148   -
149   ->> environment = Environment.default
150   ->> user = Person['guest']
151   ->> password = user.user.crypted_password
152   ->> login = user.jid
153   ->> RubyBOSH.initialize_session(login, password, "http://#{environment.default_hostname}/http-bind", :wait => 30, :hold => 1, :window => 5
154   -
155   -If you have luck, should see something like that:
  160 +Run `./script/noosfero-test-chat-session`. If you have luck, should see
  161 +something like that:
156 162  
157 163 Ruby-BOSH - SEND
158 164 <body window="5" rid="60265" xmlns="http://jabber.org/protocol/httpbind" xmlns:xmpp="urn:xmpp:xbosh" to="vagrant-debian-squeeze.vagrantup.com" wait="30" xmpp:version="1.0" hold="1"/>
... ...
INSTALL.https.md
... ... @@ -11,8 +11,8 @@ as below:
11 11  
12 12 # mkdir /etc/noosfero/ssl
13 13 # cd /etc/noosfero/ssl
14   - # openssl genrsa 1024 > noosfero.key
15   - # openssl req -new -x509 -nodes -sha1 -days $[10*365] -key noosfero.key > noosfero.cert
  14 + # openssl genrsa 2048 > noosfero.key
  15 + # openssl req -new -x509 -sha256 -nodes -days $[10*365] -key noosfero.key > noosfero.cert
16 16 # cat noosfero.key noosfero.cert > noosfero.pem
17 17  
18 18 ## Web server configuration
... ...
INSTALL.md
... ... @@ -74,7 +74,7 @@ downloading from git
74 74  
75 75 Here we are cloning the noosfero repository from git. Note: you will need to install git before.
76 76  
77   - $ git clone git://gitorious.org/noosfero/noosfero.git current
  77 + $ git clone https://gitlab.com/noosfero/noosfero.git current
78 78 $ cd current
79 79 $ git checkout -b stable origin/stable
80 80  
... ...
app/controllers/admin/admin_panel_controller.rb
... ... @@ -71,22 +71,4 @@ class AdminPanelController &lt; AdminController
71 71 end
72 72 end
73 73 end
74   -
75   - def manage_organizations_status
76   - scope = environment.organizations
77   - @filter = params[:filter] || 'any'
78   - @title = "Organization profiles"
79   - @title = @title+" - "+@filter if @filter != 'any'
80   -
81   - if @filter == 'enabled'
82   - scope = scope.visible
83   - elsif @filter == 'disabled'
84   - scope = scope.disabled
85   - end
86   -
87   - scope = scope.order('name ASC')
88   -
89   - @q = params[:q]
90   - @collection = find_by_contents(:organizations, environment, scope, @q, {:per_page => 10, :page => params[:npage]})[:results]
91   - end
92 74 end
... ...
app/controllers/admin/organizations_controller.rb 0 → 100644
... ... @@ -0,0 +1,66 @@
  1 +class OrganizationsController < AdminController
  2 +
  3 + protect 'manage_environment_organizations', :environment
  4 +
  5 + def index
  6 + @filter = params[:filter] || 'any'
  7 + @title = _('Organization profiles')
  8 + @type = params[:type] || "any"
  9 + @types_filter = [[_('All'), 'any'], [_('Community'), 'Community'], [_('Enterprise'), 'Enterprise']]
  10 + @types_filter = @types_filter | @plugins.dispatch(:organization_types_filter_options)
  11 +
  12 + scope = @plugins.dispatch_first(:filter_manage_organization_scope, @type)
  13 + if scope.blank?
  14 + scope = environment.organizations
  15 + scope = scope.where(:type => @type) if @type != 'any'
  16 + end
  17 +
  18 + if @filter == 'enabled'
  19 + scope = scope.visible
  20 + elsif @filter == 'disabled'
  21 + scope = scope.disabled
  22 + end
  23 +
  24 + scope = scope.order('name ASC')
  25 +
  26 + @q = params[:q]
  27 + @collection = find_by_contents(:organizations, environment, scope, @q, {:per_page => per_page, :page => params[:npage]})[:results]
  28 + end
  29 +
  30 + def activate
  31 + organization = environment.organizations.find(params[:id])
  32 + if organization.enable
  33 + render :text => (_('%s enabled') % organization.name).to_json
  34 + else
  35 + render :text => (_('%s could not be enabled') % organization.name).to_json
  36 + end
  37 + end
  38 +
  39 + def deactivate
  40 + organization = environment.organizations.find(params[:id])
  41 + if organization.disable
  42 + render :text => (_('%s disabled') % organization.name).to_json
  43 + else
  44 + render :text => (_('%s could not be disable') % organization.name).to_json
  45 + end
  46 + end
  47 +
  48 + def destroy
  49 + if request.post?
  50 + organization = environment.organizations.find(params[:id])
  51 + if organization && organization.destroy
  52 + render :text => (_('%s removed') % organization.name).to_json
  53 + else
  54 + render :text => (_('%s could not be removed') % organization.name).to_json
  55 + end
  56 + else
  57 + render :nothing => true
  58 + end
  59 + end
  60 +
  61 + private
  62 +
  63 + def per_page
  64 + 10
  65 + end
  66 +end
... ...
app/controllers/my_profile/cms_controller.rb
... ... @@ -112,6 +112,11 @@ class CmsController &lt; MyProfileController
112 112 end
113 113 end
114 114 end
  115 +
  116 + unless @article.kind_of?(RssFeed)
  117 + @escaped_body = CGI::escapeHTML(@article.body || '')
  118 + @escaped_abstract = CGI::escapeHTML(@article.abstract || '')
  119 + end
115 120 end
116 121  
117 122 def new
... ... @@ -144,7 +149,13 @@ class CmsController &lt; MyProfileController
144 149 article_data = environment.enabled?('articles_dont_accept_comments_by_default') ? { :accept_comments => false } : {}
145 150 article_data.merge!(params[:article]) if params[:article]
146 151 article_data.merge!(:profile => profile) if profile
147   - @article = klass.new(article_data)
  152 +
  153 + @article = if params[:clone]
  154 + current_article = profile.articles.find(params[:id])
  155 + current_article.copy_without_save
  156 + else
  157 + klass.new(article_data)
  158 + end
148 159  
149 160 parent = check_parent(params[:parent_id])
150 161 if parent
... ...
app/controllers/my_profile/friends_controller.rb
1 1 class FriendsController < MyProfileController
2   -
  2 +
3 3 protect 'manage_friends', :profile
4   -
  4 +
5 5 def index
6   - @suggestions = profile.profile_suggestions.of_person.enabled.includes(:suggestion).limit(per_page)
  6 + @suggestions = profile.suggested_profiles.of_person.enabled.includes(:suggestion).limit(per_page)
7 7 if is_cache_expired?(profile.manage_friends_cache_key(params))
8 8 @friends = profile.friends.paginate(:per_page => per_page, :page => params[:npage])
9 9 end
... ... @@ -18,7 +18,7 @@ class FriendsController &lt; MyProfileController
18 18 end
19 19  
20 20 def suggest
21   - @suggestions = profile.profile_suggestions.of_person.enabled.includes(:suggestion).limit(per_page)
  21 + @suggestions = profile.suggested_profiles.of_person.enabled.includes(:suggestion).limit(per_page)
22 22 end
23 23  
24 24 def remove_suggestion
... ... @@ -26,13 +26,13 @@ class FriendsController &lt; MyProfileController
26 26 redirect_to :action => 'suggest' unless @person
27 27 if @person && request.post?
28 28 profile.remove_suggestion(@person)
29   - @suggestions = profile.profile_suggestions.of_person.enabled.includes(:suggestion).limit(per_page)
  29 + @suggestions = profile.suggested_profiles.of_person.enabled.includes(:suggestion).limit(per_page)
30 30 render :partial => 'shared/profile_suggestions_list', :locals => { :suggestions => @suggestions, :collection => :friends_suggestions, :per_page => params[:per_page] || per_page }
31 31 end
32 32 end
33 33  
34 34 def connections
35   - @suggestion = profile.profile_suggestions.of_person.enabled.find_by_suggestion_id(params[:id])
  35 + @suggestion = profile.suggested_profiles.of_person.enabled.find_by_suggestion_id(params[:id])
36 36 if @suggestion
37 37 @tags = @suggestion.tag_connections
38 38 @profiles = @suggestion.profile_connections
... ...
app/controllers/my_profile/memberships_controller.rb
... ... @@ -40,7 +40,7 @@ class MembershipsController &lt; MyProfileController
40 40 end
41 41  
42 42 def suggest
43   - @suggestions = profile.profile_suggestions.of_community.enabled.includes(:suggestion).limit(per_page)
  43 + @suggestions = profile.suggested_profiles.of_community.enabled.includes(:suggestion).limit(per_page)
44 44 end
45 45  
46 46 def remove_suggestion
... ... @@ -49,13 +49,13 @@ class MembershipsController &lt; MyProfileController
49 49 redirect_to :action => 'suggest' unless @community
50 50 if @community && request.post?
51 51 profile.remove_suggestion(@community)
52   - @suggestions = profile.profile_suggestions.of_community.enabled.includes(:suggestion).limit(custom_per_page)
  52 + @suggestions = profile.suggested_profiles.of_community.enabled.includes(:suggestion).limit(custom_per_page)
53 53 render :partial => 'shared/profile_suggestions_list', :locals => { :suggestions => @suggestions, :collection => :communities_suggestions, :per_page => custom_per_page}
54 54 end
55 55 end
56 56  
57 57 def connections
58   - @suggestion = profile.profile_suggestions.of_community.enabled.find_by_suggestion_id(params[:id])
  58 + @suggestion = profile.suggested_profiles.of_community.enabled.find_by_suggestion_id(params[:id])
59 59 if @suggestion
60 60 @tags = @suggestion.tag_connections
61 61 @profiles = @suggestion.profile_connections
... ...
app/controllers/my_profile/tasks_controller.rb
1 1 class TasksController < MyProfileController
2 2  
3   - protect 'perform_task', :profile
4   -
  3 + protect [:perform_task, :view_tasks], :profile, :only => [:index]
  4 + protect :perform_task, :profile, :except => [:index]
  5 +
5 6 def index
6   - @filter = params[:filter_type].blank? ? nil : params[:filter_type]
  7 + @filter_type = params[:filter_type].presence
  8 + @filter_text = params[:filter_text].presence
  9 + @filter_responsible = params[:filter_responsible]
7 10 @task_types = Task.pending_types_for(profile)
8   - @tasks = Task.to(profile).without_spam.pending.of(@filter).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page])
  11 +
  12 + @tasks = Task.pending_all(profile, @filter_type, @filter_text).order_by('created_at', 'asc')
  13 + @tasks = @tasks.where(:responsible_id => @filter_responsible.to_i != -1 ? @filter_responsible : nil) if @filter_responsible.present?
  14 + @tasks = @tasks.paginate(:per_page => Task.per_page, :page => params[:page])
  15 +
9 16 @failed = params ? params[:failed] : {}
  17 +
  18 + @responsible_candidates = profile.members.by_role(profile.roles.reject {|r| !r.has_permission?('perform_task')}) if profile.organization?
  19 +
  20 + @view_only = !current_person.has_permission?(:perform_task, profile)
10 21 end
11 22  
12 23 def processed
13 24 @tasks = Task.to(profile).without_spam.closed.sort_by(&:created_at)
14 25 end
15 26  
  27 + def change_responsible
  28 + task = profile.tasks.find(params[:task_id])
  29 +
  30 + if task.responsible.present? && task.responsible.id != params[:old_responsible_id].to_i
  31 + return render :json => {:notice => _('Task already assigned!'), :success => false, :current_responsible => task.responsible.id}
  32 + end
  33 +
  34 + responsible = profile.members.find(params[:responsible_id]) if params[:responsible_id].present?
  35 + task.responsible = responsible
  36 + task.save!
  37 + render :json => {:notice => _('Task responsible successfully updated!'), :success => true, :new_responsible => {:id => responsible.present? ? responsible.id : nil}}
  38 + end
  39 +
16 40 VALID_DECISIONS = [ 'finish', 'cancel', 'skip' ]
17 41  
18 42 def close
... ... @@ -25,7 +49,7 @@ class TasksController &lt; MyProfileController
25 49 task = profile.find_in_all_tasks(id)
26 50 begin
27 51 task.update_attributes(value[:task])
28   - task.send(decision)
  52 + task.send(decision, current_person)
29 53 rescue Exception => ex
30 54 message = "#{task.title} (#{task.requestor ? task.requestor.name : task.author_name})"
31 55 failed[ex.message] ? failed[ex.message] << message : failed[ex.message] = [message]
... ...
app/controllers/public/chat_controller.rb
... ... @@ -2,6 +2,7 @@ class ChatController &lt; PublicController
2 2  
3 3 before_filter :login_required
4 4 before_filter :check_environment_feature
  5 + before_filter :can_send_message, :only => :register_message
5 6  
6 7 def start_session
7 8 login = user.jid
... ... @@ -54,6 +55,16 @@ class ChatController &lt; PublicController
54 55 end
55 56 end
56 57  
  58 + def avatars
  59 + profiles = environment.profiles.where(:identifier => params[:profiles])
  60 + avatar_map = profiles.inject({}) do |result, profile|
  61 + result[profile.identifier] = profile_icon(profile, :minor)
  62 + result
  63 + end
  64 +
  65 + render_json avatar_map
  66 + end
  67 +
57 68 def update_presence_status
58 69 if request.xhr?
59 70 current_user.update_attributes({:chat_status_at => DateTime.now}.merge(params[:status] || {}))
... ... @@ -62,11 +73,17 @@ class ChatController &lt; PublicController
62 73 end
63 74  
64 75 def save_message
65   - to = environment.profiles.find_by_identifier(params[:to])
66   - body = params[:body]
67   -
68   - ChatMessage.create!(:to => to, :from => user, :body => body)
69   - render :text => 'ok'
  76 + if request.post?
  77 + to = environment.profiles.where(:identifier => params[:to]).first
  78 + body = params[:body]
  79 +
  80 + begin
  81 + ChatMessage.create!(:to => to, :from => user, :body => body)
  82 + return render_json({:status => 0})
  83 + rescue Exception => exception
  84 + return render_json({:status => 3, :message => exception.to_s, :backtrace => exception.backtrace})
  85 + end
  86 + end
70 87 end
71 88  
72 89 def recent_messages
... ... @@ -90,8 +107,9 @@ class ChatController &lt; PublicController
90 107 end
91 108  
92 109 def recent_conversations
93   - conversations_order = ActiveRecord::Base.connection.execute("select profiles.identifier from profiles inner join (select distinct r.id as id, MAX(r.created_at) as created_at from (select from_id, to_id, created_at, (case when from_id=#{user.id} then to_id else from_id end) as id from chat_messages where from_id=#{user.id} or to_id=#{user.id}) as r group by id order by created_at desc, id) as t on profiles.id=t.id order by t.created_at desc").entries.map {|e| e['identifier']}
94   - render :json => {:order => conversations_order.reverse, :domain => environment.default_hostname.gsub('.','-')}.to_json
  110 + profiles = Profile.find_by_sql("select profiles.* from profiles inner join (select distinct r.id as id, MAX(r.created_at) as created_at from (select from_id, to_id, created_at, (case when from_id=#{user.id} then to_id else from_id end) as id from chat_messages where from_id=#{user.id} or to_id=#{user.id}) as r group by id order by created_at desc, id) as t on profiles.id=t.id order by t.created_at desc")
  111 + jids = profiles.map(&:jid).reverse
  112 + render :json => jids.to_json
95 113 end
96 114  
97 115 #TODO Ideally this is done through roster table on ejabberd.
... ... @@ -108,4 +126,14 @@ class ChatController &lt; PublicController
108 126 end
109 127 end
110 128  
  129 + def can_send_message
  130 + return render_json({:status => 1, :message => 'Missing parameters!'}) if params[:from].nil? || params[:to].nil? || params[:message].nil?
  131 + return render_json({:status => 2, :message => 'You can not send message as another user!'}) if params[:from] != user.jid
  132 + # TODO Maybe register the jid in a table someday to avoid this below
  133 + return render_json({:status => 3, :messsage => 'You can not send messages to strangers!'}) if user.friends.where(:identifier => params[:to].split('@').first).blank?
  134 + end
  135 +
  136 + def render_json(result)
  137 + render :text => result.to_json
  138 + end
111 139 end
... ...
app/controllers/public/content_viewer_controller.rb
... ... @@ -11,6 +11,7 @@ class ContentViewerController &lt; ApplicationController
11 11 path = get_path(params[:page], params[:format])
12 12  
13 13 @version = params[:version].to_i
  14 + @npage = params[:npage] || '1'
14 15  
15 16 if path.blank?
16 17 @page = profile.home_page
... ... @@ -127,7 +128,7 @@ class ContentViewerController &lt; ApplicationController
127 128 end
128 129  
129 130 unless @page.display_to?(user)
130   - if !profile.visible? || profile.secret? || (user && user.follows?(profile))
  131 + if !profile.visible? || profile.secret? || (user && user.follows?(profile)) || user.blank?
131 132 render_access_denied
132 133 else #!profile.public?
133 134 private_profile_partial_parameters
... ...
app/helpers/application_helper.rb
... ... @@ -871,7 +871,7 @@ module ApplicationHelper
871 871 field_html += capture(&block)
872 872 end
873 873  
874   - if controller.action_name == 'signup' || controller.action_name == 'new_community' || (controller.controller_name == "enterprise_registration" && controller.action_name == 'index')
  874 + if controller.action_name == 'signup' || controller.action_name == 'new_community' || (controller.controller_name == "enterprise_registration" && controller.action_name == 'index') || (controller.controller_name == 'home' && controller.action_name == 'index' && user.nil?)
875 875 if profile.signup_fields.include?(name)
876 876 result = field_html
877 877 end
... ... @@ -931,6 +931,19 @@ module ApplicationHelper
931 931 article_helper.cms_label_for_edit
932 932 end
933 933  
  934 + def label_for_clone_article(article)
  935 + translated_types = {
  936 + Folder => _('Folder'),
  937 + Blog => _('Blog'),
  938 + Event => _('Event'),
  939 + Forum => _('Forum')
  940 + }
  941 +
  942 + translated_type = translated_types[article.class] || _('Article')
  943 +
  944 + _('Clone %s') % translated_type
  945 + end
  946 +
934 947 def add_rss_feed_to_head(title, url)
935 948 content_for :feeds do
936 949 tag(:link, :rel => 'alternate', :type => 'application/rss+xml', :title => title, :href => url_for(url))
... ... @@ -1202,35 +1215,6 @@ module ApplicationHelper
1202 1215 list.sort.inject(Hash.new(0)){|h,i| h[i] += 1; h }.collect{ |x, n| [n, connector, x].join(" ") }.sort
1203 1216 end
1204 1217  
1205   - #FIXME Use time_ago_in_words instead of this method if you're using Rails 2.2+
1206   - def time_ago_as_sentence(from_time, include_seconds = false)
1207   - to_time = Time.now
1208   - from_time = Time.parse(from_time.to_s)
1209   - from_time = from_time.to_time if from_time.respond_to?(:to_time)
1210   - to_time = to_time.to_time if to_time.respond_to?(:to_time)
1211   - distance_in_minutes = (((to_time - from_time).abs)/60).round
1212   - distance_in_seconds = ((to_time - from_time).abs).round
1213   - case distance_in_minutes
1214   - when 0..1
1215   - return (distance_in_minutes == 0) ? _('less than a minute') : _('1 minute') unless include_seconds
1216   - case distance_in_seconds
1217   - when 0..4 then _('less than 5 seconds')
1218   - when 5..9 then _('less than 10 seconds')
1219   - when 10..19 then _('less than 20 seconds')
1220   - when 20..39 then _('half a minute')
1221   - when 40..59 then _('less than a minute')
1222   - else _('1 minute')
1223   - end
1224   -
1225   - when 2..44 then _('%{distance} minutes ago') % { :distance => distance_in_minutes }
1226   - when 45..89 then _('about 1 hour ago')
1227   - when 90..1439 then _('about %{distance} hours ago') % { :distance => (distance_in_minutes.to_f / 60.0).round }
1228   - when 1440..2879 then _('1 day ago')
1229   - when 2880..10079 then _('%{distance} days ago') % { :distance => (distance_in_minutes / 1440).round }
1230   - else show_time(from_time)
1231   - end
1232   - end
1233   -
1234 1218 def comment_balloon(options = {}, &block)
1235 1219 wrapper = content_tag(:div, capture(&block), :class => 'comment-balloon-content')
1236 1220 (1..8).to_a.reverse.each { |i| wrapper = content_tag(:div, wrapper, :class => "comment-wrapper-#{i}") }
... ... @@ -1498,4 +1482,26 @@ module ApplicationHelper
1498 1482 text_field(object_name, method, options.merge(:class => 'colorpicker_field'))
1499 1483 end
1500 1484  
  1485 + def fullscreen_buttons(itemId)
  1486 + content="
  1487 + <script>fullscreenPageLoad('#{itemId}')</script>
  1488 + "
  1489 + content+=content_tag('a', content_tag('span',_("Full screen")),
  1490 + { :id=>"fullscreen-btn",
  1491 + :onClick=>"toggle_fullwidth('#{itemId}')",
  1492 + :class=>"button with-text icon-fullscreen",
  1493 + :href=>"#",
  1494 + :title=>_("Go to full screen mode")
  1495 + })
  1496 +
  1497 + content+=content_tag('a', content_tag('span',_("Exit full screen")),
  1498 + { :style=>"display: none;",
  1499 + :id=>"exit-fullscreen-btn",
  1500 + :onClick=>"toggle_fullwidth('#{itemId}')",
  1501 + :class=>"button with-text icon-fullscreen",
  1502 + :href=>"#",
  1503 + :title=>_("Exit full screen mode")
  1504 + })
  1505 + end
  1506 +
1501 1507 end
... ...
app/helpers/article_helper.rb
... ... @@ -12,6 +12,7 @@ module ArticleHelper
12 12 @article = article
13 13  
14 14 visibility_options(@article, tokenized_children) +
  15 + topic_creation(@article) +
15 16 content_tag('h4', _('Options')) +
16 17 content_tag('div',
17 18 (article.profile.has_members? ?
... ... @@ -55,14 +56,7 @@ module ArticleHelper
55 56 'div',
56 57 check_box(:article, :display_versions) +
57 58 content_tag('label', _('I want this article to display a link to older versions'), :for => 'article_display_versions')
58   - ) : '') +
59   -
60   - (article.forum? && article.profile.community? ?
61   - content_tag(
62   - 'div',
63   - check_box(:article, :allows_members_to_create_topics) +
64   - content_tag('label', _('Allow members to create topics'), :for => 'article_allows_members_to_create_topics')
65   - ) : '')
  59 + ) : '')
66 60 )
67 61 end
68 62  
... ... @@ -81,6 +75,22 @@ module ArticleHelper
81 75 )
82 76 end
83 77  
  78 + def topic_creation(article)
  79 + return '' unless article.forum?
  80 +
  81 + general_options = Forum::TopicCreation.general_options(article)
  82 + slider_options = {:id => 'topic-creation-slider'}
  83 + slider_options = general_options.keys.inject(slider_options) do |result, option|
  84 + result.merge!({'data-'+option => general_options[option]})
  85 + end
  86 +
  87 + content_tag('h4', _('Topic creation')) +
  88 + content_tag( 'small', _('Who will be able to create new topics on this forum?')) +
  89 + content_tag('div', '', slider_options) +
  90 + hidden_field_tag('article[topic_creation]', article.topic_creation) +
  91 + javascript_include_tag('topic-creation-config')
  92 + end
  93 +
84 94 def privacity_exceptions(article, tokenized_children)
85 95 content_tag('div',
86 96 content_tag('div',
... ...
app/helpers/blog_helper.rb
... ... @@ -22,7 +22,9 @@ module BlogHelper
22 22 :param_name => 'npage',
23 23 :previous_label => _('&laquo; Newer posts'),
24 24 :next_label => _('Older posts &raquo;'),
25   - :params => {:action=>"view_page", :page=>articles.first.parent.path.split('/'), :controller=>"content_viewer"}
  25 + :params => {:action=>"view_page",
  26 + :page=>articles.first.parent.path.split('/'),
  27 + :controller=>"content_viewer"}
26 28 }) if articles.present? && conf[:paginate]
27 29 content = []
28 30 artic_len = articles.length
... ... @@ -44,7 +46,7 @@ module BlogHelper
44 46 end
45 47  
46 48 def display_post(article, format = 'full')
47   - no_comments = (format == 'full') ? false : true
  49 + no_comments = (format == 'full' || format == 'compact' ) ? false : true
48 50 title = article_title(article, :no_comments => no_comments)
49 51 method = "display_#{format.split('+')[0]}_format"
50 52 html = send(method, FilePresenter.for(article)).html_safe
... ... @@ -55,8 +57,12 @@ module BlogHelper
55 57 else
56 58 '<div class="post-pic" style="background-image:url('+img+')"></div>'
57 59 end
58   - end.to_s +
59   - title + html
  60 + end.to_s + title + html
  61 + end
  62 +
  63 + def display_compact_format(article)
  64 + render :file => 'content_viewer/_display_compact_format',
  65 + :locals => { :article => article, :format => "compact" }
60 66 end
61 67  
62 68 def display_full_format(article)
... ...
app/helpers/boxes_helper.rb
... ... @@ -122,7 +122,7 @@ module BoxesHelper
122 122 end
123 123  
124 124 def wrap_main_content(content)
125   - (1..8).to_a.reverse.inject(content) { |acc,n| content_tag('div', acc, :id => 'main-content-wrapper-' + n.to_s) }
  125 + content_tag('div', content, :class => 'main-content')
126 126 end
127 127  
128 128 def extract_block_content(content)
... ...
app/helpers/chat_helper.rb
... ... @@ -9,12 +9,12 @@ module ChatHelper
9 9 avatar = profile_image(user, :portrait, :class => 'avatar')
10 10 content_tag('span',
11 11 link_to(avatar + content_tag('span', user.name) + ui_icon('ui-icon-triangle-1-s'),
12   - '#',
  12 + '',
13 13 :onclick => 'toggleMenu(this); return false',
14 14 :class => icon_class + ' simplemenu-trigger'
15 15 ) +
16 16 content_tag('ul',
17   - links.map{|link| content_tag('li', link_to(link[1], '#', :class => link[0], :id => link[2], 'data-jid' => user.jid), :class => 'simplemenu-item') }.join("\n"),
  17 + links.map{|link| content_tag('li', link_to(link[1], '', :class => link[0], :id => link[2], 'data-jid' => user.jid), :class => 'simplemenu-item') }.join("\n"),
18 18 :style => 'display: none; z-index: 100',
19 19 :class => 'simplemenu-submenu'
20 20 ),
... ...
app/helpers/comment_helper.rb
1 1 module CommentHelper
  2 + include DatesHelper
2 3  
3 4 def article_title(article, args = {})
4 5 title = article.title
... ...
app/helpers/content_viewer_helper.rb
... ... @@ -2,6 +2,7 @@ module ContentViewerHelper
2 2  
3 3 include BlogHelper
4 4 include ForumHelper
  5 + include DatesHelper
5 6  
6 7 def display_number_of_comments(n)
7 8 base_str = "<span class='comment-count hide'>#{n}</span>"
... ... @@ -24,8 +25,9 @@ module ContentViewerHelper
24 25 unless args[:no_comments] || !article.accept_comments
25 26 comments = (" - %s") % link_to_comments(article)
26 27 end
  28 + date_format = show_with_right_format_date article
27 29 title << content_tag('span',
28   - content_tag('span', show_date(article.published_at), :class => 'date') +
  30 + date_format +
29 31 content_tag('span', _(", by %s") % (article.author ? link_to(article.author_name, article.author_url) : article.author_name), :class => 'author') +
30 32 content_tag('span', comments, :class => 'comments'),
31 33 :class => 'created-at'
... ... @@ -34,6 +36,24 @@ module ContentViewerHelper
34 36 title
35 37 end
36 38  
  39 + def show_with_right_format_date article
  40 + date_format = article.environment.date_format
  41 + use_numbers = false
  42 + year = true
  43 + left_time = false
  44 + if date_format == 'numbers_with_year'
  45 + use_numbers = true
  46 + elsif date_format == 'numbers'
  47 + use_numbers = true
  48 + year = false
  49 + elsif date_format == 'month_name'
  50 + year = false
  51 + elsif date_format == 'past_time'
  52 + left_time = true
  53 + end
  54 + content_tag('span', show_date(article.published_at, use_numbers , year, left_time), :class => 'date')
  55 + end
  56 +
37 57 def link_to_comments(article, args = {})
38 58 return '' unless article.accept_comments?
39 59 reference_to_article number_of_comments(article), article, 'comments_list'
... ...
app/helpers/dates_helper.rb
... ... @@ -2,6 +2,7 @@ require &#39;noosfero/i18n&#39;
2 2  
3 3 module DatesHelper
4 4  
  5 + include ActionView::Helpers::DateHelper
5 6 def months
6 7 I18n.t('date.month_names')
7 8 end
... ... @@ -15,10 +16,12 @@ module DatesHelper
15 16 end
16 17  
17 18 # formats a date for displaying.
18   - def show_date(date, use_numbers = false, year=true)
  19 + def show_date(date, use_numbers = false, year = true, left_time = false)
19 20 if date && use_numbers
20 21 date_format = year ? _('%{month}/%{day}/%{year}') : _('%{month}/%{day}')
21 22 date_format % { :day => date.day, :month => date.month, :year => date.year }
  23 + elsif date && left_time
  24 + date_format = time_ago_in_words(date)
22 25 elsif date
23 26 date_format = year ? _('%{month_name} %{day}, %{year}') : _('%{month_name} %{day}')
24 27 date_format % { :day => date.day, :month_name => month_name(date.month), :year => date.year }
... ...
app/helpers/events_helper.rb
1 1 module EventsHelper
2 2  
  3 + include DatesHelper
3 4 def list_events(date, events)
4 5 title = _('Events for %s') % show_date_month(date)
5 6 content_tag('h2', title) +
... ...
app/helpers/folder_helper.rb
... ... @@ -25,49 +25,32 @@ module FolderHelper
25 25 articles.select {|article| article.display_to?(user)}
26 26 end
27 27  
28   - def display_content_in_listing(configure={})
29   - recursive = configure[:recursive] || false
30   - list_type = configure[:list_type] || :folder
31   - level = configure[:level] || 0
32   - content = FilePresenter.for configure[:content]
  28 + def display_content_icon(content_item)
  29 + content = FilePresenter.for content_item
33 30 content_link = if content.image?
34   - link_to('&nbsp;' * (level * 4) +
35   - image_tag(icon_for_article(content)) + short_filename(content.name),
  31 + link_to(
  32 + image_tag(icon_for_article(content, :bigicon)),
36 33 content.url.merge(:view => true)
37 34 )
38 35 else
39   - link_to('&nbsp;' * (level * 4) +
40   - short_filename(content.name),
41   - content.url.merge(:view => true), :class => icon_for_article(content)
  36 + link_to('',
  37 + content.url.merge(:view => true),
  38 + :class => icon_for_article(content, :bigicon)
42 39 )
43 40 end
44   - result = content_tag(
45   - 'tr',
46   - content_tag('td', content_link ) +
47   - content_tag('td', show_date(content.updated_at), :class => 'last-update'),
48   - :class => "#{list_type}-item"
49   - )
50   - if recursive
51   - result + content.children.map {|item|
52   - display_content_in_listing :content=>item, :recursive=>recursive,
53   - :list_type=>list_type, :level=>level+1
54   - }.join("\n")
55   - else
56   - result
57   - end
58 41 end
59 42  
60   - def icon_for_article(article)
  43 + def icon_for_article(article, size = 'icon')
61 44 article = FilePresenter.for article
62   - icon = article.respond_to?(:icon_name) ?
63   - article.icon_name :
64   - article.class.icon_name(article)
65   - if (icon =~ /\//)
66   - icon
  45 + if article.respond_to?(:sized_icon)
  46 + article.sized_icon(size)
67 47 else
68   - klasses = 'icon ' + [icon].flatten.map{|name| 'icon-'+name}.join(' ')
  48 + icon = article.respond_to?(:icon_name) ?
  49 + article.icon_name :
  50 + article.class.icon_name(article)
  51 + klasses = "#{size} " + [icon].flatten.map{|name| "#{size}-"+name}.join(' ')
69 52 if article.kind_of?(UploadedFile) || article.kind_of?(FilePresenter)
70   - klasses += ' icon-upload-file'
  53 + klasses += " #{size}-upload-file"
71 54 end
72 55 klasses
73 56 end
... ...
app/helpers/forum_helper.rb
1 1 module ForumHelper
  2 + include ActionView::Helpers::DateHelper
2 3  
3 4 def cms_label_for_new_children
4 5 _('New discussion topic')
... ... @@ -42,9 +43,9 @@ module ForumHelper
42 43 def last_topic_update(article)
43 44 info = article.info_from_last_update
44 45 if info[:author_url]
45   - time_ago_as_sentence(info[:date]) + ' ' + _('by') + ' ' + link_to(info[:author_name], info[:author_url])
  46 + time_ago_in_words(info[:date]) + ' ' + _('by') + ' ' + link_to(info[:author_name], info[:author_url])
46 47 else
47   - time_ago_as_sentence(info[:date]) + ' ' + _('by') + ' ' + info[:author_name]
  48 + time_ago_in_words(info[:date]) + ' ' + _('by') + ' ' + info[:author_name]
48 49 end
49 50 end
50 51  
... ...
app/helpers/profile_editor_helper.rb
... ... @@ -141,8 +141,9 @@ module ProfileEditorHelper
141 141 )
142 142 end
143 143  
144   - def control_panel_button(title, icon, url)
145   - link_to title, url, :class => 'control-panel-%s' % icon
  144 + def control_panel_button(title, icon, url, html_options = {})
  145 + html_options ||= {}
  146 + link_to title, url, html_options.merge(:class => 'control-panel-%s' % icon)
146 147 end
147 148  
148 149 def unchangeable_privacy_field(profile)
... ...
app/helpers/search_helper.rb
... ... @@ -106,6 +106,10 @@ module SearchHelper
106 106 end
107 107 end
108 108  
  109 + def city_with_state_for_profile(p)
  110 + city_with_state(p.region) || [p.city, p.state].compact.reject(&:blank?).join(', ')
  111 + end
  112 +
109 113 def display_selector(asset, display, float = 'right')
110 114 display = nil if display.blank?
111 115 display ||= asset_class(asset).default_search_display
... ...
app/helpers/tinymce_helper.rb
... ... @@ -20,7 +20,7 @@ module TinymceHelper
20 20 :image_advtab => true,
21 21 :language => tinymce_language
22 22  
23   - options[:toolbar1] = "insertfile undo redo | copy paste | bold italic underline | styleselect fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
  23 + options[:toolbar1] = "fullscreen | insertfile undo redo | copy paste | bold italic underline | styleselect fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
24 24 if options[:mode] == 'simple'
25 25 options[:menubar] = false
26 26 else
... ...
app/helpers/users_helper.rb
... ... @@ -14,7 +14,7 @@ module UsersHelper
14 14 select_field = select_tag(:filter, options, :onchange => onchange)
15 15 content_tag('div',
16 16 content_tag('strong', _('Filter')) + ': ' + select_field,
17   - :class => "environment-users-customize-search"
  17 + :class => "environment-profiles-customize-search"
18 18 )
19 19 end
20 20  
... ...
app/models/add_friend.rb
... ... @@ -54,7 +54,7 @@ class AddFriend &lt; Task
54 54 end
55 55  
56 56 def remove_from_suggestion_list(task)
57   - suggestion = task.requestor.profile_suggestions.find_by_suggestion_id task.target.id
  57 + suggestion = task.requestor.suggested_profiles.find_by_suggestion_id task.target.id
58 58 suggestion.disable if suggestion
59 59 end
60 60 end
... ...
app/models/article.rb
... ... @@ -28,7 +28,7 @@ class Article &lt; ActiveRecord::Base
28 28 def initialize(*params)
29 29 super
30 30  
31   - if !params.blank? && params.first.has_key?(:profile)
  31 + if !params.blank? && params.first.has_key?(:profile) && !params.first[:profile].blank?
32 32 profile = params.first[:profile]
33 33 self.published = false unless profile.public?
34 34 end
... ... @@ -96,6 +96,8 @@ class Article &lt; ActiveRecord::Base
96 96 belongs_to :translation_of, :class_name => 'Article', :foreign_key => :translation_of_id
97 97 before_destroy :rotate_translations
98 98  
  99 + acts_as_voteable
  100 +
99 101 before_create do |article|
100 102 article.published_at ||= Time.now
101 103 if article.reference_article && !article.parent
... ... @@ -498,13 +500,13 @@ class Article &lt; ActiveRecord::Base
498 500  
499 501 scope :display_filter, lambda {|user, profile|
500 502 return published if (user.nil? && profile && profile.public?)
501   - return [] if user.nil? || profile.nil? || (profile && !profile.public? && !user.follows?(profile))
  503 + return [] if user.nil? || (profile && !profile.public? && !user.follows?(profile))
502 504 where(
503 505 [
504 506 "published = ? OR last_changed_by_id = ? OR profile_id = ? OR ?
505 507 OR (show_to_followers = ? AND ? AND profile_id = ?)", true, user.id, user.id,
506 508 profile.nil? ? false : user.has_permission?(:view_private_content, profile),
507   - true, user.follows?(profile), profile.id
  509 + true, user.follows?(profile), (profile.nil? ? nil : profile.id)
508 510 ]
509 511 )
510 512 }
... ... @@ -577,25 +579,24 @@ class Article &lt; ActiveRecord::Base
577 579 profile.visible? && profile.public? && published?
578 580 end
579 581  
580   -
581   - def copy(options = {})
  582 + def copy_without_save(options = {})
582 583 attrs = attributes.reject! { |key, value| ATTRIBUTES_NOT_COPIED.include?(key.to_sym) }
583 584 attrs.merge!(options)
584 585 object = self.class.new
585 586 attrs.each do |key, value|
586 587 object.send(key.to_s+'=', value)
587 588 end
  589 + object
  590 + end
  591 +
  592 + def copy(options = {})
  593 + object = copy_without_save(options)
588 594 object.save
589 595 object
590 596 end
591 597  
592 598 def copy!(options = {})
593   - attrs = attributes.reject! { |key, value| ATTRIBUTES_NOT_COPIED.include?(key.to_sym) }
594   - attrs.merge!(options)
595   - object = self.class.new
596   - attrs.each do |key, value|
597   - object.send(key.to_s+'=', value)
598   - end
  599 + object = copy_without_save(options)
599 600 object.save!
600 601 object
601 602 end
... ...
app/models/block.rb
... ... @@ -2,7 +2,7 @@ class Block &lt; ActiveRecord::Base
2 2  
3 3 attr_accessible :title, :display, :limit, :box_id, :posts_per_page,
4 4 :visualization_format, :language, :display_user,
5   - :box, :edit_modes, :move_modes
  5 + :box, :edit_modes, :move_modes, :mirror
6 6  
7 7 # to be able to generate HTML
8 8 include ActionView::Helpers::UrlHelper
... ... @@ -15,11 +15,23 @@ class Block &lt; ActiveRecord::Base
15 15  
16 16 acts_as_list :scope => :box
17 17 belongs_to :box
  18 + belongs_to :mirror_block, :class_name => "Block"
  19 + has_many :observers, :class_name => "Block", :foreign_key => "mirror_block_id"
18 20  
19 21 acts_as_having_settings
20 22  
21 23 scope :enabled, :conditions => { :enabled => true }
22 24  
  25 + after_save do |block|
  26 + if block.owner.kind_of?(Profile) && block.owner.is_template? && block.mirror?
  27 + block.observers.each do |observer|
  28 + observer.copy_from(block)
  29 + observer.title = block.title
  30 + observer.save
  31 + end
  32 + end
  33 + end
  34 +
23 35 def embedable?
24 36 false
25 37 end
... ... @@ -269,6 +281,10 @@ class Block &lt; ActiveRecord::Base
269 281 self.position = block.position
270 282 end
271 283  
  284 + def add_observer(block)
  285 + self.observers << block
  286 + end
  287 +
272 288 private
273 289  
274 290 def home_page_path
... ...
app/models/blog.rb
... ... @@ -76,9 +76,12 @@ class Blog &lt; Folder
76 76 end
77 77  
78 78 settings_items :visualization_format, :type => :string, :default => 'full'
79   - validates_inclusion_of :visualization_format, :in => [ 'full', 'short', 'short+pic' ], :if => :visualization_format
  79 + validates_inclusion_of :visualization_format,
  80 + :in => [ 'full', 'short', 'short+pic', 'compact'],
  81 + :if => :visualization_format
80 82  
81   - settings_items :display_posts_in_current_language, :type => :boolean, :default => false
  83 + settings_items :display_posts_in_current_language,
  84 + :type => :boolean, :default => false
82 85  
83 86 alias :display_posts_in_current_language? :display_posts_in_current_language
84 87  
... ...
app/models/chat_message.rb
... ... @@ -4,4 +4,5 @@ class ChatMessage &lt; ActiveRecord::Base
4 4 belongs_to :to, :class_name => 'Profile'
5 5 belongs_to :from, :class_name => 'Profile'
6 6  
  7 + validates_presence_of :from, :to
7 8 end
... ...
app/models/comment.rb
... ... @@ -37,6 +37,8 @@ class Comment &lt; ActiveRecord::Base
37 37  
38 38 xss_terminate :only => [ :body, :title, :name ], :on => 'validation'
39 39  
  40 + acts_as_voteable
  41 +
40 42 def comment_root
41 43 (reply_of && reply_of.comment_root) || self
42 44 end
... ...
app/models/environment.rb
... ... @@ -3,7 +3,17 @@
3 3 # domains.
4 4 class Environment < ActiveRecord::Base
5 5  
6   - attr_accessible :name, :is_default, :signup_welcome_text_subject, :signup_welcome_text_body, :terms_of_use, :message_for_disabled_enterprise, :news_amount_by_folder, :default_language, :languages, :description, :organization_approval_method, :enabled_plugins, :enabled_features, :redirection_after_login, :redirection_after_signup, :contact_email, :theme, :reports_lower_bound, :noreply_email, :signup_welcome_screen_body, :members_whitelist_enabled, :members_whitelist, :highlighted_news_amount, :portal_news_amount
  6 + attr_accessible :name, :is_default, :signup_welcome_text_subject,
  7 + :signup_welcome_text_body, :terms_of_use,
  8 + :message_for_disabled_enterprise, :news_amount_by_folder,
  9 + :default_language, :languages, :description,
  10 + :organization_approval_method, :enabled_plugins,
  11 + :enabled_features, :redirection_after_login,
  12 + :redirection_after_signup, :contact_email, :theme,
  13 + :reports_lower_bound, :noreply_email,
  14 + :signup_welcome_screen_body, :members_whitelist_enabled,
  15 + :members_whitelist, :highlighted_news_amount,
  16 + :portal_news_amount, :date_format
7 17  
8 18 has_many :users
9 19  
... ... @@ -14,6 +24,12 @@ class Environment &lt; ActiveRecord::Base
14 24  
15 25 IDENTIFY_SCRIPTS = /(php[0-9s]?|[sp]htm[l]?|pl|py|cgi|rb)/
16 26  
  27 + validates_inclusion_of :date_format,
  28 + :in => [ 'numbers_with_year', 'numbers',
  29 + 'month_name_with_year', 'month_name',
  30 + 'past_time'],
  31 + :if => :date_format
  32 +
17 33 def self.verify_filename(filename)
18 34 filename += '.txt' if File.extname(filename) =~ IDENTIFY_SCRIPTS
19 35 filename
... ... @@ -29,6 +45,7 @@ class Environment &lt; ActiveRecord::Base
29 45 'manage_environment_roles' => N_('Manage environment roles'),
30 46 'manage_environment_validators' => N_('Manage environment validators'),
31 47 'manage_environment_users' => N_('Manage environment users'),
  48 + 'manage_environment_organizations' => N_('Manage environment organizations'),
32 49 'manage_environment_templates' => N_('Manage environment templates'),
33 50 'manage_environment_licenses' => N_('Manage environment licenses'),
34 51 'manage_environment_trusted_sites' => N_('Manage environment trusted sites'),
... ... @@ -74,7 +91,8 @@ class Environment &lt; ActiveRecord::Base
74 91 'edit_profile_design',
75 92 'manage_products',
76 93 'manage_friends',
77   - 'perform_task'
  94 + 'perform_task',
  95 + 'view_tasks'
78 96 ]
79 97 )
80 98 end
... ... @@ -339,6 +357,16 @@ class Environment &lt; ActiveRecord::Base
339 357 self.save!
340 358 end
341 359  
  360 + def enable_all_plugins
  361 + Noosfero::Plugin.available_plugin_names.each do |plugin|
  362 + plugin_name = plugin.to_s + "Plugin"
  363 + unless self.enabled_plugins.include?(plugin_name)
  364 + self.enabled_plugins += [plugin_name]
  365 + end
  366 + end
  367 + self.save!
  368 + end
  369 +
342 370 # Disables a feature identified by its name
343 371 def disable(feature, must_save=true)
344 372 self.settings["#{feature}_enabled".to_sym] = false
... ...
app/models/forum.rb
... ... @@ -3,11 +3,11 @@ class Forum &lt; Folder
3 3 acts_as_having_posts :order => 'updated_at DESC'
4 4 include PostsLimit
5 5  
6   - attr_accessible :has_terms_of_use, :terms_of_use, :allows_members_to_create_topics
  6 + attr_accessible :has_terms_of_use, :terms_of_use, :topic_creation
7 7  
8 8 settings_items :terms_of_use, :type => :string, :default => ""
9 9 settings_items :has_terms_of_use, :type => :boolean, :default => false
10   - settings_items :allows_members_to_create_topics, :type => :boolean, :default => false
  10 + settings_items :topic_creation, :type => :string, :default => 'self'
11 11 has_and_belongs_to_many :users_with_agreement, :class_name => 'Person', :join_table => 'terms_forum_people'
12 12  
13 13 before_save do |forum|
... ... @@ -33,6 +33,23 @@ class Forum &lt; Folder
33 33 _('An internet forum, also called message board, where discussions can be held.')
34 34 end
35 35  
  36 + module TopicCreation
  37 + BASE = ActiveSupport::OrderedHash.new
  38 + BASE['users'] = _('Logged users')
  39 +
  40 + PERSON = ActiveSupport::OrderedHash.new
  41 + PERSON['self'] = _('Me')
  42 + PERSON['related'] = _('Friends')
  43 +
  44 + GROUP = ActiveSupport::OrderedHash.new
  45 + GROUP['self'] = _('Administrators')
  46 + GROUP['related'] = _('Members')
  47 +
  48 + def self.general_options(forum)
  49 + forum.profile.person? ? PERSON.merge(BASE) : GROUP.merge(BASE)
  50 + end
  51 + end
  52 +
36 53 include ActionView::Helpers::TagHelper
37 54 def to_html(options = {})
38 55 proc do
... ... @@ -69,11 +86,17 @@ class Forum &lt; Folder
69 86 self.users_with_agreement.exists? user
70 87 end
71 88  
72   - def can_create_topic?(user, profile)
73   - return profile.community? && profile.members.include?(user) && self.allows_members_to_create_topics
  89 + def can_create_topic?(user)
  90 + return true if user == profile || profile.admins.include?(user) || profile.environment.admins.include?(user)
  91 + case topic_creation
  92 + when 'related'
  93 + profile.person? ? profile.friends.include?(user) : profile.members.include?(user)
  94 + when 'users'
  95 + user.present?
  96 + end
74 97 end
75 98  
76 99 def allow_create?(user)
77   - super || can_create_topic?(user, profile)
  100 + super || can_create_topic?(user)
78 101 end
79 102 end
... ...
app/models/person.rb
... ... @@ -84,9 +84,9 @@ roles] }
84 84 has_and_belongs_to_many :acepted_forums, :class_name => 'Forum', :join_table => 'terms_forum_people'
85 85 has_and_belongs_to_many :articles_with_access, :class_name => 'Article', :join_table => 'article_privacy_exceptions'
86 86  
87   - has_many :profile_suggestions, :foreign_key => :person_id, :order => 'score DESC', :dependent => :destroy
88   - has_many :suggested_people, :through => :profile_suggestions, :source => :suggestion, :conditions => ['profile_suggestions.suggestion_type = ? AND profile_suggestions.enabled = ?', 'Person', true]
89   - has_many :suggested_communities, :through => :profile_suggestions, :source => :suggestion, :conditions => ['profile_suggestions.suggestion_type = ? AND profile_suggestions.enabled = ?', 'Community', true]
  87 + has_many :suggested_profiles, :class_name => 'ProfileSuggestion', :foreign_key => :person_id, :order => 'score DESC', :dependent => :destroy
  88 + has_many :suggested_people, :through => :suggested_profiles, :source => :suggestion, :conditions => ['profile_suggestions.suggestion_type = ? AND profile_suggestions.enabled = ?', 'Person', true]
  89 + has_many :suggested_communities, :through => :suggested_profiles, :source => :suggestion, :conditions => ['profile_suggestions.suggestion_type = ? AND profile_suggestions.enabled = ?', 'Community', true]
90 90  
91 91 scope :more_popular, :order => 'friends_count DESC'
92 92  
... ... @@ -103,6 +103,8 @@ roles] }
103 103  
104 104 belongs_to :user, :dependent => :delete
105 105  
  106 + acts_as_voter
  107 +
106 108 def can_change_homepage?
107 109 !environment.enabled?('cant_change_homepage') || is_admin?
108 110 end
... ... @@ -522,7 +524,7 @@ roles] }
522 524 end
523 525  
524 526 def remove_suggestion(profile)
525   - suggestion = profile_suggestions.find_by_suggestion_id profile.id
  527 + suggestion = suggested_profiles.find_by_suggestion_id profile.id
526 528 suggestion.disable if suggestion
527 529 end
528 530  
... ...
app/models/product_category.rb
... ... @@ -10,6 +10,9 @@ class ProductCategory &lt; Category
10 10 :joins => :products,
11 11 :conditions => ['products.profile_id = ?', enterprise.id]
12 12 }}
  13 + scope :by_environment, lambda { |environment| {
  14 + :conditions => ['environment_id = ?', environment.id]
  15 + }}
13 16 scope :unique_by_level, lambda { |level| {
14 17 :select => "DISTINCT ON (filtered_category) split_part(path, '/', #{level}) AS filtered_category, categories.*"
15 18 }}
... ...
app/models/profile.rb
... ... @@ -71,6 +71,7 @@ class Profile &lt; ActiveRecord::Base
71 71 'manage_friends' => N_('Manage friends'),
72 72 'validate_enterprise' => N_('Validate enterprise'),
73 73 'perform_task' => N_('Perform task'),
  74 + 'view_tasks' => N_('View tasks'),
74 75 'moderate_comments' => N_('Moderate comments'),
75 76 'edit_appearance' => N_('Edit appearance'),
76 77 'view_private_content' => N_('View private content'),
... ... @@ -392,6 +393,9 @@ class Profile &lt; ActiveRecord::Base
392 393 new_block = block.class.new(:title => block[:title])
393 394 new_block.copy_from(block)
394 395 new_box.blocks << new_block
  396 + if block.mirror?
  397 + block.add_observer(new_block)
  398 + end
395 399 end
396 400 end
397 401 end
... ... @@ -1021,7 +1025,7 @@ private :generate_url, :url_options
1021 1025 end
1022 1026  
1023 1027 def remove_from_suggestion_list(person)
1024   - suggestion = person.profile_suggestions.find_by_suggestion_id self.id
  1028 + suggestion = person.suggested_profiles.find_by_suggestion_id self.id
1025 1029 suggestion.disable if suggestion
1026 1030 end
1027 1031  
... ...
app/models/profile_suggestion.rb
... ... @@ -113,14 +113,14 @@ class ProfileSuggestion &lt; ActiveRecord::Base
113 113 suggested_profiles = all_suggestions(person)
114 114 return if suggested_profiles.nil?
115 115  
116   - already_suggested_profiles = person.profile_suggestions.map(&:suggestion_id).join(',')
  116 + already_suggested_profiles = person.suggested_profiles.map(&:suggestion_id).join(',')
117 117 suggested_profiles = suggested_profiles.where("profiles.id NOT IN (#{already_suggested_profiles})") if already_suggested_profiles.present?
118 118 #TODO suggested_profiles = suggested_profiles.order('score DESC')
119 119 suggested_profiles = suggested_profiles.limit(N_SUGGESTIONS)
120 120 return if suggested_profiles.blank?
121 121  
122 122 suggested_profiles.each do |suggested_profile|
123   - suggestion = person.profile_suggestions.find_or_initialize_by_suggestion_id(suggested_profile.id)
  123 + suggestion = person.suggested_profiles.find_or_initialize_by_suggestion_id(suggested_profile.id)
124 124 RULES.each do |rule, options|
125 125 begin
126 126 value = suggested_profile.send("#{rule}_count").to_i
... ... @@ -273,7 +273,7 @@ class ProfileSuggestion &lt; ActiveRecord::Base
273 273 end
274 274  
275 275 def self.generate_profile_suggestions(person, force = false)
276   - return if person.profile_suggestions.enabled.count >= MIN_LIMIT && !force
  276 + return if person.suggested_profiles.enabled.count >= MIN_LIMIT && !force
277 277 Delayed::Job.enqueue ProfileSuggestionsJob.new(person.id) unless ProfileSuggestionsJob.exists?(person.id)
278 278 end
279 279  
... ...
app/models/suggest_article.rb
... ... @@ -25,7 +25,7 @@ class SuggestArticle &lt; Task
25 25  
26 26 def article_object
27 27 if @article_object.nil?
28   - @article_object = article_type.new(article.merge({:profile => target}).except(:type))
  28 + @article_object = article_type.new(article.merge(target.present? ? {:profile => target} : {}).except(:type))
29 29 if requestor.present?
30 30 @article_object.author = requestor
31 31 else
... ...
app/models/task.rb
... ... @@ -33,6 +33,8 @@ class Task &lt; ActiveRecord::Base
33 33  
34 34 belongs_to :requestor, :class_name => 'Profile', :foreign_key => :requestor_id
35 35 belongs_to :target, :foreign_key => :target_id, :polymorphic => true
  36 + belongs_to :responsible, :class_name => 'Person', :foreign_key => :responsible_id
  37 + belongs_to :closed_by, :class_name => 'Person', :foreign_key => :closed_by_id
36 38  
37 39 validates_uniqueness_of :code, :on => :create
38 40 validates_presence_of :code
... ... @@ -76,11 +78,9 @@ class Task &lt; ActiveRecord::Base
76 78 # this method finished the task. It calls #perform, which must be overriden
77 79 # by subclasses. At the end a message (as returned by #finish_message) is
78 80 # sent to the requestor with #notify_requestor.
79   - def finish
  81 + def finish(closed_by=nil)
80 82 transaction do
81   - self.status = Task::Status::FINISHED
82   - self.end_date = Time.now
83   - self.save!
  83 + close(Task::Status::FINISHED, closed_by)
84 84 self.perform
85 85 begin
86 86 send_notification(:finished)
... ... @@ -105,11 +105,9 @@ class Task &lt; ActiveRecord::Base
105 105  
106 106 # this method cancels the task. At the end a message (as returned by
107 107 # #cancel_message) is sent to the requestor with #notify_requestor.
108   - def cancel
  108 + def cancel(closed_by=nil)
109 109 transaction do
110   - self.status = Task::Status::CANCELLED
111   - self.end_date = Time.now
112   - self.save!
  110 + close(Task::Status::CANCELLED, closed_by)
113 111 begin
114 112 send_notification(:cancelled)
115 113 rescue NotImplementedError => ex
... ... @@ -118,6 +116,13 @@ class Task &lt; ActiveRecord::Base
118 116 end
119 117 end
120 118  
  119 + def close(status, closed_by)
  120 + self.status = status
  121 + self.end_date = Time.now
  122 + self.closed_by = closed_by
  123 + self.save!
  124 + end
  125 +
121 126 # Here are the tasks customizable options.
122 127  
123 128 def title
... ... @@ -239,6 +244,10 @@ class Task &lt; ActiveRecord::Base
239 244 scope :opened, :conditions => { :status => [Task::Status::ACTIVE, Task::Status::HIDDEN] }
240 245 scope :of, lambda { |type| conditions = type ? "type LIKE '#{type}'" : "1=1"; {:conditions => [conditions]} }
241 246 scope :order_by, lambda { |attribute, ord| {:order => "#{attribute} #{ord}"} }
  247 + scope :like, lambda { |field, value| where("LOWER(#{field}) LIKE ?", "%#{value.downcase}%") if value}
  248 + scope :pending_all, lambda { |profile, filter_type, filter_text|
  249 + self.to(profile).without_spam.pending.of(filter_type).like('data', filter_text)
  250 + }
242 251  
243 252 scope :to, lambda { |profile|
244 253 environment_condition = nil
... ...
app/models/uploaded_file.rb
... ... @@ -65,7 +65,7 @@ class UploadedFile &lt; Article
65 65 # :min_size => 2.megabytes
66 66 # :max_size => 5.megabytes
67 67 has_attachment :storage => :file_system,
68   - :thumbnails => { :icon => [24,24], :thumb => '130x130>', :slideshow => '320x240>', :display => '640X480>' },
  68 + :thumbnails => { :icon => [24,24], :bigicon => [50,50], :thumb => '130x130>', :slideshow => '320x240>', :display => '640X480>' },
69 69 :thumbnail_class => Thumbnail,
70 70 :max_size => self.max_size
71 71  
... ...
app/presenters/image.rb
... ... @@ -4,6 +4,10 @@ class FilePresenter::Image &lt; FilePresenter
4 4 f.image? ? 10 : nil
5 5 end
6 6  
  7 + def sized_icon(size)
  8 + public_filename size
  9 + end
  10 +
7 11 def icon_name
8 12 public_filename :icon
9 13 end
... ...
app/views/admin_panel/_site_info.html.erb
... ... @@ -3,6 +3,21 @@
3 3 <%= labelled_form_field(_('No reply email'), text_field(:environment, :noreply_email)) %>
4 4 <% themes_options = Theme.system_themes.map {|theme| [theme.name, theme.id] }.sort %>
5 5 <%= labelled_form_field(_('Theme'), select(:environment, :theme, options_for_select(themes_options, environment.theme))) %>
  6 +
  7 +<%= labelled_form_field(
  8 + _("Article's date format"),
  9 + select(:environment, :date_format,
  10 + options_for_select([
  11 + [ _('mm/dd/yyyy'), 'numbers_with_year'],
  12 + [ _('mm/dd'), 'numbers'],
  13 + [ _('Month dd, yyyy'), 'month_name_with_year'],
  14 + [ _('Month dd'), 'month_name'],
  15 + [ _('X minutes/hours/days/months/years ago'), 'past_time']
  16 + ], environment.date_format
  17 + )
  18 + )
  19 +) %>
  20 +
6 21 <%= required f.text_field(:reports_lower_bound, :size => 3) %>
7 22 <%= labelled_form_field(_('Default language'), select(:environment, :default_language, environment.locales.invert, { :selected => environment.default_locale, :include_blank => true })) %>
8 23 <%= label_tag :languages, _('Available languages') %>
... ...
app/views/admin_panel/index.html.erb
... ... @@ -18,9 +18,9 @@
18 18 <table>
19 19 <tr><td><%= link_to _('User roles'), :controller => 'role' %></td></tr>
20 20 <tr><td><%= link_to _('Users'), :controller => 'users' %></td></tr>
  21 + <tr><td><%= link_to _('Organizations'), :controller => 'organizations' %></td></tr>
21 22 <tr><td><%= link_to _('Profile templates'), :controller => 'templates' %></td></tr>
22 23 <tr><td><%= link_to _('Fields'), :controller => 'features', :action => 'manage_fields' %></td></tr>
23   - <tr><td><%= link_to _('Manage organizations status'), :action => 'manage_organizations_status' %></td></tr>
24 24 </table>
25 25  
26 26  
... ...
app/views/admin_panel/manage_organizations_status.html.erb
... ... @@ -1,69 +0,0 @@
1   -<h1><%= _('Manage organizations') %></h1>
2   -
3   -<%= form_tag( { :action => 'manage_organizations_status' }, :method => 'get', :class => 'users-search' ) do %>
4   -
5   - <div class="search-field">
6   - <span class="formfield">
7   - <%= text_field_tag 'q', @q, :title => _("Find profiles"), :style=>"width:85%" %>
8   - </span>
9   -
10   - <%= submit_button(:search, _('Search')) %>
11   - </div>
12   -
13   - <div class="environment-users-results-header">
14   - <div id='environment-users-filter-title'><%= @title %></div>
15   -
16   - <div id="environment-users-filter-filter">
17   - <strong><%= _("Filter by: ") %></strong>
18   -
19   - <select id="profile_filter_select">
20   - <%= options_for_select([['Any', 'any'],["Disabled profiles", "disabled"], ["Enabled profiles", "enabled"]], @filter) %>
21   - </select>
22   - </div>
23   - <div style="clear: both"></div>
24   - </div>
25   -
26   - <table>
27   - <colgroup>
28   - <col width="80%">
29   - <col width="20%">
30   - </colgroup>
31   -
32   - <tr>
33   - <th><%= _('Member') %></th>
34   - <th><%= _('Actions') %></th>
35   - </tr>
36   -
37   - <% @collection.each do |p| %>
38   - <tr title="<%= p.name %>">
39   - <td><%= link_to_profile p.short_name, p.identifier, :title => p.name %> </td>
40   -
41   - <td class='actions'>
42   - <div class="members-buttons-cell">
43   - <% if p.visible %>
44   - <%= button_without_text :'deactivate-user', _('Deactivate'), {:controller => "profile_editor", :action => 'deactivate_profile', :profile => p.identifier, :id => p.id}, :confirm => _("Do you want to deactivate this profile ?") %>
45   - <% else %>
46   - <%= button_without_text :'activate-user', _('Activate'), {:controller => "profile_editor", :action => 'activate_profile', :profile => p.identifier, :id => p.id}, :confirm => _("Do you want to activate this profile ?") %>
47   - <% end %>
48   - <%= button_without_text :'delete', _('Remove'), {:controller => "profile_editor", :action => 'destroy_profile', :profile => p.identifier, :id => p.id, :return_to => "/admin/admin_panel/manage_organizations_status"}, :method => :post, :confirm => _("Do you want to deactivate this profile ?") %>
49   - </div>
50   - </td>
51   - </tr>
52   - <% end %>
53   - </table>
54   -
55   -<% end %>
56   -
57   -<%= pagination_links @collection, {:param_name => 'npage', :page_links => true} %>
58   -
59   -<% button_bar do %>
60   - <%= button :back, _('Back'), :controller => 'admin_panel' %>
61   -<% end %>
62   -
63   -<script type="text/javascript">
64   - jQuery(document).ready(function(){
65   - jQuery("#profile_filter_select").change(function(){
66   - document.location.href = '/admin/admin_panel/manage_organizations_status?filter='+this.value;
67   - });
68   - });
69   -</script>
70 0 \ No newline at end of file
app/views/blocks/profile_info_actions/_common.html.erb 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +<li><%= report_abuse(profile, :button) %></li>
  2 +<%= render_environment_features(:profile_actions) %>
... ...
app/views/blocks/profile_info_actions/_community.html.erb
... ... @@ -13,8 +13,6 @@
13 13 </li>
14 14 <% end %>
15 15  
16   - <li><%= report_abuse(profile, :button) %></li>
17   -
18   - <%= render_environment_features(:profile_actions) %>
  16 + <%= render :partial => 'blocks/profile_info_actions/common' %>
19 17 <% end %>
20 18 </ul>
... ...
app/views/blocks/profile_info_actions/_enterprise.html.erb
... ... @@ -8,5 +8,5 @@
8 8 <li><%= button(:'menu-mail', _('Send an e-mail'), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}, {:id => 'enterprise-contact-button'} ) %></li>
9 9 <% end %>
10 10  
11   - <li><%= report_abuse(profile, :button) %></li>
  11 + <%= render :partial => 'blocks/profile_info_actions/common' %>
12 12 </ul>
... ...
app/views/blocks/profile_info_actions/_person.html.erb
... ... @@ -11,6 +11,6 @@
11 11 <li><%= button(:back, _('Send an e-mail'), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}) %></li>
12 12 <% end %>
13 13  
14   - <li><%= report_abuse(profile, :button) %></li>
  14 + <%= render :partial => 'blocks/profile_info_actions/common' %>
15 15 <% end %>
16 16 </ul>
... ...
app/views/box_organizer/edit.html.erb
... ... @@ -28,6 +28,12 @@
28 28 </div>
29 29 <% end %>
30 30  
  31 + <% if @block.owner.kind_of?(Profile) && @block.owner.is_template? %>
  32 + <div class="mirror_block">
  33 + <%= labelled_check_box(_("Mirror"), "block[mirror]", value = "1", checked = @block.mirror) %>
  34 + </div>
  35 + <% end %>
  36 +
31 37 <% button_bar do %>
32 38 <%= submit_button(:save, _('Save')) %>
33 39 <%= modal_close_button(_('Cancel')) %>
... ...
app/views/chat/start_session_error.html.erb
1 1 <p>
2 2 <%= ui_icon('ui-icon-alert') %>
3   -<%= _('Could not connect to chat') %>, <a id='chat-retry' href='#' data-jid='<%= user.jid %>'><%= _('try again') %></a>.
  3 +<%= _('Could not connect to chat') %>, <a id='chat-retry' href='' data-jid='<%= user.jid %>'><%= _('try again') %></a>.
4 4 </p>
... ...
app/views/cms/_blog.html.erb
... ... @@ -67,7 +67,8 @@
67 67 <%= labelled_form_field(_('How to display posts:'), f.select(:visualization_format, [
68 68 [ _('Full post'), 'full'],
69 69 [ _('First paragraph'), 'short'],
70   - [ _('First paragraph, with post picture'), 'short+pic']
  70 + [ _('First paragraph, with post picture'), 'short+pic'],
  71 + [ _("Title, Image, Lead"), 'compact']
71 72 ])) %>
72 73  
73 74 <%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, Blog.posts_per_page_options)) %>
... ...
app/views/cms/_forum.html.erb
... ... @@ -2,6 +2,8 @@
2 2  
3 3 <h1><%= _('My Forum') %></h1>
4 4  
  5 +<%= required_fields_message %>
  6 +
5 7 <%= render :file => 'shared/tiny_mce' %>
6 8  
7 9 <%= required f.text_field(:name, :size => '64', :maxlength => 150, :onchange => "updateUrlField(this, 'article_slug')") %>
... ...
app/views/content_viewer/_article_toolbar.html.erb
1 1 <div<%= user && " class='logged-in'" %>>
2 2 <div id="article-actions">
3 3  
  4 + <%= fullscreen_buttons('#article') %>
4 5  
5 6 <% if @page.allow_edit?(user) && !remove_content_button(:edit, @page) %>
6 7 <% content = content_tag('span', label_for_edit_article(@page)) %>
... ... @@ -29,6 +30,10 @@
29 30 <% end %>
30 31  
31 32 <%= modal_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)))) unless remove_content_button(:new, @page) %>
  33 +
  34 + <% content = content_tag('span', label_for_clone_article(@page)) %>
  35 + <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'new', :id => @page.id, :clone => true, :type => @page.class }) %>
  36 + <%= expirable_button @page, :clone, content, url %>
32 37 <% end %>
33 38  
34 39 <% if @page.accept_uploads? && @page.allow_create?(user) %>
... ... @@ -57,7 +62,7 @@
57 62 <% if @page.blog? and !@page.image.nil? %>
58 63 <div class="blog-cover"><%= image_tag(@page.image.public_filename())%></div>
59 64 <% end %>
60   - <%= link_to(image_tag('icons-mime/rss-feed.png'), @page.feed.url, :class => 'blog-feed-link') if @page.has_posts? && @page.feed %>
  65 + <%= link_to(image_tag('/images/icons-mime/rss-feed.png'), @page.feed.url, :class => 'blog-feed-link') if @page.has_posts? && @page.feed %>
61 66 <%= @plugins.dispatch(:article_header_extra_contents, @page).collect { |content| instance_exec(&content) }.join("") %>
62 67 <%= article_title(@page, :no_link => true) %>
63 68 <%= article_translations(@page) %>
... ...
app/views/content_viewer/_display_compact_format.html.erb 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +<% if article.image %>
  2 + <% className = "article-compact-abstract-with-image" %>
  3 + <% if article.image.thumbnails_processed? %>
  4 + <% image_file = article.image.public_filename(:big) %>
  5 + <% else %>
  6 + <% image_file = "/images/icons-app/image-loading-thumb.png" %>
  7 + <% end %>
  8 +<% else %>
  9 + <% className = "article-compact-abstract" %>
  10 +<% end %>
  11 +
  12 +<div>
  13 + <% if article.image %>
  14 + <div class = "article-compact-image">
  15 + <%= image_tag(image_file) %>
  16 + </div>
  17 + <% end %>
  18 + <div class = <%= className %> >
  19 + <%= article.abstract.truncate(400) %>
  20 + </div>
  21 +</div>
... ...
app/views/content_viewer/blog_page.html.erb
... ... @@ -8,7 +8,7 @@
8 8 </div>
9 9 </div>
10 10 <hr class="pre-posts"/>
11   -<div class="blog-posts">
  11 +<div class="blog-posts page-<%= @npage %>">
12 12 <% paginate = true %>
13 13 <%=
14 14 posts = @posts
... ...
app/views/content_viewer/folder.html.erb
1 1 <% unless folder.body.blank? %>
2   - <div>
  2 + <div class="folder-description">
3 3 <%= folder.body %>
4 4 </div>
5   - <hr/>
6 5 <% end %>
7 6  
8 7 <% if folder.children.empty? %>
... ...
app/views/organizations/_results.html.erb 0 → 100644
... ... @@ -0,0 +1,41 @@
  1 +<div class='results'>
  2 + <table id='organizations-list'>
  3 + <colgroup>
  4 + <col width="60%">
  5 + <col width="20%">
  6 + <col width="20%">
  7 + </colgroup>
  8 +
  9 + <tr>
  10 + <th><%= _('Profile') %></th>
  11 + <th><%= _('Actions') %></th>
  12 + <th><%= _('Type') %>
  13 +
  14 + <%= select_tag(:type, options_for_select(@types_filter, @type)) %>
  15 + </th>
  16 + </tr>
  17 +
  18 + <% @collection.each do |p| %>
  19 + <tr title="<%= p.name %>">
  20 + <td><%= link_to_profile p.short_name, p.identifier, :title => p.name %> </td>
  21 +
  22 + <td class='actions'>
  23 + <div class="members-buttons-cell">
  24 + <% if p.visible %>
  25 + <%= button_without_text :'deactivate-user', _('Deactivate'), {:action => 'deactivate', :id => p.id}, :class => 'action', 'data-confirm' => _("Do you want to deactivate this organization?") %>
  26 + <% else %>
  27 + <%= button_without_text :'activate-user', _('Activate'), {:action => 'activate', :id => p.id}, :class => 'action', 'data-confirm' => _("Do you want to activate this organization?") %>
  28 + <% end %>
  29 + <%= button_without_text :'delete', _('Remove'), {:action => 'destroy', :id => p.id}, :class => 'action', 'data-method' => :post, 'data-confirm' => _("Do you want to destroy this organization?") %>
  30 + </div>
  31 + </td>
  32 +
  33 + <td> <%= _("#{p.type}") %> </td>
  34 + </tr>
  35 + <% end %>
  36 + </table>
  37 +
  38 + <div>
  39 + <%= pagination_links @collection, {:param_name => 'npage', :page_links => true} %>
  40 + </div>
  41 +</div>
... ...
app/views/organizations/index.html.erb 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +<h1><%= _('Organizations') %></h1>
  2 +
  3 +<%= form_tag( { :action => 'index' }, :method => 'get', :id => 'manage-profiles' ) do %>
  4 +
  5 + <div class="search-field">
  6 + <span class="formfield">
  7 + <%= text_field_tag 'q', @q, :title => _('Find organizations'), :style=>"width:85%" %>
  8 + </span>
  9 +
  10 + <%= submit_button(:search, _('Search')) %>
  11 + </div>
  12 +
  13 + <div class="environment-profiles-results-header">
  14 + <div id='environment-profiles-filter-title'><%= @title %></div>
  15 +
  16 + <div id="environment-profiles-filter-filter">
  17 + <strong><%= _("Filter by: ") %></strong>
  18 + <%= select_tag(:filter, options_for_select([[_('Any'), 'any'],[_('Disabled'), "disabled"], [_('Enabled') , "enabled"]], @filter)) %>
  19 + </div>
  20 + <div style="clear: both"></div>
  21 + </div>
  22 +
  23 + <%= render :partial => 'results' %>
  24 +
  25 + <% button_bar do %>
  26 + <%= button :back, _('Back'), :controller => 'admin_panel' %>
  27 + <% end %>
  28 +<% end %>
  29 +
  30 +<%= javascript_include_tag 'manage-organizations' %>
... ...
app/views/organizations/index.js.erb 0 → 120000
... ... @@ -0,0 +1 @@
  1 +../../views/shared/admin/profiles/index.js.rb
0 2 \ No newline at end of file
... ...
app/views/person_notifier/mailer/_comment.html.erb
... ... @@ -19,7 +19,7 @@
19 19 <span style="font-size: 12px;"><%= comment.title %></span><br/>
20 20 <% end %>
21 21 <span style="font-size: 10px;"><%= txt2html comment.body %></span><br/>
22   - <span style="font-size: 8px; color: #929292"><%= time_ago_as_sentence(comment.created_at) %></span>
  22 + <span style="font-size: 8px; color: #929292"><%= time_ago_in_words(comment.created_at) %></span>
23 23 <br style="clear: both;" />
24 24  
25 25 <% unless comment.replies.blank? %>
... ...
app/views/person_notifier/mailer/_create_article.html.erb
... ... @@ -6,7 +6,7 @@
6 6 <p>
7 7 <span style="font-size: 14px;"><%= link_to activity.user.short_name(20), activity.user.url %></span>
8 8 <span style="font-size: 14px;"><%= _("has published on community %s") % link_to(activity.target.profile.short_name(20), activity.target.profile.url, :style => "color: #333; font-weight: bold; text-decoration: none;") if activity.target.profile.is_a?(Community) %></span>
9   - <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  9 + <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_in_words(activity.created_at) %></span>
10 10 </p>
11 11 <p>
12 12 <span style="font-size: 14px;"><%= link_to(activity.params['name'], activity.params['url'], :style => "color: #333; font-weight: bold; text-decoration: none;") %></span>
... ...
app/views/person_notifier/mailer/_default_activity.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <td>
6 6 <p>
7 7 <span style="font-size: 14px;"><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></span>
8   - <span style="font-size: 10px; color: #929292; float: right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  8 + <span style="font-size: 10px; color: #929292; float: right;"><%= time_ago_in_words(activity.created_at) %></span>
9 9 </p>
10 10 </td>
11 11 </tr>
... ...
app/views/person_notifier/mailer/_task.html.erb
... ... @@ -12,7 +12,7 @@
12 12 <span style="font-size: 14px">
13 13 <%= task_information(task) %>
14 14 </span>
15   - <span style="font-size: 10px; color: #929292; float: right;"><%= time_ago_as_sentence(task.created_at) %></span>
  15 + <span style="font-size: 10px; color: #929292; float: right;"><%= time_ago_in_words(task.created_at) %></span>
16 16 </div>
17 17 </td>
18 18 </tr>
... ...
app/views/person_notifier/mailer/_upload_image.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <td>
6 6 <p>
7 7 <span style="font-size: 14px;"><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></span>
8   - <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  8 + <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_in_words(activity.created_at) %></span>
9 9 </p>
10 10 </td>
11 11 </tr>
... ...
app/views/profile/_comment.html.erb
... ... @@ -40,7 +40,7 @@
40 40 <%= txt2html comment.body %>
41 41 </div>
42 42 <div class="profile-activity-time">
43   - <%= time_ago_as_sentence(comment.created_at) %>
  43 + <%= time_ago_in_words(comment.created_at) %>
44 44 </div>
45 45 </div>
46 46  
... ...
app/views/profile/_create_article.html.erb
... ... @@ -12,7 +12,7 @@
12 12 <%= image_tag(activity.params['first_image']) unless activity.params['first_image'].blank? %><%= strip_tags(truncate(activity.params['lead'], :length => 1000, :ommision => '...')).gsub(/(\xC2\xA0|\s)+/, ' ').gsub(/^\s+/, '') unless activity.params['lead'].blank? %> <small><%= link_to(_('See more'), activity.params['url']) unless activity.get_lead.blank? %></small>
13 13 </div>
14 14 <%= content_tag(:p, link_to(_('See complete forum'), activity.get_url), :class => 'see-forum') if activity.target.is_a?(Forum) %>
15   - <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
  15 + <p class='profile-activity-time'><%= time_ago_in_words(activity.created_at) %></p>
16 16 <div class='profile-wall-actions'>
17 17 <%= link_to s_('profile|Comment'), '#', { :class => 'focus-on-comment'} %>
18 18 <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :only_hide => true, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
... ...
app/views/profile/_default_activity.html.erb
... ... @@ -3,7 +3,7 @@
3 3 </div>
4 4 <div class='profile-activity-description'>
5 5 <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
6   - <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
  6 + <p class='profile-activity-time'><%= time_ago_in_words(activity.created_at) %></p>
7 7 <div class='profile-wall-actions'>
8 8 <%= link_to s_('profile|Comment'), '#', { :class => 'focus-on-comment'} %>
9 9 <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
... ...
app/views/profile/_leave_scrap.html.erb
... ... @@ -3,7 +3,7 @@
3 3 </div>
4 4 <div class='profile-activity-description'>
5 5 <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
6   - <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
  6 + <p class='profile-activity-time'><%= time_ago_in_words(activity.created_at) %></p>
7 7 <div class='profile-wall-actions'>
8 8 <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
9 9 </div>
... ...
app/views/profile/_profile_scrap.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <div class='profile-activity-description'>
6 6 <p class='profile-activity-sender'><%= link_to scrap.sender.name, scrap.sender.url %></p>
7 7 <p class='profile-activity-text'><%= txt2html scrap.content %></p>
8   - <p class='profile-activity-time'><%= time_ago_as_sentence(scrap.created_at) %></p>
  8 + <p class='profile-activity-time'><%= time_ago_in_words(scrap.created_at) %></p>
9 9 <div class='profile-wall-actions'>
10 10 <% if logged_in? && current_person.follows?(scrap.sender) %>
11 11 <span class='profile-activity-send-reply'>
... ... @@ -22,5 +22,5 @@
22 22 <% end %>
23 23 </ul>
24 24 <%= render :partial => 'profile_scrap_reply_form', :locals => { :scrap => scrap } %>
25   - <hr />
  25 + <hr />
26 26 </li>
... ...
app/views/profile/_profile_scraps.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <div class='profile-activity-description'>
6 6 <p class='profile-activity-sender'><%= link_to scrap.sender.name, scrap.sender.url %></p>
7 7 <p class='profile-activity-text'><%= txt2html scrap.content %></p>
8   - <p class='profile-activity-time'><%= time_ago_as_sentence(scrap.created_at) %></p>
  8 + <p class='profile-activity-time'><%= time_ago_in_words(scrap.created_at) %></p>
9 9 <div class='profile-wall-actions'>
10 10 <% if logged_in? && current_person.follows?(scrap.sender) %>
11 11 <span class='profile-activity-send-reply'>
... ...
app/views/profile/_upload_image.html.erb
... ... @@ -4,7 +4,7 @@
4 4 </div>
5 5 <div class='profile-activity-description'>
6 6 <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
7   - <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
  7 + <p class='profile-activity-time'><%= time_ago_in_words(activity.created_at) %></p>
8 8 <div class='profile-wall-actions'>
9 9 <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
10 10 </div>
... ...
app/views/profile/content_tagged.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <h1><%= _('Content tagged with "%s"') % escaped_tag %></h1>
6 6  
7 7 <p>
8   -<%= link_to image_tag('icons-mime/rss-feed.png', :alt => _('Feed for this tag'), :title => _('Feed for this tag')), tag_feed_path, :class => 'blog-feed-link'%>
  8 +<%= link_to image_tag('/images/icons-mime/rss-feed.png', :alt => _('Feed for this tag'), :title => _('Feed for this tag')), tag_feed_path, :class => 'blog-feed-link'%>
9 9 </p>
10 10  
11 11 <% cache_timeout(@tag_cache_key, 4.hour) do %>
... ...
app/views/profile_editor/index.html.erb
... ... @@ -73,7 +73,7 @@
73 73 <%= control_panel_button(_('Edit welcome page'), 'welcome-page', :action => 'welcome_page') if has_welcome_page %>
74 74  
75 75 <% @plugins.dispatch(:control_panel_buttons).each do |button| %>
76   - <%= control_panel_button(button[:title], button[:icon], button[:url]) %>
  76 + <%= control_panel_button(button[:title], button[:icon], button[:url], button[:html_options]) %>
77 77 <% end %>
78 78  
79 79 <% end %>
... ...
app/views/shared/_content_item.html.erb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +<div id="list-item">
  2 + <div class="item-info">
  3 + <div class="item-icon" >
  4 + <%= display_content_icon(content) %>
  5 + </div>
  6 + <span class="item-description">
  7 + <%= link_to(short_filename_upper_ext(content.name), content.url) %>
  8 + </span>
  9 + <span class="item-date"><%= _("Published at: #{show_date(content.updated_at)}") %></span>
  10 + </div>
  11 +</div>
0 12 \ No newline at end of file
... ...
app/views/shared/_lead_and_body.html.erb
... ... @@ -19,17 +19,27 @@
19 19  
20 20 <div class='article-lead' id="article-lead-<%=lead_id.to_s%>">
21 21  
  22 + <% abstract_options = {:style => 'width: 100%; height: 200px;', :class => editor_type} %>
22 23 <% if f %>
23   - <%= labelled_form_field(_(abstract_label), f.text_area(abstract_method, :style => 'width: 100%; height: 200px;', :class => editor_type)) %>
  24 + <%= labelled_form_field(_(abstract_label), f.text_area(abstract_method, abstract_options)) %>
24 25 <% else %>
25   - <%= labelled_form_field(_(abstract_label), text_area(object, abstract_method, :style => 'width: 100%; height: 200px;', :class => editor_type)) %>
  26 + <% if @article.kind_of?(Article) %>
  27 + <%= labelled_form_field(_(abstract_label), text_area_tag("article[abstract]", @escaped_abstract, abstract_options)) %>
  28 + <% else %>
  29 + <%= labelled_form_field(_(abstract_label), text_area(object, abstract_method, abstract_options)) %>
  30 + <% end %>
26 31 <% end %>
27 32 </div>
28 33 <div style="margin-top: 10px;">
  34 + <% body_options = {:style => 'width: 100%; height: 400px;', :class => editor_type} %>
29 35 <% if f %>
30   - <%= labelled_form_field(_(body_label), f.text_area(body_method, :style => 'width: 100%; height: 400px;', :class => editor_type)) %>
  36 + <%= labelled_form_field(_(body_label), f.text_area(body_method, body_options)) %>
31 37 <% else %>
32   - <%= labelled_form_field(_(body_label), text_area(object, body_method, :style => 'width: 100%; height: 400px;', :class => editor_type)) %>
  38 + <% if @article.kind_of?(Article) %>
  39 + <%= labelled_form_field(_(body_label), text_area_tag("article[body]", @escaped_body, body_options)) %>
  40 + <% else %>
  41 + <%= labelled_form_field(_(body_label), text_area(object, body_method, body_options)) %>
  42 + <% end %>
33 43 <% end %>
34 44 </div>
35 45  
... ...
app/views/shared/admin/profiles/index.js.rb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +jQuery('#manage-profiles .results').replaceWith('<%= escape_javascript(render 'results') %>');
... ...
app/views/shared/content_list.html.erb
1   -<table class="<%= list_type %>-content">
2   - <tr>
3   - <th><%= _('Title') %></th>
4   - <th><%= _('Last update') %></th>
5   - </tr>
  1 +<ul class="<%= list_type %>-content">
6 2 <% contents.each do |content| %>
7   - <% if content.display_to?(user) %>
8   - <%= display_content_in_listing :content=>content, :list_type=>list_type, :recursive=>recursive %>
9   - <% end %>
  3 + <li class="<%= list_type %>-item">
  4 + <% if content.display_to?(user) %>
  5 + <%= render :partial => 'shared/content_item', :locals => { :content => content } %>
  6 + <% end %>
  7 + </li>
10 8 <% end %>
11   -</table>
  9 +</ul>
12 10  
13 11 <p><%= pagination_links contents, :param_name => 'npage', :page_links => true %></p>
... ...
app/views/shared/logged_in/xmpp_chat.html.erb
... ... @@ -7,13 +7,13 @@
7 7 var $own_name = '<%= user.name %>';
8 8 var $muc_domain = '<%= "conference.#{environment.default_hostname}" %>';
9 9 var $bosh_service = '//<%= environment.default_hostname %>/http-bind';
10   - var $user_unavailable_error = '<%= _("<strong>ooops!</strong> The message could not be sent because the user is not online") %>';
  10 + var $user_unavailable_error = '<%= _("The user is not online now. He/She will receive these messages as soon as he/she gets online.") %>';
11 11 var $update_presence_status_every = <%= User.expires_chat_status_every.minutes %>;
12 12 var $presence = '<%= current_user.last_chat_status %>';
13 13 </script>
14 14  
15   -
16 15 <div id="chat-label">
  16 + <span id="unread-messages"></span>
17 17 <span class="right-arrow">&#9654;</span>
18 18 <span class="title"><%= _('Chat') %></span>
19 19 </div>
... ... @@ -98,10 +98,5 @@
98 98 </div>
99 99 </div>
100 100 </div>
101   -
102   - <div class="error-message">
103   - <span class='error'>%{text}</span>
104   - </div>
105   -
106 101 </div>
107 102 </div>
... ...
app/views/shared/profile_actions/xmpp_chat.html.erb 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +<% label_name = profile.person? ? _('Open chat') : _('Join chat room') %>
  2 +<% display = profile.person? ? profile.friends.include?(user) : profile.members.include?(user) %>
  3 +
  4 +<% if display %>
  5 + <li>
  6 + <%= button(:chat, label_name , {}, :class => 'open-conversation', 'data-jid' => profile.jid) %>
  7 + </li>
  8 +<% end %>
... ...
app/views/tasks/_abuse_complaint_accept_details.html.erb
... ... @@ -2,7 +2,7 @@
2 2 <% task.abuse_reports.each do |abuse_report| %>
3 3 <div>
4 4 <strong style="word-wrap: break-word; display: block; padding-right: 40px">"<%= abuse_report.reason %>"</strong> <br />
5   - <i><%= _('Reported by %{reporter} %{time}.') % {:reporter => abuse_report.reporter.name, :time => time_ago_as_sentence(abuse_report.created_at) }%></i> <br />
  5 + <i><%= _('Reported by %{reporter} %{time}.') % {:reporter => abuse_report.reporter.name, :time => time_ago_in_words(abuse_report.created_at) }%></i> <br />
6 6 <% if !abuse_report.content.blank? %>
7 7 <button class="display-abuse-report-details" data-report="<%=abuse_report.id%>"><%=_('View details')%></button>
8 8 <div style='display: none' id=<%= 'abuse-report-details-'+abuse_report.id.to_s %> class="abuse-report-details">
... ...
app/views/tasks/_task.html.erb
... ... @@ -2,8 +2,26 @@
2 2  
3 3 <%= render :partial => 'task_icon', :locals => {:task => task} %>
4 4  
  5 + <% if !@view_only && profile.organization? && @responsible_candidates.present? %>
  6 + <div class="task_responsible">
  7 + <span class="label"><%= _('Assign to:') %></span>
  8 + <span>
  9 + <% change_responsible_url = url_for :action => :change_responsible, :controller => :tasks %>
  10 + <%= select_tag "tasks[#{task.id}][responsible]", options_from_collection_for_select(@responsible_candidates, :id, :name, task.responsible.present? ? task.responsible.id : nil), :include_blank => true, :onchange => "change_task_responsible(this);", 'data-old-responsible' => task.responsible.present? ? task.responsible.id : nil, 'data-task' => task.id, 'data-url' => change_responsible_url %>
  11 + </span>
  12 + </div>
  13 + <% end %>
  14 +
  15 + <% if @view_only && task.responsible.present? %>
  16 + <div class="task_responsible">
  17 + <span class="label"><%= _('Assigned to:') %></span>
  18 + <span class="value"><%= task.responsible.name %></span>
  19 + </div>
  20 + <% end %>
  21 +
5 22 <div class="task_decisions">
6   - <%=
  23 + <% unless @view_only %>
  24 + <%=
7 25 labelled_radio_button(_("Accept"), "tasks[#{task.id}][decision]", 'finish', task.default_decision == 'accept',
8 26 :id => "decision-finish-#{task.id}",
9 27 :class => 'task_accept_radio',
... ... @@ -19,9 +37,12 @@
19 37 :class => 'task_skip_radio',
20 38 :disabled => task.skip_disabled?,
21 39 :task_id => "#{task.id}")
22   - %>
  40 + %>
  41 + <% end %>
23 42 </div><!-- class="task_decisions" -->
24 43  
  44 + <div class="task_date"><%= show_time(task.created_at) %></div>
  45 +
25 46 <%= render :partial => 'task_title', :locals => {:task => task} %>
26 47  
27 48 <div class="task_information">
... ...
app/views/tasks/index.html.erb
... ... @@ -21,45 +21,66 @@
21 21 </div>
22 22 <% end %>
23 23  
  24 +<%= form_tag '#', :method => 'get' do %>
  25 + <%= field_set_tag _('Filter'), :class => 'filter_fields' do %>
  26 + <p>
  27 + <%= labelled_select(_('Type of task')+': ', :filter_type, :first, :last, @filter_type, type_collection, {:id => 'filter-type'}) %>
  28 + </p>
  29 + <p>
  30 + <%= labelled_text_field(_("Text filter")+': ', :filter_text, nil, {:id => 'filter-text',:value => @filter_text}) %>
  31 + </p>
  32 + <% if profile.organization? %>
  33 + <p>
  34 + <%= labelled_select(_('Assigned to')+': ', :filter_responsible, :id, :name, @filter_responsible, [OpenStruct.new(:name => _('All'), :id => nil), OpenStruct.new(:name => _('Unassigned'), :id => -1)] + @responsible_candidates, :class => 'filter_responsible') %>
  35 + </p>
  36 + <% end %>
  37 + <p>
  38 + <%= submit_button(:search, _('Search')) %>
  39 + </p>
  40 + <% end %>
  41 +<% end %>
  42 +
24 43 <% if @tasks.empty? %>
25 44 <p>
26   - <%= labelled_select(_('Filter')+': ', :filter_type, :first, :last, @filter, type_collection, :onchange => "document.location.href = '?filter_type='+this.value")%>
  45 + <em><%= _('No pending tasks for %s') % profile.name %></em>
27 46 </p>
28   - <em><%= _('No pending tasks for %s') % profile.name %></em>
29 47 <% else %>
30 48 <%= form_tag :action => 'close' do%>
31   - <% button_bar do %>
  49 + <% button_bar(:class => 'task-actions') do %>
32 50 <%# FiXME button(:edit, _('View my requests'), :action => 'list_requested') %>
33 51 <%# FIXME button('menu-mail', _('Send request'), :action => 'new') %>
34 52 <%= submit_button :save, _("Apply!") %>
35 53 <%= button(:edit, _('View processed tasks'), :action => 'processed') %>
36 54 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>
37   - <% end %>
  55 + <% end unless @view_only %>
38 56  
39 57 <ul class='task-list'>
40   - <p>
41   - <%= labelled_select(_('Filter')+': ', :filter_type, :first, :last, @filter, type_collection, :onchange => "document.location.href = '?filter_type='+this.value") %>
42   - </p>
43   - <p>
44   - <%= labelled_select(_("Set all to: "), 'set-decisions', 'first', 'last', nil, [['',""],['accept',_("Accept")],['reject',_("Reject")],['skip',_("Skip")]], :id => "up-set-all-tasks-to") %>
45   - </p>
46   - <% @tasks.each do |task| %>
47   - <%= render :partial => 'task', :locals => { :task => task } %>
  58 + <% unless @view_only %>
  59 + <p>
  60 + <%= labelled_select(_("Set all to: "), 'set-decisions', 'first', 'last', nil, [['',""],['accept',_("Accept")],['reject',_("Reject")],['skip',_("Skip")]], :id => "up-set-all-tasks-to") %>
  61 + </p>
  62 + <% end %>
  63 +
  64 + <div class="task_boxes">
  65 + <%= render :partial => 'task', :collection => @tasks %>
  66 + </div>
  67 +
  68 + <% unless @view_only %>
  69 + <p>
  70 + <%= labelled_select(_("Set all to: "), 'set-decisions', 'first', 'last', nil, [['',""],['accept',_("Accept")],['reject',_("Reject")],['skip',_("Skip")]], :id => "down-set-all-tasks-to") %>
  71 + </p>
48 72 <% end %>
49   - <p>
50   - <%= labelled_select(_("Set all to: "), 'set-decisions', 'first', 'last', nil, [['',""],['accept',_("Accept")],['reject',_("Reject")],['skip',_("Skip")]], :id => "down-set-all-tasks-to") %>
51   - </p>
52 73 </ul>
53 74  
54 75 <%= pagination_links(@tasks)%>
55 76  
56   - <% button_bar do %>
  77 + <% button_bar(:class => 'task-actions') do %>
57 78 <%# FiXME button(:edit, _('View my requests'), :action => 'list_requested') %>
58 79 <%# FIXME button('menu-mail', _('Send request'), :action => 'new') %>
59 80 <%= submit_button :save, _("Apply!") %>
60 81 <%= button(:edit, _('View processed tasks'), :action => 'processed') %>
61 82 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>
62   - <% end %>
  83 + <% end unless @view_only %>
63 84 <% end %>
64 85 <% end %>
65 86 </p>
... ...
app/views/users/_users_list.html.erb
1   -<div class="environment-users-results-header">
2   - <div id='environment-users-filter-title'><%= users_filter_title(@filter) %></div>
  1 +<div class="environment-profiles-results-header">
  2 + <div id='environment-profiles-filter-title'><%= users_filter_title(@filter) %></div>
3 3 <%= filter_selector(@filter) %>
4 4 <div style="clear: both"></div>
5 5 </div>
... ...
config/initializers/delayed_job_config.rb
... ... @@ -23,3 +23,13 @@ end
23 23 # end
24 24 # alias_method_chain :handle_failed_job, :loggin
25 25 #end
  26 +
  27 +# Chain delayed job's handle_failed_job method to do exception notification
  28 +Delayed::Worker.class_eval do
  29 + def handle_failed_job_with_notification job, error
  30 + handle_failed_job_without_notification job, error
  31 + ExceptionNotifier.notify_exception error, exception_recipients: NOOSFERO_CONF['exception_recipients'],
  32 + data: {job: job, handler: job.handler} rescue nil
  33 + end
  34 + alias_method_chain :handle_failed_job, :notification
  35 +end
... ...
config/initializers/noosfero_extensions.rb
1 1 require 'noosfero/role_assignment_ext'
2 2 require 'noosfero/action_tracker_ext'
  3 +require 'noosfero/vote_ext'
... ...
config/initializers/wrap_parameters.rb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +# Be sure to restart your server when you modify this file.
  2 +# This file contains settings for ActionController::ParamsWrapper which
  3 +# is enabled by default.
  4 +
  5 +# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
  6 +ActiveSupport.on_load(:action_controller) do
  7 + wrap_parameters :format => []
  8 +end
  9 +
  10 +# Disable root element in JSON by default.
  11 +ActiveSupport.on_load(:active_record) do
  12 + self.include_root_in_json = false
  13 +end
... ...
db/migrate/20140820173129_create_chat_messages.rb
1 1 class CreateChatMessages < ActiveRecord::Migration
2   - def change
  2 + def up
3 3 create_table :chat_messages do |t|
4 4 t.integer :to_id
5 5 t.integer :from_id
... ... @@ -8,4 +8,8 @@ class CreateChatMessages &lt; ActiveRecord::Migration
8 8 t.timestamps
9 9 end
10 10 end
  11 +
  12 + def down
  13 + drop_table :chat_messages
  14 + end
11 15 end
... ...
db/migrate/20141014205254_change_chat_messages_columns_and_add_indexes.rb 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +class ChangeChatMessagesColumnsAndAddIndexes < ActiveRecord::Migration
  2 + def up
  3 + change_table :chat_messages do |t|
  4 + t.change :from_id, :integer, :null => false
  5 + t.change :to_id, :integer, :null => false
  6 + t.change :body, :text
  7 + end
  8 + add_index :chat_messages, :from_id
  9 + add_index :chat_messages, :to_id
  10 + add_index :chat_messages, :created_at
  11 + end
  12 +
  13 + def down
  14 + remove_index :chat_messages, :from_id
  15 + remove_index :chat_messages, :to_id
  16 + remove_index :chat_messages, :created_at
  17 + change_table :chat_messages do |t|
  18 + t.change :from_id, :integer, :null => true
  19 + t.change :to_id, :integer, :null => true
  20 + t.change :body, :string
  21 + end
  22 + end
  23 +end
... ...
db/migrate/20150423203352_fix_tags_case_differences.rb 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +class FixTagsCaseDifferences < ActiveRecord::Migration
  2 + def up
  3 + tags = ActsAsTaggableOn::Tag.joins('LEFT JOIN tags as b on LOWER(tags.name) = b.name').where('b.id is null')
  4 + tags.find_each do |tag|
  5 + unless ActsAsTaggableOn::Tag.exists?(:name => tag.name.mb_chars.downcase)
  6 + ActsAsTaggableOn::Tag.create(:name => tag.name.mb_chars.downcase)
  7 + end
  8 + end
  9 +
  10 + execute("UPDATE taggings SET tag_id = new.id FROM taggings AS t INNER JOIN tags AS old ON t.tag_id = old.id INNER JOIN tags AS new ON LOWER(old.name) = new.name WHERE old.id != new.id AND taggings.id = t.id")
  11 +
  12 + execute("UPDATE tags SET taggings_count = (SELECT COUNT(*) FROM taggings WHERE taggings.tag_id = tags.id)")
  13 + execute("DELETE FROM tags WHERE taggings_count = 0")
  14 + end
  15 +
  16 + def down
  17 + say 'This migration is irreversible.'
  18 + end
  19 +end
... ...
db/migrate/20150429145001_add_mirror_to_block.rb 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +class AddMirrorToBlock < ActiveRecord::Migration
  2 + def up
  3 + change_table :blocks do |t|
  4 + t.boolean :mirror, :default => false
  5 + t.references :mirror_block
  6 + t.references :observers
  7 + end
  8 + end
  9 +
  10 + def down
  11 + remove_column :blocks, :mirror
  12 + remove_column :blocks, :mirror_block_id
  13 + remove_column :blocks, :observers_id
  14 + end
  15 +end
... ...
db/migrate/20150507204849_remove_broken_profile_suggestions.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class RemoveBrokenProfileSuggestions < ActiveRecord::Migration
  2 + def up
  3 + execute("DELETE FROM profile_suggestions WHERE suggestion_id NOT IN (SELECT id from profiles)")
  4 + end
  5 +
  6 + def down
  7 + say "this migration can't be reverted"
  8 + end
  9 +end
... ...
db/migrate/20150513213939_update_topic_creation_configuration.rb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +class UpdateTopicCreationConfiguration < ActiveRecord::Migration
  2 + def up
  3 + Forum.where("setting LIKE '%:allows_members_to_create_topics: true%'").find_each do |forum|
  4 + forum.setting.delete(:allows_members_to_create_topics)
  5 + forum.setting.merge!(:topic_creation => 'related')
  6 + forum.save
  7 + end
  8 + end
  9 +
  10 + def down
  11 + say "this migration can't be reverted"
  12 + end
  13 +end
... ...
db/migrate/20150525101430_add_responsible_to_task.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +class AddResponsibleToTask < ActiveRecord::Migration
  2 +
  3 + def change
  4 + add_column :tasks, :responsible_id, :integer
  5 + end
  6 +
  7 +end
... ...
db/migrate/20150529180110_add_date_format_to_environment.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddDateFormatToEnvironment < ActiveRecord::Migration
  2 + def up
  3 + add_column :environments, :date_format, :string, :default => 'month_name_with_year'
  4 + end
  5 +
  6 + def down
  7 + remove_column :environments, :date_format
  8 + end
  9 +end
... ...
db/migrate/20150602142030_add_closed_by_to_task.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +class AddClosedByToTask < ActiveRecord::Migration
  2 +
  3 + def change
  4 + add_column :tasks, :closed_by_id, :integer
  5 + end
  6 +
  7 +end
... ...
db/schema.rb
... ... @@ -11,7 +11,7 @@
11 11 #
12 12 # It's strongly recommended to check this file into your version control system.
13 13  
14   -ActiveRecord::Schema.define(:version => 20150408231524) do
  14 +ActiveRecord::Schema.define(:version => 20150602142030) do
15 15  
16 16 create_table "abuse_reports", :force => true do |t|
17 17 t.integer "reporter_id"
... ... @@ -183,10 +183,13 @@ ActiveRecord::Schema.define(:version =&gt; 20150408231524) do
183 183 t.string "type"
184 184 t.text "settings"
185 185 t.integer "position"
186   - t.boolean "enabled", :default => true
  186 + t.boolean "enabled", :default => true
187 187 t.datetime "created_at"
188 188 t.datetime "updated_at"
189 189 t.datetime "fetched_at"
  190 + t.boolean "mirror", :default => false
  191 + t.integer "mirror_block_id"
  192 + t.integer "observers_id"
190 193 end
191 194  
192 195 add_index "blocks", ["box_id"], :name => "index_blocks_on_box_id"
... ... @@ -242,13 +245,17 @@ ActiveRecord::Schema.define(:version =&gt; 20150408231524) do
242 245 end
243 246  
244 247 create_table "chat_messages", :force => true do |t|
245   - t.integer "to_id"
246   - t.integer "from_id"
247   - t.string "body"
  248 + t.integer "from_id", :null => false
  249 + t.integer "to_id", :null => false
  250 + t.text "body"
248 251 t.datetime "created_at", :null => false
249 252 t.datetime "updated_at", :null => false
250 253 end
251 254  
  255 + add_index "chat_messages", ["created_at"], :name => "index_chat_messages_on_created_at"
  256 + add_index "chat_messages", ["from_id"], :name => "index_chat_messages_on_from_id"
  257 + add_index "chat_messages", ["to_id"], :name => "index_chat_messages_on_to_id"
  258 +
252 259 create_table "comments", :force => true do |t|
253 260 t.string "title"
254 261 t.text "body"
... ... @@ -313,17 +320,18 @@ ActiveRecord::Schema.define(:version =&gt; 20150408231524) do
313 320 t.text "design_data"
314 321 t.text "custom_header"
315 322 t.text "custom_footer"
316   - t.string "theme", :default => "default", :null => false
  323 + t.string "theme", :default => "default", :null => false
317 324 t.text "terms_of_use_acceptance_text"
318 325 t.datetime "created_at"
319 326 t.datetime "updated_at"
320   - t.integer "reports_lower_bound", :default => 0, :null => false
  327 + t.integer "reports_lower_bound", :default => 0, :null => false
321 328 t.string "redirection_after_login", :default => "keep_on_same_page"
322 329 t.text "signup_welcome_text"
323 330 t.string "languages"
324 331 t.string "default_language"
325 332 t.string "noreply_email"
326 333 t.string "redirection_after_signup", :default => "keep_on_same_page"
  334 + t.string "date_format", :default => "month_name_with_year"
327 335 end
328 336  
329 337 create_table "external_feeds", :force => true do |t|
... ... @@ -677,12 +685,14 @@ ActiveRecord::Schema.define(:version =&gt; 20150408231524) do
677 685 t.date "end_date"
678 686 t.integer "requestor_id"
679 687 t.integer "target_id"
680   - t.string "code", :limit => 40
  688 + t.string "code", :limit => 40
681 689 t.string "type"
682 690 t.datetime "created_at"
683 691 t.string "target_type"
684 692 t.integer "image_id"
685   - t.boolean "spam", :default => false
  693 + t.boolean "spam", :default => false
  694 + t.integer "responsible_id"
  695 + t.integer "closed_by_id"
686 696 end
687 697  
688 698 add_index "tasks", ["requestor_id"], :name => "index_tasks_on_requestor_id"
... ...
debian/apache2/conf.d/noosfero-chat 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +<IfModule mpm_worker_module>
  2 + StartServers 8
  3 + MinSpareThreads 25
  4 + MaxSpareThreads 75
  5 + ThreadLimit 128
  6 + ThreadsPerChild 128
  7 + MaxClients 2048
  8 + MaxRequestsPerChild 0
  9 +</IfModule>
... ...
debian/changelog
1   -noosfero (1.2~0) UNRELEASED; urgency=medium
  1 +noosfero (1.2~1) UNRELEASED; urgency=medium
2 2  
  3 + [ Antonio Terceiro ]
3 4 * Temporary version in heavy development
4 5  
5   - -- Antonio Terceiro <terceiro@debian.org> Fri, 08 May 2015 16:08:18 -0300
  6 + [ Joenio Costa ]
  7 + * Build noosfero-chat package
  8 +
  9 + -- Joenio Costa <joenio@colivre.coop.br> Mon, 18 May 2015 14:32:21 -0300
6 10  
7 11 noosfero (1.1) wheezy; urgency=low
8 12  
... ...
debian/control
... ... @@ -85,3 +85,14 @@ Description: free web-based platform for social networks (apache frontend)
85 85 .
86 86 This package contains the configuration files needed to run Noosfero with the
87 87 Apache HTTPD server as frontend.
  88 +
  89 +Package: noosfero-chat
  90 +Architecture: all
  91 +Depends: noosfero (>= 1.2), ejabberd, odbc-postgresql, pidgin-data
  92 +Description: free web-based platform for social networks (ejabberd based chat)
  93 + Noosfero is a web platform for social and solidarity economy networks with
  94 + blog, e-Porfolios, CMS, RSS, thematic discussion, events agenda and collective
  95 + inteligence for solidarity economy in the same system.
  96 + .
  97 + This package contains the configuration files needed to run Noosfero with the
  98 + Ejabberd XMPP chat server.
... ...