Commit 05b6b3868ceed5b14c11afce1068f28fee8488c6

Authored by Leandro Santos
1 parent 493dd777

merging with branch AI3033-serpro_integration of rails 2.3

app/controllers/public/account_controller.rb
... ... @@ -17,6 +17,8 @@ class AccountController < ApplicationController
17 17 @user = User.find_by_activation_code(params[:activation_code]) if params[:activation_code]
18 18 if @user and @user.activate
19 19 @message = _("Your account has been activated, now you can log in!")
  20 + check_redirection
  21 + session[:join] = params[:join] unless params[:join].blank?
20 22 render :action => 'login', :userlogin => @user.login
21 23 else
22 24 session[:notice] = _("It looks like you're trying to activate an account. Perhaps have already activated this account?")
... ... @@ -35,6 +37,7 @@ class AccountController < ApplicationController
35 37 self.current_user ||= User.authenticate(params[:user][:login], params[:user][:password], environment) if params[:user]
36 38  
37 39 if logged_in?
  40 + check_join_in_community(self.current_user)
38 41 if params[:remember_me] == "1"
39 42 self.current_user.remember_me
40 43 cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at }
... ... @@ -91,6 +94,7 @@ class AccountController < ApplicationController
91 94 if session[:may_be_a_bot]
92 95 return false unless verify_recaptcha :model=>@user, :message=>_('Captcha (the human test)')
93 96 end
  97 + @user.community_to_join = session[:join]
94 98 @user.signup!
95 99 owner_role = Role.find_by_name('owner')
96 100 @user.person.affiliate(@user.person, [owner_role]) if owner_role
... ... @@ -101,6 +105,7 @@ class AccountController < ApplicationController
101 105 end
102 106 if @user.activated?
103 107 self.current_user = @user
  108 + check_join_in_community(@user)
104 109 go_to_signup_initial_page
105 110 else
106 111 @register_pending = true
... ... @@ -388,12 +393,6 @@ class AccountController < ApplicationController
388 393 end
389 394  
390 395 def go_to_initial_page
391   - if params[:redirection]
392   - session[:return_to] = @user.return_to
393   - @user.return_to = nil
394   - @user.save
395   - end
396   -
397 396 if params[:return_to]
398 397 redirect_to params[:return_to]
399 398 elsif environment.enabled?('allow_change_of_redirection_after_login')
... ... @@ -444,4 +443,19 @@ class AccountController < ApplicationController
444 443 redirect_back_or_default(default)
445 444 end
446 445 end
  446 +
  447 + def check_redirection
  448 + unless params[:redirection].blank?
  449 + session[:return_to] = @user.return_to
  450 + @user.update_attributes(:return_to => nil)
  451 + end
  452 + end
  453 +
  454 + def check_join_in_community(user)
  455 + profile_to_join = session[:join]
  456 + unless profile_to_join.blank?
  457 + environment.profiles.find_by_identifier(profile_to_join).add_member(user.person)
  458 + session.delete(:join)
  459 + end
  460 + end
447 461 end
... ...
app/controllers/public/profile_controller.rb
... ... @@ -3,7 +3,7 @@ class ProfileController < PublicController
3 3 needs_profile
4 4 before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add]
5 5 before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse, :send_mail]
6   - before_filter :login_required, :only => [:add, :join, :join_not_logged, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail]
  6 + before_filter :login_required, :only => [:add, :join, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail]
7 7  
8 8 helper TagsHelper
9 9  
... ... @@ -97,21 +97,12 @@ class ProfileController < PublicController
97 97 end
98 98  
99 99 def join_not_logged
100   - if request.post?
101   - profile.add_member(user)
102   - session[:notice] = _('%s administrator still needs to accept you as member.') % profile.name if profile.closed?
103   - redirect_to_previous_location
  100 + session[:join] = profile.identifier
  101 +
  102 + if user
  103 + redirect_to :controller => 'profile', :action => 'join'
104 104 else
105   - if user.memberships.include?(profile)
106   - session[:notice] = _('You are already a member of %s.') % profile.name
107   - redirect_to profile.url
108   - return
109   - end
110   - if request.xhr?
111   - render :layout => false
112   - else
113   - redirect_to profile.url
114   - end
  105 + redirect_to :controller => '/account', :action => 'login'
115 106 end
116 107 end
117 108  
... ...
app/models/user.rb
... ... @@ -63,6 +63,9 @@ class User < ActiveRecord::Base
63 63 self.person.preferred_domain && self.person.preferred_domain.name || self.environment.default_hostname(true)
64 64 end
65 65  
  66 + # virtual attribute used to stash which community to join on signup or login
  67 + attr_accessor :community_to_join
  68 +
66 69 class Mailer < ActionMailer::Base
67 70 def activation_email_notify(user)
68 71 user_email = "#{user.login}@#{user.email_domain}"
... ... @@ -85,7 +88,8 @@ class User &lt; ActiveRecord::Base
85 88 :activation_code => user.activation_code,
86 89 :environment => user.environment.name,
87 90 :url => user.environment.top_url,
88   - :redirection => (true if user.return_to)
  91 + :redirection => (true if user.return_to),
  92 + :join => (user.community_to_join if user.community_to_join)
89 93 end
90 94  
91 95 def signup_welcome_email(user)
... ...
features/login.feature
... ... @@ -207,3 +207,18 @@ Feature: login
207 207 | Password | 123456 |
208 208 When I press "Log in"
209 209 Then I should be on joaosilva's control panel
  210 +
  211 + Scenario: join community on login
  212 + Given the following users
  213 + | login | name |
  214 + | mariasilva | Maria Silva |
  215 + And the following communities
  216 + | name | identifier | owner |
  217 + | Free Software | freesoftware | mariasilva |
  218 + And I am on /freesoftware
  219 + When I follow "Join"
  220 + And I fill in the following:
  221 + | Username / Email | joaosilva |
  222 + | Password | 123456 |
  223 + And I press "Log in"
  224 + Then "Joao Silva" should be a member of "Free Software"
