Commit 001bf74b64072578f9f803aa8212415e9ba04024

Authored by Daniela Feitosa
Committed by Antonio Terceiro
1 parent 4957c4c1

ActionItem1020: Adding wizard on signup

app/controllers/my_profile/friends_controller.rb
... ... @@ -30,7 +30,8 @@ class FriendsController < MyProfileController
30 30 end
31 31  
32 32 def invite
33   -
  33 + @wizard = params[:wizard].blank? ? false : params[:wizard]
  34 + @step = 3
34 35 if request.post? && params[:import]
35 36 begin
36 37 case params[:import_from]
... ... @@ -80,7 +81,12 @@ class FriendsController < MyProfileController
80 81 end
81 82  
82 83 flash[:notice] = __('Your invitations have been sent.')
83   - redirect_to :action => 'index'
  84 + if @wizard
  85 + redirect_to :action => 'invite', :wizard => true
  86 + return
  87 + else
  88 + redirect_to :action => 'index'
  89 + end
84 90 else
85 91 flash.now[:notice] = __('Please enter a valid email address.')
86 92 end
... ... @@ -92,6 +98,12 @@ class FriendsController < MyProfileController
92 98  
93 99 @import_from = params[:import_from] || "manual"
94 100 @message = params[:message] || environment.message_for_friend_invitation
  101 + if @wizard
  102 + if !params[:import]
  103 + @friends = []
  104 + end
  105 + render :layout => 'wizard'
  106 + end
95 107 end
96 108  
97 109 end
... ...
app/controllers/my_profile/memberships_controller.rb
... ... @@ -8,22 +8,36 @@ class MembershipsController < MyProfileController
8 8  
9 9 def leave
10 10 @to_leave = Profile.find(params[:id])
11   -
  11 + @wizard = params[:wizard]
12 12 if request.post? && params[:confirmation]
13 13 @to_leave.remove_member(profile)
14   - redirect_to :action => 'index'
  14 + if @wizard
  15 + redirect_to :controller => 'search', :action => 'assets', :asset => 'communities', :wizard => true
  16 + else
  17 + redirect_to :action => 'index'
  18 + end
15 19 end
16 20 end
17 21  
18 22 def new_community
19 23 @community = Community.new(params[:community])
  24 + @wizard = params[:wizard].blank? ? false : params[:wizard]
20 25 if request.post?
21 26 @community.environment = environment
22 27 if @community.save
23 28 @community.add_admin(profile)
24   - redirect_to :action => 'index'
  29 + if @wizard
  30 + redirect_to :controller => 'search', :action => 'assets', :asset => 'communities', :wizard => true
  31 + return
  32 + else
  33 + redirect_to :action => 'index'
  34 + return
  35 + end
25 36 end
26 37 end
  38 + if @wizard
  39 + render :layout => 'wizard'
  40 + end
27 41 end
28 42  
29 43 def destroy_community
... ...
app/controllers/public/account_controller.rb
... ... @@ -43,6 +43,8 @@ class AccountController < ApplicationController
43 43 # action to register an user to the application
44 44 def signup
45 45 @invitation_code = params[:invitation_code]
  46 + @wizard = params[:wizard].blank? ? false : params[:wizard]
  47 + @step = 1
46 48 begin
47 49 @user = User.new(params[:user])
48 50 @user.terms_of_use = environment.terms_of_use
... ... @@ -60,15 +62,36 @@ class AccountController < ApplicationController
60 62 invitation.update_attributes!({:friend => @user.person})
61 63 invitation.finish
62 64 end
63   - go_to_user_initial_page if redirect?
64 65 flash[:notice] = _("Thanks for signing up!")
  66 + if @wizard
  67 + redirect_to :controller => 'search', :action => 'assets', :asset => 'communities', :wizard => true
  68 + return
  69 + else
  70 + go_to_user_initial_page if redirect?
  71 + end
65 72 end
  73 + if @wizard
  74 + render :layout => 'wizard'
  75 + end
66 76 rescue ActiveRecord::RecordInvalid
67 77 @person.valid?
68   - render :action => 'signup'
  78 + if @wizard
  79 + render :action => 'signup', :layout => 'wizard'
  80 + else
  81 + render :action => 'signup'
  82 + end
69 83 end
70 84 end
71 85  
  86 + def wizard
  87 + render :layout => false
  88 + end
  89 +
  90 + def profile_details
  91 + @profile = Profile.find_by_identifier(params[:profile])
  92 + render :partial => 'profile_details', :layout => 'wizard'
  93 + end
  94 +
72 95 # action to perform logout from the application
73 96 def logout
74 97 self.current_user.person.update_attribute(:last_lang, cookies[:lang])
... ... @@ -204,6 +227,20 @@ class AccountController < ApplicationController
204 227 end
205 228 end
206 229  
  230 + def check_url
  231 + @identifier = params[:identifier]
  232 + valid = Person.is_available?(@identifier)
  233 + if valid
  234 + @status = _('Available!')
  235 + @status_class = 'available'
  236 + else
  237 + @status = _('Unavailable!')
  238 + @status_class = 'unavailable'
  239 + end
  240 + @url = environment.top_url + '/' + @identifier
  241 + render :partial => 'identifier_status'
  242 + end
  243 +
207 244 protected
208 245  
209 246 def redirect?
... ...
app/controllers/public/profile_controller.rb
... ... @@ -7,11 +7,11 @@ class ProfileController < PublicController
7 7 helper TagsHelper
8 8  
9 9 def index
10   - @tags = profile.tags
  10 + @tags = profile.article_tags
11 11 end
12 12  
13 13 def tags
14   - @tags = profile.tags
  14 + @tags = profile.article_tags
15 15 end
16 16  
17 17 def tag
... ... @@ -44,10 +44,15 @@ class ProfileController < PublicController
44 44 end
45 45  
46 46 def join
  47 + @wizard = params[:wizard]
