--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.api.platform;
+
+import com.google.common.base.Preconditions;
+import org.sonar.api.ServerExtension;
+
+import javax.annotation.Nullable;
+
+/**
+ * @since 3.2
+ */
+public interface NewUserHandler extends ServerExtension {
+
+ public static final class Context {
+ private String login;
+ private String name;
+ private String email;
+
+ private Context(String login, String name, @Nullable String email) {
+ Preconditions.checkNotNull(login);
+ Preconditions.checkNotNull(name);
+ this.login = login;
+ this.name = name;
+ this.email = email;
+ }
+
+ public String getLogin() {
+ return login;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static final class Builder {
+ private String login;
+ private String name;
+ private String email;
+
+ private Builder() {
+ }
+
+ public Builder setLogin(String s) {
+ this.login = s;
+ return this;
+ }
+
+ public Builder setName(String s) {
+ this.name = s;
+ return this;
+ }
+
+ public Builder setEmail(@Nullable String s) {
+ this.email = s;
+ return this;
+ }
+
+ public Context build() {
+ return new Context(login, name, email);
+ }
+ }
+ }
+
+ void doOnNewUser(Context context);
+}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.api.platform;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class NewUserHandlerTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void build_context() {
+ NewUserHandler.Context context = NewUserHandler.Context.builder().setLogin("marius").setName("Marius").setEmail("marius@lesbronzes.fr").build();
+
+ assertThat(context.getLogin()).isEqualTo("marius");
+ assertThat(context.getName()).isEqualTo("Marius");
+ assertThat(context.getEmail()).isEqualTo("marius@lesbronzes.fr");
+ }
+
+ @Test
+ public void login_is_mandatory() {
+ thrown.expect(NullPointerException.class);
+
+ NewUserHandler.Context.builder().setName("Marius").build();
+ }
+}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.server.platform;
+
+import org.slf4j.LoggerFactory;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.platform.NewUserHandler;
+
+/**
+ * @since 3.2
+ */
+public class NewUserNotifier implements ServerComponent {
+
+ private NewUserHandler[] handlers;
+
+ public NewUserNotifier(NewUserHandler[] handlers) {
+ this.handlers = handlers;
+ }
+
+ public NewUserNotifier() {
+ this(new NewUserHandler[0]);
+ }
+
+ public void onNewUser(NewUserHandler.Context context) {
+ LoggerFactory.getLogger(NewUserNotifier.class).debug("User created: " + context.getLogin() + ". Notifying " + NewUserHandler.class.getSimpleName() + " handlers...");
+ for (NewUserHandler handler : handlers) {
+ handler.doOnNewUser(context);
+ }
+ }
+}
\ No newline at end of file
servicesContainer.addSingleton(RuleI18nManager.class);
servicesContainer.addSingleton(GwtI18n.class);
servicesContainer.addSingleton(ResourceTypes.class);
+ servicesContainer.addSingleton(NewUserNotifier.class);
// Notifications
servicesContainer.addSingleton(EmailSettings.class);
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.Settings;
import org.sonar.api.platform.ComponentContainer;
+import org.sonar.api.platform.NewUserHandler;
import org.sonar.api.platform.PluginMetadata;
import org.sonar.api.platform.PluginRepository;
import org.sonar.api.profiles.ProfileExporter;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.rules.RuleRepository;
import org.sonar.api.utils.ValidationMessages;
-import org.sonar.api.web.Footer;
-import org.sonar.api.web.NavigationSection;
-import org.sonar.api.web.Page;
-import org.sonar.api.web.RubyRailsWebservice;
-import org.sonar.api.web.Widget;
+import org.sonar.api.web.*;
import org.sonar.api.workflow.Review;
import org.sonar.api.workflow.internal.DefaultReview;
import org.sonar.api.workflow.internal.DefaultWorkflowContext;
import org.sonar.server.filters.FilterResult;
import org.sonar.server.notifications.reviews.ReviewsNotificationManager;
import org.sonar.server.platform.GlobalSettingsUpdater;
+import org.sonar.server.platform.NewUserNotifier;
import org.sonar.server.platform.Platform;
import org.sonar.server.platform.ServerIdGenerator;
-import org.sonar.server.plugins.DefaultServerPluginRepository;
-import org.sonar.server.plugins.PluginDeployer;
-import org.sonar.server.plugins.PluginDownloader;
-import org.sonar.server.plugins.UpdateCenterMatrix;
-import org.sonar.server.plugins.UpdateCenterMatrixFactory;
+import org.sonar.server.plugins.*;
import org.sonar.server.rules.ProfilesConsole;
import org.sonar.server.rules.RulesConsole;
import org.sonar.updatecenter.common.Version;
import javax.annotation.Nullable;
-
import java.net.InetAddress;
import java.sql.Connection;
import java.util.Collection;
public void ruleSeverityChanged(int parentProfileId, int activeRuleId, int oldSeverityId, int newSeverityId, String userName) {
getProfilesManager().ruleSeverityChanged(parentProfileId, activeRuleId, RulePriority.values()[oldSeverityId],
- RulePriority.values()[newSeverityId], userName);
+ RulePriority.values()[newSeverityId], userName);
}
public void ruleDeactivated(int parentProfileId, int deactivatedRuleId, String userName) {
getContainer().getComponentByType(ResourceKeyUpdaterDao.class).bulkUpdateKey(projectId, stringToReplace, replacementString);
}
+
+ // USERS
+ public void onNewUser(Map<String, String> fields) {
+ getContainer().getComponentByType(NewUserNotifier.class).onNewUser(NewUserHandler.Context.builder()
+ .setLogin(fields.get("login"))
+ .setName(fields.get("name"))
+ .setEmail(fields.get("email"))
+ .build());
+ }
}
def reactivate
user = User.find_by_login(params[:user][:login])
if user
- user.reactivate(java_facade.getSettings().getString('sonar.defaultGroup'))
- user.save!
+ user.reactivate!(java_facade.getSettings().getString('sonar.defaultGroup'))
flash[:notice] = 'User was successfully reactivated.'
else
flash[:error] = "A user with login #{params[:user][:login]} does not exist."
FAVOURITE_PROPERTY_KEY='favourite'
+ after_create :on_create
has_and_belongs_to_many :groups
has_many :user_roles, :dependent => :delete_all
include NeedAuthorization::ForUser
include NeedAuthentication::ForUser
- validates_length_of :name, :maximum => 200, :allow_blank => true, :allow_nil => true
- validates_length_of :email, :maximum => 100, :allow_blank => true, :allow_nil => true
+ validates_length_of :name, :maximum => 200, :allow_blank => true, :allow_nil => true
+ validates_length_of :email, :maximum => 100, :allow_blank => true, :allow_nil => true
# The following two validations not needed, because they come with Authentication::ByPassword - see SONAR-2656
#validates_length_of :password, :within => 4..40, :if => :password_required?
#validates_confirmation_of :password, :if => :password_required?
- validates_presence_of :login
- validates_length_of :login, :within => 2..40
- validates_uniqueness_of :login, :case_sensitive => true
- validates_format_of :login, :with => Authentication.login_regex, :message => Authentication.bad_login_message
+ validates_presence_of :login
+ validates_length_of :login, :within => 2..40
+ validates_uniqueness_of :login, :case_sensitive => true
+ validates_format_of :login, :with => Authentication.login_regex, :message => Authentication.bad_login_message
# HACK HACK HACK -- how to do attr_accessible from here?
# do not validate user, for example when user created via SSO has no password
self.save(false)
- self.user_roles.each {|role| role.delete}
- self.properties.each {|prop| prop.delete}
- self.filters.each {|f| f.destroy}
- self.dashboards.each {|d| d.destroy}
- self.active_dashboards.each {|ad| ad.destroy}
+ self.user_roles.each { |role| role.delete }
+ self.properties.each { |prop| prop.delete }
+ self.filters.each { |f| f.destroy }
+ self.dashboards.each { |d| d.destroy }
+ self.active_dashboards.each { |ad| ad.destroy }
end
# SONAR-3258
- def reactivate(default_group_name)
+ def reactivate!(default_group_name)
if default_group_name
default_group=Group.find_by_name(default_group_name)
self.groups<<default_group if default_group
end
self.active = true
+ save!
+ on_create
end
def self.find_active_by_login(login)
def self.logins_to_ids(logins=[])
if logins.size>0
- User.find(:all, :select => 'id', :conditions => ['login in (?)', logins]).map{|user| user.id}
+ User.find(:all, :select => 'id', :conditions => ['login in (?)', logins]).map { |user| user.id }
else
[]
end
def favourite_ids
@favourite_ids ||=
begin
- properties().select{|p| p.key==FAVOURITE_PROPERTY_KEY}.map{|p| p.resource_id}
+ properties().select { |p| p.key==FAVOURITE_PROPERTY_KEY }.map { |p| p.resource_id }
end
@favourite_ids
end
rid = resource.id if resource
end
if rid
- props=properties().select{|p| p.key==FAVOURITE_PROPERTY_KEY && p.resource_id==rid}
+ props=properties().select { |p| p.key==FAVOURITE_PROPERTY_KEY && p.resource_id==rid }
if props.size>0
properties().delete(props)
return true
def favourite?(resource_id)
favourite_ids().include?(resource_id.to_i)
end
+
+
+ private
+
+ def on_create
+ Java::OrgSonarServerUi::JRubyFacade.getInstance().onNewUser({'login' => self.login, 'name' => self.name, 'email' => self.email})
+ end
end
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2012 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.server.platform;
+
+import org.junit.Test;
+import org.sonar.api.platform.NewUserHandler;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class NewUserNotifierTest {
+
+ private NewUserHandler.Context context = NewUserHandler.Context.builder().setLogin("marius").setName("Marius").build();
+
+ @Test
+ public void do_not_fail_if_no_handlers() {
+ NewUserNotifier notifier = new NewUserNotifier();
+
+ notifier.onNewUser(context);
+ }
+
+ @Test
+ public void execute_handlers_on_new_user() {
+ NewUserHandler handler1 = mock(NewUserHandler.class);
+ NewUserHandler handler2 = mock(NewUserHandler.class);
+ NewUserNotifier notifier = new NewUserNotifier(new NewUserHandler[]{handler1, handler2});
+
+
+ notifier.onNewUser(context);
+
+ verify(handler1).doOnNewUser(context);
+ verify(handler2).doOnNewUser(context);
+ }
+}