... ...
features/signup.feature
... ... @@ -250,3 +250,51 @@ Feature: signup
250 250 And I fill in "Password" with "secret"
251 251 And I press "Log in"
252 252 Then I should be on the homepage
  253 +
  254 + @selenium
  255 + Scenario: join community on signup
  256 + Given the following users
  257 + | login | name |
  258 + | mariasilva | Maria Silva |
  259 + And the following communities
  260 + | name | identifier | owner |
  261 + | Free Software | freesoftware | mariasilva |
  262 + And feature "skip_new_user_email_confirmation" is disabled on environment
  263 + And I am on /freesoftware
  264 + When I follow "Join"
  265 + And I follow "New user"
  266 + And I fill in the following within ".no-boxes":
  267 + | e-Mail | josesilva@example.com |
  268 + | Username | josesilva |
  269 + | Password | secret |
  270 + | Password confirmation | secret |
  271 + | Full name | José da Silva |
  272 + And wait for the captcha signup time
  273 + And I press "Create my account"
  274 + And I go to josesilva's confirmation URL
  275 + And I fill in "Username" with "josesilva"
  276 + And I fill in "Password" with "secret"
  277 + And I press "Log in"
  278 + Then "José da Silva" should be a member of "Free Software"
  279 +
  280 + @selenium
  281 + Scenario: join community on direct signup
  282 + Given the following users
  283 + | login | name |
  284 + | mariasilva | Maria Silva |
  285 + And the following communities
  286 + | name | identifier | owner |
  287 + | Free Software | freesoftware | mariasilva |
  288 + And feature "skip_new_user_email_confirmation" is enabled on environment
  289 + And I am on /freesoftware
  290 + When I follow "Join"
  291 + And I follow "New user"
  292 + And I fill in the following within ".no-boxes":
  293 + | e-Mail | josesilva@example.com |
  294 + | Username | josesilva |
  295 + | Password | secret |
  296 + | Password confirmation | secret |
  297 + | Full name | José da Silva |
  298 + And wait for the captcha signup time
  299 + And I press "Create my account"
  300 + Then "José da Silva" should be a member of "Free Software"
... ...
plugins/serpro_integration/controllers/serpro_integration_plugin_myprofile_controller.rb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +class SerproIntegrationPluginMyprofileController < MyProfileController
  2 + append_view_path File.join(File.dirname(__FILE__) + '/../views')
  3 +
  4 + def create_gitlab
  5 + profile.create_gitlab_project
  6 + render :update do |page|
  7 + page.replace_html 'gitlab', :partial => 'gitlab'
  8 +# page.replace_html 'gitlab', 'teste'
  9 + end
  10 +# raise 'teste my profile'
  11 + end
  12 +
  13 +end
... ...
plugins/serpro_integration/features/sonar.feature 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +Feature: require authentication to comment
  2 +
  3 + Background:
  4 + Given plugin RequireAuthToCommentPlugin is enabled on environment
  5 + And the following users
  6 + | login |
  7 + | bozo |
  8 +
  9 + Scenario: enabling unauthenticated comment per profile
  10 + Given I am logged in as "bozo"
  11 + When I edit my profile
  12 + And I check "Accept comments from unauthenticated users"
  13 + And I press "Save"
  14 + Then I edit my profile
  15 + And the "Accept comments from unauthenticated users" checkbox should be checked
... ...
plugins/serpro_integration/install.rb 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +system "gem install --user-install gitlab"
  2 +system "gem install --user-install jenkins_api_client"