47 48 if request.post? && params[:confirmation]
48 49 profile.add_member(current_user.person)
49 50 flash[:notice] = _('%s administrator still needs to accept you as member.') % profile.name if profile.closed?
50   - redirect_to profile.url
  51 + if @wizard
  52 + redirect_to :controller => 'search', :action => 'assets', :asset => 'communities', :wizard => true
  53 + else
  54 + redirect_to profile.url
  55 + end
51 56 else
52 57 if request.xhr?
53 58 render :layout => false
... ...
app/controllers/public/search_controller.rb
... ... @@ -151,6 +151,8 @@ class SearchController < PublicController
151 151 end
152 152  
153 153 def index
  154 + @wizard = params[:wizard].blank? ? false : params[:wizard]
  155 + @step = 2
154 156 @query = params[:query] || ''
155 157 @filtered_query = remove_stop_words(@query)
156 158 @product_category = ProductCategory.find(params[:product_category]) if params[:product_category]
... ... @@ -175,12 +177,20 @@ class SearchController < PublicController
175 177 if respond_to?(specific_action)
176 178 @asset_name = getterm(@names[@results.keys.first])
177 179 send(specific_action)
178   - render :action => specific_action
  180 + if @wizard
  181 + render :action => specific_action, :layout => 'wizard'
  182 + else
  183 + render :action => specific_action
  184 + end
179 185 return
180 186 end
181 187 end
182 188  
183   - render :action => 'index'
  189 + if @wizard
  190 + render :action => 'index', :layout => 'wizard'
  191 + else
  192 + render :action => 'index'
  193 + end
184 194 end
185 195  
186 196 alias :assets :index
... ...
app/helpers/account_helper.rb
1 1 module AccountHelper
2   -end
3 2 \ No newline at end of file
  3 +
  4 + include GetText
  5 +
  6 + def button_to_step(type, step, current_step, html_options = {})
  7 + if current_step == step
  8 + the_class = 'active'
  9 + if html_options.has_key?(:class)
  10 + html_options[:class] << " #{the_class}"
  11 + else
  12 + html_options[:class] = the_class
  13 + end
  14 + end
  15 + if step == 1
  16 + url = '#'
  17 + else
  18 + url = send('url_step_' + step.to_s)
  19 + end
  20 + button(type, step.to_s, url, html_options)
  21 + end
  22 +
  23 + def button_to_step_without_text(type, step, html_options = {})
  24 + url = 'url_step_' + step
  25 + button_without_text(type, step, send(url), html_options)
  26 + end
  27 +
  28 + def button_to_previous_step(step, html_options = {})
  29 + step = step - 1
  30 + if step > 1
  31 + button_to_step_without_text(:left, step.to_s, html_options)
  32 + end
  33 + end
  34 +
  35 + def button_to_next_step(step, html_options = {})
  36 + step = step + 1
  37 + if step < 4
  38 + button_to_step_without_text(:forward, step.to_s, html_options)
  39 + end
  40 + end
  41 +
  42 + def url_step_1
  43 + options = {:controller => 'account', :action => 'signup', :wizard => true}
  44 + Noosfero.url_options.merge(options)
  45 + end
  46 +
  47 + def url_step_2
  48 + options = {:controller => 'search', :action => 'assets', :asset => 'communities', :wizard => true}
  49 + Noosfero.url_options.merge(options)
  50 + end
  51 +
  52 + def url_step_3
  53 + options = {:controller => 'friends', :action => 'invite', :profile => user.identifier, :wizard => true}
  54 + Noosfero.url_options.merge(options)
  55 + end
  56 +
  57 +end
... ...
app/helpers/application_helper.rb
... ... @@ -24,6 +24,8 @@ module ApplicationHelper
24 24  
25 25 include DisplayHelper
26 26  
  27 + include AccountHelper
  28 +
27 29 # Displays context help. You can pass the content of the help message as the
28 30 # first parameter or using template code inside a block passed to this
29 31 # method. *Note*: the block is ignored if <tt>content</tt> is not
... ... @@ -403,6 +405,30 @@ module ApplicationHelper
403 405 end
404 406 end
405 407  
  408 + # displays a link to add the profile with its image (as generated by
  409 + # #profile_image) or only its name below.
  410 + def profile_add_link( profile, image=false, size=:portrait, tag='li')
  411 + the_class = profile.members.include?(user) ? 'profile_member' : ''
  412 + name = profile.short_name
  413 + if image
  414 + display = content_tag( 'span', profile_image( profile, size ), :class => 'profile-image' ) +
  415 + content_tag( 'span', name, :class => 'org' ) +
  416 + profile_cat_icons( profile )
  417 + the_class << ' vcard'
  418 + else
  419 + display = content_tag( 'span', name, :class => 'org' )
  420 + end
  421 + content_tag tag,
  422 + link_to_remote( display,
  423 + :update => 'search-results',
  424 + :url => {:controller => 'account', :action => 'profile_details', :profile => profile.identifier},
  425 + :onclick => 'document.location.href = this.href', # work-arround for ie.
  426 + :class => 'profile_link url',
  427 + :help => _('Click on this icon to add <b>%s</b>\'s to your network') % profile.name,
  428 + :title => profile.name ),
  429 + :class => the_class
  430 + end
  431 +
406 432 # displays a link to the profile homepage with its image (as generated by
407 433 # #profile_image) and its name below it.
408 434 def profile_image_link( profile, size=:portrait, tag='li' )
... ...
app/helpers/friends_helper.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +module FriendsHelper
  2 +
  3 + def link_to_import(text, options = {})
  4 + options.merge!({:action => 'invite', :import => 1, :wizard => true})
  5 + link_to text, options
  6 + end
  7 +end
... ...
app/models/environment.rb
... ... @@ -46,6 +46,7 @@ class Environment &lt; ActiveRecord::Base
46 46 'wysiwyg_editor_for_environment_home' => _('Use WYSIWYG editor to edit environment home page'),
47 47 'media_panel' => _('Media panel in WYSIWYG editor'),
48 48 'select_preferred_domain' => _('Select preferred domains per profile'),
  49 + 'display_wizard_signup' => _('Display wizard signup'),
