Commit 34d3a283087086d38b318c8e5021ba60e301a1e2
Exists in
master
and in
22 other branches
Merge branch 'stoa' into 'master'
Stoa Network Features This merge-request groups 6 features developed majorly by me, @danielafeitosa and @larissa funded by Stoa Network. These features were finished during the freezing time and only now we were able to update it to the current master. I'm sorry that we'll merge them all together in a single request, but we had to group them on a single branch do improve the efficiency of our work. Here are the features grouped here: - Media gallery complete refactoring - Welcome page improvements - Better interaction with other networks - Friends and communities suggestions - Invitation improvements - Search improvements All 6 features were reviewed by at least one of us and since we are committers, I'm merging this right away. This merge-request was made more for information sake. See merge request !451
Showing
354 changed files
with
15890 additions
and
880 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 354 files displayed.
Gemfile
@@ -21,6 +21,8 @@ gem 'exception_notification', '~> 4.0.1' | @@ -21,6 +21,8 @@ gem 'exception_notification', '~> 4.0.1' | ||
21 | gem 'gettext', '~> 2.2.1', :require => false, :group => :development | 21 | gem 'gettext', '~> 2.2.1', :require => false, :group => :development |
22 | gem 'locale', '~> 2.0.5' | 22 | gem 'locale', '~> 2.0.5' |
23 | 23 | ||
24 | +gem 'whenever', :require => false | ||
25 | + | ||
24 | # FIXME list here all actual dependencies (i.e. the ones in debian/control), | 26 | # FIXME list here all actual dependencies (i.e. the ones in debian/control), |
25 | # with their GEM names (not the Debian package names) | 27 | # with their GEM names (not the Debian package names) |
26 | 28 |
app/controllers/admin/region_validators_controller.rb
@@ -33,7 +33,7 @@ class RegionValidatorsController < AdminController | @@ -33,7 +33,7 @@ class RegionValidatorsController < AdminController | ||
33 | def load_region_and_search | 33 | def load_region_and_search |
34 | @region = environment.regions.find(params[:id]) | 34 | @region = environment.regions.find(params[:id]) |
35 | if params[:search] | 35 | if params[:search] |
36 | - @search = find_by_contents(:organizations, Organization, params[:search])[:results].reject {|item| @region.validator_ids.include?(item.id) } | 36 | + @search = find_by_contents(:organizations, environment, Organization, params[:search])[:results].reject {|item| @region.validator_ids.include?(item.id) } |
37 | end | 37 | end |
38 | end | 38 | end |
39 | 39 |
app/controllers/admin/users_controller.rb
@@ -18,7 +18,7 @@ class UsersController < AdminController | @@ -18,7 +18,7 @@ class UsersController < AdminController | ||
18 | end | 18 | end |
19 | scope = scope.order('name ASC') | 19 | scope = scope.order('name ASC') |
20 | @q = params[:q] | 20 | @q = params[:q] |
21 | - @collection = find_by_contents(:people, scope, @q, {:per_page => per_page, :page => params[:npage]})[:results] | 21 | + @collection = find_by_contents(:people, environment, scope, @q, {:per_page => per_page, :page => params[:npage]})[:results] |
22 | end | 22 | end |
23 | 23 | ||
24 | def set_admin_role | 24 | def set_admin_role |
app/controllers/application_controller.rb
@@ -183,21 +183,19 @@ class ApplicationController < ActionController::Base | @@ -183,21 +183,19 @@ class ApplicationController < ActionController::Base | ||
183 | end | 183 | end |
184 | end | 184 | end |
185 | 185 | ||
186 | - def find_by_contents(asset, scope, query, paginate_options={:page => 1}, options={}) | ||
187 | - plugins.dispatch_first(:find_by_contents, asset, scope, query, paginate_options, options) || | ||
188 | - fallback_find_by_contents(asset, scope, query, paginate_options, options) | ||
189 | - end | 186 | + include SearchTermHelper |
190 | 187 | ||
191 | - private | 188 | + def find_by_contents(asset, context, scope, query, paginate_options={:page => 1}, options={}) |
189 | + search = plugins.dispatch_first(:find_by_contents, asset, scope, query, paginate_options, options) | ||
190 | + register_search_term(query, scope.count, search[:results].count, context, asset) | ||
191 | + search | ||
192 | + end | ||
192 | 193 | ||
193 | - def fallback_find_by_contents(asset, scope, query, paginate_options, options) | ||
194 | - scope = scope.like_search(query) unless query.blank? | ||
195 | - scope = scope.send(options[:filter]) unless options[:filter].blank? | ||
196 | - {:results => scope.paginate(paginate_options)} | 194 | + def find_suggestions(query, context, asset, options={}) |
195 | + plugins.dispatch_first(:find_suggestions, query, context, asset, options) | ||
197 | end | 196 | end |
198 | 197 | ||
199 | def private_environment? | 198 | def private_environment? |
200 | @environment.enabled?(:restrict_to_members) | 199 | @environment.enabled?(:restrict_to_members) |
201 | end | 200 | end |
202 | - | ||
203 | end | 201 | end |
app/controllers/my_profile/cms_controller.rb
@@ -23,6 +23,9 @@ class CmsController < MyProfileController | @@ -23,6 +23,9 @@ class CmsController < MyProfileController | ||
23 | end | 23 | end |
24 | 24 | ||
25 | before_filter :login_required, :except => [:suggest_an_article] | 25 | before_filter :login_required, :except => [:suggest_an_article] |
26 | + before_filter :load_recent_files, :only => [:new, :edit] | ||
27 | + | ||
28 | + helper_method :file_types | ||
26 | 29 | ||
27 | protect_if :only => :upload_files do |c, user, profile| | 30 | protect_if :only => :upload_files do |c, user, profile| |
28 | article_id = c.params[:parent_id] | 31 | article_id = c.params[:parent_id] |
@@ -30,7 +33,7 @@ class CmsController < MyProfileController | @@ -30,7 +33,7 @@ class CmsController < MyProfileController | ||
30 | (user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile))) | 33 | (user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile))) |
31 | end | 34 | end |
32 | 35 | ||
33 | - protect_if :except => [:suggest_an_article, :set_home_page, :edit, :destroy, :publish, :upload_files, :new] do |c, user, profile| | 36 | + protect_if :except => [:suggest_an_article, :set_home_page, :edit, :destroy, :publish, :publish_on_portal_community, :publish_on_communities, :search_communities_to_publish, :upload_files, :new] do |c, user, profile| |
34 | user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile)) | 37 | user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile)) |
35 | end | 38 | end |
36 | 39 | ||
@@ -40,7 +43,7 @@ class CmsController < MyProfileController | @@ -40,7 +43,7 @@ class CmsController < MyProfileController | ||
40 | (user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile))) | 43 | (user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile))) |
41 | end | 44 | end |
42 | 45 | ||
43 | - protect_if :only => [:destroy, :publish] do |c, user, profile| | 46 | + protect_if :only => :destroy do |c, user, profile| |
44 | profile.articles.find(c.params[:id]).allow_post_content?(user) | 47 | profile.articles.find(c.params[:id]).allow_post_content?(user) |
45 | end | 48 | end |
46 | 49 | ||
@@ -117,7 +120,7 @@ class CmsController < MyProfileController | @@ -117,7 +120,7 @@ class CmsController < MyProfileController | ||
117 | @success_back_to = params[:success_back_to] | 120 | @success_back_to = params[:success_back_to] |
118 | # user must choose an article type first | 121 | # user must choose an article type first |
119 | 122 | ||
120 | - @parent = profile.articles.find(params[:parent_id]) if params && params[:parent_id] | 123 | + @parent = profile.articles.find(params[:parent_id]) if params && params[:parent_id].present? |
121 | record_coming | 124 | record_coming |
122 | @type = params[:type] | 125 | @type = params[:type] |
123 | if @type.blank? | 126 | if @type.blank? |
@@ -163,7 +166,10 @@ class CmsController < MyProfileController | @@ -163,7 +166,10 @@ class CmsController < MyProfileController | ||
163 | if continue | 166 | if continue |
164 | redirect_to :action => 'edit', :id => @article | 167 | redirect_to :action => 'edit', :id => @article |
165 | else | 168 | else |
166 | - success_redirect | 169 | + respond_to do |format| |
170 | + format.html { success_redirect } | ||
171 | + format.json { render :text => {:id => @article.id, :full_name => profile.identifier + '/' + @article.full_name}.to_json } | ||
172 | + end | ||
167 | end | 173 | end |
168 | return | 174 | return |
169 | end | 175 | end |
@@ -256,28 +262,53 @@ class CmsController < MyProfileController | @@ -256,28 +262,53 @@ class CmsController < MyProfileController | ||
256 | render :template => 'shared/update_categories', :locals => { :category => @current_category, :object_name => 'article' } | 262 | render :template => 'shared/update_categories', :locals => { :category => @current_category, :object_name => 'article' } |
257 | end | 263 | end |
258 | 264 | ||
265 | + def search_communities_to_publish | ||
266 | + render :text => find_by_contents(:profiles, environment, user.memberships, params['q'], {:page => 1}, {:fields => ['name']})[:results].map {|community| {:id => community.id, :name => community.name} }.to_json | ||
267 | + end | ||
268 | + | ||
259 | def publish | 269 | def publish |
260 | @article = profile.articles.find(params[:id]) | 270 | @article = profile.articles.find(params[:id]) |
261 | record_coming | 271 | record_coming |
262 | - @groups = profile.memberships - [profile] | ||
263 | - @marked_groups = [] | ||
264 | - groups_ids = profile.memberships.map{|m|m.id.to_s} | ||
265 | - @marked_groups = params[:marked_groups].map do |key, item| | ||
266 | - if groups_ids.include?(item[:group_id]) | ||
267 | - item.merge :group => Profile.find(item.delete(:group_id)) | 272 | + @failed = {} |
273 | + if request.post? | ||
274 | + article_name = params[:name] | ||
275 | + task = ApproveArticle.create!(:article => @article, :name => article_name, :target => user, :requestor => user) | ||
276 | + begin | ||
277 | + task.finish | ||
278 | + rescue Exception => ex | ||
279 | + @failed[ex.message] ? @failed[ex.message] << @article.name : @failed[ex.message] = [@article.name] | ||
280 | + task.cancel | ||
281 | + end | ||
282 | + if @failed.blank? | ||
283 | + session[:notice] = _("Your publish request was sent successfully") | ||
284 | + if @back_to | ||
285 | + redirect_to @back_to | ||
286 | + else | ||
287 | + redirect_to @article.view_url | ||
288 | + end | ||
268 | end | 289 | end |
269 | - end.compact unless params[:marked_groups].nil? | 290 | + end |
291 | + end | ||
292 | + | ||
293 | + def publish_on_communities | ||
270 | if request.post? | 294 | if request.post? |
295 | + @back_to = params[:back_to] | ||
296 | + @article = profile.articles.find(params[:id]) | ||
271 | @failed = {} | 297 | @failed = {} |
298 | + article_name = params[:name] | ||
299 | + params_marked = (params['q'] || '').split(',').select { |marked| user.memberships.map(&:id).include? marked.to_i } | ||
300 | + @marked_groups = Profile.find(params_marked) | ||
272 | if @marked_groups.empty? | 301 | if @marked_groups.empty? |
302 | + redirect_to @back_to | ||
273 | return session[:notice] = _("Select some group to publish your article") | 303 | return session[:notice] = _("Select some group to publish your article") |
274 | end | 304 | end |
275 | @marked_groups.each do |item| | 305 | @marked_groups.each do |item| |
276 | - task = ApproveArticle.create!(:article => @article, :name => item[:name], :target => item[:group], :requestor => profile) | 306 | + task = ApproveArticle.create!(:article => @article, :name => article_name, :target => item, :requestor => user) |
277 | begin | 307 | begin |
278 | - task.finish unless item[:group].moderated_articles? | 308 | + task.finish unless item.moderated_articles? |
279 | rescue Exception => ex | 309 | rescue Exception => ex |
280 | - @failed[ex.message] ? @failed[ex.message] << item[:group].name : @failed[ex.message] = [item[:group].name] | 310 | + @failed[ex.message] ? @failed[ex.message] << item.name : @failed[ex.message] = [item.name] |
311 | + task.cancel | ||
281 | end | 312 | end |
282 | end | 313 | end |
283 | if @failed.blank? | 314 | if @failed.blank? |
@@ -287,23 +318,27 @@ class CmsController < MyProfileController | @@ -287,23 +318,27 @@ class CmsController < MyProfileController | ||
287 | else | 318 | else |
288 | redirect_to @article.view_url | 319 | redirect_to @article.view_url |
289 | end | 320 | end |
321 | + else | ||
322 | + session[:notice] = _("Some of your publish requests couldn't be sent.") | ||
323 | + render :action => 'publish' | ||
290 | end | 324 | end |
291 | end | 325 | end |
292 | end | 326 | end |
293 | 327 | ||
294 | def publish_on_portal_community | 328 | def publish_on_portal_community |
295 | - @article = profile.articles.find(params[:id]) | ||
296 | if request.post? | 329 | if request.post? |
297 | - if environment.portal_community | 330 | + @article = profile.articles.find(params[:id]) |
331 | + if environment.portal_enabled | ||
298 | task = ApproveArticle.create!(:article => @article, :name => params[:name], :target => environment.portal_community, :requestor => user) | 332 | task = ApproveArticle.create!(:article => @article, :name => params[:name], :target => environment.portal_community, :requestor => user) |
299 | begin | 333 | begin |
300 | task.finish unless environment.portal_community.moderated_articles? | 334 | task.finish unless environment.portal_community.moderated_articles? |
301 | - flash[:notice] = _("Your publish request was sent successfully") | 335 | + session[:notice] = _("Your publish request was sent successfully") |
302 | rescue | 336 | rescue |
303 | - flash[:error] = _("Your publish request couldn't be sent.") | 337 | + session[:notice] = _("Your publish request couldn't be sent.") |
338 | + task.cancel | ||
304 | end | 339 | end |
305 | else | 340 | else |
306 | - flash[:notice] = _("There is no portal community to publish your article.") | 341 | + session[:notice] = _("There is no portal community to publish your article.") |
307 | end | 342 | end |
308 | 343 | ||
309 | if @back_to | 344 | if @back_to |
@@ -331,7 +366,7 @@ class CmsController < MyProfileController | @@ -331,7 +366,7 @@ class CmsController < MyProfileController | ||
331 | 366 | ||
332 | def search | 367 | def search |
333 | query = params[:q] | 368 | query = params[:q] |
334 | - results = find_by_contents(:uploaded_files, profile.files.published, query)[:results] | 369 | + results = find_by_contents(:uploaded_files, profile, profile.files.published, query)[:results] |
335 | render :text => article_list_to_json(results), :content_type => 'application/json' | 370 | render :text => article_list_to_json(results), :content_type => 'application/json' |
336 | end | 371 | end |
337 | 372 | ||
@@ -342,15 +377,26 @@ class CmsController < MyProfileController | @@ -342,15 +377,26 @@ class CmsController < MyProfileController | ||
342 | end | 377 | end |
343 | 378 | ||
344 | def media_upload | 379 | def media_upload |
345 | - files_uploaded = [] | ||
346 | parent = check_parent(params[:parent_id]) | 380 | parent = check_parent(params[:parent_id]) |
347 | - files = [:file1,:file2, :file3].map { |f| params[f] }.compact | ||
348 | if request.post? | 381 | if request.post? |
349 | - files.each do |file| | ||
350 | - files_uploaded << UploadedFile.create(:uploaded_data => file, :profile => profile, :parent => parent) unless file == '' | 382 | + begin |
383 | + @file = UploadedFile.create!(:uploaded_data => params[:file], :profile => profile, :parent => parent) unless params[:file] == '' | ||
384 | + @file = FilePresenter.for(@file) | ||
385 | + rescue Exception => exception | ||
386 | + render :text => exception.to_s, :status => :bad_request | ||
351 | end | 387 | end |
352 | end | 388 | end |
353 | - render :text => article_list_to_json(files_uploaded), :content_type => 'text/plain' | 389 | + end |
390 | + | ||
391 | + def published_media_items | ||
392 | + load_recent_files(params[:parent_id], params[:q]) | ||
393 | + render :partial => 'published_media_items' | ||
394 | + end | ||
395 | + | ||
396 | + def view_all_media | ||
397 | + paginate_options = {:page => params[:page].blank? ? 1 : params[:page] } | ||
398 | + @key = params[:key].to_sym | ||
399 | + load_recent_files(params[:parent_id], params[:q], paginate_options) | ||
354 | end | 400 | end |
355 | 401 | ||
356 | protected | 402 | protected |
@@ -445,4 +491,36 @@ class CmsController < MyProfileController | @@ -445,4 +491,36 @@ class CmsController < MyProfileController | ||
445 | end | 491 | end |
446 | end | 492 | end |
447 | 493 | ||
494 | + def file_types | ||
495 | + {:images => _('Images'), :generics => _('Files')} | ||
496 | + end | ||
497 | + | ||
498 | + def load_recent_files(parent_id = nil, q = nil, paginate_options = {:page => 1, :per_page => 6}) | ||
499 | + #TODO Since we only have special support for images, I'm limiting myself to | ||
500 | + # consider generic files as non-images. In the future, with more supported | ||
501 | + # file types we'll need to have a smart way to fetch from the database | ||
502 | + # scopes of each supported type as well as the non-supported types as a | ||
503 | + # whole. | ||
504 | + @recent_files = {} | ||
505 | + | ||
506 | + parent = parent_id.present? ? profile.articles.find(parent_id) : nil | ||
507 | + if parent.present? | ||
508 | + files = parent.children.files | ||
509 | + else | ||
510 | + files = profile.files | ||
511 | + end | ||
512 | + | ||
513 | + files = files.reorder('created_at DESC') | ||
514 | + images = files.images | ||
515 | + generics = files.no_images | ||
516 | + | ||
517 | + if q.present? | ||
518 | + @recent_files[:images] = find_by_contents(:images, profile, images, q, paginate_options)[:results] | ||
519 | + @recent_files[:generics] = find_by_contents(:generics, profile, generics, q, paginate_options)[:results] | ||
520 | + else | ||
521 | + @recent_files[:images] = images.paginate(paginate_options) | ||
522 | + @recent_files[:generics] = generics.paginate(paginate_options) | ||
523 | + end | ||
524 | + end | ||
525 | + | ||
448 | end | 526 | end |
app/controllers/my_profile/friends_controller.rb
@@ -3,6 +3,7 @@ class FriendsController < MyProfileController | @@ -3,6 +3,7 @@ class FriendsController < MyProfileController | ||
3 | protect 'manage_friends', :profile | 3 | protect 'manage_friends', :profile |
4 | 4 | ||
5 | def index | 5 | def index |
6 | + @suggestions = profile.profile_suggestions.of_person.enabled.includes(:suggestion).limit(per_page) | ||
6 | if is_cache_expired?(profile.manage_friends_cache_key(params)) | 7 | if is_cache_expired?(profile.manage_friends_cache_key(params)) |
7 | @friends = profile.friends.paginate(:per_page => per_page, :page => params[:npage]) | 8 | @friends = profile.friends.paginate(:per_page => per_page, :page => params[:npage]) |
8 | end | 9 | end |
@@ -16,6 +17,30 @@ class FriendsController < MyProfileController | @@ -16,6 +17,30 @@ class FriendsController < MyProfileController | ||
16 | end | 17 | end |
17 | end | 18 | end |
18 | 19 | ||
20 | + def suggest | ||
21 | + @suggestions = profile.profile_suggestions.of_person.enabled.includes(:suggestion).limit(per_page) | ||
22 | + end | ||
23 | + | ||
24 | + def remove_suggestion | ||
25 | + @person = profile.suggested_people.find_by_identifier(params[:id]) | ||
26 | + redirect_to :action => 'suggest' unless @person | ||
27 | + if @person && request.post? | ||
28 | + profile.remove_suggestion(@person) | ||
29 | + @suggestions = profile.profile_suggestions.of_person.enabled.includes(:suggestion).limit(per_page) | ||
30 | + render :partial => 'shared/profile_suggestions_list', :locals => { :suggestions => @suggestions, :collection => :friends_suggestions, :per_page => params[:per_page] || per_page } | ||
31 | + end | ||
32 | + end | ||
33 | + | ||
34 | + def connections | ||
35 | + @suggestion = profile.profile_suggestions.of_person.enabled.find_by_suggestion_id(params[:id]) | ||
36 | + if @suggestion | ||
37 | + @tags = @suggestion.tag_connections | ||
38 | + @profiles = @suggestion.profile_connections | ||
39 | + else | ||
40 | + redirect_to :action => 'suggest' | ||
41 | + end | ||
42 | + end | ||
43 | + | ||
19 | protected | 44 | protected |
20 | 45 | ||
21 | class << self | 46 | class << self |
app/controllers/my_profile/memberships_controller.rb
@@ -20,12 +20,54 @@ class MembershipsController < MyProfileController | @@ -20,12 +20,54 @@ class MembershipsController < MyProfileController | ||
20 | @community.environment = environment | 20 | @community.environment = environment |
21 | @back_to = params[:back_to] || url_for(:action => 'index') | 21 | @back_to = params[:back_to] || url_for(:action => 'index') |
22 | if request.post? && @community.valid? | 22 | if request.post? && @community.valid? |
23 | - @community = Community.create_after_moderation(user, params[:community].merge({:environment => environment})) | ||
24 | - if @community.new_record? | 23 | + begin |
24 | + # Community was created | ||
25 | + @community = Community.create_after_moderation(user, params[:community].merge({:environment => environment})) | ||
26 | + @community.reload | ||
27 | + redirect_to :action => 'welcome', :community_id => @community.id, :back_to => @back_to | ||
28 | + rescue ActiveRecord::RecordNotFound | ||
29 | + # Community pending approval | ||
25 | session[:notice] = _('Your new community creation request will be evaluated by an administrator. You will be notified.') | 30 | session[:notice] = _('Your new community creation request will be evaluated by an administrator. You will be notified.') |
31 | + redirect_to @back_to | ||
26 | end | 32 | end |
27 | - redirect_to @back_to | ||
28 | return | 33 | return |
29 | end | 34 | end |
30 | end | 35 | end |
36 | + | ||
37 | + def welcome | ||
38 | + @community = Community.find(params[:community_id]) | ||
39 | + @back_to = params[:back_to] | ||
40 | + end | ||
41 | + | ||
42 | + def suggest | ||
43 | + @suggestions = profile.profile_suggestions.of_community.enabled.includes(:suggestion).limit(per_page) | ||
44 | + end | ||
45 | + | ||
46 | + def remove_suggestion | ||
47 | + @community = profile.suggested_communities.find_by_identifier(params[:id]) | ||
48 | + custom_per_page = params[:per_page] || per_page | ||
49 | + redirect_to :action => 'suggest' unless @community | ||
50 | + if @community && request.post? | ||
51 | + profile.remove_suggestion(@community) | ||
52 | + @suggestions = profile.profile_suggestions.of_community.enabled.includes(:suggestion).limit(custom_per_page) | ||
53 | + render :partial => 'shared/profile_suggestions_list', :locals => { :suggestions => @suggestions, :collection => :communities_suggestions, :per_page => custom_per_page} | ||
54 | + end | ||
55 | + end | ||
56 | + | ||
57 | + def connections | ||
58 | + @suggestion = profile.profile_suggestions.of_community.enabled.find_by_suggestion_id(params[:id]) | ||
59 | + if @suggestion | ||
60 | + @tags = @suggestion.tag_connections | ||
61 | + @profiles = @suggestion.profile_connections | ||
62 | + else | ||
63 | + redirect_to :action => 'suggest' | ||
64 | + end | ||
65 | + end | ||
66 | + | ||
67 | + protected | ||
68 | + | ||
69 | + def per_page | ||
70 | + 12 | ||
71 | + end | ||
72 | + | ||
31 | end | 73 | end |
app/controllers/my_profile/profile_editor_controller.rb
@@ -3,6 +3,10 @@ class ProfileEditorController < MyProfileController | @@ -3,6 +3,10 @@ class ProfileEditorController < MyProfileController | ||
3 | protect 'edit_profile', :profile, :except => [:destroy_profile] | 3 | protect 'edit_profile', :profile, :except => [:destroy_profile] |
4 | protect 'destroy_profile', :profile, :only => [:destroy_profile] | 4 | protect 'destroy_profile', :profile, :only => [:destroy_profile] |
5 | 5 | ||
6 | + before_filter :access_welcome_page, :only => [:welcome_page] | ||
7 | + before_filter :back_to | ||
8 | + helper_method :has_welcome_page | ||
9 | + | ||
6 | def index | 10 | def index |
7 | @pending_tasks = Task.to(profile).pending.without_spam.select{|i| user.has_permission?(i.permission, profile)} | 11 | @pending_tasks = Task.to(profile).pending.without_spam.select{|i| user.has_permission?(i.permission, profile)} |
8 | end | 12 | end |
@@ -85,6 +89,21 @@ class ProfileEditorController < MyProfileController | @@ -85,6 +89,21 @@ class ProfileEditorController < MyProfileController | ||
85 | end | 89 | end |
86 | end | 90 | end |
87 | 91 | ||
92 | + def welcome_page | ||
93 | + @welcome_page = profile.welcome_page || TinyMceArticle.new(:name => 'Welcome Page', :profile => profile, :published => false) | ||
94 | + if request.post? | ||
95 | + begin | ||
96 | + @welcome_page.update_attributes!(params[:welcome_page]) | ||
97 | + profile.welcome_page = @welcome_page | ||
98 | + profile.save! | ||
99 | + session[:notice] = _('Welcome page saved successfully.') | ||
100 | + redirect_to :action => 'index' | ||
101 | + rescue Exception => exception | ||
102 | + session[:notice] = _('Welcome page could not be saved.') | ||
103 | + end | ||
104 | + end | ||
105 | + end | ||
106 | + | ||
88 | def deactivate_profile | 107 | def deactivate_profile |
89 | if environment.admins.include?(current_person) | 108 | if environment.admins.include?(current_person) |
90 | profile = environment.profiles.find(params[:id]) | 109 | profile = environment.profiles.find(params[:id]) |
@@ -116,9 +135,24 @@ class ProfileEditorController < MyProfileController | @@ -116,9 +135,24 @@ class ProfileEditorController < MyProfileController | ||
116 | protected | 135 | protected |
117 | 136 | ||
118 | def redirect_to_previous_location | 137 | def redirect_to_previous_location |
119 | - back = request.referer | ||
120 | - back = "/" if back.nil? | 138 | + redirect_to @back_to |
139 | + end | ||
121 | 140 | ||
122 | - redirect_to back | 141 | + #TODO Consider using this as a general controller feature to be available on every action. |
142 | + def back_to | ||
143 | + @back_to = params[:back_to] || request.referer || "/" | ||
123 | end | 144 | end |
145 | + | ||
146 | + private | ||
147 | + | ||
148 | + def has_welcome_page | ||
149 | + profile.is_template | ||
150 | + end | ||
151 | + | ||
152 | + def access_welcome_page | ||
153 | + unless has_welcome_page | ||
154 | + render_access_denied | ||
155 | + end | ||
156 | + end | ||
157 | + | ||
124 | end | 158 | end |
app/controllers/public/account_controller.rb
@@ -82,10 +82,12 @@ class AccountController < ApplicationController | @@ -82,10 +82,12 @@ class AccountController < ApplicationController | ||
82 | if @plugins.dispatch(:allow_user_registration).include?(false) | 82 | if @plugins.dispatch(:allow_user_registration).include?(false) |
83 | redirect_back_or_default(:controller => 'home') | 83 | redirect_back_or_default(:controller => 'home') |
84 | session[:notice] = _("This environment doesn't allow user registration.") | 84 | session[:notice] = _("This environment doesn't allow user registration.") |
85 | + return | ||
85 | end | 86 | end |
86 | 87 | ||
87 | store_location(request.referer) unless params[:return_to] or session[:return_to] | 88 | store_location(request.referer) unless params[:return_to] or session[:return_to] |
88 | 89 | ||
90 | + # Tranforming to boolean | ||
89 | @block_bot = !!session[:may_be_a_bot] | 91 | @block_bot = !!session[:may_be_a_bot] |
90 | @invitation_code = params[:invitation_code] | 92 | @invitation_code = params[:invitation_code] |
91 | begin | 93 | begin |
@@ -129,8 +131,8 @@ class AccountController < ApplicationController | @@ -129,8 +131,8 @@ class AccountController < ApplicationController | ||
129 | check_join_in_community(@user) | 131 | check_join_in_community(@user) |
130 | go_to_signup_initial_page | 132 | go_to_signup_initial_page |
131 | else | 133 | else |
134 | + redirect_to :controller => :home, :action => :welcome, :template_id => (@user.person.template && @user.person.template.id) | ||
132 | session[:notice] = _('Thanks for registering!') | 135 | session[:notice] = _('Thanks for registering!') |
133 | - @register_pending = true | ||
134 | end | 136 | end |
135 | end | 137 | end |
136 | end | 138 | end |
@@ -461,6 +463,8 @@ class AccountController < ApplicationController | @@ -461,6 +463,8 @@ class AccountController < ApplicationController | ||
461 | redirect_to user.url | 463 | redirect_to user.url |
462 | when 'user_control_panel' | 464 | when 'user_control_panel' |
463 | redirect_to user.admin_url | 465 | redirect_to user.admin_url |
466 | + when 'welcome_page' | ||
467 | + redirect_to :controller => :home, :action => :welcome, :template_id => (user.template && user.template.id) | ||
464 | else | 468 | else |
465 | redirect_back_or_default(default) | 469 | redirect_back_or_default(default) |
466 | end | 470 | end |
app/controllers/public/home_controller.rb
@@ -18,4 +18,10 @@ class HomeController < PublicController | @@ -18,4 +18,10 @@ class HomeController < PublicController | ||
18 | @no_design_blocks = true | 18 | @no_design_blocks = true |
19 | end | 19 | end |
20 | 20 | ||
21 | + def welcome | ||
22 | + @no_design_blocks = true | ||
23 | + @display_confirmation_tips = !user.present? && !environment.enabled?(:skip_new_user_email_confirmation) | ||
24 | + @person_template = user && user.template || params[:template_id] && Person.find(params[:template_id]) | ||
25 | + end | ||
26 | + | ||
21 | end | 27 | end |
app/controllers/public/invite_controller.rb
@@ -4,8 +4,15 @@ class InviteController < PublicController | @@ -4,8 +4,15 @@ class InviteController < PublicController | ||
4 | before_filter :login_required | 4 | before_filter :login_required |
5 | before_filter :check_permissions_to_invite | 5 | before_filter :check_permissions_to_invite |
6 | 6 | ||
7 | - def select_address_book | 7 | + def invite_friends |
8 | @import_from = params[:import_from] || "manual" | 8 | @import_from = params[:import_from] || "manual" |
9 | + @mail_template = params[:mail_template] || environment.invitation_mail_template(profile) | ||
10 | + | ||
11 | + labels = Profile::SEARCHABLE_FIELDS.except(:nickname).merge(User::SEARCHABLE_FIELDS).map { |name,info| info[:label].downcase } | ||
12 | + last = labels.pop | ||
13 | + label = labels.join(', ') | ||
14 | + @search_fields = "#{label} #{_('or')} #{last}" | ||
15 | + | ||
9 | if request.post? | 16 | if request.post? |
10 | contact_list = ContactList.create | 17 | contact_list = ContactList.create |
11 | Delayed::Job.enqueue GetEmailContactsJob.new(@import_from, params[:login], params[:password], contact_list.id) if @import_from != 'manual' | 18 | Delayed::Job.enqueue GetEmailContactsJob.new(@import_from, params[:login], params[:password], contact_list.id) if @import_from != 'manual' |
@@ -22,7 +29,7 @@ class InviteController < PublicController | @@ -22,7 +29,7 @@ class InviteController < PublicController | ||
22 | webmail_import_addresses = params[:webmail_import_addresses] | 29 | webmail_import_addresses = params[:webmail_import_addresses] |
23 | contacts_to_invite = Invitation.join_contacts(manual_import_addresses, webmail_import_addresses) | 30 | contacts_to_invite = Invitation.join_contacts(manual_import_addresses, webmail_import_addresses) |
24 | if !contacts_to_invite.empty? | 31 | if !contacts_to_invite.empty? |
25 | - Delayed::Job.enqueue InvitationJob.new(current_user.person.id, contacts_to_invite, params[:mail_template], profile.id, @contact_list.id, locale) | 32 | + Delayed::Job.enqueue InvitationJob.new(user.id, contacts_to_invite, params[:mail_template], profile.id, @contact_list.id, locale) |
26 | session[:notice] = _('Your invitations are being sent.') | 33 | session[:notice] = _('Your invitations are being sent.') |
27 | if profile.person? | 34 | if profile.person? |
28 | redirect_to :controller => 'profile', :action => 'friends' | 35 | redirect_to :controller => 'profile', :action => 'friends' |
@@ -52,16 +59,36 @@ class InviteController < PublicController | @@ -52,16 +59,36 @@ class InviteController < PublicController | ||
52 | def cancel_fetching_emails | 59 | def cancel_fetching_emails |
53 | contact_list = ContactList.find(params[:contact_list]) | 60 | contact_list = ContactList.find(params[:contact_list]) |
54 | contact_list.destroy | 61 | contact_list.destroy |
55 | - redirect_to :action => 'select_address_book' | 62 | + redirect_to :action => 'invite_friends' |
63 | + end | ||
64 | + | ||
65 | + def invite_registered_friend | ||
66 | + contacts_to_invite = params['q'].split(',') | ||
67 | + if !contacts_to_invite.empty? && request.post? | ||
68 | + Delayed::Job.enqueue InvitationJob.new(user.id, contacts_to_invite, '', profile.id, nil, locale) | ||
69 | + session[:notice] = _('Your invitations are being sent.') | ||
70 | + if profile.person? | ||
71 | + redirect_to :controller => 'profile', :action => 'friends' | ||
72 | + else | ||
73 | + redirect_to :controller => 'profile', :action => 'members' | ||
74 | + end | ||
75 | + else | ||
76 | + redirect_to :action => 'invite_friends' | ||
77 | + session[:notice] = _('Please enter a valid profile.') | ||
78 | + end | ||
79 | + end | ||
80 | + | ||
81 | + def search | ||
82 | + scope = profile.invite_friends_only ? user.friends : environment.people | ||
83 | + scope = scope.not_members_of(profile) if profile.organization? | ||
84 | + scope = scope.not_friends_of(profile) if profile.person? | ||
85 | + results = find_by_contents(:people, environment, scope, params['q'], {:page => 1}, {:joins => :user})[:results] | ||
86 | + render :text => prepare_to_token_input(results).to_json | ||
56 | end | 87 | end |
57 | 88 | ||
58 | protected | 89 | protected |
59 | 90 | ||
60 | def check_permissions_to_invite | 91 | def check_permissions_to_invite |
61 | - if profile.person? and !current_user.person.has_permission?(:manage_friends, profile) or | ||
62 | - profile.community? and !current_user.person.has_permission?(:invite_members, profile) | ||
63 | - render_access_denied | ||
64 | - end | 92 | + render_access_denied if !profile.allow_invitation_from?(user) |
65 | end | 93 | end |
66 | - | ||
67 | end | 94 | end |
app/controllers/public/profile_search_controller.rb
@@ -9,9 +9,12 @@ class ProfileSearchController < PublicController | @@ -9,9 +9,12 @@ class ProfileSearchController < PublicController | ||
9 | @q = params[:q] | 9 | @q = params[:q] |
10 | unless @q.blank? | 10 | unless @q.blank? |
11 | if params[:where] == 'environment' | 11 | if params[:where] == 'environment' |
12 | - redirect_to :controller => 'search', :query => @q | 12 | + # user is using global search, redirects to the search controller with |
13 | + # the query | ||
14 | + search_path = url_for(:controller => 'search', :query => @q) | ||
15 | + request.xhr? ? render(:js => "window.location.href = #{search_path.to_json}") : redirect_to(search_path) | ||
13 | else | 16 | else |
14 | - @results = find_by_contents(:articles, profile.articles.published, @q, {:per_page => 10, :page => params[:page]})[:results] | 17 | + @results = find_by_contents(:articles, profile, profile.articles.published, @q, {:per_page => 10, :page => params[:page]})[:results] |
15 | end | 18 | end |
16 | end | 19 | end |
17 | end | 20 | end |
app/controllers/public/search_controller.rb
@@ -4,11 +4,11 @@ class SearchController < PublicController | @@ -4,11 +4,11 @@ class SearchController < PublicController | ||
4 | include SearchHelper | 4 | include SearchHelper |
5 | include ActionView::Helpers::NumberHelper | 5 | include ActionView::Helpers::NumberHelper |
6 | 6 | ||
7 | - before_filter :redirect_asset_param, :except => :assets | ||
8 | - before_filter :load_category | ||
9 | - before_filter :load_search_assets | ||
10 | - before_filter :load_query | ||
11 | - before_filter :load_filter | 7 | + before_filter :redirect_asset_param, :except => [:assets, :suggestions] |
8 | + before_filter :load_category, :except => :suggestions | ||
9 | + before_filter :load_search_assets, :except => :suggestions | ||
10 | + before_filter :load_query, :except => :suggestions | ||
11 | + before_filter :load_order, :except => :suggestions | ||
12 | 12 | ||
13 | # Backwards compatibility with old URLs | 13 | # Backwards compatibility with old URLs |
14 | def redirect_asset_param | 14 | def redirect_asset_param |
@@ -20,7 +20,7 @@ class SearchController < PublicController | @@ -20,7 +20,7 @@ class SearchController < PublicController | ||
20 | 20 | ||
21 | def index | 21 | def index |
22 | @searches = {} | 22 | @searches = {} |
23 | - @order = [] | 23 | + @assets = [] |
24 | @names = {} | 24 | @names = {} |
25 | @results_only = true | 25 | @results_only = true |
26 | 26 | ||
@@ -28,7 +28,7 @@ class SearchController < PublicController | @@ -28,7 +28,7 @@ class SearchController < PublicController | ||
28 | load_query | 28 | load_query |
29 | @asset = key | 29 | @asset = key |
30 | send(key) | 30 | send(key) |
31 | - @order << key | 31 | + @assets << key |
32 | @names[key] = _(description) | 32 | @names[key] = _(description) |
33 | end | 33 | end |
34 | @asset = nil | 34 | @asset = nil |
@@ -42,7 +42,7 @@ class SearchController < PublicController | @@ -42,7 +42,7 @@ class SearchController < PublicController | ||
42 | # view the summary of one category | 42 | # view the summary of one category |
43 | def category_index | 43 | def category_index |
44 | @searches = {} | 44 | @searches = {} |
45 | - @order = [] | 45 | + @assets = [] |
46 | @names = {} | 46 | @names = {} |
47 | limit = MULTIPLE_SEARCH_LIMIT | 47 | limit = MULTIPLE_SEARCH_LIMIT |
48 | [ | 48 | [ |
@@ -53,7 +53,7 @@ class SearchController < PublicController | @@ -53,7 +53,7 @@ class SearchController < PublicController | ||
53 | [ :communities, _('Communities'), :recent_communities ], | 53 | [ :communities, _('Communities'), :recent_communities ], |
54 | [ :articles, _('Contents'), :recent_articles ] | 54 | [ :articles, _('Contents'), :recent_articles ] |
55 | ].each do |asset, name, filter| | 55 | ].each do |asset, name, filter| |
56 | - @order << asset | 56 | + @assets << asset |
57 | @searches[asset]= {:results => @category.send(filter, limit)} | 57 | @searches[asset]= {:results => @category.send(filter, limit)} |
58 | raise "No total_entries for: #{asset}" unless @searches[asset][:results].respond_to?(:total_entries) | 58 | raise "No total_entries for: #{asset}" unless @searches[asset][:results].respond_to?(:total_entries) |
59 | @names[asset] = name | 59 | @names[asset] = name |
@@ -147,12 +147,16 @@ class SearchController < PublicController | @@ -147,12 +147,16 @@ class SearchController < PublicController | ||
147 | render :partial => 'events/events' | 147 | render :partial => 'events/events' |
148 | end | 148 | end |
149 | 149 | ||
150 | + def suggestions | ||
151 | + render :text => find_suggestions(normalize_term(params[:term]), environment, params[:asset]).to_json | ||
152 | + end | ||
153 | + | ||
150 | ####################################################### | 154 | ####################################################### |
151 | protected | 155 | protected |
152 | 156 | ||
153 | def load_query | 157 | def load_query |
154 | @asset = (params[:asset] || params[:action]).to_sym | 158 | @asset = (params[:asset] || params[:action]).to_sym |
155 | - @order ||= [@asset] | 159 | + @assets ||= [@asset] |
156 | @searches ||= {} | 160 | @searches ||= {} |
157 | 161 | ||
158 | @query = params[:query] || '' | 162 | @query = params[:query] || '' |
@@ -173,13 +177,22 @@ class SearchController < PublicController | @@ -173,13 +177,22 @@ class SearchController < PublicController | ||
173 | end | 177 | end |
174 | end | 178 | end |
175 | 179 | ||
180 | + AVAILABLE_SEARCHES = ActiveSupport::OrderedHash[ | ||
181 | + :articles, _('Contents'), | ||
182 | + :people, _('People'), | ||
183 | + :communities, _('Communities'), | ||
184 | + :enterprises, _('Enterprises'), | ||
185 | + :products, _('Products and Services'), | ||
186 | + :events, _('Events'), | ||
187 | + ] | ||
188 | + | ||
176 | def load_search_assets | 189 | def load_search_assets |
177 | - if SEARCHES.keys.include?(params[:action].to_sym) && environment.enabled?("disable_asset_#{params[:action]}") | 190 | + if AVAILABLE_SEARCHES.keys.include?(params[:action].to_sym) && environment.enabled?("disable_asset_#{params[:action]}") |
178 | render_not_found | 191 | render_not_found |
179 | return | 192 | return |
180 | end | 193 | end |
181 | 194 | ||
182 | - @enabled_searches = SEARCHES.select {|key, name| environment.disabled?("disable_asset_#{key}") } | 195 | + @enabled_searches = AVAILABLE_SEARCHES.select {|key, name| environment.disabled?("disable_asset_#{key}") } |
183 | @searching = {} | 196 | @searching = {} |
184 | @titles = {} | 197 | @titles = {} |
185 | @enabled_searches.each do |key, name| | 198 | @enabled_searches.each do |key, name| |
@@ -189,11 +202,11 @@ class SearchController < PublicController | @@ -189,11 +202,11 @@ class SearchController < PublicController | ||
189 | @names = @titles if @names.nil? | 202 | @names = @titles if @names.nil? |
190 | end | 203 | end |
191 | 204 | ||
192 | - def load_filter | ||
193 | - @filter = 'more_recent' | ||
194 | - if SEARCHES.keys.include?(@asset.to_sym) | ||
195 | - available_filters = asset_class(@asset)::SEARCH_FILTERS | ||
196 | - @filter = params[:filter] if available_filters.include?(params[:filter]) | 205 | + def load_order |
206 | + @order = 'more_recent' | ||
207 | + if AVAILABLE_SEARCHES.keys.include?(@asset.to_sym) | ||
208 | + available_orders = asset_class(@asset)::SEARCH_FILTERS[:order] | ||
209 | + @order = params[:order] if available_orders.include?(params[:order]) | ||
197 | end | 210 | end |
198 | end | 211 | end |
199 | 212 | ||
@@ -217,7 +230,7 @@ class SearchController < PublicController | @@ -217,7 +230,7 @@ class SearchController < PublicController | ||
217 | end | 230 | end |
218 | 231 | ||
219 | def full_text_search | 232 | def full_text_search |
220 | - @searches[@asset] = find_by_contents(@asset, @scope, @query, paginate_options, {:category => @category, :filter => @filter}) | 233 | + @searches[@asset] = find_by_contents(@asset, environment, @scope, @query, paginate_options, {:category => @category, :filter => @order}) |
221 | end | 234 | end |
222 | 235 | ||
223 | private | 236 | private |
@@ -232,4 +245,14 @@ class SearchController < PublicController | @@ -232,4 +245,14 @@ class SearchController < PublicController | ||
232 | 20 | 245 | 20 |
233 | end | 246 | end |
234 | 247 | ||
248 | + def available_assets | ||
249 | + assets = ActiveSupport::OrderedHash[ | ||
250 | + :articles, _('Contents'), | ||
251 | + :enterprises, _('Enterprises'), | ||
252 | + :people, _('People'), | ||
253 | + :communities, _('Communities'), | ||
254 | + :products, _('Products and Services'), | ||
255 | + ] | ||
256 | + end | ||
257 | + | ||
235 | end | 258 | end |
app/helpers/application_helper.rb
@@ -1307,8 +1307,19 @@ module ApplicationHelper | @@ -1307,8 +1307,19 @@ module ApplicationHelper | ||
1307 | end | 1307 | end |
1308 | end | 1308 | end |
1309 | 1309 | ||
1310 | - def remove_content_button(action) | ||
1311 | - @plugins.dispatch("content_remove_#{action.to_s}", @page).include?(true) | 1310 | + def content_remove_spread(content) |
1311 | + !content.public? || content.folder? || (profile == user && user.communities.blank? && !environment.portal_enabled) | ||
1312 | + end | ||
1313 | + | ||
1314 | + def remove_content_button(action, content) | ||
1315 | + method_name = "content_remove_#{action.to_s}" | ||
1316 | + plugin_condition = @plugins.dispatch(method_name, content).include?(true) | ||
1317 | + begin | ||
1318 | + core_condition = self.send(method_name, content) | ||
1319 | + rescue NoMethodError | ||
1320 | + core_condition = false | ||
1321 | + end | ||
1322 | + core_condition || plugin_condition | ||
1312 | end | 1323 | end |
1313 | 1324 | ||
1314 | def template_options(kind, field_name) | 1325 | def template_options(kind, field_name) |
@@ -1411,6 +1422,43 @@ module ApplicationHelper | @@ -1411,6 +1422,43 @@ module ApplicationHelper | ||
1411 | content_tag('ul', article.versions.map {|v| link_to("r#{v.version}", @page.url.merge(:version => v.version))}) | 1422 | content_tag('ul', article.versions.map {|v| link_to("r#{v.version}", @page.url.merge(:version => v.version))}) |
1412 | end | 1423 | end |
1413 | 1424 | ||
1425 | + def search_input_with_suggestions(name, asset, default, options = {}) | ||
1426 | + text_field_tag name, default, options.merge({:class => 'search-input-with-suggestions', 'data-asset' => asset}) | ||
1427 | + end | ||
1428 | + | ||
1429 | + def profile_suggestion_profile_connections(suggestion) | ||
1430 | + profiles = suggestion.profile_connections.first(4).map do |profile| | ||
1431 | + link_to(profile_image(profile, :icon, :title => profile.name), profile.url, :class => 'profile-suggestion-connection-icon') | ||
1432 | + end | ||
1433 | + | ||
1434 | + controller_target = suggestion.suggestion_type == 'Person' ? :friends : :memberships | ||
1435 | + profiles << link_to("<big> +#{suggestion.profile_connections.count - 4}</big>", :controller => controller_target, :action => :connections, :id => suggestion.suggestion_id) if suggestion.profile_connections.count > 4 | ||
1436 | + | ||
1437 | + if profiles.present? | ||
1438 | + content_tag(:div, profiles.join , :class => 'profile-connections') | ||
1439 | + else | ||
1440 | + '' | ||
1441 | + end | ||
1442 | + end | ||
1443 | + | ||
1444 | + def profile_suggestion_tag_connections(suggestion) | ||
1445 | + tags = suggestion.tag_connections.first(4).map do |tag| | ||
1446 | + tag.name + ', ' | ||
1447 | + end | ||
1448 | + last_tag = tags.pop | ||
1449 | + tags << last_tag.strip.chop if last_tag.present? | ||
1450 | + title = tags.join | ||
1451 | + | ||
1452 | + controller_target = suggestion.suggestion_type == 'Person' ? :friends : :memberships | ||
1453 | + tags << ' ' + link_to('...', {:controller => controller_target, :action => :connections, :id => suggestion.suggestion_id}, :class => 'more-tag-connections', :title => _('See all connections')) if suggestion.tag_connections.count > 4 | ||
1454 | + | ||
1455 | + if tags.present? | ||
1456 | + content_tag(:div, tags.join, :class => 'tag-connections', :title => title) | ||
1457 | + else | ||
1458 | + '' | ||
1459 | + end | ||
1460 | + end | ||
1461 | + | ||
1414 | def labelled_colorpicker_field(human_name, object_name, method, options = {}) | 1462 | def labelled_colorpicker_field(human_name, object_name, method, options = {}) |
1415 | options[:id] ||= 'text-field-' + FormsHelper.next_id_number | 1463 | options[:id] ||= 'text-field-' + FormsHelper.next_id_number |
1416 | content_tag('label', human_name, :for => options[:id], :class => 'formlabel') + | 1464 | content_tag('label', human_name, :for => options[:id], :class => 'formlabel') + |
app/helpers/cms_helper.rb
@@ -40,12 +40,8 @@ module CmsHelper | @@ -40,12 +40,8 @@ module CmsHelper | ||
40 | end | 40 | end |
41 | end | 41 | end |
42 | 42 | ||
43 | - def display_spread_button(profile, article) | ||
44 | - if profile.person? | ||
45 | - expirable_button article, :spread, _('Spread this'), :action => 'publish', :id => article.id | ||
46 | - elsif profile.community? && environment.portal_community | ||
47 | - expirable_button article, :spread, _('Spread this'), :action => 'publish_on_portal_community', :id => article.id | ||
48 | - end | 43 | + def display_spread_button(article) |
44 | + expirable_button article, :spread, _('Spread this'), {:action => 'publish', :id => article.id}, {:class => 'colorbox'} | ||
49 | end | 45 | end |
50 | 46 | ||
51 | def display_delete_button(article) | 47 | def display_delete_button(article) |
app/helpers/forms_helper.rb
@@ -265,7 +265,7 @@ module FormsHelper | @@ -265,7 +265,7 @@ module FormsHelper | ||
265 | ) | 265 | ) |
266 | end | 266 | end |
267 | 267 | ||
268 | - def select_profile_folder(label_text, field_id, profile, default_value='', html_options = {}, js_options = {}, find_options = {}) | 268 | + def select_profile_folder(label_text, field_id, profile, default_value='', html_options = {}, js_options = {}, find_options = {}, extra_options = {}) |
269 | if find_options.empty? | 269 | if find_options.empty? |
270 | folders = profile.folders | 270 | folders = profile.folders |
271 | else | 271 | else |
@@ -276,7 +276,7 @@ module FormsHelper | @@ -276,7 +276,7 @@ module FormsHelper | ||
276 | select_tag( | 276 | select_tag( |
277 | field_id, | 277 | field_id, |
278 | options_for_select( | 278 | options_for_select( |
279 | - [[profile.identifier, '']] + | 279 | + [[(extra_options[:root_label] || profile.identifier), '']] + |
280 | folders.collect {|f| [ profile.identifier + '/' + f.full_name, f.id.to_s ] }, | 280 | folders.collect {|f| [ profile.identifier + '/' + f.full_name, f.id.to_s ] }, |
281 | default_value.to_s | 281 | default_value.to_s |
282 | ), | 282 | ), |
app/helpers/layout_helper.rb
@@ -48,6 +48,7 @@ module LayoutHelper | @@ -48,6 +48,7 @@ module LayoutHelper | ||
48 | 'thickbox', | 48 | 'thickbox', |
49 | 'lightbox', | 49 | 'lightbox', |
50 | 'colorbox', | 50 | 'colorbox', |
51 | + 'selectordie', | ||
51 | 'inputosaurus', | 52 | 'inputosaurus', |
52 | pngfix_stylesheet_path, | 53 | pngfix_stylesheet_path, |
53 | ] + tokeninput_stylesheets | 54 | ] + tokeninput_stylesheets |
app/helpers/search_helper.rb
@@ -5,20 +5,23 @@ module SearchHelper | @@ -5,20 +5,23 @@ module SearchHelper | ||
5 | BLOCKS_SEARCH_LIMIT = 24 | 5 | BLOCKS_SEARCH_LIMIT = 24 |
6 | MULTIPLE_SEARCH_LIMIT = 8 | 6 | MULTIPLE_SEARCH_LIMIT = 8 |
7 | 7 | ||
8 | - SEARCHES = ActiveSupport::OrderedHash[ | ||
9 | - :articles, _('Contents'), | ||
10 | - :enterprises, _('Enterprises'), | ||
11 | - :people, _('People'), | ||
12 | - :communities, _('Communities'), | ||
13 | - :products, _('Products and Services'), | ||
14 | - :events, _('Events'), | ||
15 | - ] | 8 | + FILTERS_TRANSLATIONS = { |
9 | + :order => _('Order'), | ||
10 | + :display => _('Display') | ||
11 | + } | ||
16 | 12 | ||
17 | - FILTER_TRANSLATION = { | ||
18 | - 'more_popular' => _('More popular'), | ||
19 | - 'more_active' => _('More active'), | ||
20 | - 'more_recent' => _('More recent'), | ||
21 | - 'more_comments' => _('More comments') | 13 | + FILTERS_OPTIONS_TRANSLATION = { |
14 | + :order => { | ||
15 | + 'more_popular' => _('More popular'), | ||
16 | + 'more_active' => _('More active'), | ||
17 | + 'more_recent' => _('More recent'), | ||
18 | + 'more_comments' => _('More comments') | ||
19 | + }, | ||
20 | + :display => { | ||
21 | + 'map' => _('Map'), | ||
22 | + 'full' => _('Full'), | ||
23 | + 'compact' => _('Compact') | ||
24 | + } | ||
22 | } | 25 | } |
23 | 26 | ||
24 | COMMON_PROFILE_LIST_BLOCK = [ | 27 | COMMON_PROFILE_LIST_BLOCK = [ |
@@ -56,7 +59,7 @@ module SearchHelper | @@ -56,7 +59,7 @@ module SearchHelper | ||
56 | end | 59 | end |
57 | 60 | ||
58 | def display?(asset, mode) | 61 | def display?(asset, mode) |
59 | - defined?(asset_class(asset)::SEARCH_DISPLAYS) && asset_class(asset)::SEARCH_DISPLAYS.include?(mode.to_s) | 62 | + defined?(asset_class(asset)::SEARCH_FILTERS[:display]) && asset_class(asset)::SEARCH_FILTERS[:display].include?(mode.to_s) |
60 | end | 63 | end |
61 | 64 | ||
62 | def display_results(searches=nil, asset=nil) | 65 | def display_results(searches=nil, asset=nil) |
@@ -93,6 +96,16 @@ module SearchHelper | @@ -93,6 +96,16 @@ module SearchHelper | ||
93 | end | 96 | end |
94 | end | 97 | end |
95 | 98 | ||
99 | + def select_filter(name, options, default = nil) | ||
100 | + if options.size <= 1 | ||
101 | + return | ||
102 | + else | ||
103 | + options = options.map {|option| [FILTERS_OPTIONS_TRANSLATION[name][option], option]} | ||
104 | + options = options_for_select(options, :selected => (params[name] || default)) | ||
105 | + select_tag(name, options) | ||
106 | + end | ||
107 | + end | ||
108 | + | ||
96 | def display_selector(asset, display, float = 'right') | 109 | def display_selector(asset, display, float = 'right') |
97 | display = nil if display.blank? | 110 | display = nil if display.blank? |
98 | display ||= asset_class(asset).default_search_display | 111 | display ||= asset_class(asset).default_search_display |
@@ -107,36 +120,32 @@ module SearchHelper | @@ -107,36 +120,32 @@ module SearchHelper | ||
107 | end | 120 | end |
108 | end | 121 | end |
109 | 122 | ||
110 | - def filter_selector(asset, filter, float = 'right') | 123 | + def filters(asset) |
124 | + return if !asset | ||
111 | klass = asset_class(asset) | 125 | klass = asset_class(asset) |
112 | - if klass::SEARCH_FILTERS.count > 1 | ||
113 | - options = options_for_select(klass::SEARCH_FILTERS.map {|f| [FILTER_TRANSLATION[f], f]}, filter) | ||
114 | - url_params = url_for(params.merge(:filter => 'FILTER')) | ||
115 | - onchange = "document.location.href = '#{url_params}'.replace('FILTER', this.value)" | ||
116 | - select_field = select_tag(:filter, options, :onchange => onchange) | ||
117 | - content_tag('div', | ||
118 | - content_tag('strong', _('Filter')) + ': ' + select_field, | ||
119 | - :class => "search-customize-options" | ||
120 | - ) | ||
121 | - end | 126 | + content_tag('div', klass::SEARCH_FILTERS.map do |name, options| |
127 | + default = klass.respond_to?("default_search_#{name}") ? klass.send("default_search_#{name}".to_s) : nil | ||
128 | + select_filter(name, options, default) | ||
129 | + end.join("\n"), :id => 'search-filters') | ||
130 | + end | ||
131 | + | ||
132 | + def assets_menu(selected) | ||
133 | + assets = @enabled_searches.keys | ||
134 | + # Events is a search asset but do not have a good interface for | ||
135 | + #TODO searching. When this is solved we may add it back again to the assets | ||
136 | + # menu. | ||
137 | + assets.delete(:events) | ||
138 | + content_tag('ul', | ||
139 | + assets.map do |asset| | ||
140 | + options = {} | ||
141 | + options.merge!(:class => 'selected') if selected.to_s == asset.to_s | ||
142 | + content_tag('li', asset_link(asset), options) | ||
143 | + end.join("\n"), | ||
144 | + :id => 'assets-menu') | ||
122 | end | 145 | end |
123 | 146 | ||
124 | - def filter_title(asset, filter) | ||
125 | - { | ||
126 | - 'articles_more_recent' => _('More recent contents from network'), | ||
127 | - 'articles_more_popular' => _('More viewed contents from network'), | ||
128 | - 'articles_more_comments' => _('Most commented contents from network'), | ||
129 | - 'people_more_recent' => _('More recent people from network'), | ||
130 | - 'people_more_active' => _('More active people from network'), | ||
131 | - 'people_more_popular' => _('More popular people from network'), | ||
132 | - 'communities_more_recent' => _('More recent communities from network'), | ||
133 | - 'communities_more_active' => _('More active communities from network'), | ||
134 | - 'communities_more_popular' => _('More popular communities from network'), | ||
135 | - 'enterprises_more_recent' => _('More recent enterprises from network'), | ||
136 | - 'enterprises_more_active' => _('More active enterprises from network'), | ||
137 | - 'enterprises_more_popular' => _('More popular enterprises from network'), | ||
138 | - 'products_more_recent' => _('Highlights'), | ||
139 | - }[asset.to_s + '_' + filter].to_s | 147 | + def asset_link(asset) |
148 | + link_to(@enabled_searches[asset], "/search/#{asset}") | ||
140 | end | 149 | end |
141 | 150 | ||
142 | end | 151 | end |
@@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
1 | +module SearchTermHelper | ||
2 | + def register_search_term(term, total, indexed, context, asset='all') | ||
3 | + normalized_term = normalize_term(term) | ||
4 | + if normalized_term.present? | ||
5 | + search_term = SearchTerm.find_or_create(normalized_term, context, asset) | ||
6 | + SearchTermOccurrence.create!(:search_term => search_term, :total => total, :indexed => indexed) | ||
7 | + end | ||
8 | + end | ||
9 | + | ||
10 | + #FIXME For some reason the job is created but nothing is ran. | ||
11 | + #handle_asynchronously :register_search_term | ||
12 | + | ||
13 | + #TODO Think smarter criteria to normalize search terms properly | ||
14 | + def normalize_term(search_term) | ||
15 | + search_term ||= '' | ||
16 | + search_term.downcase | ||
17 | + end | ||
18 | +end |
app/helpers/token_helper.rb
@@ -12,6 +12,7 @@ module TokenHelper | @@ -12,6 +12,7 @@ module TokenHelper | ||
12 | options[:search_delay] ||= 1000 | 12 | options[:search_delay] ||= 1000 |
13 | options[:prevent_duplicates] ||= true | 13 | options[:prevent_duplicates] ||= true |
14 | options[:backspace_delete_item] ||= false | 14 | options[:backspace_delete_item] ||= false |
15 | + options[:zindex] ||= 999 | ||
15 | options[:focus] ||= false | 16 | options[:focus] ||= false |
16 | options[:avoid_enter] ||= true | 17 | options[:avoid_enter] ||= true |
17 | options[:on_result] ||= 'null' | 18 | options[:on_result] ||= 'null' |
@@ -31,6 +32,7 @@ module TokenHelper | @@ -31,6 +32,7 @@ module TokenHelper | ||
31 | searchDelay: #{options[:search_delay].to_json}, | 32 | searchDelay: #{options[:search_delay].to_json}, |
32 | preventDuplicates: #{options[:prevent_duplicates].to_json}, | 33 | preventDuplicates: #{options[:prevent_duplicates].to_json}, |
33 | backspaceDeleteItem: #{options[:backspace_delete_item].to_json}, | 34 | backspaceDeleteItem: #{options[:backspace_delete_item].to_json}, |
35 | + zindex: #{options[:zindex].to_json}, | ||
34 | queryParam: #{options[:query_param].to_json}, | 36 | queryParam: #{options[:query_param].to_json}, |
35 | tokenLimit: #{options[:token_limit].to_json}, | 37 | tokenLimit: #{options[:token_limit].to_json}, |
36 | onResult: #{options[:on_result]}, | 38 | onResult: #{options[:on_result]}, |
app/mailers/user_mailer.rb
@@ -41,6 +41,23 @@ class UserMailer < ActionMailer::Base | @@ -41,6 +41,23 @@ class UserMailer < ActionMailer::Base | ||
41 | ) | 41 | ) |
42 | end | 42 | end |
43 | 43 | ||
44 | + def profiles_suggestions_email(user) | ||
45 | + @recipient = user.name | ||
46 | + @environment = user.environment.name | ||
47 | + @url = user.environment.top_url | ||
48 | + @people_suggestions_url = user.people_suggestions_url | ||
49 | + @people_suggestions = user.suggested_people.sample(3) | ||
50 | + @communities_suggestions_url = user.communities_suggestions_url | ||
51 | + @communities_suggestions = user.suggested_communities.sample(3) | ||
52 | + | ||
53 | + mail( | ||
54 | + content_type: 'text/html', | ||
55 | + to: user.email, | ||
56 | + from: "#{user.environment.name} <#{user.environment.contact_email}>", | ||
57 | + subject: _("[%s] What about grow up your network?") % user.environment.name | ||
58 | + ) | ||
59 | + end | ||
60 | + | ||
44 | class Job < Struct.new(:user, :method) | 61 | class Job < Struct.new(:user, :method) |
45 | def perform | 62 | def perform |
46 | UserMailer.send(method, user).deliver | 63 | UserMailer.send(method, user).deliver |
app/models/add_friend.rb
@@ -14,6 +14,11 @@ class AddFriend < Task | @@ -14,6 +14,11 @@ class AddFriend < Task | ||
14 | alias :friend :target | 14 | alias :friend :target |
15 | alias :friend= :target= | 15 | alias :friend= :target= |
16 | 16 | ||
17 | + after_create do |task| | ||
18 | + TaskMailer.invitation_notification(task).deliver unless task.friend | ||
19 | + remove_from_suggestion_list(task) | ||
20 | + end | ||
21 | + | ||
17 | def perform | 22 | def perform |
18 | target.add_friend(requestor, group_for_friend) | 23 | target.add_friend(requestor, group_for_friend) |
19 | requestor.add_friend(target, group_for_person) | 24 | requestor.add_friend(target, group_for_person) |
@@ -48,4 +53,8 @@ class AddFriend < Task | @@ -48,4 +53,8 @@ class AddFriend < Task | ||
48 | {:type => :profile_image, :profile => requestor, :url => requestor.url} | 53 | {:type => :profile_image, :profile => requestor, :url => requestor.url} |
49 | end | 54 | end |
50 | 55 | ||
56 | + def remove_from_suggestion_list(task) | ||
57 | + suggestion = task.requestor.profile_suggestions.find_by_suggestion_id task.target.id | ||
58 | + suggestion.disable if suggestion | ||
59 | + end | ||
51 | end | 60 | end |
app/models/add_member.rb
@@ -10,6 +10,10 @@ class AddMember < Task | @@ -10,6 +10,10 @@ class AddMember < Task | ||
10 | 10 | ||
11 | settings_items :roles | 11 | settings_items :roles |
12 | 12 | ||
13 | + after_create do |task| | ||
14 | + remove_from_suggestion_list(task) | ||
15 | + end | ||
16 | + | ||
13 | def perform | 17 | def perform |
14 | if !self.roles or (self.roles.uniq.compact.length == 1 and self.roles.uniq.compact.first.to_i.zero?) | 18 | if !self.roles or (self.roles.uniq.compact.length == 1 and self.roles.uniq.compact.first.to_i.zero?) |
15 | self.roles = [Profile::Roles.member(organization.environment.id).id] | 19 | self.roles = [Profile::Roles.member(organization.environment.id).id] |
@@ -46,4 +50,9 @@ class AddMember < Task | @@ -46,4 +50,9 @@ class AddMember < Task | ||
46 | _('You will need login to %{system} in order to accept or reject %{requestor} as a member of %{organization}.') % { :system => target.environment.name, :requestor => requestor.name, :organization => organization.name } | 50 | _('You will need login to %{system} in order to accept or reject %{requestor} as a member of %{organization}.') % { :system => target.environment.name, :requestor => requestor.name, :organization => organization.name } |
47 | end | 51 | end |
48 | 52 | ||
53 | + def remove_from_suggestion_list(task) | ||
54 | + suggestion = task.requestor.profile_suggestions.find_by_suggestion_id task.target.id | ||
55 | + suggestion.disable if suggestion | ||
56 | + end | ||
57 | + | ||
49 | end | 58 | end |
app/models/article.rb
@@ -14,20 +14,17 @@ class Article < ActiveRecord::Base | @@ -14,20 +14,17 @@ class Article < ActiveRecord::Base | ||
14 | acts_as_having_image | 14 | acts_as_having_image |
15 | 15 | ||
16 | SEARCHABLE_FIELDS = { | 16 | SEARCHABLE_FIELDS = { |
17 | - :name => 10, | ||
18 | - :abstract => 3, | ||
19 | - :body => 2, | ||
20 | - :slug => 1, | ||
21 | - :filename => 1, | 17 | + :name => {:label => _('Name'), :weight => 10}, |
18 | + :abstract => {:label => _('Abstract'), :weight => 3}, | ||
19 | + :body => {:label => _('Content'), :weight => 2}, | ||
20 | + :slug => {:label => _('Slug'), :weight => 1}, | ||
21 | + :filename => {:label => _('Filename'), :weight => 1}, | ||
22 | } | 22 | } |
23 | 23 | ||
24 | - SEARCH_FILTERS = %w[ | ||
25 | - more_recent | ||
26 | - more_popular | ||
27 | - more_comments | ||
28 | - ] | ||
29 | - | ||
30 | - SEARCH_DISPLAYS = %w[full] | 24 | + SEARCH_FILTERS = { |
25 | + :order => %w[more_recent more_popular more_comments], | ||
26 | + :display => %w[full] | ||
27 | + } | ||
31 | 28 | ||
32 | def self.default_search_display | 29 | def self.default_search_display |
33 | 'full' | 30 | 'full' |
@@ -477,7 +474,9 @@ class Article < ActiveRecord::Base | @@ -477,7 +474,9 @@ class Article < ActiveRecord::Base | ||
477 | scope :no_folders, lambda {|profile|{:conditions => ['articles.type NOT IN (?)', profile.folder_types]}} | 474 | scope :no_folders, lambda {|profile|{:conditions => ['articles.type NOT IN (?)', profile.folder_types]}} |
478 | scope :galleries, :conditions => [ "articles.type IN ('Gallery')" ] | 475 | scope :galleries, :conditions => [ "articles.type IN ('Gallery')" ] |
479 | scope :images, :conditions => { :is_image => true } | 476 | scope :images, :conditions => { :is_image => true } |
477 | + scope :no_images, :conditions => { :is_image => false } | ||
480 | scope :text_articles, :conditions => [ 'articles.type IN (?)', text_article_types ] | 478 | scope :text_articles, :conditions => [ 'articles.type IN (?)', text_article_types ] |
479 | + scope :files, :conditions => { :type => 'UploadedFile' } | ||
481 | scope :with_types, lambda { |types| { :conditions => [ 'articles.type IN (?)', types ] } } | 480 | scope :with_types, lambda { |types| { :conditions => [ 'articles.type IN (?)', types ] } } |
482 | 481 | ||
483 | scope :more_popular, :order => 'hits DESC' | 482 | scope :more_popular, :order => 'hits DESC' |
@@ -528,7 +527,10 @@ class Article < ActiveRecord::Base | @@ -528,7 +527,10 @@ class Article < ActiveRecord::Base | ||
528 | end | 527 | end |
529 | 528 | ||
530 | alias :allow_delete? :allow_post_content? | 529 | alias :allow_delete? :allow_post_content? |
531 | - alias :allow_spread? :allow_post_content? | 530 | + |
531 | + def allow_spread?(user = nil) | ||
532 | + user && public? | ||
533 | + end | ||
532 | 534 | ||
533 | def allow_create?(user) | 535 | def allow_create?(user) |
534 | allow_post_content?(user) || allow_publish_content?(user) | 536 | allow_post_content?(user) || allow_publish_content?(user) |
app/models/category.rb
@@ -3,10 +3,10 @@ class Category < ActiveRecord::Base | @@ -3,10 +3,10 @@ class Category < ActiveRecord::Base | ||
3 | attr_accessible :name, :parent_id, :display_color, :display_in_menu, :image_builder, :environment, :parent | 3 | attr_accessible :name, :parent_id, :display_color, :display_in_menu, :image_builder, :environment, :parent |
4 | 4 | ||
5 | SEARCHABLE_FIELDS = { | 5 | SEARCHABLE_FIELDS = { |
6 | - :name => 10, | ||
7 | - :acronym => 5, | ||
8 | - :abbreviation => 5, | ||
9 | - :slug => 1, | 6 | + :name => {:label => _('Name'), :weight => 10}, |
7 | + :acronym => {:label => _('Acronym'), :weight => 5}, | ||
8 | + :abbreviation => {:label => _('Abbreviation'), :weight => 5}, | ||
9 | + :slug => {:label => _('Slug'), :weight => 1}, | ||
10 | } | 10 | } |
11 | 11 | ||
12 | validates_exclusion_of :slug, :in => [ 'index' ], :message => N_('{fn} cannot be like that.').fix_i18n | 12 | validates_exclusion_of :slug, :in => [ 'index' ], :message => N_('{fn} cannot be like that.').fix_i18n |
app/models/certifier.rb
@@ -3,9 +3,9 @@ class Certifier < ActiveRecord::Base | @@ -3,9 +3,9 @@ class Certifier < ActiveRecord::Base | ||
3 | attr_accessible :name, :environment | 3 | attr_accessible :name, :environment |
4 | 4 | ||
5 | SEARCHABLE_FIELDS = { | 5 | SEARCHABLE_FIELDS = { |
6 | - :name => 10, | ||
7 | - :description => 3, | ||
8 | - :link => 1, | 6 | + :name => {:label => _('Name'), :weight => 10}, |
7 | + :description => {:label => _('Description'), :weight => 3}, | ||
8 | + :link => {:label => _('Link'), :weight => 1}, | ||
9 | } | 9 | } |
10 | 10 | ||
11 | belongs_to :environment | 11 | belongs_to :environment |
app/models/comment.rb
1 | class Comment < ActiveRecord::Base | 1 | class Comment < ActiveRecord::Base |
2 | 2 | ||
3 | SEARCHABLE_FIELDS = { | 3 | SEARCHABLE_FIELDS = { |
4 | - :title => 10, | ||
5 | - :name => 4, | ||
6 | - :body => 2, | 4 | + :title => {:label => _('Title'), :weight => 10}, |
5 | + :name => {:label => _('Name'), :weight => 4}, | ||
6 | + :body => {:label => _('Content'), :weight => 2}, | ||
7 | } | 7 | } |
8 | 8 | ||
9 | attr_accessible :body, :author, :name, :email, :title, :reply_of_id, :source | 9 | attr_accessible :body, :author, :name, :email, :title, :reply_of_id, :source |
app/models/communities_block.rb
@@ -14,19 +14,17 @@ class CommunitiesBlock < ProfileListBlock | @@ -14,19 +14,17 @@ class CommunitiesBlock < ProfileListBlock | ||
14 | _('This block displays the communities in which the user is a member.') | 14 | _('This block displays the communities in which the user is a member.') |
15 | end | 15 | end |
16 | 16 | ||
17 | + def suggestions | ||
18 | + return nil unless owner.kind_of?(Profile) | ||
19 | + owner.profile_suggestions.of_community.enabled.limit(3).includes(:suggestion) | ||
20 | + end | ||
21 | + | ||
17 | def footer | 22 | def footer |
18 | owner = self.owner | 23 | owner = self.owner |
19 | - case owner | ||
20 | - when Profile | ||
21 | - lambda do |context| | ||
22 | - link_to s_('communities|View all'), :profile => owner.identifier, :controller => 'profile', :action => 'communities' | ||
23 | - end | ||
24 | - when Environment | ||
25 | - lambda do |context| | ||
26 | - link_to s_('communities|View all'), :controller => 'search', :action => 'communities' | ||
27 | - end | ||
28 | - else | ||
29 | - '' | 24 | + suggestions = self.suggestions |
25 | + return '' unless owner.kind_of?(Profile) || owner.kind_of?(Environment) | ||
26 | + proc do | ||
27 | + render :file => 'blocks/communities', :locals => { :owner => owner, :suggestions => suggestions } | ||
30 | end | 28 | end |
31 | end | 29 | end |
32 | 30 |
app/models/create_enterprise.rb
@@ -73,7 +73,13 @@ class CreateEnterprise < Task | @@ -73,7 +73,13 @@ class CreateEnterprise < Task | ||
73 | 73 | ||
74 | # sets the associated region for the enterprise creation | 74 | # sets the associated region for the enterprise creation |
75 | def region=(value) | 75 | def region=(value) |
76 | - raise ArgumentError.new("Region expected, but got #{value.class}") unless value.kind_of?(Region) | 76 | + unless value.kind_of?(Region) |
77 | + begin | ||
78 | + value = Region.find(value) | ||
79 | + rescue | ||
80 | + raise ArgumentError.new("Could not find any region with the id #{value}") | ||
81 | + end | ||
82 | + end | ||
77 | 83 | ||
78 | @region = value | 84 | @region = value |
79 | self.region_id = value.id | 85 | self.region_id = value.id |
app/models/enterprise.rb
@@ -4,7 +4,10 @@ class Enterprise < Organization | @@ -4,7 +4,10 @@ class Enterprise < Organization | ||
4 | 4 | ||
5 | attr_accessible :business_name, :address_reference, :district, :tag_list, :organization_website, :historic_and_current_context, :activities_short_description, :products_per_catalog_page | 5 | attr_accessible :business_name, :address_reference, :district, :tag_list, :organization_website, :historic_and_current_context, :activities_short_description, :products_per_catalog_page |
6 | 6 | ||
7 | - SEARCH_DISPLAYS += %w[map full] | 7 | + SEARCH_FILTERS = { |
8 | + :order => %w[more_recent more_popular more_active], | ||
9 | + :display => %w[compact full map] | ||
10 | + } | ||
8 | 11 | ||
9 | def self.type_name | 12 | def self.type_name |
10 | _('Enterprise') | 13 | _('Enterprise') |
app/models/environment.rb
@@ -10,6 +10,7 @@ class Environment < ActiveRecord::Base | @@ -10,6 +10,7 @@ class Environment < ActiveRecord::Base | ||
10 | self.partial_updates = false | 10 | self.partial_updates = false |
11 | 11 | ||
12 | has_many :tasks, :dependent => :destroy, :as => 'target' | 12 | has_many :tasks, :dependent => :destroy, :as => 'target' |
13 | + has_many :search_terms, :as => :context | ||
13 | 14 | ||
14 | IDENTIFY_SCRIPTS = /(php[0-9s]?|[sp]htm[l]?|pl|py|cgi|rb)/ | 15 | IDENTIFY_SCRIPTS = /(php[0-9s]?|[sp]htm[l]?|pl|py|cgi|rb)/ |
15 | 16 | ||
@@ -85,7 +86,9 @@ class Environment < ActiveRecord::Base | @@ -85,7 +86,9 @@ class Environment < ActiveRecord::Base | ||
85 | end | 86 | end |
86 | 87 | ||
87 | def admins | 88 | def admins |
88 | - Person.members_of(self).all(:conditions => ['role_assignments.role_id = ?', Environment::Roles.admin(self).id]) | 89 | + admin_role = Environment::Roles.admin(self) |
90 | + return [] if admin_role.blank? | ||
91 | + Person.members_of(self).all(:conditions => ['role_assignments.role_id = ?', admin_role.id]) | ||
89 | end | 92 | end |
90 | 93 | ||
91 | # returns the available features for a Environment, in the form of a | 94 | # returns the available features for a Environment, in the form of a |
@@ -155,7 +158,8 @@ class Environment < ActiveRecord::Base | @@ -155,7 +158,8 @@ class Environment < ActiveRecord::Base | ||
155 | 'site_homepage' => _('Redirects the user to the environment homepage.'), | 158 | 'site_homepage' => _('Redirects the user to the environment homepage.'), |
156 | 'user_profile_page' => _('Redirects the user to his profile page.'), | 159 | 'user_profile_page' => _('Redirects the user to his profile page.'), |
157 | 'user_homepage' => _('Redirects the user to his homepage.'), | 160 | 'user_homepage' => _('Redirects the user to his homepage.'), |
158 | - 'user_control_panel' => _('Redirects the user to his control panel.') | 161 | + 'user_control_panel' => _('Redirects the user to his control panel.'), |
162 | + 'welcome_page' => _('Redirects the user to the environment welcome page.') | ||
159 | } | 163 | } |
160 | end | 164 | end |
161 | validates_inclusion_of :redirection_after_signup, :in => Environment.signup_redirection_options.keys, :allow_nil => true | 165 | validates_inclusion_of :redirection_after_signup, :in => Environment.signup_redirection_options.keys, :allow_nil => true |
@@ -824,6 +828,10 @@ class Environment < ActiveRecord::Base | @@ -824,6 +828,10 @@ class Environment < ActiveRecord::Base | ||
824 | "home-page-news/#{cache_key}-#{language}" | 828 | "home-page-news/#{cache_key}-#{language}" |
825 | end | 829 | end |
826 | 830 | ||
831 | + def portal_enabled | ||
832 | + portal_community && enabled?('use_portal_community') | ||
833 | + end | ||
834 | + | ||
827 | def notification_emails | 835 | def notification_emails |
828 | [contact_email].select(&:present?) + admins.map(&:email) | 836 | [contact_email].select(&:present?) + admins.map(&:email) |
829 | end | 837 | end |
app/models/invitation.rb
@@ -51,7 +51,10 @@ class Invitation < Task | @@ -51,7 +51,10 @@ class Invitation < Task | ||
51 | next if contact_to_invite == _("Firstname Lastname <friend@email.com>") | 51 | next if contact_to_invite == _("Firstname Lastname <friend@email.com>") |
52 | 52 | ||
53 | contact_to_invite.strip! | 53 | contact_to_invite.strip! |
54 | - if match = contact_to_invite.match(/(.*)<(.*)>/) and match[2].match(Noosfero::Constants::EMAIL_FORMAT) | 54 | + find_by_profile_id = false |
55 | + if contact_to_invite.match(/^\d*$/) | ||
56 | + find_by_profile_id = true | ||
57 | + elsif match = contact_to_invite.match(/(.*)<(.*)>/) and match[2].match(Noosfero::Constants::EMAIL_FORMAT) | ||
55 | friend_name = match[1].strip | 58 | friend_name = match[1].strip |
56 | friend_email = match[2] | 59 | friend_email = match[2] |
57 | elsif match = contact_to_invite.strip.match(Noosfero::Constants::EMAIL_FORMAT) | 60 | elsif match = contact_to_invite.strip.match(Noosfero::Constants::EMAIL_FORMAT) |
@@ -61,11 +64,15 @@ class Invitation < Task | @@ -61,11 +64,15 @@ class Invitation < Task | ||
61 | next | 64 | next |
62 | end | 65 | end |
63 | 66 | ||
64 | - user = User.find_by_email(friend_email) | 67 | + begin |
68 | + user = find_by_profile_id ? Person.find_by_id(contact_to_invite).user : User.find_by_email(friend_email) | ||
69 | + rescue | ||
70 | + user = nil | ||
71 | + end | ||
65 | 72 | ||
66 | - task_args = if user.nil? | 73 | + task_args = if user.nil? && !find_by_profile_id |
67 | {:person => person, :friend_name => friend_name, :friend_email => friend_email, :message => message} | 74 | {:person => person, :friend_name => friend_name, :friend_email => friend_email, :message => message} |
68 | - else | 75 | + elsif user.present? && !(user.person.is_a_friend?(person) && profile.person?) |
69 | {:person => person, :target => user.person} | 76 | {:person => person, :target => user.person} |
70 | end | 77 | end |
71 | 78 |
app/models/invite_friend.rb
1 | class InviteFriend < Invitation | 1 | class InviteFriend < Invitation |
2 | 2 | ||
3 | settings_items :group_for_person, :group_for_friend | 3 | settings_items :group_for_person, :group_for_friend |
4 | + before_create :check_for_invitation_existence | ||
4 | 5 | ||
5 | def perform | 6 | def perform |
6 | person.add_friend(friend, group_for_person) | 7 | person.add_friend(friend, group_for_person) |
@@ -41,4 +42,11 @@ class InviteFriend < Invitation | @@ -41,4 +42,11 @@ class InviteFriend < Invitation | ||
41 | ].join("\n\n") | 42 | ].join("\n\n") |
42 | end | 43 | end |
43 | 44 | ||
45 | + private | ||
46 | + def check_for_invitation_existence | ||
47 | + if friend | ||
48 | + friend.tasks.pending.of("InviteFriend").find(:all, :conditions => {:requestor_id => person.id, :target_id => friend.id}).blank? | ||
49 | + end | ||
50 | + end | ||
51 | + | ||
44 | end | 52 | end |
app/models/invite_member.rb
@@ -2,6 +2,7 @@ class InviteMember < Invitation | @@ -2,6 +2,7 @@ class InviteMember < Invitation | ||
2 | 2 | ||
3 | settings_items :community_id, :type => :integer | 3 | settings_items :community_id, :type => :integer |
4 | validates_presence_of :community_id | 4 | validates_presence_of :community_id |
5 | + before_create :check_for_invitation_existence | ||
5 | 6 | ||
6 | def community | 7 | def community |
7 | Community.find(community_id) | 8 | Community.find(community_id) |
@@ -39,6 +40,14 @@ class InviteMember < Invitation | @@ -39,6 +40,14 @@ class InviteMember < Invitation | ||
39 | _('%{requestor} invited you to join %{community}.') % {:requestor => requestor.name, :community => community.name} | 40 | _('%{requestor} invited you to join %{community}.') % {:requestor => requestor.name, :community => community.name} |
40 | end | 41 | end |
41 | 42 | ||
43 | + def target_notification_message | ||
44 | + if friend | ||
45 | + _('%{requestor} is inviting you to join "%{community}" on %{system}.') % { :system => target.environment.name, :requestor => requestor.name, :community => community.name } | ||
46 | + else | ||
47 | + super | ||
48 | + end | ||
49 | + end | ||
50 | + | ||
42 | def expanded_message | 51 | def expanded_message |
43 | super.gsub /<community>/, community.name | 52 | super.gsub /<community>/, community.name |
44 | end | 53 | end |
@@ -53,4 +62,11 @@ class InviteMember < Invitation | @@ -53,4 +62,11 @@ class InviteMember < Invitation | ||
53 | ].join("\n\n") | 62 | ].join("\n\n") |
54 | end | 63 | end |
55 | 64 | ||
65 | + private | ||
66 | + def check_for_invitation_existence | ||
67 | + if friend | ||
68 | + friend.tasks.pending.of("InviteMember").find(:all, :conditions => {:requestor_id => person.id}).select { |t| t.data[:community_id] == community_id }.blank? | ||
69 | + end | ||
70 | + end | ||
71 | + | ||
56 | end | 72 | end |
app/models/license.rb
@@ -3,8 +3,8 @@ class License < ActiveRecord::Base | @@ -3,8 +3,8 @@ class License < ActiveRecord::Base | ||
3 | attr_accessible :name, :url | 3 | attr_accessible :name, :url |
4 | 4 | ||
5 | SEARCHABLE_FIELDS = { | 5 | SEARCHABLE_FIELDS = { |
6 | - :name => 10, | ||
7 | - :url => 5, | 6 | + :name => {:label => _('Name'), :weight => 10}, |
7 | + :url => {:label => _('URL'), :weight => 5}, | ||
8 | } | 8 | } |
9 | 9 | ||
10 | belongs_to :environment | 10 | belongs_to :environment |
app/models/national_region.rb
1 | class NationalRegion < ActiveRecord::Base | 1 | class NationalRegion < ActiveRecord::Base |
2 | 2 | ||
3 | SEARCHABLE_FIELDS = { | 3 | SEARCHABLE_FIELDS = { |
4 | - :name => 1, | ||
5 | - :national_region_code => 1, | 4 | + :name => {:label => _('Name'), :weight => 1}, |
5 | + :national_region_code => {:label => _('Region Code'), :weight => 1}, | ||
6 | } | 6 | } |
7 | 7 | ||
8 | def self.search_city(city_name, like = false, state = nil) | 8 | def self.search_city(city_name, like = false, state = nil) |
app/models/organization.rb
@@ -3,10 +3,11 @@ class Organization < Profile | @@ -3,10 +3,11 @@ class Organization < Profile | ||
3 | 3 | ||
4 | attr_accessible :moderated_articles, :foundation_year, :contact_person, :acronym, :legal_form, :economic_activity, :management_information, :cnpj, :display_name, :enable_contact_us | 4 | attr_accessible :moderated_articles, :foundation_year, :contact_person, :acronym, :legal_form, :economic_activity, :management_information, :cnpj, :display_name, :enable_contact_us |
5 | 5 | ||
6 | - SEARCH_FILTERS += %w[ | ||
7 | - more_popular | ||
8 | - more_active | ||
9 | - ] | 6 | + SEARCH_FILTERS = { |
7 | + :order => %w[more_recent more_popular more_active], | ||
8 | + :display => %w[compact] | ||
9 | + } | ||
10 | + | ||
10 | 11 | ||
11 | settings_items :closed, :type => :boolean, :default => false | 12 | settings_items :closed, :type => :boolean, :default => false |
12 | def closed? | 13 | def closed? |
@@ -176,4 +177,8 @@ class Organization < Profile | @@ -176,4 +177,8 @@ class Organization < Profile | ||
176 | self.visible = false | 177 | self.visible = false |
177 | save! | 178 | save! |
178 | end | 179 | end |
180 | + | ||
181 | + def allow_invitation_from?(person) | ||
182 | + (followed_by?(person) && self.allow_members_to_invite) || person.has_permission?('invite-members', self) | ||
183 | + end | ||
179 | end | 184 | end |
app/models/person.rb
@@ -3,10 +3,11 @@ class Person < Profile | @@ -3,10 +3,11 @@ class Person < Profile | ||
3 | 3 | ||
4 | attr_accessible :organization, :contact_information, :sex, :birth_date, :cell_phone, :comercial_phone, :jabber_id, :personal_website, :nationality, :address_reference, :district, :schooling, :schooling_status, :formation, :custom_formation, :area_of_study, :custom_area_of_study, :professional_activity, :organization_website | 4 | attr_accessible :organization, :contact_information, :sex, :birth_date, :cell_phone, :comercial_phone, :jabber_id, :personal_website, :nationality, :address_reference, :district, :schooling, :schooling_status, :formation, :custom_formation, :area_of_study, :custom_area_of_study, :professional_activity, :organization_website |
5 | 5 | ||
6 | - SEARCH_FILTERS += %w[ | ||
7 | - more_popular | ||
8 | - more_active | ||
9 | - ] | 6 | + SEARCH_FILTERS = { |
7 | + :order => %w[more_recent more_popular more_active], | ||
8 | + :display => %w[compact] | ||
9 | + } | ||
10 | + | ||
10 | 11 | ||
11 | def self.type_name | 12 | def self.type_name |
12 | _('Person') | 13 | _('Person') |
@@ -21,16 +22,34 @@ class Person < Profile | @@ -21,16 +22,34 @@ class Person < Profile | ||
21 | { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => [conditions] } | 22 | { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => [conditions] } |
22 | } | 23 | } |
23 | 24 | ||
25 | + scope :not_members_of, lambda { |resources| | ||
26 | + resources = [resources] if !resources.kind_of?(Array) | ||
27 | + conditions = resources.map {|resource| "role_assignments.resource_type = '#{resource.class.base_class.name}' AND role_assignments.resource_id = #{resource.id || -1}"}.join(' OR ') | ||
28 | + { :select => 'DISTINCT profiles.*', :conditions => ['"profiles"."id" NOT IN (SELECT DISTINCT profiles.id FROM "profiles" INNER JOIN "role_assignments" ON "role_assignments"."accessor_id" = "profiles"."id" AND "role_assignments"."accessor_type" = (\'Profile\') WHERE "profiles"."type" IN (\'Person\') AND (%s))' % conditions] | ||
29 | + } | ||
30 | + | ||
24 | scope :by_role, lambda { |roles| | 31 | scope :by_role, lambda { |roles| |
25 | roles = [roles] unless roles.kind_of?(Array) | 32 | roles = [roles] unless roles.kind_of?(Array) |
26 | { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => ['role_assignments.role_id IN (?)', | 33 | { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => ['role_assignments.role_id IN (?)', |
27 | roles] } | 34 | roles] } |
28 | } | 35 | } |
29 | 36 | ||
30 | - def has_permission_with_plugins?(permission, profile) | ||
31 | - permissions = [has_permission_without_plugins?(permission, profile)] | 37 | + scope :not_friends_of, lambda { |resources| |
38 | + resources = Array(resources) | ||
39 | + { :select => 'DISTINCT profiles.*', :conditions => ['"profiles"."id" NOT IN (SELECT DISTINCT profiles.id FROM "profiles" INNER JOIN "friendships" ON "friendships"."person_id" = "profiles"."id" WHERE "friendships"."friend_id" IN (%s))' % resources.map(&:id)] } | ||
40 | + } | ||
41 | + | ||
42 | + def has_permission_with_admin?(permission, resource) | ||
43 | + return true if resource.blank? || resource.admins.include?(self) | ||
44 | + return true if resource.kind_of?(Profile) && resource.environment.admins.include?(self) | ||
45 | + has_permission_without_admin?(permission, resource) | ||
46 | + end | ||
47 | + alias_method_chain :has_permission?, :admin | ||
48 | + | ||
49 | + def has_permission_with_plugins?(permission, resource) | ||
50 | + permissions = [has_permission_without_plugins?(permission, resource)] | ||
32 | permissions += plugins.map do |plugin| | 51 | permissions += plugins.map do |plugin| |
33 | - plugin.has_permission?(self, permission, profile) | 52 | + plugin.has_permission?(self, permission, resource) |
34 | end | 53 | end |
35 | permissions.include?(true) | 54 | permissions.include?(true) |
36 | end | 55 | end |
@@ -65,6 +84,10 @@ roles] } | @@ -65,6 +84,10 @@ roles] } | ||
65 | has_and_belongs_to_many :acepted_forums, :class_name => 'Forum', :join_table => 'terms_forum_people' | 84 | has_and_belongs_to_many :acepted_forums, :class_name => 'Forum', :join_table => 'terms_forum_people' |
66 | has_and_belongs_to_many :articles_with_access, :class_name => 'Article', :join_table => 'article_privacy_exceptions' | 85 | has_and_belongs_to_many :articles_with_access, :class_name => 'Article', :join_table => 'article_privacy_exceptions' |
67 | 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] | ||
90 | + | ||
68 | scope :more_popular, :order => 'friends_count DESC' | 91 | scope :more_popular, :order => 'friends_count DESC' |
69 | 92 | ||
70 | scope :abusers, :joins => :abuse_complaints, :conditions => ['tasks.status = 3'], :select => 'DISTINCT profiles.*' | 93 | scope :abusers, :joins => :abuse_complaints, :conditions => ['tasks.status = 3'], :select => 'DISTINCT profiles.*' |
@@ -497,6 +520,15 @@ roles] } | @@ -497,6 +520,15 @@ roles] } | ||
497 | person.notifier.reschedule_next_notification_mail | 520 | person.notifier.reschedule_next_notification_mail |
498 | end | 521 | end |
499 | 522 | ||
523 | + def remove_suggestion(profile) | ||
524 | + suggestion = profile_suggestions.find_by_suggestion_id profile.id | ||
525 | + suggestion.disable if suggestion | ||
526 | + end | ||
527 | + | ||
528 | + def allow_invitation_from?(person) | ||
529 | + person.has_permission?(:manage_friends, self) | ||
530 | + end | ||
531 | + | ||
500 | protected | 532 | protected |
501 | 533 | ||
502 | def followed_by?(profile) | 534 | def followed_by?(profile) |
app/models/product.rb
1 | class Product < ActiveRecord::Base | 1 | class Product < ActiveRecord::Base |
2 | 2 | ||
3 | SEARCHABLE_FIELDS = { | 3 | SEARCHABLE_FIELDS = { |
4 | - :name => 10, | ||
5 | - :description => 1, | 4 | + :name => {:label => _('Name'), :weight => 10}, |
5 | + :description => {:label => _('Description'), :weight => 1}, | ||
6 | } | 6 | } |
7 | 7 | ||
8 | - SEARCH_FILTERS = %w[ | ||
9 | - more_recent | ||
10 | - ] | ||
11 | - | ||
12 | - SEARCH_DISPLAYS = %w[map full] | 8 | + SEARCH_FILTERS = { |
9 | + :order => %w[more_recent], | ||
10 | + :display => %w[full map] | ||
11 | + } | ||
13 | 12 | ||
14 | attr_accessible :name, :product_category, :highlighted, :price, :enterprise, :image_builder, :description, :available, :qualifiers, :unit_id, :discount, :inputs, :qualifiers_list | 13 | attr_accessible :name, :product_category, :highlighted, :price, :enterprise, :image_builder, :description, :available, :qualifiers, :unit_id, :discount, :inputs, :qualifiers_list |
15 | 14 |
app/models/profile.rb
@@ -3,7 +3,7 @@ | @@ -3,7 +3,7 @@ | ||
3 | # which by default is the one returned by Environment:default. | 3 | # which by default is the one returned by Environment:default. |
4 | class Profile < ActiveRecord::Base | 4 | class Profile < ActiveRecord::Base |
5 | 5 | ||
6 | - attr_accessible :name, :identifier, :public_profile, :nickname, :custom_footer, :custom_header, :address, :zip_code, :contact_phone, :image_builder, :description, :closed, :template_id, :environment, :lat, :lng, :is_template, :fields_privacy, :preferred_domain_id, :category_ids, :country, :city, :state, :national_region_code, :email, :contact_email, :redirect_l10n, :notification_time, :redirection_after_login | 6 | + attr_accessible :name, :identifier, :public_profile, :nickname, :custom_footer, :custom_header, :address, :zip_code, :contact_phone, :image_builder, :description, :closed, :template_id, :environment, :lat, :lng, :is_template, :fields_privacy, :preferred_domain_id, :category_ids, :country, :city, :state, :national_region_code, :email, :contact_email, :redirect_l10n, :notification_time, :redirection_after_login, :email_suggestions, :allow_members_to_invite, :invite_friends_only |
7 | 7 | ||
8 | # use for internationalizable human type names in search facets | 8 | # use for internationalizable human type names in search facets |
9 | # reimplement on subclasses | 9 | # reimplement on subclasses |
@@ -12,16 +12,15 @@ class Profile < ActiveRecord::Base | @@ -12,16 +12,15 @@ class Profile < ActiveRecord::Base | ||
12 | end | 12 | end |
13 | 13 | ||
14 | SEARCHABLE_FIELDS = { | 14 | SEARCHABLE_FIELDS = { |
15 | - :name => 10, | ||
16 | - :identifier => 5, | ||
17 | - :nickname => 2, | 15 | + :name => {:label => _('Name'), :weight => 10}, |
16 | + :identifier => {:label => _('Username'), :weight => 5}, | ||
17 | + :nickname => {:label => _('Nickname'), :weight => 2}, | ||
18 | } | 18 | } |
19 | 19 | ||
20 | - SEARCH_FILTERS = %w[ | ||
21 | - more_recent | ||
22 | - ] | ||
23 | - | ||
24 | - SEARCH_DISPLAYS = %w[compact] | 20 | + SEARCH_FILTERS = { |
21 | + :order => %w[more_recent], | ||
22 | + :display => %w[compact] | ||
23 | + } | ||
25 | 24 | ||
26 | def self.default_search_display | 25 | def self.default_search_display |
27 | 'compact' | 26 | 'compact' |
@@ -140,6 +139,17 @@ class Profile < ActiveRecord::Base | @@ -140,6 +139,17 @@ class Profile < ActiveRecord::Base | ||
140 | 139 | ||
141 | has_many :comments_received, :class_name => 'Comment', :through => :articles, :source => :comments | 140 | has_many :comments_received, :class_name => 'Comment', :through => :articles, :source => :comments |
142 | 141 | ||
142 | + # Although this should be a has_one relation, there are no non-silly names for | ||
143 | + # a foreign key on article to reference the template to which it is | ||
144 | + # welcome_page... =P | ||
145 | + belongs_to :welcome_page, :class_name => 'Article', :dependent => :destroy | ||
146 | + | ||
147 | + def welcome_page_content | ||
148 | + welcome_page && welcome_page.published ? welcome_page.body : nil | ||
149 | + end | ||
150 | + | ||
151 | + has_many :search_terms, :as => :context | ||
152 | + | ||
143 | def scraps(scrap=nil) | 153 | def scraps(scrap=nil) |
144 | scrap = scrap.is_a?(Scrap) ? scrap.id : scrap | 154 | scrap = scrap.is_a?(Scrap) ? scrap.id : scrap |
145 | scrap.nil? ? Scrap.all_scraps(self) : Scrap.all_scraps(self).find(scrap) | 155 | scrap.nil? ? Scrap.all_scraps(self) : Scrap.all_scraps(self).find(scrap) |
@@ -155,6 +165,7 @@ class Profile < ActiveRecord::Base | @@ -155,6 +165,7 @@ class Profile < ActiveRecord::Base | ||
155 | settings_items :public_content, :type => :boolean, :default => true | 165 | settings_items :public_content, :type => :boolean, :default => true |
156 | settings_items :description | 166 | settings_items :description |
157 | settings_items :fields_privacy, :type => :hash, :default => {} | 167 | settings_items :fields_privacy, :type => :hash, :default => {} |
168 | + settings_items :email_suggestions, :type => :boolean, :default => false | ||
158 | 169 | ||
159 | validates_length_of :description, :maximum => 550, :allow_nil => true | 170 | validates_length_of :description, :maximum => 550, :allow_nil => true |
160 | 171 | ||
@@ -219,6 +230,8 @@ class Profile < ActiveRecord::Base | @@ -219,6 +230,8 @@ class Profile < ActiveRecord::Base | ||
219 | 230 | ||
220 | has_many :abuse_complaints, :foreign_key => 'requestor_id', :dependent => :destroy | 231 | has_many :abuse_complaints, :foreign_key => 'requestor_id', :dependent => :destroy |
221 | 232 | ||
233 | + has_many :profile_suggestions, :foreign_key => :suggestion_id, :dependent => :destroy | ||
234 | + | ||
222 | def top_level_categorization | 235 | def top_level_categorization |
223 | ret = {} | 236 | ret = {} |
224 | self.profile_categorizations.each do |c| | 237 | self.profile_categorizations.each do |c| |
@@ -514,6 +527,14 @@ class Profile < ActiveRecord::Base | @@ -514,6 +527,14 @@ class Profile < ActiveRecord::Base | ||
514 | generate_url(:profile => identifier, :controller => 'profile', :action => 'index') | 527 | generate_url(:profile => identifier, :controller => 'profile', :action => 'index') |
515 | end | 528 | end |
516 | 529 | ||
530 | + def people_suggestions_url | ||
531 | + generate_url(:profile => identifier, :controller => 'friends', :action => 'suggest') | ||
532 | + end | ||
533 | + | ||
534 | + def communities_suggestions_url | ||
535 | + generate_url(:profile => identifier, :controller => 'memberships', :action => 'suggest') | ||
536 | + end | ||
537 | + | ||
517 | def generate_url(options) | 538 | def generate_url(options) |
518 | url_options.merge(options) | 539 | url_options.merge(options) |
519 | end | 540 | end |
@@ -603,7 +624,7 @@ private :generate_url, :url_options | @@ -603,7 +624,7 @@ private :generate_url, :url_options | ||
603 | end | 624 | end |
604 | 625 | ||
605 | def copy_article_tree(article, parent=nil) | 626 | def copy_article_tree(article, parent=nil) |
606 | - return if article.is_a?(RssFeed) | 627 | + return if !copy_article?(article) |
607 | original_article = self.articles.find_by_name(article.name) | 628 | original_article = self.articles.find_by_name(article.name) |
608 | if original_article | 629 | if original_article |
609 | num = 2 | 630 | num = 2 |
@@ -623,6 +644,11 @@ private :generate_url, :url_options | @@ -623,6 +644,11 @@ private :generate_url, :url_options | ||
623 | end | 644 | end |
624 | end | 645 | end |
625 | 646 | ||
647 | + def copy_article?(article) | ||
648 | + !article.is_a?(RssFeed) && | ||
649 | + !(is_template && article.slug=='welcome-page') | ||
650 | + end | ||
651 | + | ||
626 | # Adds a person as member of this Profile. | 652 | # Adds a person as member of this Profile. |
627 | def add_member(person) | 653 | def add_member(person) |
628 | if self.has_members? | 654 | if self.has_members? |
@@ -632,6 +658,8 @@ private :generate_url, :url_options | @@ -632,6 +658,8 @@ private :generate_url, :url_options | ||
632 | self.affiliate(person, Profile::Roles.admin(environment.id)) if members.count == 0 | 658 | self.affiliate(person, Profile::Roles.admin(environment.id)) if members.count == 0 |
633 | self.affiliate(person, Profile::Roles.member(environment.id)) | 659 | self.affiliate(person, Profile::Roles.member(environment.id)) |
634 | end | 660 | end |
661 | + person.tasks.pending.of("InviteMember").select { |t| t.data[:community_id] == self.id }.each { |invite| invite.cancel } | ||
662 | + remove_from_suggestion_list person | ||
635 | else | 663 | else |
636 | raise _("%s can't have members") % self.class.name | 664 | raise _("%s can't have members") % self.class.name |
637 | end | 665 | end |
@@ -769,7 +797,10 @@ private :generate_url, :url_options | @@ -769,7 +797,10 @@ private :generate_url, :url_options | ||
769 | end | 797 | end |
770 | 798 | ||
771 | def admins | 799 | def admins |
772 | - self.members_by_role(Profile::Roles.admin(environment.id)) | 800 | + return [] if environment.blank? |
801 | + admin_role = Profile::Roles.admin(environment.id) | ||
802 | + return [] if admin_role.blank? | ||
803 | + self.members_by_role(admin_role) | ||
773 | end | 804 | end |
774 | 805 | ||
775 | def enable_contact? | 806 | def enable_contact? |
@@ -967,4 +998,14 @@ private :generate_url, :url_options | @@ -967,4 +998,14 @@ private :generate_url, :url_options | ||
967 | def preferred_login_redirection | 998 | def preferred_login_redirection |
968 | redirection_after_login.blank? ? environment.redirection_after_login : redirection_after_login | 999 | redirection_after_login.blank? ? environment.redirection_after_login : redirection_after_login |
969 | end | 1000 | end |
1001 | + | ||
1002 | + def remove_from_suggestion_list(person) | ||
1003 | + suggestion = person.profile_suggestions.find_by_suggestion_id self.id | ||
1004 | + suggestion.disable if suggestion | ||
1005 | + end | ||
1006 | + | ||
1007 | + def allow_invitation_from(person) | ||
1008 | + false | ||
1009 | + end | ||
1010 | + | ||
970 | end | 1011 | end |
@@ -0,0 +1,290 @@ | @@ -0,0 +1,290 @@ | ||
1 | +class ProfileSuggestion < ActiveRecord::Base | ||
2 | + belongs_to :person | ||
3 | + belongs_to :suggestion, :class_name => 'Profile', :foreign_key => :suggestion_id | ||
4 | + | ||
5 | + attr_accessible :person, :suggestion, :suggestion_type, :categories, :enabled | ||
6 | + | ||
7 | + has_many :suggestion_connections, :foreign_key => 'suggestion_id' | ||
8 | + has_many :profile_connections, :through => :suggestion_connections, :source => :connection, :source_type => 'Profile' | ||
9 | + has_many :tag_connections, :through => :suggestion_connections, :source => :connection, :source_type => 'ActsAsTaggableOn::Tag' | ||
10 | + | ||
11 | + before_create do |profile_suggestion| | ||
12 | + profile_suggestion.suggestion_type = self.suggestion.class.to_s | ||
13 | + end | ||
14 | + | ||
15 | + after_destroy do |profile_suggestion| | ||
16 | + self.class.generate_profile_suggestions(profile_suggestion.person) | ||
17 | + end | ||
18 | + | ||
19 | + acts_as_having_settings :field => :categories | ||
20 | + | ||
21 | + validate :must_be_a_valid_category, :on => :create | ||
22 | + def must_be_a_valid_category | ||
23 | + if categories.keys.map { |cat| self.respond_to?(cat)}.include?(false) | ||
24 | + errors.add(:categories, 'Category must be valid') | ||
25 | + end | ||
26 | + end | ||
27 | + | ||
28 | + validates_uniqueness_of :suggestion_id, :scope => [ :person_id ] | ||
29 | + scope :of_person, :conditions => { :suggestion_type => 'Person' } | ||
30 | + scope :of_community, :conditions => { :suggestion_type => 'Community' } | ||
31 | + scope :enabled, :conditions => { :enabled => true } | ||
32 | + | ||
33 | + # {:category_type => ['category-icon', 'category-label']} | ||
34 | + CATEGORIES = { | ||
35 | + :people_with_common_friends => ['menu-people', _('Friends in common')], | ||
36 | + :people_with_common_communities => ['menu-community',_('Communities in common')], | ||
37 | + :people_with_common_tags => ['edit', _('Tags in common')], | ||
38 | + :communities_with_common_friends => ['menu-people', _('Friends in common')], | ||
39 | + :communities_with_common_tags => ['edit', _('Tags in common')] | ||
40 | + } | ||
41 | + | ||
42 | + def category_icon(category) | ||
43 | + 'icon-' + ProfileSuggestion::CATEGORIES[category][0] | ||
44 | + end | ||
45 | + | ||
46 | + def category_label(category) | ||
47 | + ProfileSuggestion::CATEGORIES[category][1] | ||
48 | + end | ||
49 | + | ||
50 | + RULES = { | ||
51 | + :people_with_common_communities => { | ||
52 | + :threshold => 2, :weight => 1, :connection => 'Profile' | ||
53 | + }, | ||
54 | + :people_with_common_friends => { | ||
55 | + :threshold => 2, :weight => 1, :connection => 'Profile' | ||
56 | + }, | ||
57 | + :people_with_common_tags => { | ||
58 | + :threshold => 2, :weight => 1, :connection => 'ActsAsTaggableOn::Tag' | ||
59 | + }, | ||
60 | + :communities_with_common_friends => { | ||
61 | + :threshold => 2, :weight => 1, :connection => 'Profile' | ||
62 | + }, | ||
63 | + :communities_with_common_tags => { | ||
64 | + :threshold => 2, :weight => 1, :connection => 'ActsAsTaggableOn::Tag' | ||
65 | + } | ||
66 | + } | ||
67 | + | ||
68 | + RULES.keys.each do |rule| | ||
69 | + settings_items rule | ||
70 | + attr_accessible rule | ||
71 | + end | ||
72 | + | ||
73 | + # Number of suggestions by rule | ||
74 | + N_SUGGESTIONS = 30 | ||
75 | + | ||
76 | + # Minimum number of suggestions | ||
77 | + MIN_LIMIT = 10 | ||
78 | + | ||
79 | + def self.profile_id(rule) | ||
80 | + "#{rule}_profile_id" | ||
81 | + end | ||
82 | + | ||
83 | + def self.connections(rule) | ||
84 | + "#{rule}_connections" | ||
85 | + end | ||
86 | + | ||
87 | + def self.counter(rule) | ||
88 | + "#{rule}_count" | ||
89 | + end | ||
90 | + | ||
91 | + # If you are about to rewrite the following sql queries, think twice. After | ||
92 | + # that make sure that whatever you are writing to replace it should be faster | ||
93 | + # than how it is now. Yes, sqls are ugly but are fast! And fast is what we | ||
94 | + # need here. | ||
95 | + # | ||
96 | + # The logic behind this code is to produce a table somewhat like this: | ||
97 | + # profile_id | rule1_count | rule1_connections | rule2_count | rule2_connections | ... | score | | ||
98 | + # 12 | 2 | {32,54} | 3 | {8,22,27} | ... | 13 | | ||
99 | + # 13 | 4 | {3,12,32,54} | 2 | {11,24} | ... | 15 | | ||
100 | + # 14 | | | 2 | {44,56} | ... | 17 | | ||
101 | + # ... | ||
102 | + # ... | ||
103 | + # | ||
104 | + # This table has the suggested profile id and the count and connections of | ||
105 | + # each rule that made this profile be suggested. Each suggestion has a score | ||
106 | + # associated based on the rules' counts and rules' weights. | ||
107 | + # | ||
108 | + # From this table, we can sort suggestions by the score and save a small | ||
109 | + # amount of them in the database. At this moment we also register the | ||
110 | + # connections of each suggestion. | ||
111 | + | ||
112 | + def self.calculate_suggestions(person) | ||
113 | + suggested_profiles = all_suggestions(person) | ||
114 | + return if suggested_profiles.nil? | ||
115 | + | ||
116 | + already_suggested_profiles = person.profile_suggestions.map(&:suggestion_id).join(',') | ||
117 | + suggested_profiles = suggested_profiles.where("profiles.id NOT IN (#{already_suggested_profiles})") if already_suggested_profiles.present? | ||
118 | + #TODO suggested_profiles = suggested_profiles.order('score DESC') | ||
119 | + suggested_profiles = suggested_profiles.limit(N_SUGGESTIONS) | ||
120 | + return if suggested_profiles.blank? | ||
121 | + | ||
122 | + suggested_profiles.each do |suggested_profile| | ||
123 | + suggestion = person.profile_suggestions.find_or_initialize_by_suggestion_id(suggested_profile.id) | ||
124 | + RULES.each do |rule, options| | ||
125 | + begin | ||
126 | + value = suggested_profile.send("#{rule}_count").to_i | ||
127 | + rescue NoMethodError | ||
128 | + next | ||
129 | + end | ||
130 | + connections = suggested_profile.send("#{rule}_connections") | ||
131 | + if connections.present? | ||
132 | + connections = connections[1..-2].split(',') | ||
133 | + else | ||
134 | + connections = [] | ||
135 | + end | ||
136 | + suggestion.send("#{rule}=", value) | ||
137 | + connections.each do |connection_id| | ||
138 | + next if SuggestionConnection.where(:suggestion_id => suggestion.id, :connection_id => connection_id, :connection_type => options[:connection]).present? | ||
139 | + SuggestionConnection.create!(:suggestion => suggestion, :connection_id => connection_id, :connection_type => options[:connection]) | ||
140 | + end | ||
141 | + suggestion.score += value * options[:weight] | ||
142 | + end | ||
143 | + suggestion.save! | ||
144 | + end | ||
145 | + end | ||
146 | + | ||
147 | + def self.people_with_common_friends(person) | ||
148 | + person_friends = person.friends.map(&:id) | ||
149 | + rule = "people_with_common_friends" | ||
150 | + return if person_friends.blank? | ||
151 | + "SELECT person_id as #{profile_id(rule)}, | ||
152 | + array_agg(friend_id) as #{connections(rule)}, | ||
153 | + count(person_id) as #{counter(rule)} | ||
154 | + FROM friendships WHERE friend_id IN (#{person_friends.join(',')}) | ||
155 | + AND person_id NOT IN (#{(person_friends << person.id).join(',')}) | ||
156 | + GROUP BY person_id" | ||
157 | + end | ||
158 | + | ||
159 | + def self.people_with_common_communities(person) | ||
160 | + person_communities = person.communities.map(&:id) | ||
161 | + rule = "people_with_common_communities" | ||
162 | + return if person_communities.blank? | ||
163 | + "SELECT common_members.accessor_id as #{profile_id(rule)}, | ||
164 | + array_agg(common_members.resource_id) as #{connections(rule)}, | ||
165 | + count(common_members.accessor_id) as #{counter(rule)} | ||
166 | + FROM | ||
167 | + (SELECT DISTINCT accessor_id, resource_id FROM | ||
168 | + role_assignments WHERE role_assignments.resource_id IN (#{person_communities.join(',')}) AND | ||
169 | + role_assignments.accessor_id != #{person.id} AND role_assignments.resource_type = 'Profile' AND | ||
170 | + role_assignments.accessor_type = 'Profile') AS common_members | ||
171 | + GROUP BY common_members.accessor_id" | ||
172 | + end | ||
173 | + | ||
174 | + def self.people_with_common_tags(person) | ||
175 | + profile_tags = person.articles.select('tags.id').joins(:tags).map(&:id) | ||
176 | + rule = "people_with_common_tags" | ||
177 | + return if profile_tags.blank? | ||
178 | + "SELECT results.profiles_id as #{profile_id(rule)}, | ||
179 | + array_agg(results.tags_id) as #{connections(rule)}, | ||
180 | + count(results.profiles_id) as #{counter(rule)} | ||
181 | + FROM ( | ||
182 | + SELECT DISTINCT tags.id as tags_id, profiles.id as profiles_id FROM profiles | ||
183 | + INNER JOIN articles ON articles.profile_id = profiles.id | ||
184 | + INNER JOIN taggings ON taggings.taggable_id = articles.id AND taggings.context = ('tags') AND taggings.taggable_type = 'Article' | ||
185 | + INNER JOIN tags ON tags.id = taggings.tag_id | ||
186 | + WHERE (tags.id in (#{profile_tags.join(',')}) AND profiles.id != #{person.id})) AS results | ||
187 | + GROUP BY results.profiles_id" | ||
188 | + end | ||
189 | + | ||
190 | + def self.communities_with_common_friends(person) | ||
191 | + person_friends = person.friends.map(&:id) | ||
192 | + rule = "communities_with_common_friends" | ||
193 | + return if person_friends.blank? | ||
194 | + "SELECT common_communities.resource_id as #{profile_id(rule)}, | ||
195 | + array_agg(common_communities.accessor_id) as #{connections(rule)}, | ||
196 | + count(common_communities.resource_id) as #{counter(rule)} | ||
197 | + FROM | ||
198 | + (SELECT DISTINCT accessor_id, resource_id FROM | ||
199 | + role_assignments WHERE role_assignments.accessor_id IN (#{person_friends.join(',')}) AND | ||
200 | + role_assignments.accessor_id != #{person.id} AND role_assignments.resource_type = 'Profile' AND | ||
201 | + role_assignments.accessor_type = 'Profile') AS common_communities | ||
202 | + GROUP BY common_communities.resource_id" | ||
203 | + end | ||
204 | + | ||
205 | + def self.communities_with_common_tags(person) | ||
206 | + profile_tags = person.articles.select('tags.id').joins(:tags).map(&:id) | ||
207 | + rule = "communities_with_common_tags" | ||
208 | + return if profile_tags.blank? | ||
209 | + "SELECT results.profiles_id as #{profile_id(rule)}, | ||
210 | + array_agg(results.tags_id) as #{connections(rule)}, | ||
211 | + count(results.profiles_id) as #{counter(rule)} | ||
212 | + FROM | ||
213 | + (SELECT DISTINCT tags.id as tags_id, profiles.id AS profiles_id FROM profiles | ||
214 | + INNER JOIN articles ON articles.profile_id = profiles.id | ||
215 | + INNER JOIN taggings ON taggings.taggable_id = articles.id AND taggings.context = ('tags') AND taggings.taggable_type = 'Article' | ||
216 | + INNER JOIN tags ON tags.id = taggings.tag_id | ||
217 | + WHERE (tags.id IN (#{profile_tags.join(',')}) AND profiles.id != #{person.id})) AS results | ||
218 | + GROUP BY results.profiles_id" | ||
219 | + end | ||
220 | + | ||
221 | + def self.all_suggestions(person) | ||
222 | + select_string = ["profiles.*"] | ||
223 | + suggestions_join = [] | ||
224 | + where_string = [] | ||
225 | + valid_rules = [] | ||
226 | + previous_rule = nil | ||
227 | + join_column = nil | ||
228 | + RULES.each do |rule, options| | ||
229 | + rule_select = self.send(rule, person) | ||
230 | + next if !rule_select.present? | ||
231 | + | ||
232 | + valid_rules << rule | ||
233 | + select_string << "suggestions.#{counter(rule)} as #{counter(rule)}, suggestions.#{connections(rule)} as #{connections(rule)}" | ||
234 | + where_string << "#{counter(rule)} >= #{options[:threshold]}" | ||
235 | + rule_select = " | ||
236 | + (SELECT profiles.id as #{profile_id(rule)}, | ||
237 | + #{rule}_sub.#{counter(rule)} as #{counter(rule)}, | ||
238 | + #{rule}_sub.#{connections(rule)} as #{connections(rule)} | ||
239 | + FROM profiles | ||
240 | + LEFT OUTER JOIN (#{rule_select}) as #{rule}_sub | ||
241 | + ON profiles.id = #{rule}_sub.#{profile_id(rule)}) AS #{rule}" | ||
242 | + | ||
243 | + if previous_rule.nil? | ||
244 | + result = rule_select | ||
245 | + else | ||
246 | + result = "INNER JOIN #{rule_select} | ||
247 | + ON #{previous_rule}.#{profile_id(previous_rule)} = #{rule}.#{profile_id(rule)}" | ||
248 | + end | ||
249 | + previous_rule = rule | ||
250 | + suggestions_join << result | ||
251 | + end | ||
252 | + | ||
253 | + return if valid_rules.blank? | ||
254 | + | ||
255 | + select_string = select_string.compact.join(',') | ||
256 | + join_string = "INNER JOIN (SELECT * FROM #{suggestions_join.compact.join(' ')}) AS suggestions ON profiles.id = suggestions.#{profile_id(valid_rules.first)}" | ||
257 | + where_string = where_string.compact.join(' OR ') | ||
258 | + | ||
259 | + person.environment.profiles. | ||
260 | + select(select_string). | ||
261 | + joins(join_string). | ||
262 | + where(where_string) | ||
263 | + end | ||
264 | + | ||
265 | + def disable | ||
266 | + self.enabled = false | ||
267 | + self.save! | ||
268 | + self.class.generate_profile_suggestions(self.person) | ||
269 | + end | ||
270 | + | ||
271 | + def self.generate_all_profile_suggestions | ||
272 | + Delayed::Job.enqueue(ProfileSuggestion::GenerateAllJob.new) unless ProfileSuggestion::GenerateAllJob.exists? | ||
273 | + end | ||
274 | + | ||
275 | + def self.generate_profile_suggestions(person, force = false) | ||
276 | + return if person.profile_suggestions.enabled.count >= MIN_LIMIT && !force | ||
277 | + Delayed::Job.enqueue ProfileSuggestionsJob.new(person.id) unless ProfileSuggestionsJob.exists?(person.id) | ||
278 | + end | ||
279 | + | ||
280 | + class GenerateAllJob | ||
281 | + def self.exists? | ||
282 | + Delayed::Job.by_handler("--- !ruby/object:ProfileSuggestion::GenerateAllJob {}\n").count > 0 | ||
283 | + end | ||
284 | + | ||
285 | + def perform | ||
286 | + Person.find_each {|person| ProfileSuggestion.generate_profile_suggestions(person) } | ||
287 | + end | ||
288 | + end | ||
289 | + | ||
290 | +end |
app/models/qualifier.rb
@@ -3,7 +3,7 @@ class Qualifier < ActiveRecord::Base | @@ -3,7 +3,7 @@ class Qualifier < ActiveRecord::Base | ||
3 | attr_accessible :name, :environment | 3 | attr_accessible :name, :environment |
4 | 4 | ||
5 | SEARCHABLE_FIELDS = { | 5 | SEARCHABLE_FIELDS = { |
6 | - :name => 1, | 6 | + :name => {:label => _('Name'), :weight => 1}, |
7 | } | 7 | } |
8 | 8 | ||
9 | belongs_to :environment | 9 | belongs_to :environment |
app/models/scrap.rb
@@ -3,7 +3,7 @@ class Scrap < ActiveRecord::Base | @@ -3,7 +3,7 @@ class Scrap < ActiveRecord::Base | ||
3 | attr_accessible :content, :sender_id, :receiver_id, :scrap_id | 3 | attr_accessible :content, :sender_id, :receiver_id, :scrap_id |
4 | 4 | ||
5 | SEARCHABLE_FIELDS = { | 5 | SEARCHABLE_FIELDS = { |
6 | - :content => 1, | 6 | + :content => {:label => _('Content'), :weight => 1}, |
7 | } | 7 | } |
8 | validates_presence_of :content | 8 | validates_presence_of :content |
9 | validates_presence_of :sender_id, :receiver_id | 9 | validates_presence_of :sender_id, :receiver_id |
@@ -0,0 +1,63 @@ | @@ -0,0 +1,63 @@ | ||
1 | +class SearchTerm < ActiveRecord::Base | ||
2 | + validates_presence_of :term, :context | ||
3 | + validates_uniqueness_of :term, :scope => [:context_id, :context_type, :asset] | ||
4 | + | ||
5 | + belongs_to :context, :polymorphic => true | ||
6 | + has_many :occurrences, :class_name => 'SearchTermOccurrence' | ||
7 | + | ||
8 | + attr_accessible :term, :context, :asset | ||
9 | + | ||
10 | + def self.calculate_scores | ||
11 | + os = occurrences_scores | ||
12 | + find_each { |search_term| search_term.calculate_score(os) } | ||
13 | + end | ||
14 | + | ||
15 | + def self.find_or_create(term, context, asset='all') | ||
16 | + context.search_terms.where(:term => term, :asset => asset).first || context.search_terms.create!(:term => term, :asset=> asset) | ||
17 | + end | ||
18 | + | ||
19 | + # Fast way of getting the occurrences score for each search_term. Ugly but fast! | ||
20 | + # | ||
21 | + # Each occurrence of a search_term has a score that is smaller the older the | ||
22 | + # occurrence happened. We subtract the amount of time between now and the | ||
23 | + # moment it happened from the total time any occurrence is valid to happen. E.g.: | ||
24 | + # The expiration time is 100 days and an occurrence happened 3 days ago. | ||
25 | + # Therefore the score is 97. Them we sum every score to get the total score | ||
26 | + # for a search term. | ||
27 | + def self.occurrences_scores | ||
28 | + ActiveSupport::OrderedHash[*ActiveRecord::Base.connection.execute( | ||
29 | + joins(:occurrences). | ||
30 | + select("search_terms.id, sum(#{SearchTermOccurrence::EXPIRATION_TIME.to_i} - extract(epoch from (now() - search_term_occurrences.created_at))) as value"). | ||
31 | + where("search_term_occurrences.created_at > ?", DateTime.now - SearchTermOccurrence::EXPIRATION_TIME). | ||
32 | + group("search_terms.id"). | ||
33 | + order('value DESC'). | ||
34 | + to_sql | ||
35 | + ).map {|result| [result['id'].to_i, result['value'].to_i]}.flatten] | ||
36 | + end | ||
37 | + | ||
38 | + def calculate_occurrence(occurrences_scores) | ||
39 | + max_score = occurrences_scores.first[1] | ||
40 | + (occurrences_scores[id]/max_score.to_f)*100 | ||
41 | + end | ||
42 | + | ||
43 | + def calculate_relevance(valid_occurrences) | ||
44 | + indexed = valid_occurrences.last.indexed.to_f | ||
45 | + return 0 if indexed == 0 | ||
46 | + total = valid_occurrences.last.total.to_f | ||
47 | + (1 - indexed/total)*100 | ||
48 | + end | ||
49 | + | ||
50 | + def calculate_score(occurrences_scores) | ||
51 | + valid_occurrences = occurrences.valid | ||
52 | + if valid_occurrences.present? | ||
53 | + # These scores vary from 1~100 | ||
54 | + self.occurrence_score = calculate_occurrence(occurrences_scores) | ||
55 | + self.relevance_score = calculate_relevance(valid_occurrences) | ||
56 | + else | ||
57 | + self.occurrence_score = 0 | ||
58 | + self.relevance_score = 0 | ||
59 | + end | ||
60 | + self.score = (occurrence_score * relevance_score)/100.0 | ||
61 | + self.save! | ||
62 | + end | ||
63 | +end |
@@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
1 | +class SearchTermOccurrence < ActiveRecord::Base | ||
2 | + belongs_to :search_term | ||
3 | + validates_presence_of :search_term | ||
4 | + attr_accessible :search_term, :created_at, :total, :indexed | ||
5 | + | ||
6 | + EXPIRATION_TIME = 1.year | ||
7 | + | ||
8 | + scope :valid, :conditions => ["search_term_occurrences.created_at > ?", DateTime.now - EXPIRATION_TIME] | ||
9 | +end |
@@ -0,0 +1,6 @@ | @@ -0,0 +1,6 @@ | ||
1 | +class SuggestionConnection < ActiveRecord::Base | ||
2 | + attr_accessible :suggestion, :connection_type, :connection_id | ||
3 | + | ||
4 | + belongs_to :suggestion, :class_name => 'ProfileSuggestion', :foreign_key => 'suggestion_id' | ||
5 | + belongs_to :connection, :polymorphic => true | ||
6 | +end |
app/models/user.rb
@@ -11,6 +11,10 @@ class User < ActiveRecord::Base | @@ -11,6 +11,10 @@ class User < ActiveRecord::Base | ||
11 | N_('Password confirmation') | 11 | N_('Password confirmation') |
12 | N_('Terms accepted') | 12 | N_('Terms accepted') |
13 | 13 | ||
14 | + SEARCHABLE_FIELDS = { | ||
15 | + :email => {:label => _('Email'), :weight => 5}, | ||
16 | + } | ||
17 | + | ||
14 | def self.[](login) | 18 | def self.[](login) |
15 | self.find_by_login(login) | 19 | self.find_by_login(login) |
16 | end | 20 | end |
app/views/account/signup.html.erb
1 | -<% if @register_pending %> | ||
2 | - <div id='thanks-for-signing'> | ||
3 | - <% if environment.has_custom_welcome_screen? %> | ||
4 | - <%= environment.settings[:signup_welcome_screen_body].html_safe %> | ||
5 | - <% elsif environment.enabled?('admin_must_approve_new_users')%> | ||
6 | - <h1><%= _("Welcome to %s!") % environment.name %></h1> | ||
7 | - <h3><%= _("Thanks for signing up, we're thrilled to have you on our social network!") %></h3> | ||
8 | - <p><%= _("Firstly, some tips for getting started:") %></p> | ||
9 | - <% unless environment.enabled?('skip_new_user_email_confirmation') %> | ||
10 | - <h4><%= _("Confirm your account and wait for admin approvement!") %></h4> | ||
11 | - <p><%= _("You should receive a welcome email from us shortly. Please take a second to follow the link within to confirm your account.") %></p> | ||
12 | - <p><%= _("You won't appear as %s until your account is confirmed and approved.") % link_to(_('user'), {:controller => :search, :action => :people, :filter => 'more_recent'}, :target => '_blank') %></p> | ||
13 | - <% else %> | ||
14 | - <h4><%= _("Wait for admin approvement!") %></h4> | ||
15 | - <p><%= _("The administrators will evaluate your signup request for approvement.") %></p> | ||
16 | - <p><%= _("You won't appear as %s until your account is approved.") % link_to(_('user'), {:controller => :search, :action => :people, :filter => 'more_recent'}, :target => '_blank') %></p> | ||
17 | - <% end %> | ||
18 | - <h4><%= _("What to do next?") %></h4> | ||
19 | - <p><%= _("%s. Upload an avatar and let your friends find you easily :)") % link_to(_('Customize your profile'), {:controller => 'doc', :section => 'user', :topic => 'editing-person-info'}, :target => '_blank') %></p> | ||
20 | - <p><%= _("Learn the guidelines. Read the %s for more details on how to use this social network!") % link_to(_('Documentation'), {:controller => 'doc'}, :target => '_blank') %></p> | ||
21 | - <p><%= _("%s your Gmail, Yahoo and Hotmail contacts!") % link_to(_('Invite and find'), {:controller => 'doc', :section => 'user', :topic => 'invite-contacts'}, :target => '_blank') %></p> | ||
22 | - <p><%= _("Start exploring and have fun!") %></p> | ||
23 | - <% else %> | ||
24 | - <h1><%= _("Welcome to %s!") % environment.name %></h1> | ||
25 | - <h3><%= _("Thanks for signing up, we're thrilled to have you on our social network!") %></h3> | ||
26 | - <p><%= _("Firstly, some tips for getting started:") %></p> | ||
27 | - <h4><%= _("Confirm your account!") %></h4> | ||
28 | - <p><%= _("You should receive a welcome email from us shortly. Please take a second to follow the link within to confirm your account.") %></p> | ||
29 | - <p><%= _("You won't appear as %s until your account is confirmed.") % link_to(_('user'), {:controller => :search, :action => :people, :filter => 'more_recent'}, :target => '_blank') %></p> | ||
30 | - <h4><%= _("What to do next?") %></h4> | ||
31 | - <p><%= _("%s. Upload an avatar and let your friends find you easily :)") % link_to(_('Customize your profile'), {:controller => 'doc', :section => 'user', :topic => 'editing-person-info'}, :target => '_blank') %></p> | ||
32 | - <p><%= _("Learn the guidelines. Read the %s for more details on how to use this social network!") % link_to(_('Documentation'), {:controller => 'doc'}, :target => '_blank') %></p> | ||
33 | - <p><%= _("%s your Gmail, Yahoo and Hotmail contacts!") % link_to(_('Invite and find'), {:controller => 'doc', :section => 'user', :topic => 'invite-contacts'}, :target => '_blank') %></p> | ||
34 | - <p><%= _("Start exploring and have fun!") %></p> | ||
35 | - <% end %> | ||
36 | - </div> | ||
37 | -<% else %> | ||
38 | - <h1><%= _('Sign up for %s!') % environment.name %></h1> | ||
39 | - <%= render :partial => 'signup_form' %> | ||
40 | -<% end %> | 1 | +<h1><%= _('Sign up for %s!') % environment.name %></h1> |
2 | +<%= render :partial => 'signup_form' %> |
app/views/admin_panel/_signup_welcome_screen.html.erb
1 | <div class='description'> | 1 | <div class='description'> |
2 | - <%= _('This text will be showed as a welcome message to users after signup') %><br/><br/> | 2 | + <%= _('If you enable this feature on the "Features" section of the Administration Panel, this text will be shown as a welcome message to users after signup.') %> |
3 | </div> | 3 | </div> |
4 | - | ||
5 | <%= labelled_form_field(_('Body'), text_area(:environment, :signup_welcome_screen_body, :cols => 40, :style => 'width: 100%', :class => 'mceEditor')) %> | 4 | <%= labelled_form_field(_('Body'), text_area(:environment, :signup_welcome_screen_body, :cols => 40, :style => 'width: 100%', :class => 'mceEditor')) %> |
5 | + | ||
6 | +<div class='description'> | ||
7 | + <%= _('If this content is left blank, the following page will be displayed to the user:') %> | ||
8 | +</div> | ||
9 | + | ||
10 | +<%= render :file => 'home/welcome', :locals => {:default_message => true} %> |
app/views/admin_panel/site_info.html.erb
@@ -10,9 +10,12 @@ | @@ -10,9 +10,12 @@ | ||
10 | :content => (render :partial => 'site_info', :locals => {:f => f})} %> | 10 | :content => (render :partial => 'site_info', :locals => {:f => f})} %> |
11 | <% tabs << {:title => _('Terms of use'), :id => 'terms-of-use', | 11 | <% tabs << {:title => _('Terms of use'), :id => 'terms-of-use', |
12 | :content => (render :partial => 'terms_of_use', :locals => {:f => f})} %> | 12 | :content => (render :partial => 'terms_of_use', :locals => {:f => f})} %> |
13 | - <% tabs << {:title => _('Signup welcome text'), :id => 'signup-welcome-text', | 13 | + <% #TODO I renamed the labels of signup-welcome-text and signup-welcome-page |
14 | + # so texts more meaningful but I'm not rewriting every variable or reference to | ||
15 | + # this. I leave this task to whoever thinks this is too annoying.%> | ||
16 | + <% tabs << {:title => _('Signup welcome email'), :id => 'signup-welcome-text', | ||
14 | :content => (render :partial => 'signup_welcome_text', :locals => {:f => f})} %> | 17 | :content => (render :partial => 'signup_welcome_text', :locals => {:f => f})} %> |
15 | - <% tabs << {:title => _('Signup welcome message'), :id => 'signup-welcome-message', | 18 | + <% tabs << {:title => _('Signup welcome page'), :id => 'signup-welcome-message', |
16 | :content => (render :partial => 'signup_welcome_screen', :locals => {:f => f}) }%> | 19 | :content => (render :partial => 'signup_welcome_screen', :locals => {:f => f}) }%> |
17 | <%= render_tabs(tabs) %> | 20 | <%= render_tabs(tabs) %> |
18 | <% button_bar do %> | 21 | <% button_bar do %> |
@@ -0,0 +1,17 @@ | @@ -0,0 +1,17 @@ | ||
1 | +<% if owner.kind_of?(Profile) %> | ||
2 | + <%= link_to s_('communities|View all'), {:profile => owner.identifier, :controller => 'profile', :action => 'communities'}, :class => 'view-all' %> | ||
3 | +<% elsif owner.kind_of?(Environment) %> | ||
4 | + <%= link_to s_('communities|View all'), {:controller => 'search', :action => 'communities'}, :class => 'view-all' %> | ||
5 | +<% end %> | ||
6 | + | ||
7 | +<% if user && user == profile && suggestions && !suggestions.empty? %> | ||
8 | + <div class='suggestions-block common-profile-list-block'> | ||
9 | + <h4 class='block-subtitle'><%= _('Some suggestions for you') %></h4> | ||
10 | + <div class='profiles-suggestions'> | ||
11 | + <%= render :partial => 'shared/profile_suggestions_list', :locals => { :suggestions => suggestions, :collection => :communities_suggestions, :per_page => 3 } %> | ||
12 | + </div> | ||
13 | + <div class='more-suggestions'> | ||
14 | + <%= link_to _('See all suggestions'), profile.communities_suggestions_url %> | ||
15 | + </div> | ||
16 | + </div> | ||
17 | +<% end %> |
app/views/cms/_drag_and_drop_note.html.erb
@@ -0,0 +1,15 @@ | @@ -0,0 +1,15 @@ | ||
1 | +<%= form_tag({:action => 'new', :profile => profile.identifier}, :id => 'new-folder-dialog', :title => _('Create new folder'), :style => 'display: none;') do %> | ||
2 | + <%= select_profile_folder( | ||
3 | + _('Choose parent folder:'), | ||
4 | + :parent_id, profile, default_folder, {}, {}, | ||
5 | + "type='Folder' or type='Gallery'") | ||
6 | + %> | ||
7 | + | ||
8 | + <%= labelled_radio_button _('Gallery'), :folder_type, 'Gallery', true %> | ||
9 | + <%= labelled_radio_button _('Folder'), :folder_type, 'Folder', false %> | ||
10 | + | ||
11 | + <%= labelled_form_field _('Name:'), text_field_tag(:new_folder, nil, 'data-url' => url_for({:action => 'new', :profile => profile.identifier})) %> | ||
12 | + <% button_bar do %> | ||
13 | + <%= submit_button(:newfolder, _('Create')) %> | ||
14 | + <% end %> | ||
15 | +<% end %> |
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +<% file_types.each do |key, header| %> | ||
2 | + <% display = @recent_files[key].present? ? '' : 'none' %> | ||
3 | + <div class='<%= key.to_s %>' style='display: <%= display%>;'> | ||
4 | + <div class='section-title'> | ||
5 | + <h3><%= header %></h3> | ||
6 | + <% if @recent_files[key].total_pages > 1 %> | ||
7 | + <%= link_to(_('View all'), {:controller => 'cms', :action => 'view_all_media', :profile => profile.identifier, :key => key}, :class => 'view-all colorbox', 'data-key' => key) %> | ||
8 | + <% end %> | ||
9 | + </div> | ||
10 | + <%= render :partial => "cms/media_panel/list_published_media_items", :locals => { key: key, show_pagination_links: false } %> | ||
11 | + </div> | ||
12 | +<% end %> |
app/views/cms/_text_editor_sidebar.html.erb
1 | +<% default_folder = content_id_to_str default_folder_for_image_upload(profile) %> | ||
2 | + | ||
1 | <div class='text-editor-sidebar'> | 3 | <div class='text-editor-sidebar'> |
2 | <span class='button-add' data-value='<%= _('Add to the text') %>'></span> | 4 | <span class='button-add' data-value='<%= _('Add to the text') %>'></span> |
3 | <span class='button-zoom' data-value='<%= _('Zoom in') %>'></span> | 5 | <span class='button-zoom' data-value='<%= _('Zoom in') %>'></span> |
4 | <span class='button-close' data-value='<%= _('Close') %>'></span> | 6 | <span class='button-close' data-value='<%= _('Close') %>'></span> |
5 | 7 | ||
8 | + <div class='header'><strong><%= _('Insert media') %></strong><%= button('vertical-toggle', _('Show/Hide'), '#') %></div> | ||
9 | + | ||
6 | <%= render(:partial => 'textile_quick_reference') if @article.is_a?(TextileArticle) %> | 10 | <%= render(:partial => 'textile_quick_reference') if @article.is_a?(TextileArticle) %> |
7 | <div class='text-editor-sidebar-box' id='media-upload-box'> | 11 | <div class='text-editor-sidebar-box' id='media-upload-box'> |
8 | - <div class='header'><strong><%= _('Insert media') %></strong></div> | ||
9 | <div id='media-upload-form'> | 12 | <div id='media-upload-form'> |
10 | <%= form_tag({ :action => 'media_upload' }, :multipart => true) do %> | 13 | <%= form_tag({ :action => 'media_upload' }, :multipart => true) do %> |
11 | <div class='formfield'> | 14 | <div class='formfield'> |
12 | - <% default_folder = content_id_to_str default_folder_for_image_upload(profile) %> | ||
13 | <%= select_profile_folder( | 15 | <%= select_profile_folder( |
14 | _('Choose folder to upload files:'), | 16 | _('Choose folder to upload files:'), |
15 | :parent_id, profile, default_folder, {}, {}, | 17 | :parent_id, profile, default_folder, {}, {}, |
16 | "type='Folder' or type='Gallery'" | 18 | "type='Folder' or type='Gallery'" |
17 | ) %> | 19 | ) %> |
18 | </div> | 20 | </div> |
19 | - <p><%= file_field_tag('file1') %></p> | ||
20 | - <p><%= file_field_tag('file2') %></p> | ||
21 | - <p><%= file_field_tag('file3') %></p> | ||
22 | - <% button_bar do %> | ||
23 | - <%= submit_button(:save, _('Upload')) %> | ||
24 | - <% end %> | 21 | + <%= button(:newfolder, _('New folder'), '#', :id => 'new-folder-button') %> |
22 | + <p><%= file_field_tag('file', :multiple => true) %></p> | ||
25 | <% end %> | 23 | <% end %> |
26 | </div> | 24 | </div> |
27 | - <div id='media-upload-results' style='display: none'> | ||
28 | - <%= render :partial => 'drag_and_drop_note' %> | ||
29 | - <div class='items'> | ||
30 | - </div> | ||
31 | - <p><%= link_to(_('Upload more files ...'), '#', :id => 'media-upload-more-files')%></p> | 25 | + <div class='hide-and-show-uploads'> |
26 | + <%= link_to(_('Hide all uploads'), nil, :id => 'hide-uploads', :style => 'display: none;', 'data-bootstraped' => false) %> | ||
27 | + <%= link_to(_('Show all uploads'), nil, :id => 'show-uploads', :style => 'display: none;') %> | ||
32 | </div> | 28 | </div> |
33 | </div> | 29 | </div> |
34 | - <div id='media-search-box' class='text-editor-sidebar-box'> | ||
35 | - <div class='header'><strong><%= _('Media search') %></strong></div> | ||
36 | - <p> | ||
37 | - <%= form_tag({ :action => 'search' }) do %> | ||
38 | - <span class='formfield'> | ||
39 | - <input name='q' type='text' id='media-search-query' style='width: 250px;'/> | ||
40 | - </span> | ||
41 | - <%= submit_button :search, _('Search'), :id => 'media-search-button' %> | ||
42 | - <% end %> | ||
43 | - </p> | ||
44 | - <div id='media-search-results' style='display: none'> | ||
45 | - <%= render :partial => 'drag_and_drop_note' %> | ||
46 | - <div class='items'> | ||
47 | - </div> | 30 | + |
31 | + <div id='published-media' class='text-editor-sidebar-box' data-url='<%= url_for({:controller => 'cms', :action => 'published_media_items', :profile => profile.identifier}) %>'> | ||
32 | + <%= select_profile_folder(nil, :parent_id, profile, 'recent-media', {}, {}, | ||
33 | + "type='Folder' or type='Gallery'", {:root_label => _('Recent media')}) %> | ||
34 | + <%= labelled_form_field _('Search'), text_field_tag('q') %> | ||
35 | + <%= render :partial => 'drag_and_drop_note' %> | ||
36 | + <div class='items'> | ||
37 | + <%= render :partial => 'published_media_items' %> | ||
48 | </div> | 38 | </div> |
49 | </div> | 39 | </div> |
50 | </div> | 40 | </div> |
51 | 41 | ||
42 | +<script id="template-upload" type="text/x-tmpl"> | ||
43 | + <div id="file-{%= o.id %}" class="upload" title="{%= o.name %}"> | ||
44 | + <div class="file-name">{%=o.name%}</div> | ||
45 | + <div class="percentage"></div> | ||
46 | + <div class="progress"><div class="bar" style="width: 0%;"></div></div> | ||
47 | + </div> | ||
48 | +</script> | ||
52 | 49 | ||
50 | +<%= render :partial => 'media_new_folder', :locals => {:default_folder => default_folder} %> | ||
51 | +<%= javascript_include_tag 'jquery.fileupload.js', 'tmpl.js', 'media-panel.js' %> |
app/views/cms/_textile_quick_reference.html.erb
@@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
15 | <pre># <%= _('first item') %> | 15 | <pre># <%= _('first item') %> |
16 | # <%= _('second item') %></pre> | 16 | # <%= _('second item') %></pre> |
17 | <p><%= h(_('For code, use HTML tags <pre> and <code>, and indent the code inside them:')) %> | 17 | <p><%= h(_('For code, use HTML tags <pre> and <code>, and indent the code inside them:')) %> |
18 | + </p> | ||
18 | <pre> | 19 | <pre> |
19 | <pre> | 20 | <pre> |
20 | <code> | 21 | <code> |
app/views/cms/edit.html.erb
1 | <%= error_messages_for 'article' %> | 1 | <%= error_messages_for 'article' %> |
2 | 2 | ||
3 | -<div class='<%= (environment.enabled?('media_panel') ? 'with_media_panel' : 'no_media_panel') %>'> | 3 | +<% show_media_panel = environment.enabled?('media_panel') && [TinyMceArticle, TextileArticle, Event, EnterpriseHomepage].any?{|klass| @article.kind_of?(klass)} %> |
4 | + | ||
5 | +<div class='<%= (show_media_panel ? 'with_media_panel' : 'no_media_panel') %>'> | ||
4 | <%= labelled_form_for 'article', :html => { :multipart => true, :class => @type } do |f| %> | 6 | <%= labelled_form_for 'article', :html => { :multipart => true, :class => @type } do |f| %> |
5 | 7 | ||
6 | <%= hidden_field_tag("type", @type) if @type %> | 8 | <%= hidden_field_tag("type", @type) if @type %> |
@@ -66,7 +68,7 @@ | @@ -66,7 +68,7 @@ | ||
66 | <% end %> | 68 | <% end %> |
67 | </div> | 69 | </div> |
68 | 70 | ||
69 | -<% if environment.enabled?('media_panel') && [TinyMceArticle, TextileArticle, Event, EnterpriseHomepage].any?{|klass| @article.kind_of?(klass)} %> | 71 | +<% if show_media_panel %> |
70 | <%= render :partial => 'text_editor_sidebar' %> | 72 | <%= render :partial => 'text_editor_sidebar' %> |
71 | <% end %> | 73 | <% end %> |
72 | 74 |
@@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
1 | +<div class="item image" data-item="span" title="<%= @file.name %>"> | ||
2 | + <span> | ||
3 | + <img src="<%= @file.public_filename(:uploaded) %>"/> | ||
4 | + </span> | ||
5 | + <div class="controls image-controls"> | ||
6 | + <a class="button icon-add add-to-text" href="#"><span><%= _('Add to the text') %></span></a> | ||
7 | + <a class="button icon-zoom zoom" href="#" title="<%= _('Zoom in') %>"><span><%= _('Zoom in') %></span></a> | ||
8 | + </div> | ||
9 | +</div> |
app/views/cms/media_panel/_list_published_media_items.html.erb
0 → 100644
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | +loadPublishedMedia(); |
app/views/cms/publish.html.erb
1 | -<h1><%= _('Select the groups where you want to publish your article') %></h1> | 1 | +<div class="select-publish-target"> |
2 | + | ||
3 | +<h2><%= _('Where do you want to publish this article?') %></h2> | ||
2 | 4 | ||
3 | <% if !@failed.blank? %> | 5 | <% if !@failed.blank? %> |
4 | <div class="errorExplanation" id="errorExplanation"> | 6 | <div class="errorExplanation" id="errorExplanation"> |
@@ -14,15 +16,54 @@ | @@ -14,15 +16,54 @@ | ||
14 | </div> | 16 | </div> |
15 | <% end %> | 17 | <% end %> |
16 | 18 | ||
17 | -<%= form_tag do%> | ||
18 | - <%= hidden_field_tag :back_to, @back_to %> | ||
19 | - <% @groups.each do |group| %> | ||
20 | - <%= labelled_check_box group.name, "marked_groups[#{group.id}][group_id]", group.id, @marked_groups.include?(group) %><br /> | ||
21 | - <%= labelled_text_field _('Title') + ': ', "marked_groups[#{group.id}][name]", @article.name, :style => 'width: 100%' %> | ||
22 | - <hr /> | 19 | +<ul class='publish-targets'> |
20 | + <% if profile != user %> | ||
21 | + <li onmouseover="javascript: jQuery(this).addClass('mouseover')" onmouseout="jQuery(this).removeClass('mouseover')"> | ||
22 | + <strong><%= _("Publish this article on your profile") %></strong> | ||
23 | + <div class='description'><%= _('You can publish this article on your profile where your friends and followers will see.') %></div> | ||
24 | + <%= form_tag do %> | ||
25 | + <%= hidden_field_tag :back_to, @back_to %> | ||
26 | + <%= labelled_form_field _('Title'), text_field_tag('name', @article.name) %> | ||
27 | + | ||
28 | + <% button_bar do %> | ||
29 | + <%= submit_button 'spread', _('Spread this') %> | ||
30 | + <% end %> | ||
31 | + <% end %> | ||
32 | + </li> | ||
23 | <% end %> | 33 | <% end %> |
24 | 34 | ||
25 | - <% button_bar do %> | ||
26 | - <%= submit_button 'spread', _('Spread this'), :cancel => @back_to %> | 35 | + <% if user.communities.present? %> |
36 | + <li onmouseover="javascript: jQuery(this).addClass('mouseover')" onmouseout="jQuery(this).removeClass('mouseover')"> | ||
37 | + <strong><%= _("Publish this article on communities you are part of") %></strong> | ||
38 | + <div class='description'><%= _('You can submit this article to one or more communities you are a member of, just search for the community below.') %></div> | ||
39 | + <%= form_tag :action => 'publish_on_communities', :id => @article.id do %> | ||
40 | + <%= hidden_field_tag :back_to, @back_to %> | ||
41 | + <% search_action = url_for(:action => 'search_communities_to_publish') %> | ||
42 | + <%= token_input_field_tag(:q, 'search-communities-to-publish', search_action, { :hint_text => _('Type in a search for your community'), :zindex => 10000, :focus => false }) %> | ||
43 | + <%= labelled_form_field _('Title'), text_field_tag('name', @article.name) %> | ||
44 | + <% button_bar do %> | ||
45 | + <%= submit_button 'spread', _('Spread this') %> | ||
46 | + <% end %> | ||
47 | + <% end %> | ||
48 | + </li> | ||
27 | <% end %> | 49 | <% end %> |
28 | -<% end %> | 50 | + |
51 | + | ||
52 | + <% if environment.portal_enabled %> | ||
53 | + <li onmouseover="javascript: jQuery(this).addClass('mouseover')" onmouseout="jQuery(this).removeClass('mouseover')"> | ||
54 | + <strong><%= _("Publish your article on portal community") %></strong> | ||
55 | + <div class='description'><%= _('You can suggest this article to the portal community, where it can show up on the homepage.') %></div> | ||
56 | + | ||
57 | + <%= form_tag :action => 'publish_on_portal_community', :id => @article.id do %> | ||
58 | + <%= hidden_field_tag :back_to, @back_to %> | ||
59 | + <%= labelled_form_field _('Title'), text_field_tag('name', @article.name) %> | ||
60 | + | ||
61 | + <% button_bar do %> | ||
62 | + <%= submit_button 'spread', _('Spread this') %> | ||
63 | + <% end %> | ||
64 | + <% end %> | ||
65 | + </li> | ||
66 | + <% end %> | ||
67 | +</ul> | ||
68 | + | ||
69 | +</div> |
app/views/cms/view.html.erb
@@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
2 | <%= _('Content management') %> | 2 | <%= _('Content management') %> |
3 | </h1> | 3 | </h1> |
4 | 4 | ||
5 | -<% if user.can_change_homepage? && !remove_content_button(:home) %> | 5 | +<% if user.can_change_homepage? && !remove_content_button(:home, profile.home_page) %> |
6 | <div class="cms-homepage"> | 6 | <div class="cms-homepage"> |
7 | <%= _('Profile homepage:') %> | 7 | <%= _('Profile homepage:') %> |
8 | <% if profile.home_page %> | 8 | <% if profile.home_page %> |
@@ -66,17 +66,17 @@ | @@ -66,17 +66,17 @@ | ||
66 | <%= short_description %> | 66 | <%= short_description %> |
67 | </td> | 67 | </td> |
68 | <td class="article-controls"> | 68 | <td class="article-controls"> |
69 | - <%= expirable_button article, :edit, _('Edit'), {:action => 'edit', :id => article.id} if !remove_content_button(:edit) %> | 69 | + <%= expirable_button article, :edit, _('Edit'), {:action => 'edit', :id => article.id} if !remove_content_button(:edit, article) %> |
70 | <%= button_without_text :eyes, _('Public view'), article.view_url %> | 70 | <%= button_without_text :eyes, _('Public view'), article.view_url %> |
71 | - <%= display_spread_button(profile, article) unless article.folder? || remove_content_button(:spread)%> | ||
72 | - <% if user.can_change_homepage? && !remove_content_button(:home) %> | 71 | + <%= display_spread_button(article) unless remove_content_button(:spread, article) %> |
72 | + <% if user.can_change_homepage? && !remove_content_button(:home, article) %> | ||
73 | <% if profile.home_page != article %> | 73 | <% if profile.home_page != article %> |
74 | <%= expirable_button article, :home, _('Use as homepage'), { :action => 'set_home_page', :id => article.id }, :method => :post %> | 74 | <%= expirable_button article, :home, _('Use as homepage'), { :action => 'set_home_page', :id => article.id }, :method => :post %> |
75 | <% else %> | 75 | <% else %> |
76 | <%= button_without_text(:'home-not', _('Reset homepage'), { :action => 'set_home_page', :id => nil }, :method => :post) %> | 76 | <%= button_without_text(:'home-not', _('Reset homepage'), { :action => 'set_home_page', :id => nil }, :method => :post) %> |
77 | <% end %> | 77 | <% end %> |
78 | <% end %> | 78 | <% end %> |
79 | - <%= display_delete_button(article) if !remove_content_button(:delete) %> | 79 | + <%= display_delete_button(article) if !remove_content_button(:delete, article) %> |
80 | </td> | 80 | </td> |
81 | </tr> | 81 | </tr> |
82 | <% end %> | 82 | <% end %> |
@@ -0,0 +1,7 @@ | @@ -0,0 +1,7 @@ | ||
1 | +<h1><%= file_types[@key] %></h1> | ||
2 | + | ||
3 | +<div class='view-all-media view-all-<%= @key %>'> | ||
4 | + <%= render :partial => "cms/media_panel/list_published_media_items", :locals => { key: @key, show_pagination_links: true } %> | ||
5 | +</div> | ||
6 | + | ||
7 | +<%= javascript_include_tag 'media-panel.js' %> |
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | +jQuery('.view-all-media').html('<%= escape_javascript(render :partial => "cms/media_panel/list_published_media_items", :locals => { key: @key, show_pagination_links: true }) %>'); |
app/views/content_viewer/_article_toolbar.html.erb
@@ -2,46 +2,40 @@ | @@ -2,46 +2,40 @@ | ||
2 | <div id="article-actions"> | 2 | <div id="article-actions"> |
3 | 3 | ||
4 | 4 | ||
5 | - <% if @page.allow_edit?(user) && !remove_content_button(:edit) %> | 5 | + <% if @page.allow_edit?(user) && !remove_content_button(:edit, @page) %> |
6 | <% content = content_tag('span', label_for_edit_article(@page)) %> | 6 | <% content = content_tag('span', label_for_edit_article(@page)) %> |
7 | <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'edit', :id => @page.id }) %> | 7 | <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'edit', :id => @page.id }) %> |
8 | <%= expirable_button @page, :edit, content, url %> | 8 | <%= expirable_button @page, :edit, content, url %> |
9 | <% end %> | 9 | <% end %> |
10 | 10 | ||
11 | - <% if @page != profile.home_page && !@page.has_posts? && @page.allow_delete?(user) && !remove_content_button(:delete)%> | 11 | + <% if @page != profile.home_page && !@page.has_posts? && @page.allow_delete?(user) && !remove_content_button(:delete, @page)%> |
12 | <% content = content_tag( 'span', _('Delete') ) %> | 12 | <% content = content_tag( 'span', _('Delete') ) %> |
13 | <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'destroy', :id => @page.id}) %> | 13 | <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'destroy', :id => @page.id}) %> |
14 | <% options = {:method => :post, :confirm => delete_article_message(@page)} %> | 14 | <% options = {:method => :post, :confirm => delete_article_message(@page)} %> |
15 | <%= expirable_button @page, :delete, content, url, options %> | 15 | <%= expirable_button @page, :delete, content, url, options %> |
16 | <% end %> | 16 | <% end %> |
17 | 17 | ||
18 | - <% if !@page.folder? && @page.allow_spread?(user) && !remove_content_button(:spread) %> | ||
19 | - <% content = content_tag( 'span', _('Spread this') ) %> | ||
20 | - <% url = nil %> | ||
21 | - <% if profile.kind_of?(Person) %> | ||
22 | - <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'publish', :id => @page.id }) %> | ||
23 | - <% elsif profile.kind_of?(Community) && environment.portal_community %> | ||
24 | - <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'publish_on_portal_community', :id => @page.id }) %> | ||
25 | - <% end %> | ||
26 | - <%= expirable_button @page, :spread, content, url if url %> | 18 | + <% if @page.allow_spread?(user) && !remove_content_button(:spread, @page) %> |
19 | + <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'publish', :id => @page.id }) %> | ||
20 | + <%= expirable_button @page, :spread, content_tag( 'span', _('Spread this') ), url, {:class => 'colorbox'} if url %> | ||
27 | <% end %> | 21 | <% end %> |
28 | 22 | ||
29 | <% if !@page.gallery? && (@page.allow_create?(user) || (@page.parent && @page.parent.allow_create?(user))) %> | 23 | <% if !@page.gallery? && (@page.allow_create?(user) || (@page.parent && @page.parent.allow_create?(user))) %> |
30 | - <% if @page.translatable? && !@page.native_translation.language.blank? && !remove_content_button(:locale) %> | 24 | + <% if @page.translatable? && !@page.native_translation.language.blank? && !remove_content_button(:locale, @page) %> |
31 | <% content = _('Add translation') %> | 25 | <% content = _('Add translation') %> |
32 | <% parent_id = (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)) %> | 26 | <% parent_id = (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)) %> |
33 | <% url = profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => parent_id, :type => @page.type, :article => { :translation_of_id => @page.native_translation.id })%> | 27 | <% url = profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => parent_id, :type => @page.type, :article => { :translation_of_id => @page.native_translation.id })%> |
34 | <%= expirable_button @page, :locale, content, url %> | 28 | <%= expirable_button @page, :locale, content, url %> |
35 | <% end %> | 29 | <% end %> |
36 | 30 | ||
37 | - <%= colorbox_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) unless remove_content_button(:new) %> | 31 | + <%= colorbox_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) unless remove_content_button(:new, @page) %> |
38 | <% end %> | 32 | <% end %> |
39 | 33 | ||
40 | <% if @page.accept_uploads? && @page.allow_create?(user) %> | 34 | <% if @page.accept_uploads? && @page.allow_create?(user) %> |
41 | - <%= button('upload-file', _('Upload files'), profile.admin_url.merge(:controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent))) unless remove_content_button(:upload)%> | 35 | + <%= button('upload-file', _('Upload files'), profile.admin_url.merge(:controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent))) unless remove_content_button(:upload, @page)%> |
42 | <% end %> | 36 | <% end %> |
43 | 37 | ||
44 | - <% if !@page.allow_create?(user) && profile.community? && (@page.blog? || @page.parent && @page.parent.blog?) && !remove_content_button(:suggest) %> | 38 | + <% if !@page.allow_create?(user) && profile.community? && (@page.blog? || @page.parent && @page.parent.blog?) && !remove_content_button(:suggest, @page) %> |
45 | <% content = content_tag( 'span', _('Suggest an article') ) %> | 39 | <% content = content_tag( 'span', _('Suggest an article') ) %> |
46 | <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'suggest_an_article'}) %> | 40 | <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'suggest_an_article'}) %> |
47 | <% options = {:id => 'suggest-article-link'} %> | 41 | <% options = {:id => 'suggest-article-link'} %> |
app/views/content_viewer/versioned_article.html.erb
@@ -7,7 +7,7 @@ | @@ -7,7 +7,7 @@ | ||
7 | <div id="article-actions"> | 7 | <div id="article-actions"> |
8 | <%= button(:clock, _('All versions'), {:controller => 'content_viewer', :profile => profile.identifier, :action => 'article_versions'}, :id => 'article-versions-link') %> | 8 | <%= button(:clock, _('All versions'), {:controller => 'content_viewer', :profile => profile.identifier, :action => 'article_versions'}, :id => 'article-versions-link') %> |
9 | 9 | ||
10 | - <% if @page.allow_edit?(user) && !remove_content_button(:undo) %> | 10 | + <% if @page.allow_edit?(user) && !remove_content_button(:undo, @page) %> |
11 | <% content = content_tag('span', _('Revert to this version')) %> | 11 | <% content = content_tag('span', _('Revert to this version')) %> |
12 | <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'edit', :id => @page.id, :version => @version }) %> | 12 | <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'edit', :id => @page.id, :version => @version }) %> |
13 | <%= expirable_button @page, :undo, content, url, :id => 'article-revert-version-link' %> | 13 | <%= expirable_button @page, :undo, content, url, :id => 'article-revert-version-link' %> |
app/views/enterprise_registration/creation.html.erb
1 | <h1><%= _('Enterprise registration completed') %></h1> | 1 | <h1><%= _('Enterprise registration completed') %></h1> |
2 | +<p><%= _("Your enterprise (%s) was successfully registered.") % @enterprise.name %></p> | ||
3 | +<p><%= link_to _('You can manage your enterprise now.'), @enterprise.admin_url %></p> | ||
2 | 4 | ||
3 | -<p> | ||
4 | -<%= _("Your enterprise (%s) was successfully registered.") % @enterprise.name %> | ||
5 | -</p> | 5 | +<%= render :partial => 'shared/template_welcome_page', :locals => {:template => @enterprise.template, :header => _("What can I do with a %s?")} %> |
6 | + | ||
7 | +<% button_bar do %> | ||
8 | + <%= button :back, _('Back'), {:controller => 'memberships', :action => 'index', :profile => user.identifier} %> | ||
9 | +<% end %> | ||
6 | 10 | ||
7 | -<p> | ||
8 | -<%= link_to _('You can manage your enterprise now.'), @enterprise.admin_url %> | ||
9 | -</p> |
@@ -0,0 +1,16 @@ | @@ -0,0 +1,16 @@ | ||
1 | +<ul class="profile-list"> | ||
2 | + <% profiles.each do |profile| %> | ||
3 | + <li> | ||
4 | + <%= link_to_profile profile_image(profile) + '<br/>' + profile.short_name, | ||
5 | + profile.identifier, :class => 'profile-link' %> | ||
6 | + <div class="controll"> | ||
7 | + <%= button_without_text :remove, content_tag('span',_('remove')), | ||
8 | + { :action => 'remove', :id => profile.id }, | ||
9 | + :title => _('remove') %> | ||
10 | + <%= button_without_text 'menu-mail', content_tag('span',_('contact')), | ||
11 | + profile.url.merge(:controller => 'contact', :action => 'new', :profile => profile.identifier), | ||
12 | + :title => _('contact') %> | ||
13 | + </div><!-- end class="controll" --> | ||
14 | + </li> | ||
15 | + <% end %> | ||
16 | +</ul> |
@@ -0,0 +1,7 @@ | @@ -0,0 +1,7 @@ | ||
1 | +<h1><%= _("Connections with %s") % @suggestion.suggestion.name %></h1> | ||
2 | + | ||
3 | +<% button_bar do %> | ||
4 | + <%= button(:back, _('Go to friends list'), :controller => 'friends') %> | ||
5 | +<% end %> | ||
6 | + | ||
7 | +<%= render :partial => 'shared/profile_connections', :locals => { :suggestion => @suggestion, :tags => @tags, :profiles => @profiles } %> |
app/views/friends/index.html.erb
@@ -10,46 +10,28 @@ | @@ -10,46 +10,28 @@ | ||
10 | <%= link_to _('Do you want to see other people in this environment?'), :controller => 'search', :action => 'assets', :asset => 'people' %> | 10 | <%= link_to _('Do you want to see other people in this environment?'), :controller => 'search', :action => 'assets', :asset => 'people' %> |
11 | </em> | 11 | </em> |
12 | </p> | 12 | </p> |
13 | - <% else %> | ||
14 | - <% button_bar do %> | ||
15 | - <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> | ||
16 | - <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %> | ||
17 | - <% unless @plugins.dispatch(:remove_invite_friends_button).include?(true) %> | ||
18 | - <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'select_address_book') %> | ||
19 | - <% end %> | ||
20 | - <% end %> | ||
21 | <% end %> | 13 | <% end %> |
22 | 14 | ||
23 | - <ul class="profile-list"> | ||
24 | - <% @friends.each do |friend| %> | ||
25 | - <li> | ||
26 | - <%= link_to_profile profile_image(friend) + '<br/>' + friend.short_name, | ||
27 | - friend.identifier, :class => 'profile-link' %> | ||
28 | - <div class="controll"> | ||
29 | - <%= link_to content_tag('span',_('remove')), | ||
30 | - { :action => 'remove', :id => friend.id }, | ||
31 | - :class => 'button icon-remove', | ||
32 | - :title => _('remove') %> | ||
33 | - <%= link_to content_tag('span',_('contact')), | ||
34 | - friend.url.merge(:controller => 'contact', :action => 'new', :profile => friend.identifier), | ||
35 | - :class => 'button icon-menu-mail', | ||
36 | - :title => _('contact') %> | ||
37 | - </div><!-- end class="controll" --> | ||
38 | - </li> | ||
39 | - <% end %> | ||
40 | - </ul> | ||
41 | - <div id='pagination-friends'> | ||
42 | - <%= pagination_links @friends, :param_name => 'npage' %> | ||
43 | - </div> | ||
44 | - | ||
45 | <% button_bar do %> | 15 | <% button_bar do %> |
46 | <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> | 16 | <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> |
47 | <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %> | 17 | <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %> |
48 | <% unless @plugins.dispatch(:remove_invite_friends_button).include?(true) %> | 18 | <% unless @plugins.dispatch(:remove_invite_friends_button).include?(true) %> |
49 | - <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'select_address_book') %> | 19 | + <%= button(:person, _('Invite people'), :controller => 'invite', :action => 'invite_friends') %> |
50 | <% end %> | 20 | <% end %> |
51 | <% end %> | 21 | <% end %> |
22 | + | ||
23 | + <%= render :partial => 'profile_list', :locals => { :profiles => @friends } %> | ||
24 | + | ||
25 | + <br style="clear:both" /> | ||
26 | + <%= pagination_links @friends, :param_name => 'npage' %> | ||
52 | <% end %> | 27 | <% end %> |
53 | 28 | ||
54 | -</div><!-- end id="manage_friends" --> | 29 | +<% unless @suggestions.empty? %> |
30 | + <br style="clear:both" /> | ||
31 | + <h2><%= _("Friends suggestions") %></h2> | ||
32 | + <div class="profiles-suggestions"> | ||
33 | + <%= render :partial => 'shared/profile_suggestions_list', :locals => { :suggestions => @suggestions, :collection => :friends_suggestions, :per_page => 12 } %> | ||
34 | + </div> | ||
35 | +<% end %> | ||
55 | 36 | ||
37 | +</div><!-- end id="manage_friends" --> |
@@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
1 | +<h1><%= _("Friends suggestions for %s") % profile.name %></h1> | ||
2 | + | ||
3 | +<% button_bar do %> | ||
4 | + <%= button(:back, _('Go to friends list'), :controller => 'friends') %> | ||
5 | +<% end %> | ||
6 | + | ||
7 | +<div class="profiles-suggestions"> | ||
8 | + <%= render :partial => 'shared/profile_suggestions_list', :locals => { :suggestions => @suggestions, :collection => :friends_suggestions, :per_page => 12 } %> | ||
9 | +</div> |
@@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
1 | +<% default_message = defined?(default_message) ? default_message : false %> | ||
2 | + | ||
3 | +<div id='thanks-for-signing'> | ||
4 | + <h1><%= _("Welcome to %s!") % environment.name %></h1> | ||
5 | + <% if environment.has_custom_welcome_screen? && !default_message %> | ||
6 | + <%= environment.settings[:signup_welcome_screen_body].html_safe %> | ||
7 | + <% else %> | ||
8 | + <h3><%= _("Thanks for signing up, we're thrilled to have you on our social network!") %></h3> | ||
9 | + <% if @display_confirmation_tips %> | ||
10 | + <p><%= _("Firstly, some tips for getting started:") %></p> | ||
11 | + <h4><%= _("Confirm your account!") %></h4> | ||
12 | + <p><%= _("You should receive a welcome email from us shortly. Please take a second to follow the link within to confirm your account.") %></p> | ||
13 | + <p><%= _("You won't appear as %s until your account is confirmed.") % link_to(_('user'), {:controller => :search, :action => :people, :filter => 'more_recent'}, :target => '_blank') %></p> | ||
14 | + <% else %> | ||
15 | + <h4><%= _("Wait for admin approvement!") %></h4> | ||
16 | + <p><%= _("The administrators will evaluate your signup request for approvement.") %></p> | ||
17 | + <p><%= _("You won't appear as %s until your account is approved.") % link_to(_('user'), {:controller => :search, :action => :people, :filter => 'more_recent'}, :target => '_blank') %></p> | ||
18 | + <% end %> | ||
19 | + <h4><%= _("What to do next?") %></h4> | ||
20 | + <p><%= _("Access your %s and see your face on the network!") % | ||
21 | + (user.present? ? link_to(_('Profile'), {:controller => 'profile', :profile => user.identifier}, :target => '_blank') : 'Profile') %> | ||
22 | + <%= _("You can also explore your %s to customize your profile. Here are some %s on what you can do there.") % | ||
23 | + [user.present? ? link_to(_('Control Panel'), {:controller => 'profile_editor', :profile => user.identifier}, :target => '_blank') : 'Control Panel', | ||
24 | + link_to(_('tips'), {:controller => 'doc', :action => 'topic', :section => 'user', :topic => 'editing-person-info'}, :target => '_blank')] %></p> | ||
25 | + <p><%= _("%s your Gmail, Yahoo and Hotmail contacts!") % link_to(_('Invite and find'), {:controller => 'doc', :action => 'topic', :section => 'user', :topic => 'invite-contacts'}, :target => '_blank') %></p> | ||
26 | + <p><%= _("Learn the guidelines. Read the %s for more details on how to use this social network!") % link_to(_('Documentation'), {:controller => 'doc'}, :target => '_blank') %></p> | ||
27 | + <p><%= _("Start exploring and have fun!") %></p> | ||
28 | + <% end %> | ||
29 | + <%= render :partial => 'shared/template_welcome_page', :locals => {:template => @person_template, :header => _("What can I do as a %s?")} %> | ||
30 | +</div> |
@@ -0,0 +1,8 @@ | @@ -0,0 +1,8 @@ | ||
1 | +<br/> | ||
2 | + | ||
3 | +<%= link_to ('Personalize invitation mail'), nil, :onclick => "jQuery('#invitation-mail_template').show(); return false;" %> | ||
4 | + | ||
5 | +<div id='invitation-mail_template' style='display:none'> | ||
6 | + <%= h _("Now enter an invitation message. You must keep the <url> code in your invitation text. When your friends receive the invitation e-mail, <url> will be replaced by a link that they need to click to activate their account. <user> and <friend> codes will be replaced by your name and friend name, but they are optional.") %> | ||
7 | + <%= labelled_form_field(_('Invitation text:'), text_area_tag(:mail_template, mail_template, :cols => 72, :rows => 8)) %> | ||
8 | +</div> |
@@ -0,0 +1,41 @@ | @@ -0,0 +1,41 @@ | ||
1 | +<% header ||='h2' %> | ||
2 | +<<%= header %>><%= _('Step 1 of 2: Select address book') %></<%= header %>> | ||
3 | + | ||
4 | +<%= form_tag do %> | ||
5 | + | ||
6 | + <%= [ | ||
7 | + radio_button_tag(:import_from, "manual", @import_from == "manual", :onclick => 'hide_invite_friend_login_password()') + content_tag('label', _('Manually (empty field)'), :for => "import_from_manual"), | ||
8 | + radio_button_tag(:import_from, "gmail", @import_from == "gmail", :onclick => 'show_invite_friend_login_password(this.value)') + content_tag('label', 'Gmail', :for => 'import_from_gmail'), | ||
9 | + radio_button_tag(:import_from, "yahoo", @import_from == "yahoo", :onclick => 'show_invite_friend_login_password(this.value)') + content_tag('label', 'Yahoo', :for => "import_from_yahoo"), | ||
10 | + radio_button_tag(:import_from, "hotmail", @import_from == "hotmail", :onclick => 'show_invite_friend_login_password(this.value)') + content_tag('label', 'Hotmail', :for => "import_from_hotmail") | ||
11 | + ].join("\n<br/>\n") %> | ||
12 | + | ||
13 | + <script type="text/javascript"> | ||
14 | + function hide_invite_friend_login_password() { | ||
15 | + $('invite-friends-login-password').hide(); | ||
16 | + } | ||
17 | + function show_invite_friend_login_password(option) { | ||
18 | + if (option == 'hotmail') { | ||
19 | + $('hotmail_username_tip').show(); | ||
20 | + } else { | ||
21 | + $('hotmail_username_tip').hide(); | ||
22 | + } | ||
23 | + $('invite-friends-login-password').show(); | ||
24 | + $('login').focus(); | ||
25 | + } | ||
26 | + </script> | ||
27 | + <div id='invite-friends-login-password' <%= "style='display: none;'" if (@import_from == 'manual') %>> | ||
28 | + <div id='hotmail_username_tip'> | ||
29 | + <%= ui_icon('ui-icon-alert') %> | ||
30 | + <%= _('Please type your username in the format yourname@example.com') %> | ||
31 | + </div> | ||
32 | + | ||
33 | + <%= labelled_form_field(_("Username") + ":", text_field_tag(:login, @login)) %> | ||
34 | + <%= labelled_form_field(_("Password") + ":", password_field_tag(:password)) %> | ||
35 | + </div> | ||
36 | + | ||
37 | + <% button_bar do %> | ||
38 | + <%= submit_button(:forward, _("Next")) %> | ||
39 | + <% end %> | ||
40 | + <p><%= _("We won't store your password or contact anyone without your permission.") %></p> | ||
41 | +<% end %> |
@@ -0,0 +1,42 @@ | @@ -0,0 +1,42 @@ | ||
1 | +<% if profile.person? %> | ||
2 | + <h1><%= _('Ask for friendship') %></h1> | ||
3 | + <% description = _('You can search for user profiles and ask them to become your friends.') %> | ||
4 | +<% else %> | ||
5 | + <h1><%= _('Invite people to join') %></h1> | ||
6 | + <% description = _('You can search for user profiles and invite them to join this group.') %> | ||
7 | +<% end %> | ||
8 | + | ||
9 | +<h3> | ||
10 | + <%= _("Choose person by:") %> | ||
11 | +</h3> | ||
12 | + | ||
13 | +<p> | ||
14 | + <%= labelled_radio_button _("Name"), :invite_friend_by, 1, true, :id => "invite_friend_by_name", :class => "invite_friend_by" %> | ||
15 | + <%= labelled_radio_button _("Email"), :invite_friend_by, 2, false, :id => "invite_friend_by_email", :class => "invite_friend_by" %> | ||
16 | +</p> | ||
17 | + | ||
18 | +<div class='invite_by_name'> | ||
19 | + <p><%= description %></p> | ||
20 | + <%= form_tag :action => 'invite_registered_friend' do %> | ||
21 | + <% search_action = url_for(:action => 'search') %> | ||
22 | + <%= token_input_field_tag( | ||
23 | + :q, 'search-people', search_action, | ||
24 | + { :hint_text => _('Type in the person\'s %{search_fields}') % {:search_fields => @search_fields}, | ||
25 | + :focus => false }) %> | ||
26 | + | ||
27 | + <% button_bar do %> | ||
28 | + <%= submit_button('save', _('Invite'))%> | ||
29 | + <%= button('cancel', _('Cancel'), profile.url)%> | ||
30 | + <% end %> | ||
31 | + <% end %> | ||
32 | +</div> | ||
33 | + | ||
34 | +<div class='invite_by_email' style="display: none;"> | ||
35 | + <h2><%= _('Invite people from my e-mail contacts') %></h2> | ||
36 | + <% header = 'h3' %> | ||
37 | + | ||
38 | +<%= render :partial => 'invite/select_address_book', :locals => {:header => header} %> | ||
39 | +</div> | ||
40 | + | ||
41 | +<div id="loadingScreen"></div> | ||
42 | +<%= javascript_include_tag 'invite' %> |
app/views/invite/select_address_book.html.erb
@@ -1,51 +0,0 @@ | @@ -1,51 +0,0 @@ | ||
1 | -<% if profile.person? %> | ||
2 | - <h1><%= _('Invite your friends') %></h1> | ||
3 | -<% else %> | ||
4 | - <h1><%= _('Invite your friends to join %s') % profile.name %></h1> | ||
5 | -<% end %> | ||
6 | - | ||
7 | -<h2><%= _('Step 1 of 2: Select address book') %></h2> | ||
8 | - | ||
9 | -<%= form_tag do %> | ||
10 | - | ||
11 | - <%= [ | ||
12 | - radio_button_tag(:import_from, "manual", @import_from == "manual", :onclick => 'hide_invite_friend_login_password()') + content_tag('label', _('Manually (empty field)'), :for => "import_from_manual"), | ||
13 | - radio_button_tag(:import_from, "gmail", @import_from == "gmail", :onclick => 'show_invite_friend_login_password(this.value)') + content_tag('label', 'Gmail', :for => 'import_from_gmail'), | ||
14 | - radio_button_tag(:import_from, "yahoo", @import_from == "yahoo", :onclick => 'show_invite_friend_login_password(this.value)') + content_tag('label', 'Yahoo', :for => "import_from_yahoo"), | ||
15 | - radio_button_tag(:import_from, "hotmail", @import_from == "hotmail", :onclick => 'show_invite_friend_login_password(this.value)') + content_tag('label', 'Hotmail', :for => "import_from_hotmail") | ||
16 | - ].join("\n<br/>\n") %> | ||
17 | - | ||
18 | - <script type="text/javascript"> | ||
19 | - function hide_invite_friend_login_password() { | ||
20 | - $('invite-friends-login-password').hide(); | ||
21 | - } | ||
22 | - function show_invite_friend_login_password(option) { | ||
23 | - if (option == 'hotmail') { | ||
24 | - $('hotmail_username_tip').show(); | ||
25 | - } else { | ||
26 | - $('hotmail_username_tip').hide(); | ||
27 | - } | ||
28 | - $('invite-friends-login-password').show(); | ||
29 | - $('login').focus(); | ||
30 | - } | ||
31 | - </script> | ||
32 | - <div id='invite-friends-login-password' <%= "style='display: none;'" if (@import_from == 'manual') %>> | ||
33 | - <div id='hotmail_username_tip'> | ||
34 | - <%= ui_icon('ui-icon-alert') %> | ||
35 | - <%= _('Please type your username in the format yourname@example.com') %> | ||
36 | - </div> | ||
37 | - | ||
38 | - <%= labelled_form_field(_("Username") + ":", text_field_tag(:login, @login)) %> | ||
39 | - <%= labelled_form_field(_("Password") + ":", password_field_tag(:password)) %> | ||
40 | - </div> | ||
41 | - | ||
42 | - <% button_bar do %> | ||
43 | - <%= submit_button(:forward, _("Next")) %> | ||
44 | - <% end %> | ||
45 | - <p><%= _("We won't store your password or contact anyone without your permission.") %></p> | ||
46 | -<% end %> | ||
47 | - | ||
48 | -<div id="loadingScreen"></div> | ||
49 | - | ||
50 | - | ||
51 | - |
app/views/invite/select_friends.html.erb
1 | <%= render :partial => 'invite/dialog_wait_loading', :locals => {:contact_list => @contact_list.id } if @import_from != 'manual' %> | 1 | <%= render :partial => 'invite/dialog_wait_loading', :locals => {:contact_list => @contact_list.id } if @import_from != 'manual' %> |
2 | 2 | ||
3 | <% if profile.person? %> | 3 | <% if profile.person? %> |
4 | - <h1><%= _('Invite your friends') %></h1> | 4 | + <h1><%= _('Invite people') %></h1> |
5 | <% else %> | 5 | <% else %> |
6 | - <h1><%= _('Invite your friends to join %s') % profile.name %></h1> | 6 | + <h1><%= _('Invite people to join') %></h1> |
7 | <% end %> | 7 | <% end %> |
8 | 8 | ||
9 | 9 | ||
10 | -<h2><%= _('Step 2 of 2: Selecting Friends') %></h2> | 10 | +<h2><%= _('Step 2 of 2: Selecting People') %></h2> |
11 | 11 | ||
12 | -<%= button(:back, _('Back'), { :action => 'select_address_book' }, :id => 'invitation_back_button') %> | 12 | +<%= button(:back, _('Back'), { :action => 'invite_friends' }, :id => 'invitation_back_button') %> |
13 | 13 | ||
14 | <p> | 14 | <p> |
15 | -<%= _('Indicate which friends you want to invite.') %> | 15 | +<%= _('Indicate which people you want to invite.') %> |
16 | </p> | 16 | </p> |
17 | 17 | ||
18 | <%= form_tag do %> | 18 | <%= form_tag do %> |
@@ -30,16 +30,9 @@ | @@ -30,16 +30,9 @@ | ||
30 | </div> | 30 | </div> |
31 | <% end -%> | 31 | <% end -%> |
32 | 32 | ||
33 | - <br/> | ||
34 | - | ||
35 | - <%= link_to ('Personalize invitation mail'), nil, :onclick => "jQuery('#invitation-mail_template').show(); return false;" %> | ||
36 | - | ||
37 | - <div id='invitation-mail_template' style='display:none'> | ||
38 | - <%= h _("Now enter an invitation message. You must keep the <url> code in your invitation text. When your friends receive the invitation e-mail, <url> will be replaced by a link that they need to click to activate their account. <user> and <friend> codes will be replaced by your name and friend name, but they are optional.") %> | ||
39 | - <%= labelled_form_field(_('Invitation text:'), text_area_tag(:mail_template, @mail_template, :cols => 72, :rows => 8)) %> | ||
40 | - </div> | 33 | + <%= render :partial => 'invite/personalize_invitation_mail', :locals => {:mail_template => @mail_template } %> |
41 | 34 | ||
42 | <% button_bar do %> | 35 | <% button_bar do %> |
43 | - <%= submit_button(:ok, _("Invite my friends!")) %> | 36 | + <%= submit_button(:ok, _("Invite!")) %> |
44 | <% end %> | 37 | <% end %> |
45 | <% end %> | 38 | <% end %> |
app/views/layouts/_javascript.html.erb
@@ -2,8 +2,8 @@ | @@ -2,8 +2,8 @@ | ||
2 | 'jquery-2.1.1.min', 'jquery-migrate-1.2.1', | 2 | 'jquery-2.1.1.min', 'jquery-migrate-1.2.1', |
3 | 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'colorbox', | 3 | 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'colorbox', |
4 | 'jquery-ui-1.10.4/js/jquery-ui-1.10.4.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery-validation/jquery.validate', | 4 | 'jquery-ui-1.10.4/js/jquery-ui-1.10.4.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery-validation/jquery.validate', |
5 | -'jquery.cookie', 'jquery.ba-bbq.min.js', 'reflection', 'jquery.tokeninput', | ||
6 | -'add-and-join', 'report-abuse', 'catalog', 'manage-products', 'autogrow', | 5 | +'jquery.cookie', 'jquery.ba-bbq.min.js', 'reflection', 'jquery.tokeninput', 'jquery.typewatch', 'jquery.textchange', |
6 | +'add-and-join', 'report-abuse', 'catalog', 'manage-products', 'autogrow', 'select-or-die/_src/selectordie', | ||
7 | 'jquery-timepicker-addon/dist/jquery-ui-timepicker-addon', 'application.js', 'rails.js', 'inputosaurus.js', :cache => 'cache/application' %> | 7 | 'jquery-timepicker-addon/dist/jquery-ui-timepicker-addon', 'application.js', 'rails.js', 'inputosaurus.js', :cache => 'cache/application' %> |
8 | 8 | ||
9 | <% language = FastGettext.locale %> | 9 | <% language = FastGettext.locale %> |
app/views/layouts/_user.html.erb
@@ -10,16 +10,17 @@ | @@ -10,16 +10,17 @@ | ||
10 | <%= _("<span class='login'>%s</span>") % thickbox_inline_popup_link('<i class="icon-menu-login"></i><strong>' + _('Login') + '</strong>', login_url, 'inlineLoginBox', :id => 'link_login') %> | 10 | <%= _("<span class='login'>%s</span>") % thickbox_inline_popup_link('<i class="icon-menu-login"></i><strong>' + _('Login') + '</strong>', login_url, 'inlineLoginBox', :id => 'link_login') %> |
11 | <%= @plugins.dispatch(:alternative_authentication_link).collect { |content| instance_exec(&content) }.join("") %> | 11 | <%= @plugins.dispatch(:alternative_authentication_link).collect { |content| instance_exec(&content) }.join("") %> |
12 | 12 | ||
13 | - <div id='inlineLoginBox' style='display: none;'> | ||
14 | - <%= render :file => 'account/login', :locals => { :is_thickbox => true } %> | ||
15 | - </div> | 13 | + <div id='inlineLoginBox' style='display: none;'> |
14 | + <%= render :file => 'account/login', :locals => { :is_thickbox => true } %> | ||
15 | + </div> | ||
16 | 16 | ||
17 | - <% unless @plugins.dispatch(:allow_user_registration).include?(false) %> | ||
18 | - <%= _("<span class='or'>or</span> <span class='signup'>%s</span>") % link_to('<strong>' + _('Sign up') + '</strong>', :controller => 'account', :action => 'signup')%> | ||
19 | - <% end %> | ||
20 | - </span> | 17 | + <% unless @plugins.dispatch(:allow_user_registration).include?(false) %> |
18 | + <%= _("<span class='or'>or</span> <span class='signup'>%s</span>") % link_to('<strong>' + _('Sign up') + '</strong>', :controller => 'account', :action => 'signup')%> | ||
19 | + <% end %> | ||
20 | + | ||
21 | + </span> | ||
21 | <% end %> | 22 | <% end %> |
22 | - <form action="/search" id="top-search" class="search_form clean" method="get"> | 23 | + <form action="/search/articles" id="top-search" class="search_form clean" method="get"> |
23 | <input name="query" size="15" title="<%=_('Search...')%>" onfocus="this.form.className='focused';" onblur="this.form.className=''" /> | 24 | <input name="query" size="15" title="<%=_('Search...')%>" onfocus="this.form.className='focused';" onblur="this.form.className=''" /> |
24 | <div><%=_('Press <strong>Enter</strong> to send the search query.')%></div> | 25 | <div><%=_('Press <strong>Enter</strong> to send the search query.')%></div> |
25 | <%= javascript_tag 'jQuery("#user form input").hint();' %> | 26 | <%= javascript_tag 'jQuery("#user form input").hint();' %> |
@@ -0,0 +1,7 @@ | @@ -0,0 +1,7 @@ | ||
1 | +<h1><%= _("Connections with %s") % @suggestion.suggestion.name %></h1> | ||
2 | + | ||
3 | +<% button_bar do %> | ||
4 | + <%= button(:back, _('Go to groups list'), :controller => 'memberships') %> | ||
5 | +<% end %> | ||
6 | + | ||
7 | +<%= render :partial => 'shared/profile_connections', :locals => { :suggestion => @suggestion, :tags => @tags, :profiles => @profiles } %> |
app/views/memberships/index.html.erb
@@ -16,6 +16,8 @@ | @@ -16,6 +16,8 @@ | ||
16 | <%= labelled_select(_('Filter')+': ', :filter_type, :first, :last, @filter, type_collection, :id => 'memberships_filter')%> | 16 | <%= labelled_select(_('Filter')+': ', :filter_type, :first, :last, @filter, type_collection, :id => 'memberships_filter')%> |
17 | </p> | 17 | </p> |
18 | 18 | ||
19 | +<p><%= link_to _('See some suggestions of communities...'), :action => 'suggest' %></p> | ||
20 | + | ||
19 | <% if @memberships.empty? %> | 21 | <% if @memberships.empty? %> |
20 | <p> | 22 | <p> |
21 | <em><%= _('No groups to list') %></em> | 23 | <em><%= _('No groups to list') %></em> |
@@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
1 | +<h1><%= _("Communities suggestions for %s") % profile.name %></h1> | ||
2 | + | ||
3 | +<% button_bar do %> | ||
4 | + <%= button(:back, _('Go to groups list'), :controller => 'memberships') %> | ||
5 | +<% end %> | ||
6 | + | ||
7 | +<div class="profiles-suggestions"> | ||
8 | + <%= render :partial => 'shared/profile_suggestions_list', :locals => { :suggestions => @suggestions, :collection => :communities_suggestions, :per_page => 12 } %> | ||
9 | +</div> |
@@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
1 | +<h1><%= _('Community created') %></h1> | ||
2 | +<p><%= _("Your community (%s) was successfully created.") % @community.name %></p> | ||
3 | +<p><%= link_to _('You can manage your community now.'), @community.admin_url %></p> | ||
4 | + | ||
5 | +<%= render :partial => 'shared/template_welcome_page', :locals => {:template => @community.template, :header => _("What can I do with a %s?")} %> | ||
6 | + | ||
7 | +<% button_bar do %> | ||
8 | + <%= button :back, _('Back'), @back_to %> | ||
9 | +<% end %> |
app/views/profile/_upload_image.html.erb
@@ -10,5 +10,5 @@ | @@ -10,5 +10,5 @@ | ||
10 | </div> | 10 | </div> |
11 | </div> | 11 | </div> |
12 | </div> | 12 | </div> |
13 | -<div title='<%= activity.target.class.short_description %>' class='profile-activity-icon icon-new icon-newgallery'></div> | 13 | +<div title='<%#= activity.target.class.short_description %>' class='profile-activity-icon icon-new icon-newgallery'></div> |
14 | <br/> | 14 | <br/> |
app/views/profile/friends.html.erb
@@ -18,7 +18,7 @@ | @@ -18,7 +18,7 @@ | ||
18 | <%= button :back, _('Go back'), { :controller => 'profile' } %> | 18 | <%= button :back, _('Go back'), { :controller => 'profile' } %> |
19 | <% if user == profile %> | 19 | <% if user == profile %> |
20 | <%= button :edit, _('Manage my friends'), :controller => 'friends', :action => 'index', :profile => profile.identifier %> | 20 | <%= button :edit, _('Manage my friends'), :controller => 'friends', :action => 'index', :profile => profile.identifier %> |
21 | - <%= button(:search, _('Invite people from my e-mail contacts'), :controller => 'invite', :action => 'select_address_book') %> | 21 | + <%= button(:person, _('Invite people'), :controller => 'invite', :action => 'invite_friends') %> |
22 | <% end %> | 22 | <% end %> |
23 | <% end %> | 23 | <% end %> |
24 | 24 |
app/views/profile/members.html.erb
@@ -18,7 +18,7 @@ | @@ -18,7 +18,7 @@ | ||
18 | <%= button :back, _('Go back'), { :controller => 'profile' } %> | 18 | <%= button :back, _('Go back'), { :controller => 'profile' } %> |
19 | <% if profile.community? and user %> | 19 | <% if profile.community? and user %> |
20 | <% if user.has_permission?(:invite_members, profile) %> | 20 | <% if user.has_permission?(:invite_members, profile) %> |
21 | - <%= button :search, _('Invite your friends to join %s') % profile.name, :controller => 'invite', :action => 'select_address_book' %> | 21 | + <%= button :person, _('Invite people to join'), :controller => 'invite', :action => 'invite_friends' %> |
22 | <% end %> | 22 | <% end %> |
23 | <% if user.has_permission?(:send_mail_to_members, profile) %> | 23 | <% if user.has_permission?(:send_mail_to_members, profile) %> |
24 | <%= button :send, _('Send e-mail to members'), :controller => 'profile', :action => 'send_mail' %> | 24 | <%= button :send, _('Send e-mail to members'), :controller => 'profile', :action => 'send_mail' %> |
app/views/profile_editor/_moderation.html.erb
1 | <h2><%= _('Moderation options') %></h2> | 1 | <h2><%= _('Moderation options') %></h2> |
2 | <% if profile.community? %> | 2 | <% if profile.community? %> |
3 | <div style='margin-bottom: 1em'> | 3 | <div style='margin-bottom: 1em'> |
4 | + <h4><%= _('Invitation moderation:')%></h4> | ||
5 | + </div> | ||
6 | + <div style='margin-bottom: 0.5em'> | ||
7 | + <%= check_box(:profile_data, :allow_members_to_invite, :style => 'float: left') %> | ||
8 | + <div style='margin-left: 30px'> | ||
9 | + <%= _('Allow all members to send invitation (Default: only administrator)') %> | ||
10 | + </div> | ||
11 | + <br> | ||
12 | + <div class = 'invite_friends_only' > | ||
13 | + <%= check_box(:profile_data, :invite_friends_only, :style => 'float: left') %> | ||
14 | + <div style='margin-left: 30px'> | ||
15 | + <%= _('Allow members to invite only friends (Default: all users)') %> | ||
16 | + </div> | ||
17 | + </div> | ||
18 | + </div> | ||
19 | + <br> | ||
20 | + | ||
21 | + <div style='margin-bottom: 1em'> | ||
4 | <%= _('New members must be approved:')%> | 22 | <%= _('New members must be approved:')%> |
5 | </div> | 23 | </div> |
6 | <div style='margin-bottom: 0.5em'> | 24 | <div style='margin-bottom: 0.5em'> |
@@ -33,3 +51,5 @@ | @@ -33,3 +51,5 @@ | ||
33 | <%= _('<strong>After</strong> being published in this group (a moderator can always remove publicated articles later).') %> | 51 | <%= _('<strong>After</strong> being published in this group (a moderator can always remove publicated articles later).') %> |
34 | </div> | 52 | </div> |
35 | </div> | 53 | </div> |
54 | + | ||
55 | +<%= javascript_include_tag('invite') %> |
app/views/profile_editor/edit.html.erb
@@ -52,6 +52,12 @@ | @@ -52,6 +52,12 @@ | ||
52 | 'profile_data[redirect_l10n]', true, @profile.redirect_l10n | 52 | 'profile_data[redirect_l10n]', true, @profile.redirect_l10n |
53 | )%> | 53 | )%> |
54 | 54 | ||
55 | + <h2><%= _('Suggestions') %></h2> | ||
56 | + <%= labelled_check_box( | ||
57 | + _('Send me relationship suggestions by email'), | ||
58 | + 'profile_data[email_suggestions]', true, @profile.email_suggestions | ||
59 | + )%> | ||
60 | + | ||
55 | <%= | 61 | <%= |
56 | @plugins.dispatch(:profile_editor_extras).map do |content| | 62 | @plugins.dispatch(:profile_editor_extras).map do |content| |
57 | content.kind_of?(Proc) ? self.instance_exec(&content) : content | 63 | content.kind_of?(Proc) ? self.instance_exec(&content) : content |
app/views/profile_editor/index.html.erb
@@ -68,6 +68,8 @@ | @@ -68,6 +68,8 @@ | ||
68 | 68 | ||
69 | <%= control_panel_button(_('Manage SPAM'), 'manage-spam', :controller => 'spam', :action => 'index') %> | 69 | <%= control_panel_button(_('Manage SPAM'), 'manage-spam', :controller => 'spam', :action => 'index') %> |
70 | 70 | ||
71 | + <%= control_panel_button(_('Edit welcome page'), 'welcome-page', :action => 'welcome_page') if has_welcome_page %> | ||
72 | + | ||
71 | <% @plugins.dispatch(:control_panel_buttons).each do |button| %> | 73 | <% @plugins.dispatch(:control_panel_buttons).each do |button| %> |
72 | <%= control_panel_button(button[:title], button[:icon], button[:url]) %> | 74 | <%= control_panel_button(button[:title], button[:icon], button[:url]) %> |
73 | <% end %> | 75 | <% end %> |
@@ -0,0 +1,21 @@ | @@ -0,0 +1,21 @@ | ||
1 | +<h1><%= _('Edit welcome page') %></h1> | ||
2 | + | ||
3 | +<%= labelled_form_for :welcome_page do |f| %> | ||
4 | + <%= error_messages_for :welcome_page %> | ||
5 | + | ||
6 | + <%= f.check_box(:published) %> | ||
7 | + <div class='explanation'> | ||
8 | + <%= _('Your welcome page will only be displayed if this options is selected.') %> | ||
9 | + </div> | ||
10 | + | ||
11 | + <%= f.text_area(:body, :cols => 40, :style => 'width: 100%', :class => 'mceEditor') %> | ||
12 | + <div class='explanation'> | ||
13 | + <%= _('This page will be displayed to the user after his signup with this template.') %> | ||
14 | + </div> | ||
15 | + | ||
16 | + <% button_bar do%> | ||
17 | + <%= submit_button('save', _('Save'), :cancel => @back_to) %> | ||
18 | + <% end %> | ||
19 | +<% end %> | ||
20 | + | ||
21 | +<%= render :file => 'shared/tiny_mce' %> |
app/views/profile_members/_index_buttons.html.erb
@@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
2 | <%= button :back, _('Back'), :controller => 'profile_editor' %> | 2 | <%= button :back, _('Back'), :controller => 'profile_editor' %> |
3 | <%= button :add, _('Add members'), :action => 'add_members' if profile.enterprise? %> | 3 | <%= button :add, _('Add members'), :action => 'add_members' if profile.enterprise? %> |
4 | <% if profile.community? and user.has_permission?(:invite_members, profile) %> | 4 | <% if profile.community? and user.has_permission?(:invite_members, profile) %> |
5 | - <%= button :search, _('Invite your friends to join %s') % profile.short_name, :controller => 'invite', :action => 'select_address_book' %> | 5 | + <%= button :person, _('Invite people to join'), :controller => 'invite', :action => 'invite_friends' %> |
6 | <% end %> | 6 | <% end %> |
7 | <% if profile.community? and user.has_permission?(:send_mail_to_members, profile) %> | 7 | <% if profile.community? and user.has_permission?(:send_mail_to_members, profile) %> |
8 | <%= button :send, _('Send e-mail to members'), :controller => 'profile', :action => 'send_mail' %> | 8 | <%= button :send, _('Send e-mail to members'), :controller => 'profile', :action => 'send_mail' %> |
@@ -0,0 +1,15 @@ | @@ -0,0 +1,15 @@ | ||
1 | +<div id='search-content'> | ||
2 | + <% if @results %> | ||
3 | + <div class='results-found-message'> | ||
4 | + <%= _("%s results found") % @results.total_entries %> | ||
5 | + </div> | ||
6 | + | ||
7 | + <ul class='results-list'> | ||
8 | + <% @results.sort_by { |r| r.is_image? ? 0 : 1}.each do |result| %> | ||
9 | + <%= render :partial => partial_for_class(result.class), :locals => { :article => result } %> | ||
10 | + <% end %> | ||
11 | + </ul> | ||
12 | + | ||
13 | + <%= pagination_links @results %> | ||
14 | + <% end %> | ||
15 | +</div> |
app/views/profile_search/index.html.erb
@@ -3,17 +3,7 @@ | @@ -3,17 +3,7 @@ | ||
3 | 3 | ||
4 | <%= render :partial => 'shared/profile_search_form' %> | 4 | <%= render :partial => 'shared/profile_search_form' %> |
5 | 5 | ||
6 | - <% if @results %> | ||
7 | - <div class='results-found-message'> | ||
8 | - <%= _("%s results found") % @results.total_entries %> | ||
9 | - </div> | 6 | + <%= render :partial => 'results-list' %> |
10 | 7 | ||
11 | - <ul class='results-list'> | ||
12 | - <% @results.sort_by { |r| r.is_image? ? 0 : 1}.each do |result| %> | ||
13 | - <%= render :partial => partial_for_class(result.class), :locals => { :article => result } %> | ||
14 | - <% end %> | ||
15 | - </ul> | ||
16 | - | ||
17 | - <%= pagination_links @results %> | ||
18 | - <% end %> | ||
19 | </div> | 8 | </div> |
9 | +<%= javascript_include_tag 'search' %> |
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | +jQuery('#search-content').html('<%= escape_javascript(render :partial => "results-list") %>'); |
app/views/search/_compact_profile.html.erb
1 | -<% filter_label = profile.send(@filter + '_label') %> | ||
2 | -<% filter_label += show_date(profile.created_at) if @filter == 'more_recent' %> | 1 | +<% filter_label = profile.send(@order + '_label') %> |
2 | +<% filter_label += show_date(profile.created_at) if @order == 'more_recent' %> | ||
3 | <li class="search-profile-item"> | 3 | <li class="search-profile-item"> |
4 | <%= profile_image_link profile, :portrait, 'div', filter_label %> | 4 | <%= profile_image_link profile, :portrait, 'div', filter_label %> |
5 | </li> | 5 | </li> |
app/views/search/_display_results.html.erb
1 | <div id="search-results" class="<%= !multiple_search? ? 'only-one-result-box' : 'multiple-results-boxes' %>"> | 1 | <div id="search-results" class="<%= !multiple_search? ? 'only-one-result-box' : 'multiple-results-boxes' %>"> |
2 | - <% @order.each do |name| %> | 2 | + <% @assets.each do |name| %> |
3 | <% search = @searches[name] %> | 3 | <% search = @searches[name] %> |
4 | 4 | ||
5 | <div class="search-results-<%= name %> search-results-box <%= "search-results-empty" if search[:results].blank? %>"> | 5 | <div class="search-results-<%= name %> search-results-box <%= "search-results-empty" if search[:results].blank? %>"> |
app/views/search/_full_enterprise.html.erb
@@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
2 | <div class="search-enterprise-item"> | 2 | <div class="search-enterprise-item"> |
3 | <div class="search-enterprise-item-column-left"> | 3 | <div class="search-enterprise-item-column-left"> |
4 | <%= profile_image_link enterprise, :portrait, 'div', | 4 | <%= profile_image_link enterprise, :portrait, 'div', |
5 | - @filter == 'more_recent' ? enterprise.send(@filter + '_label') + show_date(enterprise.created_at) : enterprise.send(@filter + '_label') %> | 5 | + @order == 'more_recent' ? enterprise.send(@order + '_label') + show_date(enterprise.created_at) : enterprise.send(@order + '_label') %> |
6 | </div> | 6 | </div> |
7 | <div class="search-enterprise-item-column-right"> | 7 | <div class="search-enterprise-item-column-right"> |
8 | <%= link_to_homepage(enterprise.name, enterprise.identifier, :class => "search-result-title") %> | 8 | <%= link_to_homepage(enterprise.name, enterprise.identifier, :class => "search-result-title") %> |