... ...
plugins/serpro_integration/lib/ext/community.rb 0 → 100644
... ... @@ -0,0 +1,220 @@
  1 +require_dependency 'community'
  2 +require 'gitlab'
  3 +#require 'jenkins_api_client'
  4 +
  5 +class Community
  6 +
  7 + settings_items :allow_sonar_integration, :type => :boolean, :default => true
  8 + settings_items :allow_gitlab_integration, :type => :boolean, :default => true
  9 + settings_items :allow_jenkins_integration, :type => :boolean, :default => true
  10 +
  11 + #FIXME make test for default option
  12 + settings_items :serpro_integration_plugin, :type => Hash, :default => {}
  13 +
  14 + ##########################################
  15 + # Gitlab stuff #
  16 + ##########################################
  17 +
  18 + after_create :create_gitlab_project
  19 +
  20 + def gitlab= params
  21 + self.serpro_integration_plugin[:gitlab] = params
  22 + end
  23 +
  24 + def gitlab
  25 + self.serpro_integration_plugin[:gitlab] ||= {}
  26 + self.serpro_integration_plugin[:gitlab]
  27 + end
  28 +
  29 + def create_gitlab_project
  30 + Gitlab.endpoint = self.gitlab_host
  31 + Gitlab.private_token = self.gitlab_private_token
  32 +
  33 + user = nil
  34 +
  35 + #Find user by email
  36 + begin
  37 + user = Gitlab.users(:search => email)
  38 + rescue Gitlab::Error::NotFound, Gitlab::Error::Parsing
  39 + user = nil
  40 + end
  41 +
  42 + #User not found, create user
  43 + if user == nil || user.count == 0
  44 + user = self.admins.first
  45 + gitlab_user = Gitlab.create_user(user.email, '123456', {:username => user.identifier, :name => user.name, :provider => 'ldap'})
  46 + end
  47 +
  48 + if gitlab_user.nil?
  49 + self.gitlab[:errors] = _('Gitlab user could not be created')
  50 + return nil
  51 + end
  52 +
  53 + #Create project for user
  54 + begin
  55 + #FIXME Why this?
  56 + if gitlab_user.is_a?(Array)
  57 + gitlab_user = user[0]
  58 + end
  59 +
  60 + project_options = {}
  61 + project_options[:user_id] = gitlab_user.id
  62 + project_options[:issues_enabled ] = true
  63 + project_options[:wall_enabled] = true
  64 + project_options[:wiki_enabled] = true
  65 + project_options[:public] = true
  66 + project = Gitlab.create_project(self.identifier, project_options)
  67 +
  68 + #Create Web Hook for Jenkins' integration
  69 +# Gitlab.add_project_hook(project.id, "#{self.jenkins[:url]}/gitlab/build_now")
  70 +# createJenkinsJob(project.name, project.path_with_namespace, project.web_url, project.http_url_to_repo)
  71 +
  72 + rescue Gitlab::Error::NotFound, Gitlab::Error::Parsing
  73 + #Project already exists
  74 + end
  75 +
  76 + self.gitlab[:errors] = nil
  77 + end
  78 +
  79 + # set an API endpoint
  80 + def gitlab_host
  81 + self.serpro_integration_plugin[:gitlab_host]
  82 + end
  83 +
  84 + # set a user private token
  85 + def gitlab_private_token
  86 + self.serpro_integration_plugin[:gitlab_private_token]
  87 + end
  88 +
  89 + ##########################################
  90 + # Sonar stuff #
  91 + ##########################################
  92 +
  93 +# after_create :create_sonar_project
  94 +
  95 + def sonar= params
  96 + self.serpro_integration_plugin[:sonar] = params
  97 + end
  98 +
  99 + def sonar
  100 + self.serpro_integration_plugin[:sonar] ||= {}
  101 + self.serpro_integration_plugin[:sonar]
  102 + end
  103 +
  104 + ##########################################
  105 + # Jenkins stuff #
  106 + ##########################################
  107 +
  108 +# after_create :create_jenkis_project
  109 +
  110 + def jenkins= params
  111 + self.serpro_integration_plugin[:jenkins] = params
  112 + end
  113 +
  114 + def jenkins
  115 + self.serpro_integration_plugin[:jenkins] ||= {}
  116 + url = "#{self.serpro_integration_plugin[:jenkins][:host]}:"
  117 + url += "#{self.serpro_integration_plugin[:jenkins][:port]}/"
  118 + url += "#{self.serpro_integration_plugin[:jenkins][:context_name]}"
  119 + self.serpro_integration_plugin[:jenkins][:url] = url
  120 + self.serpro_integration_plugin[:jenkins]
  121 + end
  122 +
  123 +
  124 + #FIXME make jenkins integration works
  125 + def create_jenkis_project
  126 +#(projectName, repositoryPath, webUrl, gitUrl)
  127 +
  128 + @client = JenkinsApi::Client.new(:server_url => "#{$jenkins_url}/",
  129 + :password => $jenkins_private_token,
  130 + :username => $jenkins_user)
  131 +
  132 + xmlJenkins = "
  133 + <maven2-moduleset plugin='maven-plugin@1.509'>
  134 + <actions/>
  135 + <description>Projeto criado para o repositório #{repositoryPath} do Gitlab - #{webUrl}</description>
  136 + <logRotator class='hudson.tasks.LogRotator'>
  137 + <daysToKeep>-1</daysToKeep>
  138 + <numToKeep>2</numToKeep>
  139 + <artifactDaysToKeep>-1</artifactDaysToKeep>
  140 + <artifactNumToKeep>-1</artifactNumToKeep>
  141 + </logRotator>
  142 + <keepDependencies>false</keepDependencies>
  143 + <properties/>
  144 + <scm class='hudson.plugins.git.GitSCM' plugin='git@2.2.1'>
  145 + <configVersion>2</configVersion>
  146 + <userRemoteConfigs>
  147 + <hudson.plugins.git.UserRemoteConfig>
  148 + <url>#{gitUrl}</url>
  149 + </hudson.plugins.git.UserRemoteConfig>
  150 + </userRemoteConfigs>
  151 + <branches>
  152 + <hudson.plugins.git.BranchSpec>
  153 + <name>*/master</name>
  154 + </hudson.plugins.git.BranchSpec>
  155 + </branches>
  156 + <doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
  157 + <submoduleCfg class='list'/>
  158 + <extensions/>
  159 + </scm>
  160 + <canRoam>true</canRoam>
  161 + <disabled>false</disabled>
  162 + <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  163 + <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  164 + <jdk>(Inherit From Job)</jdk>
  165 + <triggers class='vector'/>
  166 + <concurrentBuild>false</concurrentBuild>
  167 + <goals>clean package install deploy</goals>
  168 + <aggregatorStyleBuild>true</aggregatorStyleBuild>
  169 + <incrementalBuild>false</incrementalBuild>
  170 + <perModuleEmail>true</perModuleEmail>
  171 + <ignoreUpstremChanges>false</ignoreUpstremChanges>
  172 + <archivingDisabled>false</archivingDisabled>
  173 + <resolveDependencies>false</resolveDependencies>
  174 + <processPlugins>false</processPlugins>
  175 + <mavenValidationLevel>-1</mavenValidationLevel>
  176 + <runHeadless>false</runHeadless>
  177 + <disableTriggerDownstreamProjects>false</disableTriggerDownstreamProjects>
  178 + <settings class='jenkins.mvn.DefaultSettingsProvider'/>
  179 + <globalSettings class='jenkins.mvn.DefaultGlobalSettingsProvider'/>
  180 + <reporters>
  181 + <hudson.maven.reporters.MavenMailer>
  182 + <recipients/>
  183 + <dontNotifyEveryUnstableBuild>false</dontNotifyEveryUnstableBuild>
  184 + <sendToIndividuals>true</sendToIndividuals>
  185 + <perModuleEmail>true</perModuleEmail>
  186 + </hudson.maven.reporters.MavenMailer>
  187 + </reporters>
  188 + <publishers>
  189 + <hudson.plugins.sonar.SonarPublisher plugin='sonar@2.1'>
  190 + <jdk>(Inherit From Job)</jdk>
  191 + <branch/>
  192 + <language/>
  193 + <mavenOpts/>
  194 + <jobAdditionalProperties/>
  195 + <settings class='jenkins.mvn.DefaultSettingsProvider'/>
  196 + <globalSettings class='jenkins.mvn.DefaultGlobalSettingsProvider'/>
  197 + <usePrivateRepository>false</usePrivateRepository>
  198 + </hudson.plugins.sonar.SonarPublisher>
  199 + </publishers>
  200 + <buildWrappers/>
  201 + <prebuilders/>
  202 + <postbuilders/>
  203 + <runPostStepsIfResult>
  204 + <name>FAILURE</name>
  205 + <ordinal>2</ordinal>
  206 + <color>RED</color>
  207 + </runPostStepsIfResult>
  208 + </maven2-moduleset>
  209 + "
  210 +
  211 + begin
  212 + @client.job.create(projectName, xmlJenkins)
  213 + rescue JenkinsApi::Exceptions::ApiException
  214 +
  215 + end
  216 +
  217 + end
  218 +
  219 +
  220 +end
... ...
plugins/serpro_integration/lib/ext/profile.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +require_dependency 'profile'
  2 +
  3 +class Profile
  4 + settings_items :allow_sonar_integration, :type => :boolean, :default => true
  5 + settings_items :allow_gitlab_integration, :type => :boolean, :default => true
  6 +
  7 + #FIXME make test for default option
  8 + settings_items :serpro_integration_plugin, :type => Hash, :default => {}
  9 +end
... ...
plugins/serpro_integration/lib/serpro_integration_plugin.rb 0 → 100644
... ... @@ -0,0 +1,64 @@
  1 +class SerproIntegrationPlugin < Noosfero::Plugin
  2 +
  3 +#include ActionController::UrlWriter
  4 +# include ActionView::Helpers::TagHelper
  5 +# include ActionView::Helpers::FormTagHelper
  6 +# include FormsHelper
  7 +
  8 +
  9 +# include ActionView::Helpers
  10 +# include FormsHelper
  11 +
  12 + def self.plugin_name
  13 + "Serpro Integration Plugin"
  14 + end
  15 +
  16 + def self.plugin_description
  17 + _("Make integration with serpro servers.")
  18 + end
  19 +
  20 +# def filter_comment(c)
  21 +# c.reject! unless logged_in? || allowed_by_profile
  22 +# end
  23 +
  24 + #FIXME make this test
  25 + # User could not have this block
  26 + def self.extra_blocks
  27 + { SonarPlugin::SonarWidgetBlock => {:type => [Community] },
  28 + SonarPlugin::SmileBlock => {:type => [Community] }
  29 + }
  30 + end
  31 +
  32 + #FIXME make this test
  33 + def profile_editor_extras
  34 + lambda do
  35 + render :file => 'profile-editor-extras'
  36 + end
  37 + end
  38 +
  39 + def profile_id
  40 + context.profile
  41 + end
  42 +
  43 + def stylesheet?
  44 + true
  45 + end
  46 +
  47 +# FIXME make this test
  48 + def js_files
  49 + ['smile_face.js']
  50 + end
  51 +
  52 +# def body_beginning
  53 +# "<meta name='profile.allow_unauthenticated_comments'/>" if allowed_by_profile
  54 +# end
  55 +#
  56 +# protected
  57 +#
  58 +# delegate :logged_in?, :to => :context
  59 +#
  60 +# def allowed_by_profile
  61 +# context.profile && context.profile.allow_unauthenticated_comments
  62 +# end
  63 +
  64 +end