49 50 }
50 51 end
51 52  
... ...
app/models/profile.rb
... ... @@ -45,6 +45,8 @@ class Profile &lt; ActiveRecord::Base
45 45  
46 46 acts_as_searchable :additional_fields => [ :extra_data_for_index ]
47 47  
  48 + acts_as_taggable
  49 +
48 50 # FIXME ugly workaround
49 51 def self.human_attribute_name(attrib)
50 52 _(self.superclass.human_attribute_name(attrib))
... ... @@ -193,6 +195,10 @@ class Profile &lt; ActiveRecord::Base
193 195 self[:identifier] = value
194 196 end
195 197  
  198 + def self.is_available?(identifier)
  199 + !(identifier =~ IDENTIFIER_FORMAT).nil? && !RESERVED_IDENTIFIERS.include?(identifier) && Profile.find(:first, :conditions => ['environment_id = ? and identifier = ?', Environment.default.id, identifier]).nil?
  200 + end
  201 +
196 202 validates_presence_of :identifier, :name
197 203 validates_format_of :identifier, :with => IDENTIFIER_FORMAT, :if => lambda { |profile| !profile.identifier.blank? }
198 204 validates_exclusion_of :identifier, :in => RESERVED_IDENTIFIERS
... ... @@ -370,7 +376,7 @@ class Profile &lt; ActiveRecord::Base
370 376 end
371 377  
372 378 # FIXME this can be SLOW
373   - def tags
  379 + def article_tags
374 380 totals = {}
375 381 articles.each do |article|
376 382 article.tags.each do |tag|
... ...
app/models/tags_block.rb
... ... @@ -18,12 +18,12 @@ class TagsBlock &lt; Block
18 18 end
19 19  
20 20 def content
21   - tags = owner.tags
  21 + tags = owner.article_tags