... ...
plugins/serpro_integration/lib/serpro_integration_plugin/smile_block.rb 0 → 100644
... ... @@ -0,0 +1,100 @@
  1 +require 'open-uri'
  2 +require 'json'
  3 +
  4 +class SonarPlugin::SmileBlock < Block
  5 +
  6 +
  7 + METRIC_SUCCESS_DENSITY = 'test_success_density'
  8 + METRIC_LOC = 'ncloc'
  9 + METRIC_UNCOVERED_LINE = 'uncovered_lines'
  10 + METRIC_COVERAGE = 'coverage'
  11 +
  12 + #FIXME make this test
  13 + settings_items :sonar_info, :type => Hash, :default => {}
  14 +
  15 + def self.description
  16 + _('Sonar Smile')
  17 + end
  18 +
  19 + def help
  20 + _('This block adds a smile face that make tecnical debits visible with funny way.')
  21 + end
  22 +
  23 + #FIXME make this test
  24 + def sonar_host
  25 + self.owner.sonar_plugin['host']
  26 + end
  27 +
  28 + #FIXME make this test
  29 + def sonar_project
  30 + self.owner.sonar_plugin['project'] #|| ''
  31 + end
  32 +
  33 +#FIXME make this test
  34 + def smile_factor
  35 + collect_sonar_information
  36 + factor = (self.sonar_info[METRIC_COVERAGE] * self.sonar_info[METRIC_SUCCESS_DENSITY]).to_f/1000
  37 + factor
  38 + end
  39 +
  40 + #FIXME make this test
  41 + def content(args={})
  42 + smile_face_id = 'smileFace-' + self.id.to_s
  43 +
  44 + content_tag(:div,
  45 + content_tag(:canvas, '', :id => smile_face_id, :width => '95%', :height => '95%' ) +
  46 + "<script type='text/javascript'>drawFace('#{smile_face_id}', '#{self.smile_factor}')</script>",
  47 + :class => 'smile'
  48 + )
  49 + end
  50 +
  51 + #FIXME make this test
  52 + def self.metrics
  53 + [
  54 + METRIC_SUCCESS_DENSITY,
  55 + METRIC_LOC,
  56 + METRIC_UNCOVERED_LINE,
  57 + METRIC_COVERAGE
  58 + ]
  59 + end
  60 +
  61 + private
  62 +
  63 + #FIXME make this test
  64 + def collect_sonar_information
  65 + return false unless cache_expired?
  66 + begin
  67 + data = open("#{self.sonar_host}/api/resources?resource=#{self.sonar_project}&metrics=ncloc,coverage,weighted_violations,uncovered_lines,test_success_density&format=json").read
  68 + self.sonar_info = parse_sonar_resource(JSON.parse(data).first)
  69 + rescue
  70 + self.sonar_info = {}
  71 + end
  72 + self.sonar_info[:updated_at] = Time.now
  73 + self.save
  74 + end
  75 +
  76 + #FIXME make this test
  77 + def parse_sonar_resource(data)
  78 + parsed_data = {}
  79 + return {} if data['msr'].nil?
  80 + data['msr'].map do |metric|
  81 + self.class.metrics.map do |defined_metric|
  82 + parsed_data[defined_metric] = metric['val'] if metric['key'] == defined_metric
  83 + end
  84 + end
  85 + parsed_data
  86 + end
  87 +
  88 + #FIXME make this test
  89 + def cache_expired?
  90 + return true if self.sonar_info[:updated_at].nil?
  91 + (Time.now - self.sonar_info[:updated_at]) > cache_timestamp
  92 + end
  93 +
  94 + #FIXME make this test
  95 + # Cach time to load new data in seconds
  96 + def cache_timestamp
  97 + 60 * 60
  98 + end
  99 +
  100 +end
... ...
plugins/serpro_integration/lib/serpro_integration_plugin/sonar_widget_block.rb 0 → 100644
... ... @@ -0,0 +1,81 @@
  1 +class SerproIntegrationrPlugin::SonarWidgetBlock < Block
  2 +
  3 + #FIXME make this test
  4 + AVAILABLE_WIDGETS = {
  5 + 'project_motion_chart' => 'Project Motion Chart',
  6 + 'timeline' => 'Timeline',
  7 + 'complexity' => 'Complexity'
  8 + }
  9 +
  10 + #FIXME make this test. Make test for default widget
  11 + settings_items :widget, :type => String, :default => 'timeline'
  12 +
  13 + def self.description
  14 + _('Sonar Widgets')
  15 + end
  16 +
  17 + def help
  18 + _('This block adds sonar widgets on profile.')
  19 + end
  20 +
  21 + #FIXME make this test
  22 + def sonar_host
  23 + self.owner.serpro_integration_plugin['host']
  24 + end
  25 +
  26 + #FIXME make this test
  27 + def sonar_project
  28 + self.owner.serpro_integration_plugin['project']
  29 + end
  30 +
  31 + #FIXME make this test
  32 + def widget_url
  33 + self.sonar_host + 'widget?id=' + self.widget + '&resource=' + self.sonar_project + '&metric1=complexity&metric2=ncloc'
  34 + end
  35 +
  36 + #FIXME make this test
  37 + def is_widget_well_formed_url?
  38 + !self.widget_url.match(/http[s]?:\/\/[\w|.|\/]+\/widget\?id=[\w]+&resource=[\w|\W]+/).nil?
  39 + end
  40 +
  41 + #FIXME make this test
  42 + def widget_width
  43 + case widget
  44 + when 'project_motion_chart'
  45 + '360px'
  46 + when 'timeline'
  47 + '100%'
  48 + when 'complexity'
  49 + '100%'
  50 + else
  51 + '300px'
  52 + end
  53 + end
  54 +
  55 + #FIXME make this test
  56 + def widget_height
  57 + case widget
  58 + when 'project_motion_chart'
  59 + '450px'
  60 + when 'timeline'
  61 + '205px'
  62 + when 'complexity'
  63 + '170px'
  64 + else
  65 + '300px'
  66 + end
  67 + end
  68 +
  69 + def content(args={})
  70 +# render this url
  71 +#http://sonar.serpro/widget?id=timeline&resource=br.gov.fazenda.coaf.siscoaf:siscoaf-parent&metric1=complexity&metric2=ncloc
  72 +
  73 + block = self
  74 +
  75 + lambda do
  76 + render :file => 'sonar_widget_block', :locals => { :block => block }
  77 + end
  78 +
  79 + end
  80 +
  81 +end
... ...
plugins/serpro_integration/public/smile_face.js 0 → 100644
... ... @@ -0,0 +1,129 @@
  1 +function drawBaseFace(element_id) {
  2 + var canvas = document.getElementById(element_id);
  3 + var ctx = canvas.getContext("2d");
  4 +
  5 + var x = canvas.width / 2;
  6 + var y = canvas.height / 2;
  7 + var radius = canvas.width/2 - 1;
  8 + var startAngle = 0;
  9 + var endAngle = 2 * Math.PI;
  10 +
  11 + ctx.beginPath();
  12 + ctx.arc(x, y, radius, startAngle, endAngle);
  13 + ctx.stroke();
  14 + ctx.fillStyle = "yellow";
  15 + ctx.fill();
  16 +}
  17 +
  18 +function drawSmile(element_id, factor){
  19 + var canvas = document.getElementById(element_id);
  20 + var ctx = canvas.getContext("2d");
  21 + var x = canvas.width / 2;
  22 + var y = canvas.height / 2
  23 + var radius = canvas.width/2 - canvas.width/4;
  24 +
  25 + var startAngle = 0;
  26 + var endAngle = 0;
  27 + var delta = 0;
  28 +
  29 + ctx.beginPath();
  30 + ctx.lineWidth = canvas.width/100 * 2;
  31 +
  32 + if (factor >= 0 && factor < 5){
  33 + //Draw sadness mouth
  34 + delta = 0.5 - factor* 0.1
  35 + startAngle = (1.5 - delta) * Math.PI;
  36 + endAngle = (1.5 + delta) * Math.PI;
  37 + radius = radius - radius*delta;
  38 + y = y + (radius + radius*(1 - delta));
  39 + ctx.arc(x, y, radius, startAngle, endAngle);
  40 + } else if (factor == 5) {
  41 + //Draw normal mouth
  42 + ctx.moveTo(x-canvas.width/8,y+canvas.width/8);
  43 + ctx.lineTo(x-canvas.width/8+(canvas.width/4),y+canvas.width/8);
  44 + } else if (factor > 5 && factor <= 10) {
  45 + //Draw happiness mouth
  46 + delta = 1 - factor * 0.1
  47 + startAngle = delta * Math.PI;
  48 + endAngle = (1 - delta) * Math.PI;
  49 + radius = radius - radius*delta;
  50 + y = y - (radius - radius*(1-delta));
  51 + ctx.arc(x, y, radius, startAngle, endAngle);
  52 + }else{
  53 + //Draw scare mouth
  54 + radius = radius*0.4
  55 + y = y + radius;
  56 + ctx.ellipse(x,y,radius*0.4, radius,0,0,2 * Math.PI, false);
  57 + ctx.fill();
  58 + }
  59 +
  60 +
  61 + // line color
  62 + ctx.strokeStyle = 'black';
  63 + ctx.stroke();
  64 +}
  65 +
  66 +function drawEyes(element_id){
  67 + var canvas = document.getElementById(element_id);
  68 + var ctx = canvas.getContext("2d");
  69 + var centerX = canvas.width/5;
  70 + var centerY = 0;
  71 + var radius = canvas.width * 0.05;
  72 +
  73 + // save state
  74 + ctx.save();
  75 +
  76 + // translate context so height is 1/3'rd from top of enclosing circle
  77 + ctx.translate(canvas.width / 2, canvas.height / 3);
  78 +
  79 + // scale context horizontally by 50%
  80 + ctx.scale(.5, 1);
  81 +
  82 + // draw circle which will be stretched into an oval
  83 + ctx.beginPath();
  84 + ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
  85 +
  86 + // restore to original state
  87 + ctx.restore();
  88 +
  89 + // apply styling
  90 + ctx.fillStyle = 'black';
  91 + ctx.fill();
  92 + ctx.lineWidth = 2;
  93 + ctx.strokeStyle = 'black';
  94 + ctx.stroke();
  95 +
  96 +
  97 + //left eye
  98 + centerX = centerX * -1;
  99 +
  100 + // save state
  101 + ctx.save();
  102 +
  103 + // translate context so height is 1/3'rd from top of enclosing circle
  104 + ctx.translate(canvas.width / 2, canvas.height / 3);
  105 +
  106 + // scale context horizontally by 50%
  107 + ctx.scale(.5, 1);
  108 +
  109 + // draw circle which will be stretched into an oval
  110 + ctx.beginPath();
  111 + ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
  112 +
  113 + // restore to original state
  114 + ctx.restore();
  115 +
  116 + // apply styling
  117 + ctx.fillStyle = 'black';
  118 + ctx.fill();
  119 + ctx.lineWidth = 2;
  120 + ctx.strokeStyle = 'black';
  121 + ctx.stroke();
  122 +}
  123 +
  124 +
  125 +function drawFace(element_id, factor){
  126 + drawBaseFace(element_id);
  127 + drawEyes(element_id);
  128 + drawSmile(element_id, factor);
  129 +}
... ...
plugins/serpro_integration/public/style.css 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +.serpro-integration-plugin_smile-block .smile {
  2 + text-align: center;
  3 +}