22 22 return '' if tags.empty?
23 23  
24 24 block_title(title) +
25 25 "\n<div class='tag_cloud'>\n"+
26   - tag_cloud( owner.tags, :id,
  26 + tag_cloud( tags, :id,
27 27 owner.generate_url(:controller => 'profile', :action => 'tag'),
28 28 :max_size => 16, :min_size => 9 ) +
29 29 "\n</div><!-- end class='tag_cloud' -->\n";
... ...
app/views/account/_identifier_status.rhtml 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +<div class='status-identifier'>
  2 + <p><%= @url %> <span class='<%= @status_class %>'><%= @status %></span> </p>
  3 +</div>
... ...
app/views/account/_profile_details.rhtml 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +<div id='profile-details'>
  2 + <%= image_tag(profile_icon(@profile, :portrait)) %>
  3 +
  4 + <strong><%= @profile.short_name %></strong><br/>
  5 + <%= _('Type: %s') % getterm(@profile.class.name) %> <br/>
  6 + <%= _('Description: %s') % @profile.description %> <br/>
  7 + <%= _('Members: %s') % @profile.members.size.to_s %> <br/>
  8 + <%= _('Created at: %s') % show_date(@profile.created_at) %> <br/>
  9 +
  10 +<% form_tag({ :profile => @profile.identifier, :controller => 'profile', :action => 'join'}) do %>
  11 + <%= hidden_field_tag(:confirmation, 1) %>
  12 + <%= hidden_field_tag(:wizard, true) %>
  13 + <% if @profile.members.include?(user) %>
  14 + <%= link_to( _('Leave'), { :profile => user.identifier, :controller => 'memberships', :action => 'leave', :id => @profile.id, :confirmation => 1, :wizard => true }, :method => 'post') %>
  15 + <% else %>
  16 + <%= submit_button(:ok, _("Join now")) %>
  17 + <% end %>
  18 + <%= button(:back, _('Back'), {:controller => 'search', :action => 'assets', :asset => 'communities', :wizard => true}) %>
  19 +<% end %>
  20 +
  21 +</div>
... ...
app/views/account/_signup_form.rhtml
1 1 <%= error_messages_for :user, :person %>
2 2  
3   -<% if ! defined? hidden_atention || ! hidden_atention %>
4   -<p/>
5   -<div class="atention">
6   -<%= _('Dear user, welcome to the %s network. To start your participation
7   -in this space, fill in the fields below. After this operation, your login and
8   -password will be registered, allowing you to create %s and %s
9   -in this environment.') % [environment.name, __('communities'), __('enterprises')] %>
10   -</div>
  3 +<% if !@wizard %>
  4 + <% if ! defined? hidden_atention || ! hidden_atention %>
  5 + <p/>
  6 + <div class="atention">
  7 + <%= _('Dear user, welcome to the %s network. To start your participation
  8 + in this space, fill in the fields below. After this operation, your login and
  9 + password will be registered, allowing you to create %s and %s
  10 + in this environment.') % [environment.name, __('communities'), __('enterprises')] %>
  11 + </div>
  12 + <% end %>
11 13 <% end %>
12 14  
13 15 <% labelled_form_for :user, @user,
... ... @@ -16,12 +18,19 @@ in this environment.&#39;) % [environment.name, __(&#39;communities&#39;), __(&#39;enterprises&#39;)
16 18  
17 19 <%= hidden_field_tag :invitation_code, @invitation_code %>
18 20  
  21 +<%= hidden_field_tag :wizard, @wizard %>
  22 +
19 23 <%= required_fields_message %>
20 24  
21 25 <%= required f.text_field(:login,
22   - :onchange => 'this.value = convToValidLogin( this.value )') %>
  26 + :onchange => 'this.value = convToValidLogin( this.value )') %>
23 27 <small><%= help %></small>
24 28  
  29 +<%= observe_field 'user_login', :url => {:action => 'check_url'}, :with => 'identifier', :update => 'url-check' %>
  30 +
  31 +<div id='url-check'>
  32 +</div>
  33 +
25 34 <%= required f.text_field(:email,
26 35 :help => help=_('This e-mail address will be used to contact you.')) %>
27 36 <small><%= help %></small>
... ... @@ -41,13 +50,18 @@ in this environment.&#39;) % [environment.name, __(&#39;communities&#39;), __(&#39;enterprises&#39;)
41 50 <%= icaptcha_field() %>
42 51  
43 52 <% if @terms_of_use %>
44   - <div style='height: 200px; overflow: auto;'>
  53 + <%= _("By clicking on 'I accept the terms of use' below you are agreeing to the %s") %
  54 + link_to_function(_('Terms of use'), nil) do |page|
  55 + page['terms-of-use'].show
  56 + end %>
  57 +
  58 + <div id='terms-of-use' style='max-height: 200px; overflow: auto; display:none;'>
45 59 <%= @terms_of_use %>
  60 + <%= link_to_function(_('Hide'), nil) do |page|
  61 + page['terms-of-use'].hide
  62 + end %>
46 63 </div>
47   - <p>
48   - <%= check_box 'user', 'terms_accepted' %>
49   - <%= _('I accept the terms of use') %>
50   - </p>
  64 + <p><%= labelled_check_box(_('I accept the terms of use'), 'user[terms_accepted]') %></p>
51 65 <% end %>
52 66  
53 67 <% if params[:enterprise_code] %>
... ... @@ -58,6 +72,10 @@ in this environment.&#39;) % [environment.name, __(&#39;communities&#39;), __(&#39;enterprises&#39;)
58 72 <% end %>
59 73  
60 74 <% button_bar do %>
61   - <%= submit_button('save', _('Sign up'), :cancel => {:action => 'index'}, :class => 'icon-menu-login') %>
  75 + <% if @wizard %>
  76 + <%= submit_button('save', _('Sign up'), :class => 'icon-menu-login') %>
  77 + <% else %>
  78 + <%= submit_button('save', _('Sign up'), :cancel => {:action => 'index'}, :class => 'icon-menu-login') %>
  79 + <% end %>
62 80 <% end %>
63 81 <% end -%>
... ...
app/views/account/_wizard_steps.rhtml 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +<div id='wizard-steps'>
  2 + <% button_bar do %>
  3 + <%= button_to_previous_step(@step) if @step %>
  4 + <%= button_to_step(:step, 1, @step, :class => (logged_in? ? 'logged' : 'not-logged')) %>
  5 + <% if logged_in? %>
  6 + <%= button_to_step(:step, 2, @step) %>
  7 + <%= button_to_step(:step, 3, @step) %>
  8 + <%= button_to_next_step(@step) if @step %>
  9 + <% end %>
  10 + <%= button(:ok, _('Finish'), user.url, :target => '_top') if @step == 3 %>
  11 + <% end %>
  12 +</div>
... ...
app/views/account/signup.rhtml
1 1 <h1><%= _('Signup') %></h1>
2 2 <%= render :partial => 'signup_form' %>
  3 +
  4 +<% if @wizard %>
  5 + <%= render :partial => 'wizard_steps' %>
  6 +<% end %>
... ...
app/views/account/wizard.rhtml 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<%= lightbox_close_button _('Close') %>
  2 +
  3 +<iframe id='wizard-iframe' width=100% height='420px' src="<%= url_for(:controller => 'account', :action => 'signup', :wizard => true) %>" >
  4 + <p><%= _('Your browser does not support iframes.') %></p>
  5 +</iframe>
... ...
app/views/blocks/my_network/community.rhtml
... ... @@ -4,6 +4,6 @@
4 4 <% members = owner.members.size %>
5 5 <li><%= link_to(n_( 'One member', '%s members', members) %
6 6 content_tag('b', members), owner.public_profile_url.merge(:action => 'members') ) %></li>
7   - <li><%= link_to(n_('One tag', '%s tags', owner.tags.size) %
8   - content_tag('b', owner.tags.size), owner.public_profile_url.merge(:action => 'tags')) %></li>
  7 + <li><%= link_to(n_('One tag', '%s tags', owner.article_tags.size) %
  8 + content_tag('b', owner.article_tags.size), owner.public_profile_url.merge(:action => 'tags')) %></li>
9 9 </ul>
... ...
app/views/blocks/my_network/person.rhtml
... ... @@ -5,6 +5,6 @@
5 5 content_tag('b', owner.friends.count), owner.public_profile_url.merge(:action => 'friends')) %></li>
6 6 <li><%= link_to(n__('One community', '%s communities', owner.communities.size) %
7 7 content_tag('b', owner.communities.size), owner.public_profile_url.merge(:action => 'communities')) %></li>
8   - <li><%= link_to(n_('One tag', '%s tags', owner.tags.size) %
9   - content_tag('b', owner.tags.size), owner.public_profile_url.merge(:action => 'tags')) %></li>
  8 + <li><%= link_to(n_('One tag', '%s tags', owner.article_tags.size) %
  9 + content_tag('b', owner.article_tags.size), owner.public_profile_url.merge(:action => 'tags')) %></li>
10 10 </ul>
... ...
app/views/friends/invite.rhtml
1 1 <h1><%= __('Invite your friends') %></h1>
2 2  
3   -
4 3 <% unless @friends %>
5 4  
6   - <h2><%= __('Step 1 of 1: Select address book') %></h2>
  5 + <% if !@wizard %>
  6 + <h2><%= __('Step 1 of 1: Select address book') %></h2>
  7 + <% end %>
7 8  
8 9 <% form_tag do %>
9 10 <%= hidden_field_tag(:import, 1) %>
10 11  
  12 + <%= hidden_field_tag(:wizard, @wizard) %>
  13 +
11 14 <%= [
12 15 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 16 radio_button_tag(:import_from, "gmail", @import_from == "gmail", :onclick => 'show_invite_friend_login_password()') + content_tag('label', 'Gmail', :for => 'import_from_gmail'),
... ... @@ -38,7 +41,9 @@
38 41  
39 42 <% else %>
40 43  
41   - <h2><%= __('Step 2 of 2: Selecting Friends') %></h2>
  44 + <% if !@wizard %>
  45 + <h2><%= __('Step 2 of 2: Selecting Friends') %></h2>
  46 + <% end %>
42 47 <p>
43 48 <%= __('Indicate which friends you want to invite.') %>
44 49 </p>
... ... @@ -46,6 +51,7 @@
46 51 <% form_tag do %>
47 52 <%= hidden_field_tag(:confirmation, 1) %>
48 53 <%= hidden_field_tag(:import_from, @import_from) %>
  54 + <%= hidden_field_tag(:wizard, @wizard) %>
49 55  
50 56 <div>
51 57 <%= labelled_form_field(__('Enter one e-mail address per line:'), text_area_tag(:manual_import_addresses, (@manual_import_addresses || ''), :cols => 72, :rows => 5)) %>
... ... @@ -66,7 +72,12 @@
66 72 <% end -%>
67 73  
68 74 <br/>
69   - <div>
  75 +
  76 + <%= link_to_function(_('Personalize invitation message'), nil) do |page|
  77 + page['invitation-message'].show
  78 + end %>
  79 +
  80 + <div id='invitation-message' style='display:none'>
70 81 <%= h __("Now enter an invitation message. You must keep the <url> code in your invitation message. 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.") %>
71 82 <%= labelled_form_field(__('Invitation message:'), text_area_tag(:message, @message, :cols => 72, :rows => 8)) %>
72 83 </div>
... ... @@ -76,4 +87,11 @@
76 87 <% end %>
77 88 <% end %>
78 89  
  90 + <% if @wizard && @import_from == 'manual' %>
  91 + <%= __('Import now your contacts from %s, %s or %s') % [link_to_import('GMail', :import_from => 'gmail'), link_to_import('Yahoo', :import_from => 'yahoo'), link_to_import('Hotmail', :import_from => 'hotmail')] %>
  92 + <% end %>
  93 +<% end %>
  94 +
  95 +<% if @wizard %>
  96 + <%= render :partial => 'account/wizard_steps'%>
79 97 <% end %>
... ...
app/views/home/index.rhtml
  1 +<% if environment.enabled?('display_wizard_signup') && !logged_in? %>
  2 + <%= lightbox_button(:new, _('Signup'), { :controller => 'account', :action => 'wizard' }, :class => 'wizard') %>
  3 +<% end %>
  4 +
1 5 <%= environment.description %>
2 6  
3 7 <% if environment.enabled?('enterprise_activation') %>
... ...
app/views/layouts/wizard.rhtml 0 → 100644
... ... @@ -0,0 +1,34 @@
  1 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2 +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<%= html_language %>" lang="<%= html_language %>">
  3 + <head>
  4 + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5 + <%= javascript_include_tag :defaults %>
  6 + <%= stylesheet_link_tag '/designs/icons/default/style.css' %>
  7 + <%= javascript_include_tag 'jquery-latest.js' %>
  8 + <script type="text/javascript">
  9 + jQuery.noConflict();
  10 + </script>
  11 +
  12 + <%=
  13 + # Load the principal css files:
  14 + stylesheet_import( %w( common button search forms)
  15 + ) + "\n" +
  16 + stylesheet_import( %w( common button search forms),
  17 + :themed_source => true ) + "\n" +
  18 + # Load the boxes's css file if each exists:
  19 + import_blocks_stylesheets +
  20 + stylesheet_import( "controller_"+ @controller.controller_name() ) + "\n" +
  21 + stylesheet_import( "controller_"+ @controller.controller_name(), :themed_source => true )
  22 + %>
  23 + </head>
  24 +
  25 + <body class='noosfero'>
  26 + <div id="iframe">
  27 + <div id="content">
  28 + <div id="wizard-content">
  29 + <%= yield %>
  30 + </div><!-- id="wizard-content" -->
  31 + </div><!-- id="content" -->
  32 + </div><!-- id="frame" -->
  33 + </body>
  34 +</html>
... ...
app/views/memberships/new_community.rhtml
... ... @@ -4,7 +4,7 @@
4 4  
5 5 <div style='margin-left: 20%; margin-right: 20%'>
6 6  
7   -<% labelled_form_for :community, @community do |f| %>
  7 +<% labelled_form_for :community, @community, :html => { :multipart => true } do |f| %>
8 8  
9 9 <%= required_fields_message %>
10 10  
... ... @@ -12,6 +12,17 @@
12 12  
13 13 <%= f.text_area :description, :style => 'width: 100%; height: 150px;' %>
14 14  
  15 + <%= hidden_field_tag :wizard, params[:wizard] %>
  16 +
  17 + <%= f.text_field('tag_list', :size => 64) %>
  18 + <%= content_tag( 'small', _('Separate tags with commas') ) %>
  19 +
  20 + <div id="profile_change_picture">
  21 + <% f.fields_for :image_builder, @community.image do |i| %>
  22 + <%= file_field_or_thumbnail(_('Image:'), @community.image, i) %>
  23 + <% end %>
  24 + </div>
  25 +
15 26 <div style='margin-bottom: 1em; margin-top: 1em;'>
16 27 <%= _('New members must be approved:')%>
17 28 </div>
... ... @@ -30,9 +41,17 @@
30 41  
31 42 <% button_bar do %>
32 43 <%= submit_button(:save, _('Create')) %>
33   - <%= button(:cancel, _('Cancel'), :action => 'index') %>
  44 + <% if @wizard %>
  45 + <%= button(:back, _('Back'), {:controller => 'search', :action => 'assets', :asset => 'communities', :wizard => true}) %>
  46 + <% else %>
  47 + <%= button(:cancel, _('Cancel'), :action => 'index') %>
  48 + <% end %>
34 49 <% end %>
35 50  
36 51 <% end %>
37 52  
38 53 </div>
  54 +
  55 +<% if @wizard %>
  56 + <%= render :partial => 'account/wizard_steps' %>
  57 +<% end %>
... ...
app/views/search/_display_results.rhtml
1 1 <div id="search-results" class="<%= 'only-one-result-box' if @results.size == 1 %>">
2 2  
  3 +<% if @wizard %>
  4 + <div id='visualization-mode'>
  5 + <%= button_without_text('product', '', params.merge(:visualization_mode => 'icons'), :title => _('View as icons')) %>
  6 + <%= button_without_text('todo', '', params.merge(:visualization_mode => 'list'), :title => _('View as list')) %>
  7 + </div>
  8 +<% end %>
  9 +
3 10 <%
4 11 pos2 = :odd # allow to format in a two columns layout
5 12 pos3 = 3 # allow to format in a thre columns layout
... ...
app/views/search/_profile.rhtml
1 1 <%# FIXME add more information %>
2   -<li> <%= profile_image_link profile, :portrait %> </li>
  2 +<% if (params[:visualization_mode] == 'list') && params[:wizard] %>
  3 + <%= profile_add_link profile %>
  4 +<% elsif params[:wizard] %>
  5 + <%= profile_add_link profile, true, :portrait %>
  6 +<% else %>
  7 + <%= profile_image_link profile, :portrait %>
  8 +<% end %>
... ...
app/views/search/_search_form.rhtml
1 1 <div class='search-form'>
2 2 <% simple_search = false unless defined? simple_search %>
3 3  
4   -<% form_tag( { :action => 'index', :asset => nil, :category_path => ( @category ? @category.explode_path : [] ) },
  4 +<% form_tag( { :controller => 'search', :action => 'index', :asset => nil, :category_path => ( @category ? @category.explode_path : [] ) },
5 5 :method => 'get', :class => 'search_form' ) do %>
6 6 <%= '<h3>%s</h3>' % form_title if defined? form_title %>
7 7  
8 8 <%= hidden_field_tag :display, params[:display] %>
9 9  
  10 + <%= hidden_field_tag :wizard, @wizard %>
  11 +
  12 + <%= hidden_field_tag :asset, params[:asset] %>
  13 +
10 14 <div class="search-field">
11 15 <span class="formfield">
12 16 <%= text_field_tag 'query', @query, :id => ( lightbox? ? 'popup-search-input' : '' ), :size => 50 %>
... ... @@ -18,6 +22,7 @@
18 22 <% end %>
19 23 </div>
20 24  
  25 + <% if !@wizard %>
21 26 <div id='advanced-search-options' style="display: <%= simple_search ? 'none' : 'block' %>">
22 27 <div class="search-options search-within">
23 28 <h4><%= _('Search within:') %></h4>
... ... @@ -52,6 +57,7 @@
52 57 page['advanced-search-options'].toggle
53 58 end %>
54 59 <% end %>
  60 + <% end %>
55 61  
56 62 <% if lightbox?; button_bar do %>
57 63 <%= lightbox_close_button _('Close') %>
... ...
app/views/search/communities.rhtml
... ... @@ -6,9 +6,12 @@
6 6  
7 7 <%= search_page_link_to_all( { :asset => params[:asset],
8 8 :category => @category }) %>
9   -
10 9 <%= render :partial => 'search_form', :locals => { :form_title => @query.blank? ? _('Search') : _("Refine your search"), :simple_search => true } %>
11 10  
  11 +<% if @wizard %>
  12 + <div class='atention'><%= __('Choose the communities you want to join and/or create your own.') %></div>
  13 +<% end %>
  14 +
12 15 <%# FIXME ARMENGUE %>
13 16 <%= display_results(false) %>
14 17  
... ... @@ -18,8 +21,13 @@
18 21 <% if logged_in? %>
19 22 <% button_bar do %>
20 23 <%# FIXME shouldn't the user create the community in the current environment instead of going to its home environment? %>
21   - <%= button(:add, _('New community'), user.url.merge(:controller => 'memberships', :action => 'new_community')) %>
  24 + <%= button(:add, _('New community'), user.url.merge(:controller => 'memberships', :action => 'new_community', :wizard => @wizard)) %>
22 25 <% end %>
23 26 <% end %>
24 27  
25 28 <br style="clear:both" />
  29 +
  30 +<% if @wizard %>
  31 + <%= render :partial => 'account/wizard_steps' %>
  32 +<% end %>
  33 +
... ...
public/stylesheets/common.css
... ... @@ -468,3 +468,17 @@ div.pending-tasks {
468 468 #content #access-denied p {
469 469 text-align: justify;
470 470 }
  471 +
  472 +/**** Signup wizard ****/
  473 +
  474 +#wizard-iframe {
  475 + border: none;
  476 +}
  477 +
  478 +#wizard-content {
  479 + font-size: 13px;
  480 +}
  481 +
  482 +#wizard-content h1 {
  483 + font-size: 22px;
  484 +}