... ...
plugins/serpro_integration/smile.html 0 → 100644
... ... @@ -0,0 +1,142 @@
  1 +<html>
  2 + <head> </head>
  3 + <body>
  4 + <canvas id="smileFace" width="60" height="60"></canvas>
  5 +<script>
  6 +
  7 +function drawBaseFace() {
  8 + var canvas = document.getElementById("smileFace");
  9 + var ctx = canvas.getContext("2d");
  10 +
  11 + var x = canvas.width / 2;
  12 + var y = canvas.height / 2;
  13 + var radius = canvas.width/2 - 1;
  14 + var startAngle = 0;
  15 + var endAngle = 2 * Math.PI;
  16 +
  17 + ctx.beginPath();
  18 + ctx.arc(x, y, radius, startAngle, endAngle);
  19 + ctx.stroke();
  20 + ctx.fillStyle = "yellow";
  21 + ctx.fill();
  22 +}
  23 +
  24 +function drawSmile(factor){
  25 + var canvas = document.getElementById("smileFace");
  26 + var ctx = canvas.getContext("2d");
  27 + var x = canvas.width / 2;
  28 + var y = canvas.height / 2
  29 + var radius = canvas.width/2 - canvas.width/4;
  30 +
  31 + var startAngle = 0;
  32 + var endAngle = 0;
  33 + var delta = 0;
  34 +
  35 + ctx.beginPath();
  36 + ctx.lineWidth = canvas.width/100 * 2;
  37 +
  38 + if (factor >= 0 && factor < 5){
  39 + //Draw sadness mouth
  40 + delta = 0.5 - factor* 0.1
  41 + startAngle = (1.5 - delta) * Math.PI;
  42 + endAngle = (1.5 + delta) * Math.PI;
  43 + radius = radius - radius*delta;
  44 + y = y + (radius + radius*(1 - delta));
  45 + ctx.arc(x, y, radius, startAngle, endAngle);
  46 + } else if (factor == 5) {
  47 + //Draw normal mouth
  48 + ctx.moveTo(x-canvas.width/8,y+canvas.width/8);
  49 + ctx.lineTo(x-canvas.width/8+(canvas.width/4),y+canvas.width/8);
  50 + } else if (factor > 5 && factor <= 10) {
  51 + //Draw happiness mouth
  52 + delta = 1 - factor * 0.1
  53 + startAngle = delta * Math.PI;
  54 + endAngle = (1 - delta) * Math.PI;
  55 + radius = radius - radius*delta;
  56 + y = y - (radius - radius*(1-delta));
  57 + ctx.arc(x, y, radius, startAngle, endAngle);
  58 + }else{
  59 + //Draw scare mouth
  60 + radius = radius*0.4
  61 + y = y + radius;
  62 + ctx.ellipse(x,y,radius*0.4, radius,0,0,2 * Math.PI, false);
  63 + ctx.fill();
  64 + }
  65 +
  66 +
  67 + // line color
  68 + ctx.strokeStyle = 'black';
  69 + ctx.stroke();
  70 +}
  71 +
  72 +function drawEyes(){
  73 + var canvas = document.getElementById("smileFace");
  74 + var ctx = canvas.getContext("2d");
  75 + var centerX = canvas.width/5;
  76 + var centerY = 0;
  77 + var radius = canvas.width * 0.05;
  78 +
  79 + // save state
  80 + ctx.save();
  81 +
  82 + // translate context so height is 1/3'rd from top of enclosing circle
  83 + ctx.translate(canvas.width / 2, canvas.height / 3);
  84 +
  85 + // scale context horizontally by 50%
  86 + ctx.scale(.5, 1);
  87 +
  88 + // draw circle which will be stretched into an oval
  89 + ctx.beginPath();
  90 + ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
  91 +
  92 + // restore to original state
  93 + ctx.restore();
  94 +
  95 + // apply styling
  96 + ctx.fillStyle = 'black';
  97 + ctx.fill();
  98 + ctx.lineWidth = 2;
  99 + ctx.strokeStyle = 'black';
  100 + ctx.stroke();
  101 +
  102 +
  103 + //left eye
  104 + centerX = centerX * -1;
  105 +
  106 + // save state
  107 + ctx.save();
  108 +
  109 + // translate context so height is 1/3'rd from top of enclosing circle
  110 + ctx.translate(canvas.width / 2, canvas.height / 3);
  111 +
  112 + // scale context horizontally by 50%
  113 + ctx.scale(.5, 1);
  114 +
  115 + // draw circle which will be stretched into an oval
  116 + ctx.beginPath();
  117 + ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
  118 +
  119 + // restore to original state
  120 + ctx.restore();
  121 +
  122 + // apply styling
  123 + ctx.fillStyle = 'black';
  124 + ctx.fill();
  125 + ctx.lineWidth = 2;
  126 + ctx.strokeStyle = 'black';
  127 + ctx.stroke();
  128 +}
  129 +
  130 +
  131 +function drawFace(factor){
  132 + drawBaseFace();
  133 + drawEyes();
  134 + drawSmile(factor);
  135 +}
  136 +
  137 +drawFace(9);
  138 +
  139 +</script>
  140 +
  141 + </body>
  142 +</html>
... ...
plugins/serpro_integration/test/unit/sonar_plugin_test.rb 0 → 100644
... ... @@ -0,0 +1,41 @@
  1 +require File.dirname(__FILE__) + '/../../../../test/test_helper'
  2 +
  3 +class RequireAuthToCommentPluginTest < ActiveSupport::TestCase
  4 +
  5 + def setup
  6 + @plugin = RequireAuthToCommentPlugin.new
  7 + @comment = Comment.new
  8 + end
  9 +
  10 + attr_reader :plugin, :comment
  11 +
  12 + should 'reject comments for unauthenticated users' do
  13 + plugin.context = logged_in(false)
  14 + plugin.filter_comment(comment)
  15 + assert comment.rejected?
  16 + end
  17 +
  18 + should 'allow comments from authenticated users' do
  19 + plugin.context = logged_in(true)
  20 + plugin.filter_comment(comment)
  21 + assert !comment.rejected?
  22 + end
  23 +
  24 + should 'allow comments from unauthenticated users if allowed by profile' do
  25 + plugin.context = logged_in(false)
  26 + plugin.context.profile.allow_unauthenticated_comments = true
  27 +
  28 + plugin.filter_comment(comment)
  29 + assert !comment.rejected?
  30 + end
  31 +
  32 + protected
  33 +
  34 + def logged_in(boolean)
  35 + controller = mock()
  36 + controller.stubs(:logged_in?).returns(boolean)
  37 + controller.stubs(:profile).returns(Profile.new)
  38 + controller
  39 + end
  40 +
  41 +end
... ...
plugins/serpro_integration/views/profile-editor-extras.html.erb 0 → 100644
... ... @@ -0,0 +1,49 @@
  1 +
  2 +<div id='serpro-integration'>
  3 + <div id='gitlab' class='gitlab'>
  4 + <%= render :partial => 'gitlab' %>
  5 + </div>
  6 +
  7 + <div>
  8 + <%= labelled_check_box(_('Uses sonar integration'), 'profile_data[allow_sonar_integration]', true, profile.allow_sonar_integration) %>
  9 + </div>
  10 +
  11 + <ul class='sonar'>
  12 + <h2><%= _('Sonar Integration') %></h2>
  13 + <li>
  14 + <%= labelled_text_field(_('Server Host'), 'profile_data[sonar]host]', profile.sonar[:host]) %>
  15 + </li>
  16 + <li>
  17 + <%= labelled_text_field(_('Project: '), 'profile_data[sonar][project]', profile.sonar[:project]) %>
  18 + </li>
  19 + </ul>
  20 +
  21 +
  22 + <div>
  23 + <%= labelled_check_box(_('Uses Jenkins integration'), 'profile_data[allow_jenkins_integration]', true, profile.allow_jenkins_integration) %>
  24 + </div>
  25 +
  26 + <ul class='jenkins'>
  27 + <h2><%= _('Jenkins Integration') %></h2>
  28 + <li>
  29 + <%= labelled_text_field(_('Server Host'), 'profile_data[jenkins][host]', profile.jenkins[:host]) %>
  30 + </li>
  31 + <li>
  32 + <%= labelled_text_field(_('Server Port'), 'profile_data[jenkins][port]', profile.jenkins[:port]) %>
  33 + </li>
  34 + <li>
  35 + <%= labelled_text_field(_('Server Context Name'), 'profile_data[jenkins][context_name]', profile.jenkins[:context_name]) %>
  36 + </li>
  37 + <li>
  38 + <%= labelled_text_field(_('Server User'), 'profile_data[jenkins][user]', profile.jenkins[:user]) %>
  39 + </li>
  40 + <li>
  41 + <%= labelled_text_field(_('Server Private Token'), 'profile_data[jenkins][private_token]', profile.jenkins[:private_token]) %>
  42 + </li>
  43 + <li>
  44 + <%= labelled_text_field(_('Server Url'), 'profile_data[jenkins][url]', profile.jenkins[:url], {:disabled => true}) %>
  45 + </li>
  46 +
  47 + </ul>
  48 +
  49 +</div>