... ...
test/functional/account_controller_test.rb
... ... @@ -311,6 +311,21 @@ class AccountControllerTest &lt; Test::Unit::TestCase
311 311 assert_not_equal 'unknow', Person['save_lang'].last_lang
312 312 end
313 313  
  314 + should 'signup from wizard' do
  315 + assert_difference User, :count do
  316 + post :signup, :user => { :login => 'mylogin', :password => 'mypassword', :password_confirmation => 'mypassword', :email => 'mylogin@example.com' }, :wizard => true
  317 + end
  318 + assert_redirected_to :controller => 'search', :action => 'assets', :asset => 'communities', :wizard => true
  319 + end
  320 +
  321 + should 'not have layout when fail signup from wizard' do
  322 + user = create_user('mylogin').person
  323 + post :signup, :user => { :login => 'mylogin', :password => 'mypassword', :password_confirmation => 'mypassword', :email => 'mylogin@example.com' }, :wizard => true
  324 + assert_response :success
  325 + assert_template 'signup'
  326 + assert_equal 'layouts/wizard', @response.layout
  327 + end
  328 +
314 329 ################################
315 330 # #
316 331 # Enterprise activation tests #
... ...
test/functional/friends_controller_test.rb
... ... @@ -87,6 +87,13 @@ class FriendsControllerTest &lt; Test::Unit::TestCase
87 87 end
88 88 end
89 89  
  90 + should 'actualy invite manually added addresses with name and e-mail on wizard' do
  91 + assert_difference InviteFriend, :count, 1 do
  92 + post :invite, :manual_import_addresses => "Test Name <test@test.com>", :import_from => "manual", :message => "click: <url>", :confirmation => 1, :wizard => true
  93 + assert_redirected_to :action => 'invite', :wizard => true
  94 + end
  95 + end
  96 +