... ...
plugins/serpro_integration/views/profile_design/sonar_plugin/_sonar_widget_block.rhtml 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +
  2 +<%= labelled_form_field(_('Widget'), select(:block, :widget, SerproIntegrationPlugin::SonarWidgetBlock::AVAILABLE_WIDGETS.map {|id, name| [name, id]} )) %>
  3 +
  4 +
... ...
plugins/serpro_integration/views/profile_editor/_gitlab.html.erb 0 → 100644
... ... @@ -0,0 +1,22 @@
  1 +<div class='option'>
  2 + <%= labelled_check_box(_('Uses Gitlab integration'), 'profile_data[allow_gitlab_integration]', true, profile.allow_gitlab_integration) %>
  3 +</div>
  4 +
  5 +<ul>
  6 + <h2>
  7 + <%= _('Gitlab Integration') %>
  8 + <%= link_to_remote _('Force'), :url => {:controller => 'serpro_integration_plugin_myprofile', :action => 'create_gitlab'} %>
  9 +
  10 + </h2>
  11 + <li>
  12 + <%= labelled_text_field(_('Server Host'), 'profile_data[gitlab][host]', profile.gitlab[:host]) %>
  13 + </li>
  14 + <li>
  15 + <%= labelled_text_field(_('User private token: '), 'profile_data[gitlab][private_token]', profile.gitlab[:private_token]) %>
  16 + </li>
  17 + <li>
  18 + <%= _('Erros: %s') % (profile.gitlab[:errors] || _('None')) %>
  19 + </li>
  20 +
  21 +</ul>
  22 +
... ...
plugins/serpro_integration/views/sonar_widget_block.rhtml 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +<div class='widget'>
  2 + <% if block.is_widget_well_formed_url? %>
  3 + <iframe width='<%=block.widget_width%>' height='<%=block.widget_height%>' src='<%=block.widget_url%>' frameborder="0" allowfullscreen></iframe>
  4 + <% else %>
  5 + <div class='wrong'>
  6 + <iframe width='<%=block.widget_width%>' height='<%=block.widget_height%>' src='<%=block.widget_url%>' frameborder="0" allowfullscreen></iframe>
  7 + <%= _('Something wrong happened. Please see your sonar configuration.') %>
  8 + </div>
  9 + <% end %>
  10 +</div>
... ...
test/fixtures/files/500.html
... ... @@ -1 +0,0 @@
1   -../../../public/500.html
2 0 \ No newline at end of file
test/fixtures/files/500.html 0 → 100644
... ... @@ -0,0 +1,151 @@
  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" >
  3 + <head>
  4 + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  5 + <meta http-equiv="refresh" content="60"/>
  6 + <title>Technical problems</title>
  7 + <link rel="stylesheet" type="text/css" href="/designs/themes/default/errors.css"/>
  8 + <link rel="shortcut icon" href='/designs/themes/default/favicon.ico' type="image/x-icon" />
  9 + <script type='text/javascript' src='/javascripts/prototype.js'></script>
  10 + <script type='text/javascript' src='/javascripts/errors.js'></script>
  11 +</head>
  12 +<body onload='display_error_message()'>
  13 + <div id='wrap'>
  14 + <div id='header'>
  15 + <div id='logo'>
  16 + &nbsp;
  17 + </div>
  18 + </div>
  19 +
  20 +
  21 + <div id='de' style='display: none' class='message'>
  22 + <h1>Kurzzeitiges Systemproblem</h1>
  23 + <p>
  24 + Unser technisches Team arbeitet gerade daran, bitte probieren Sie es nachher erneut. Wir entschuldigen uns für die Unannehmlichkeiten.
  25 + </p>
  26 + <ul>
  27 + <li><a href='javascript: history.back()'>Zurück</a></li>
  28 + <li><a href='/'>Gehe zur Homepage</a></li>
  29 + </ul>
  30 + </div>
  31 +
  32 +
  33 + <div id='en' style='display: none' class='message'>
  34 + <h1>Temporary system problem</h1>
  35 + <p>
  36 + Our technical team is working on it, please try again later. Sorry for the inconvenience.
  37 + </p>
  38 + <ul>
  39 + <li><a href='javascript: history.back()'>Go back</a></li>
  40 + <li><a href='/'>Go to the site home page</a></li>
  41 + </ul>
  42 + </div>
  43 +
  44 +
  45 + <div id='eo' style='display: none' class='message'>
  46 + <h1>Temporary system problem</h1>
  47 + <p>
  48 + Our technical team is working on it, please try again later. Sorry for the inconvenience.
  49 + </p>
  50 + <ul>
  51 + <li><a href='javascript: history.back()'>Go back</a></li>
  52 + <li><a href='/'>Go to the site home page</a></li>
  53 + </ul>
  54 + </div>
  55 +
  56 +
  57 + <div id='es' style='display: none' class='message'>
  58 + <h1>Problema temporal del sistema</h1>
  59 + <p>
  60 + Nuestro equipo técnico está trabajando en ello, por favor, inténtalo de nuevo más tarde. Disculpa las molestias.
  61 + </p>
  62 + <ul>
  63 + <li><a href='javascript: history.back()'>Regresar</a></li>
  64 + <li><a href='/'>Ir a la página de inicio del sitio</a></li>
  65 + </ul>
  66 + </div>
  67 +
  68 +
  69 + <div id='fr' style='display: none' class='message'>
  70 + <h1>Problème temporaire du système.</h1>
  71 + <p>
  72 + Notre équipe technique est en train d'y travailler. Merci de réessayer plus tard. Nous sommes désolés de la gêne occasionnée.
  73 + </p>
  74 + <ul>
  75 + <li><a href='javascript: history.back()'>Retour</a></li>
  76 + <li><a href='/'>Aller à la page d'accueil du site</a></li>
  77 + </ul>
  78 + </div>
  79 +
  80 +
  81 + <div id='hy' style='display: none' class='message'>
  82 + <h1>Temporary system problem</h1>
  83 + <p>
  84 + Our technical team is working on it, please try again later. Sorry for the inconvenience.
  85 + </p>
  86 + <ul>
  87 + <li><a href='javascript: history.back()'>Վերադառնալ</a></li>
  88 + <li><a href='/'>Go to the site home page</a></li>
  89 + </ul>
  90 + </div>
  91 +
  92 +
  93 + <div id='it' style='display: none' class='message'>
  94 + <h1>Temporary system problem</h1>
  95 + <p>
  96 + Our technical team is working on it, please try again later. Sorry for the inconvenience.
  97 + </p>
  98 + <ul>
  99 + <li><a href='javascript: history.back()'>Go back</a></li>
  100 + <li><a href='/'>Go to the site home page</a></li>
  101 + </ul>
  102 + </div>
  103 +
  104 +
  105 + <div id='pt' style='display: none' class='message'>
  106 + <h1>Problema temporário no sistema</h1>
  107 + <p>
  108 + Nossa equipe técnica está trabalhando nele, por favor tente mais tarde. Perdoe o incoveniente.
  109 + </p>
  110 + <ul>
  111 + <li><a href='javascript: history.back()'>Voltar</a></li>
  112 + <li><a href='/'>Ir para a página inicial do site.</a></li>
  113 + </ul>
  114 + </div>
  115 +
  116 +
  117 + <div id='ru' style='display: none' class='message'>
  118 + <h1>Временная ошибка системы</h1>
  119 + <p>
  120 + Техники уже работают над проблемой, пожалуйста, попробуйте позже.
  121 + </p>
  122 + <ul>
  123 + <li><a href='javascript: history.back()'>Назад</a></li>
  124 + <li><a href='/'>Перейти на домашнюю страницу сайта</a></li>
  125 + </ul>
  126 + </div>
  127 +
  128 + <div id='languages'>
  129 +
  130 + <a href="javascript: display_error_message('de')">Deutsch</a>
  131 +
  132 + <a href="javascript: display_error_message('en')">English</a>
  133 +
  134 + <a href="javascript: display_error_message('eo')">Esperanto</a>
  135 +
  136 + <a href="javascript: display_error_message('es')">Español</a>
  137 +
  138 + <a href="javascript: display_error_message('fr')">Français</a>
  139 +
  140 + <a href="javascript: display_error_message('hy')">հայերեն լեզու</a>
  141 +
  142 + <a href="javascript: display_error_message('it')">Italiano</a>
  143 +
  144 + <a href="javascript: display_error_message('pt')">Português</a>
  145 +
  146 + <a href="javascript: display_error_message('ru')">русский язык</a>
  147 +
  148 + </div>
  149 + </div>
  150 +</body>
  151 +</html>