90 97 should 'actually invite manually added address with only e-mail' do
91 98 assert_difference InviteFriend, :count, 1 do
92 99 post :invite, :manual_import_addresses => "test@test.com", :import_from => "manual", :message => "click: <url>", :confirmation => 1
... ... @@ -94,6 +101,13 @@ class FriendsControllerTest &lt; Test::Unit::TestCase
94 101 end
95 102 end
96 103  
  104 + should 'actually invite manually added address with only e-mail on wizard' do
  105 + assert_difference InviteFriend, :count, 1 do
  106 + post :invite, :manual_import_addresses => "test@test.com", :import_from => "manual", :message => "click: <url>", :confirmation => 1, :wizard => true
  107 + assert_redirected_to :action => 'invite', :wizard => true
  108 + end
  109 + end
  110 +
97 111 should 'actually invite manually added addresses with e-mail and other format' do
98 112 assert_difference InviteFriend, :count, 1 do
99 113 post :invite, :manual_import_addresses => "test@test.cz.com", :import_from => "manual", :message => "click: <url>", :confirmation => 1
... ... @@ -101,6 +115,13 @@ class FriendsControllerTest &lt; Test::Unit::TestCase
101 115 end
102 116 end
103 117  
  118 + should 'actually invite manually added addresses with e-mail and other format on wizard' do
  119 + assert_difference InviteFriend, :count, 1 do
  120 + post :invite, :manual_import_addresses => "test@test.cz.com", :import_from => "manual", :message => "click: <url>", :confirmation => 1, :wizard => true
  121 + assert_redirected_to :action => 'invite', :wizard => true
  122 + end
  123 + end
  124 +
104 125 should 'actually invite manually added address with friend object' do
105 126 assert_difference InviteFriend, :count, 1 do
106 127 post :invite, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :message => "click: <url>", :confirmation => 1
... ... @@ -108,10 +129,25 @@ class FriendsControllerTest &lt; Test::Unit::TestCase
108 129 end
109 130 end
110 131  
  132 + should 'actually invite manually added address with friend object on wizard' do
  133 + assert_difference InviteFriend, :count, 1 do
  134 + post :invite, :manual_import_addresses => "#{friend.name} <#{friend.email}>", :import_from => "manual", :message => "click: <url>", :confirmation => 1, :wizard => true
  135 + assert_redirected_to :action => 'invite', :wizard => true
  136 + end
  137 + end
  138 +
111 139 should 'actually invite more than one manually added addres' do
112 140 assert_difference InviteFriend, :count, 2 do
113 141 post :invite, :manual_import_addresses => "Some Friend <somefriend@email.com>\r\notherperson@bleble.net\r\n", :import_from => "manual", :message => "click: <url>", :confirmation => 1
114 142 assert_redirected_to :action => 'index'
115 143 end
116 144 end
  145 +
  146 + should 'actually invite more than one manually added addres on wizard' do
  147 + assert_difference InviteFriend, :count, 2 do
  148 + post :invite, :manual_import_addresses => "Some Friend <somefriend@email.com>\r\notherperson@bleble.net\r\n", :import_from => "manual", :message => "click: <url>", :confirmation => 1, :wizard => true
  149 + assert_redirected_to :action => 'invite', :wizard => true
  150 + end
  151 + end
  152 +
117 153 end
... ...
test/functional/memberships_controller_test.rb
... ... @@ -50,6 +50,16 @@ class MembershipsControllerTest &lt; Test::Unit::TestCase
50 50 end
51 51 end
52 52  
  53 + should 'be able to create a new community on wizard' do
  54 + assert_difference Community, :count do
  55 + post :new_community, :profile => profile.identifier, :community => { :name => 'My shiny new community', :description => 'This is a community devoted to anything interesting we find in the internet '}, :wizard => true
  56 + assert_response :redirect
  57 + assert_redirected_to :controller => 'search', :action => 'assets', :asset => 'communities', :wizard => true
  58 +
  59 + assert Community.find_by_identifier('my-shiny-new-community').members.include?(profile), "Creator user should be added as member of the community just created"
  60 + end
  61 + end
  62 +
53 63 should 'link to new community creation in index' do
54 64 get :index, :profile => profile.identifier
55 65 assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}/memberships/new_community" }
... ... @@ -124,6 +134,18 @@ class MembershipsControllerTest &lt; Test::Unit::TestCase
124 134 assert_not_includes profile.memberships, community
125 135 end
126 136  
  137 + should 'leave profile when on wizard' do
  138 + community = Community.create!(:name => 'my test community')
  139 + community.add_member(profile)
  140 + post :leave, :profile => profile.identifier, :id => community.id, :confirmation => '1', :wizard => true
  141 +
  142 + assert_response :redirect
  143 + assert_redirected_to :controller => 'search', :action => 'assets', :asset => 'communities', :wizard => true
  144 +
  145 + profile = Profile.find(@profile.id)
  146 + assert_not_includes profile.memberships, community
  147 + end
  148 +