... ...
test/functional/profile_controller_test.rb
... ... @@ -474,17 +474,23 @@ class ProfileControllerTest &lt; ActionController::TestCase
474 474 assert_equal "/profile/#{community.identifier}", @request.session[:previous_location]
475 475 end
476 476  
477   - should 'redirect to location before login after join community' do
  477 + should 'redirect to login after user not logged asks to join a community' do
478 478 community = Community.create!(:name => 'my test community')
479 479  
480   - @request.expects(:referer).returns("/profile/#{community.identifier}/to_go")
481   - login_as(profile.identifier)
  480 + get :join_not_logged, :profile => community.identifier
482 481  
483   - post :join_not_logged, :profile => community.identifier
  482 + assert_equal community.identifier, @request.session[:join]
  483 + assert_redirected_to :controller => :account, :action => :login
  484 + end
484 485  
485   - assert_redirected_to "/profile/#{community.identifier}/to_go"
  486 + should 'redirect to join after user logged asks to join_not_logged a community' do
  487 + community = Community.create!(:name => 'my test community')
  488 +
  489 + login_as(profile.identifier)
  490 + get :join_not_logged, :profile => community.identifier
486 491  
487   - assert_nil @request.session[:previous_location]
  492 + assert_equal community.identifier, @request.session[:join]
  493 + assert_redirected_to :controller => :profile, :action => :join
488 494 end
489 495  
490 496 should 'show number of published events in index' do
... ... @@ -1186,7 +1192,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
1186 1192 20.times {comment = fast_create(Comment, :source_id => article, :title => 'a comment', :body => 'lalala', :created_at => Time.now)}
1187 1193 article.reload
1188 1194 get :index, :profile => profile.identifier
1189   - assert_tag 'ul', :attributes => {:class => 'profile-wall-activities-comments'}, :children => {:count => 0 }
  1195 + assert_tag 'ul', :attributes => {:class => 'profile-wall-activities-comments'}, :children => {:count => 0 }
1190 1196 end
1191 1197  
1192 1198 should "view more comments paginated" do
... ... @@ -1212,7 +1218,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
1212 1218 20.times {fast_create(Scrap, :sender_id => profile.id, :receiver_id => profile.id, :scrap_id => scrap.id)}
1213 1219 profile.reload
1214 1220 get :index, :profile => profile.identifier
1215   - assert_tag 'ul', :attributes => {:class => 'profile-wall-activities-comments scrap-replies'}, :children => {:count => 0 }
  1221 + assert_tag 'ul', :attributes => {:class => 'profile-wall-activities-comments scrap-replies'}, :children => {:count => 0 }
1216 1222 end
1217 1223  
1218 1224 should "view more replies paginated" do
... ... @@ -1269,15 +1275,6 @@ class ProfileControllerTest &lt; ActionController::TestCase
1269 1275 assert_tag :tag => 'div', :content => /#{instance_eval(&plugin2.profile_tabs[:content])}/, :attributes => {:id => /#{plugin2.profile_tabs[:id]}/}
1270 1276 end
1271 1277  
1272   - should 'redirect to profile page when try to request join_not_logged via GET method' do
1273   - community = Community.create!(:name => 'my test community')
1274   - login_as(profile.identifier)
1275   - get :join_not_logged, :profile => community.identifier
1276   - assert_nothing_raised do
1277   - assert_redirected_to community.url
1278   - end
1279   - end
1280   -
1281 1278 should 'check different profile from the domain profile' do
1282 1279 default = Environment.default
1283 1280 default.domains.create!(:name => 'environment.com')
... ...
test/functional/profile_editor_controller_test.rb
... ... @@ -894,6 +894,23 @@ class ProfileEditorControllerTest &lt; ActionController::TestCase
894 894 assert_tag :tag => 'input', :attributes => {:id => 'field_added_by_plugin', :value => 'value_of_field_added_by_plugin'}
895 895 end
896 896  
  897 + should 'add extra content with block provided by plugins on edit' do
  898 + class TestProfileEditPlugin < Noosfero::Plugin
  899 + def profile_editor_extras
  900 + lambda do
  901 + render :text => "<input id='field_added_by_plugin' value='value_of_field_added_by_plugin'/>"
  902 + end
  903 + end
  904 + end
  905 + Noosfero::Plugin.stubs(:all).returns([TestProfileEditPlugin.to_s])
  906 +
  907 + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([TestProfileEditPlugin.new])
  908 +
  909 + get :edit, :profile => profile.identifier
  910 +
  911 + assert_tag :tag => 'input', :attributes => {:id => 'field_added_by_plugin', :value => 'value_of_field_added_by_plugin'}
  912 + end
  913 +
897 914 should 'show image upload field from profile editor' do
898 915 env = Environment.default
899 916 env.custom_person_fields = { }
... ...