127 149 should 'current user is added as admin after create new community' do
128 150 post :new_community, :profile => profile.identifier, :community => { :name => 'My shiny new community', :description => 'This is a community devoted to anything interesting we find in the internet '}
129 151 assert_equal Profile::Roles.admin, profile.find_roles(Community.find_by_identifier('my-shiny-new-community')).first.role
... ... @@ -199,13 +221,4 @@ class MembershipsControllerTest &lt; Test::Unit::TestCase
199 221 assert_equal 1, assigns(:community).boxes[0].blocks.size
200 222 end
201 223  
202   - should 'leave community' do
203   - community = Community.create!(:name =>'Boca do Siri', :identifier => 'boca_do_siri')
204   - community.affiliate(profile, Profile::Roles.all_roles)
205   - post :leave, :profile => profile.identifier, :id => community.id, :confirmation => true
206   -
207   - profile = Profile.find(@profile.id)
208   - assert_not_includes profile.memberships, community
209   - end
210   -
211 224 end
... ...
test/functional/profile_controller_test.rb
... ... @@ -324,7 +324,7 @@ class ProfileControllerTest &lt; Test::Unit::TestCase
324 324 end
325 325  
326 326 should 'list tags' do
327   - Person.any_instance.stubs(:tags).returns({ 'one' => 1, 'two' => 2})
  327 + Person.any_instance.stubs(:article_tags).returns({ 'one' => 1, 'two' => 2})
328 328 get :tags, :profile => 'testuser'
329 329  
330 330 assert_tag :tag => 'div', :attributes => { :class => /main-block/ }, :descendant => { :tag => 'a', :attributes => { :href => '/profile/testuser/tag/one'} }
... ... @@ -451,6 +451,18 @@ class ProfileControllerTest &lt; Test::Unit::TestCase
451 451 assert profile.memberships.include?(community), 'profile should be actually added to the community'
452 452 end
453 453  
  454 + should 'join profile from wizard' do
  455 + community = Community.create!(:name => 'my test community')
  456 + login_as @profile.identifier
  457 + post :join, :profile => community.identifier, :confirmation => '1', :wizard => true
  458 +
  459 + assert_response :redirect
  460 + assert_redirected_to :controller => 'search', :action => 'assets', :asset => 'communities', :wizard => true
  461 +
  462 + profile = Profile.find(@profile.id)
  463 + assert profile.memberships.include?(community), 'profile should be actually added to the community'
  464 + end
  465 +
454 466 should 'create task when join to closed organization' do
455 467 community = Community.create!(:name => 'my test community', :closed => true)
456 468 login_as @profile.identifier
... ...
test/functional/search_controller_test.rb
... ... @@ -238,6 +238,13 @@ class SearchControllerTest &lt; Test::Unit::TestCase
238 238 assert_equivalent [c3, c1], assigns(:results)[:communities]
239 239 end
240 240  
  241 + should 'find communities in signup wizard' do
  242 + c1 = Community.create!(:name => 'a beautiful community', :identifier => 'bea_comm', :environment => Environment.default)
  243 + get :index, :query => 'beautiful', :find_in => [ 'communities' ], :wizard => true
  244 + assert_includes assigns(:results)[:communities], c1
  245 + assert_equal 'layouts/wizard', @response.layout
  246 + end
  247 +
241 248 should 'find products' do
242 249 ent = Enterprise.create!(:name => 'teste', :identifier => 'teste')
243 250 prod = ent.products.create!(:name => 'a beautiful product')
... ... @@ -971,6 +978,19 @@ class SearchControllerTest &lt; Test::Unit::TestCase
971 978 end
972 979 end
973 980  
  981 + should 'display steps when searching on wizard' do
  982 + c1 = Community.create!(:name => 'a beautiful community', :identifier => 'bea_comm', :environment => Environment.default)
  983 + get :index, :query => 'beautiful', :find_in => [ 'communities' ], :wizard => true
  984 + assert_equal 'layouts/wizard', @response.layout
  985 + assert_tag :tag => 'div', :attributes => {:id => 'wizard-steps'}
  986 + end
  987 +
  988 + should 'not display steps when searching not on wizard' do
  989 + c1 = Community.create!(:name => 'a beautiful community', :identifier => 'bea_comm', :environment => Environment.default)
  990 + get :index, :query => 'beautiful', :find_in => [ 'communities' ]
  991 + assert_equal 'layouts/application', @response.layout
  992 + assert_no_tag :tag => 'div', :attributes => {:id => 'wizard-steps'}
  993 + end
974 994  
975 995 ##################################################################
976 996 ##################################################################
... ...
test/unit/profile_test.rb
... ... @@ -304,14 +304,20 @@ class ProfileTest &lt; Test::Unit::TestCase
304 304 ok('Profile#url must include port options when running in developers mode') { profile.url[:port] == 9999 }
305 305 end
306 306  
307   - should 'list tags for profile' do
  307 + should 'list article tags for profile' do
308 308 profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile')
309 309 profile.articles.build(:name => 'first', :tag_list => 'first-tag').save!
310 310 profile.articles.build(:name => 'second', :tag_list => 'first-tag, second-tag').save!
311 311 profile.articles.build(:name => 'third', :tag_list => 'first-tag, second-tag, third-tag').save!
312 312  
313   - assert_equal({ 'first-tag' => 3, 'second-tag' => 2, 'third-tag' => 1 }, profile.tags)
  313 + assert_equal({ 'first-tag' => 3, 'second-tag' => 2, 'third-tag' => 1 }, profile.article_tags)
  314 +
  315 + end
  316 +
  317 + should 'list tags for profile' do
  318 + profile = Profile.create!(:name => "Test Profile", :identifier => 'testprofile', :tag_list => 'first-tag, second-tag')
314 319  
  320 + assert_equal(['first-tag', 'second-tag'], profile.tags.map(&:name))
315 321 end
316 322  
317 323 should 'find content tagged with given tag' do
... ...
test/unit/tags_block_test.rb
... ... @@ -28,7 +28,7 @@ class TagsBlockTest &lt; Test::Unit::TestCase
28 28 end
29 29  
30 30 should 'return (none) when no tags to display' do
31   - block.owner.expects(:tags).returns([])
  31 + block.owner.expects(:article_tags).returns([])
32 32 assert_equal '', block.content
33 33 end
34 34  
... ...