-INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, EXTERNAL_IDENTITY, EXTERNAL_IDENTITY_PROVIDER, USER_LOCAL, CRYPTED_PASSWORD, SALT, IS_ROOT, CREATED_AT, UPDATED_AT) VALUES (1, 'admin', 'Administrator', '', 'admin', 'sonarqube', true, 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', false, '1418215735482', '1418215735482');
+INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, EXTERNAL_IDENTITY, EXTERNAL_IDENTITY_PROVIDER, USER_LOCAL, CRYPTED_PASSWORD, SALT, IS_ROOT, ONBOARDED, CREATED_AT, UPDATED_AT) VALUES (1, 'admin', 'Administrator', '', 'admin', 'sonarqube', true, 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', false, false, '1418215735482', '1418215735482');
ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;
INSERT INTO GROUPS(ID, ORGANIZATION_UUID, NAME, DESCRIPTION, CREATED_AT, UPDATED_AT) VALUES (1, 'AVdqnciQUUs7Zd3KPvFD', 'sonar-administrators', 'System administrators', '2011-09-26 22:27:51.0', '2011-09-26 22:27:51.0');
"EXTERNAL_IDENTITY_PROVIDER" VARCHAR(100),
"IS_ROOT" BOOLEAN NOT NULL,
"USER_LOCAL" BOOLEAN,
+ "ONBOARDED" BOOLEAN NOT NULL,
"CREATED_AT" BIGINT,
"UPDATED_AT" BIGINT
);
private Long updatedAt;
private boolean local = true;
private boolean root = false;
+ private boolean onboarded = false;
public Integer getId() {
return id;
this.root = root;
}
+ public boolean isOnboarded() {
+ return onboarded;
+ }
+
+ public UserDto setOnboarded(boolean onboarded) {
+ this.onboarded = onboarded;
+ return this;
+ }
+
public static String encryptPassword(String password, String salt) {
requireNonNull(password, "Password cannot be empty");
requireNonNull(salt, "Salt cannot be empty");
u.external_identity_provider as "externalIdentityProvider",
u.user_local as "local",
u.is_root as "root",
+ u.onboarded as "onboarded",
u.created_at as "createdAt",
u.updated_at as "updatedAt"
</sql>
salt,
crypted_password,
is_root,
+ onboarded,
created_at,
updated_at
)
#{salt,jdbcType=VARCHAR},
#{cryptedPassword,jdbcType=VARCHAR},
#{root,jdbcType=BOOLEAN},
+ #{onboarded,jdbcType=BOOLEAN},
#{createdAt,jdbcType=BIGINT},
#{updatedAt,jdbcType=BIGINT}
)
external_identity=#{externalIdentity,jdbcType=VARCHAR},
external_identity_provider=#{externalIdentityProvider,jdbcType=VARCHAR},
user_local=#{local,jdbcType=BOOLEAN},
+ onboarded=#{onboarded,jdbcType=BOOLEAN},
salt=#{salt,jdbcType=VARCHAR},
crypted_password=#{cryptedPassword,jdbcType=BIGINT},
updated_at=#{updatedAt,jdbcType=BIGINT}
.setEmail("jo@hn.com")
.setScmAccounts(",jo.hn,john2,")
.setActive(true)
+ .setOnboarded(true)
.setSalt("1234")
.setCryptedPassword("abcd")
.setExternalIdentity("johngithub")
assertThat(user.getName()).isEqualTo("John");
assertThat(user.getEmail()).isEqualTo("jo@hn.com");
assertThat(user.isActive()).isTrue();
+ assertThat(user.isOnboarded()).isTrue();
assertThat(user.getScmAccounts()).isEqualTo(",jo.hn,john2,");
assertThat(user.getSalt()).isEqualTo("1234");
assertThat(user.getCryptedPassword()).isEqualTo("abcd");
.setCreatedAt(1418215735482L)
.setUpdatedAt(1418215735482L)
.setActive(true)
- .setLocal(true);
+ .setLocal(true)
+ .setOnboarded(false);
db.getDbClient().userDao().insert(db.getSession(), existingUser);
db.getSession().commit();
.setEmail("jodoo@hn.com")
.setScmAccounts(",jo.hn,john2,johndoo,")
.setActive(false)
+ .setOnboarded(true)
.setSalt("12345")
.setCryptedPassword("abcde")
.setExternalIdentity("johngithub")
assertThat(user.getName()).isEqualTo("John Doo");
assertThat(user.getEmail()).isEqualTo("jodoo@hn.com");
assertThat(user.isActive()).isFalse();
+ assertThat(user.isOnboarded()).isTrue();
assertThat(user.getScmAccounts()).isEqualTo(",jo.hn,john2,johndoo,");
assertThat(user.getSalt()).isEqualTo("12345");
assertThat(user.getCryptedPassword()).isEqualTo("abcde");
import static java.util.Collections.singletonList;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
+import static org.apache.commons.lang.math.RandomUtils.nextBoolean;
import static org.apache.commons.lang.math.RandomUtils.nextInt;
import static org.apache.commons.lang.math.RandomUtils.nextLong;
public class UserTesting {
public static UserDto newUserDto() {
- return newUserDto(randomAlphanumeric(30), randomAlphanumeric(30), randomAlphanumeric(30));
- }
-
- public static UserDto newUserDto(String login, String name, @Nullable String email) {
return new UserDto()
.setId(nextInt())
.setActive(true)
- .setLocal(true)
- .setName(name)
- .setEmail(email)
- .setLogin(login)
+ .setLocal(nextBoolean())
+ .setLogin(randomAlphanumeric(30))
+ .setName(randomAlphanumeric(30))
+ .setEmail(randomAlphanumeric(30))
+ .setOnboarded(nextBoolean())
.setScmAccounts(singletonList(randomAlphanumeric(40)))
- .setExternalIdentity(login)
- .setExternalIdentityProvider("sonarqube")
+ .setExternalIdentity(randomAlphanumeric(40))
+ .setExternalIdentityProvider(randomAlphanumeric(40))
.setSalt(randomAlphanumeric(40))
.setCryptedPassword(randomAlphanumeric(40))
.setCreatedAt(nextLong())
.setUpdatedAt(nextLong());
}
+ public static UserDto newUserDto(String login, String name, @Nullable String email) {
+ return newUserDto()
+ .setName(name)
+ .setEmail(email)
+ .setLogin(login);
+ }
+
public static UserDto newLocalUser(String login, String name, @Nullable String email) {
- return new UserDto()
- .setId(nextInt())
- .setActive(true)
+ return newUserDto()
.setLocal(true)
.setName(name)
.setEmail(email)
.setLogin(login)
- .setScmAccounts(singletonList(randomAlphanumeric(40)))
.setExternalIdentity(login)
- .setExternalIdentityProvider("sonarqube")
- .setSalt(randomAlphanumeric(40))
- .setCryptedPassword(randomAlphanumeric(40))
- .setCreatedAt(nextLong())
- .setUpdatedAt(nextLong());
+ .setExternalIdentityProvider("sonarqube");
}
public static UserDto newExternalUser(String login, String name, @Nullable String email) {
- return new UserDto()
- .setId(nextInt())
- .setActive(true)
+ return newUserDto()
.setLocal(false)
.setName(name)
.setEmail(email)
.setLogin(login)
- .setScmAccounts(singletonList(randomAlphanumeric(40)))
.setExternalIdentity(randomAlphanumeric(40))
- .setExternalIdentityProvider(randomAlphanumeric(40))
- .setCreatedAt(nextLong())
- .setUpdatedAt(nextLong());
+ .setExternalIdentityProvider(randomAlphanumeric(40));
}
public static UserDto newDisabledUser(String login) {
- return new UserDto()
- .setId(nextInt())
+ return newUserDto()
.setLogin(login)
- .setActive(false)
- .setCreatedAt(nextLong())
- .setUpdatedAt(nextLong());
+ .setActive(false);
}
}
login="user1"
name="User1"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="201"
login="user2"
name="User2"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="202"
login="user3"
name="User3"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="999"
login="disabledUser"
name="disabledUser"
active="[false]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<organization_members
user_id="200"
login="user1"
name="User1"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="201"
login="user2"
name="User2"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="202"
login="user3"
name="User3"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<organization_members
user_id="200"
login="user3"
name="User3"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="201"
login="user1"
name="User1"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="202"
login="user2"
name="User2"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<organization_members
user_id="200"
updated_at="1418215735485"
salt="79bd6a8e79fb8c76ac8b121cc7e8e11ad1af8365"
crypted_password="650d2261c98361e2f67f90ce5c65a95e7d8ea2fg"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="102"
login="sbrandhof"
name="Simon Brandhof"
updated_at="1418215735485"
salt="79bd6a8e79fb8c76ac8b121cc7e8e11ad1af8366"
crypted_password="650d2261c98361e2f67f90ce5c65a95e7d8ea2fh"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
</dataset>
created_at="1418215735482"
updated_at="1418215735482"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
</dataset>
created_at="1418215735482"
updated_at="1418215735485"
active="[false]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<!-- active -->
<users id="101"
created_at="1418215735482"
updated_at="1418215735485"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="102"
login="jcdus"
created_at="1418215735482"
updated_at="1418215735485"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
</dataset>
created_at="1418215735482"
updated_at="1418215735485"
active="[false]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="101"
login="marius"
name="Marius"
created_at="1418215735482"
updated_at="1418215735485"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="102"
login="jcdus"
name="Jean-Claude Dus"
created_at="1418215735482"
updated_at="1418215735485"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
</dataset>
created_at="1418215735482"
updated_at="1418215735485"
active="[false]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="101"
login="marius"
name="Marius"
created_at="1418215735482"
updated_at="1418215735485"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="102"
login="jcdus"
name="Jean-Claude Dus"
created_at="1418215735482"
updated_at="1418215735485"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
</dataset>
created_at="1418215735482"
updated_at="1418215735485"
active="[false]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="101"
login="marius"
name="Marius"
created_at="1418215735482"
updated_at="1418215735485"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
</dataset>
created_at="1418215735482"
updated_at="1418215735485"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="102"
login="sbrandhof"
name="Simon Brandhof"
created_at="1418215735482"
updated_at="1418215735485"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
</dataset>
updated_at="1418215735485"
salt="79bd6a8e79fb8c76ac8b121cc7e8e11ad1af8365"
crypted_password="650d2261c98361e2f67f90ce5c65a95e7d8ea2fg"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="102"
login="sbrandhof"
name="Simon Brandhof"
updated_at="1418215735485"
salt="79bd6a8e79fb8c76ac8b121cc7e8e11ad1af8366"
crypted_password="650d2261c98361e2f67f90ce5c65a95e7d8ea2fh"
- is_root="[true]"/>
+ is_root="[true]"
+ onboarded="[true]"/>
</dataset>
updated_at="1418215735485"
salt="79bd6a8e79fb8c76ac8b121cc7e8e11ad1af8365"
crypted_password="650d2261c98361e2f67f90ce5c65a95e7d8ea2fg"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="102"
login="sbrandhof"
name="Simon Brandhof"
updated_at="1418215735485"
salt="79bd6a8e79fb8c76ac8b121cc7e8e11ad1af8366"
crypted_password="650d2261c98361e2f67f90ce5c65a95e7d8ea2fh"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
</dataset>
updated_at="1418215735485"
salt="79bd6a8e79fb8c76ac8b121cc7e8e11ad1af8365"
crypted_password="650d2261c98361e2f67f90ce5c65a95e7d8ea2fg"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="102"
login="sbrandhof"
name="Simon Brandhof"
updated_at="1418215735485"
salt="79bd6a8e79fb8c76ac8b121cc7e8e11ad1af8366"
crypted_password="650d2261c98361e2f67f90ce5c65a95e7d8ea2fh"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
</dataset>
created_at="1418215735482"
updated_at="1418215735482"
active="[true]"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
</dataset>
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v65;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.def.BooleanColumnDef.newBooleanColumnDefBuilder;
+
+public class AddUsersOnboarded extends DdlChange {
+ public AddUsersOnboarded(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ context.execute(new AddColumnsBuilder(getDialect(), "users")
+ .addColumn(newBooleanColumnDefBuilder()
+ .setColumnName("onboarded")
+ .setIsNullable(true)
+ .build())
+ .build());
+ }
+}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+
package org.sonar.server.platform.db.migration.version.v65;
import org.sonar.server.platform.db.migration.step.MigrationStepRegistry;
.add(1726, "Update org_qprofiles to reference built-in profiles", UpdateOrgQProfilesToPointToBuiltInProfiles.class)
.add(1727, "Delete rules_profiles orphans", DeleteOrphansFromRulesProfiles.class)
.add(1728, "Rename column qprofile_changes.qprofile_key to qprofile_changes.rules_profile_uuid", RenameQProfileKeyToRulesProfileUuidOnQProfileChanges.class)
- .add(1729, "Add index on qprofile_changes.rules_profile_uuid", AddIndexRulesProfileUuidOnQProfileChanges.class);
+ .add(1729, "Add index on qprofile_changes.rules_profile_uuid", AddIndexRulesProfileUuidOnQProfileChanges.class)
+ .add(1730, "Add USERS.ONBOARDED", AddUsersOnboarded.class)
+ .add(1731, "Populate USERS.ONBOARDED", PopulateUsersOnboarded.class)
+ .add(1732, "Make USERS.ONBOARDED not nullable", MakeUsersOnboardedNotNullable.class)
+ ;
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v65;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.def.BooleanColumnDef;
+import org.sonar.server.platform.db.migration.sql.AlterColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.def.BooleanColumnDef.newBooleanColumnDefBuilder;
+
+public class MakeUsersOnboardedNotNullable extends DdlChange {
+
+ public MakeUsersOnboardedNotNullable(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ BooleanColumnDef column = newBooleanColumnDefBuilder()
+ .setColumnName("onboarded")
+ .setIsNullable(false)
+ .build();
+ context.execute(new AlterColumnsBuilder(getDialect(), "users")
+ .updateColumn(column)
+ .build());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v65;
+
+import java.sql.SQLException;
+import org.sonar.api.utils.System2;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.step.DataChange;
+import org.sonar.server.platform.db.migration.step.Select;
+
+public class PopulateUsersOnboarded extends DataChange {
+
+ private final System2 system2;
+
+ public PopulateUsersOnboarded(Database db, System2 system2) {
+ super(db);
+ this.system2 = system2;
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ context.prepareUpsert("update users set onboarded=?, updated_at=?")
+ .setBoolean(1, true)
+ .setLong(2, system2.now())
+ .execute()
+ .commit();
+ long users = context.prepareSelect("select count(u.id) from users u").get(Select.LONG_READER);
+ if (users == 1) {
+ context.prepareUpsert("update users set onboarded=?, updated_at=? where login=?")
+ .setBoolean(1, false)
+ .setLong(2, system2.now())
+ .setString(3, "admin")
+ .execute()
+ .commit();
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v65;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.db.CoreDbTester;
+
+public class AddUsersOnboardedTest {
+ @Rule
+ public CoreDbTester db = CoreDbTester.createForSchema(AddUsersOnboardedTest.class, "users_without_onboarded_column.sql");
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private AddUsersOnboarded underTest = new AddUsersOnboarded(db.database());
+
+ @Test
+ public void execute_adds_nullable_boolean_column_private_to_table_PROJECTS() throws SQLException {
+ underTest.execute();
+
+ db.assertColumnDefinition("users", "onboarded", Types.BOOLEAN, null, true);
+ }
+}
@Test
public void verify_migration_count() {
- verifyMigrationCount(underTest, 30);
+ verifyMigrationCount(underTest, 33);
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v65;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+public class MakeUsersOnboardedNotNullableTest {
+
+ @Rule
+ public CoreDbTester db = CoreDbTester.createForSchema(MakeUsersOnboardedNotNullableTest.class, "users_with_nullable_onboarded_column.sql");
+
+ private MakeUsersOnboardedNotNullable underTest = new MakeUsersOnboardedNotNullable(db.database());
+
+ @Test
+ public void execute_makes_column_component_uuid_not_nullable_on_empty_table() throws SQLException {
+ underTest.execute();
+
+ verifyColumn();
+ }
+
+ @Test
+ public void execute_makes_column_component_uuid_not_nullable_on_populated_table() throws SQLException {
+ insertUser();
+ insertUser();
+ insertUser();
+
+ underTest.execute();
+
+ verifyColumn();
+ }
+
+ private void verifyColumn() {
+ db.assertColumnDefinition("users", "onboarded", Types.BOOLEAN, null, false);
+ }
+
+ private void insertUser() {
+ db.executeInsert(
+ "users",
+ "ONBOARDED", true,
+ "IS_ROOT", true);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v65;
+
+import java.sql.SQLException;
+import java.util.stream.Collectors;
+import org.assertj.core.groups.Tuple;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.api.utils.internal.TestSystem2;
+import org.sonar.db.CoreDbTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.groups.Tuple.tuple;
+
+public class PopulateUsersOnboardedTest {
+
+ private final static long PAST = 100_000_000_000l;
+ private final static long NOW = 500_000_000_000l;
+
+ private System2 system2 = new TestSystem2().setNow(NOW);
+
+ @Rule
+ public CoreDbTester db = CoreDbTester.createForSchema(PopulateUsersOnboardedTest.class, "users_with_onboarded_column.sql");
+
+ public PopulateUsersOnboarded underTest = new PopulateUsersOnboarded(db.database(), system2);
+
+ @Test
+ public void set_onboarded_to_true() throws SQLException {
+ insertUser("admin");
+ insertUser("user");
+ assertUsers(tuple("admin", false, PAST), tuple("user", false, PAST));
+
+ underTest.execute();
+
+ assertUsers(tuple("admin", true, NOW), tuple("user", true, NOW));
+ }
+
+ @Test
+ public void set_onboarded_to_false_when_single_admin_user() throws SQLException {
+ insertUser("admin");
+
+ underTest.execute();
+
+ assertUsers(tuple("admin", false, NOW));
+ }
+
+ @Test
+ public void set_onboarded_to_true_when_single_user_but_not_admin() throws SQLException {
+ insertUser("user");
+
+ underTest.execute();
+
+ assertUsers(tuple("user", true, NOW));
+ }
+
+ private void insertUser(String login) {
+ db.executeInsert("USERS", "LOGIN", login, "ONBOARDED", false, "IS_ROOT", true, "CREATED_AT", PAST, "UPDATED_AT", PAST);
+ }
+
+ private void assertUsers(Tuple... expectedTuples) {
+ assertThat(db.select("SELECT LOGIN, ONBOARDED, UPDATED_AT FROM USERS")
+ .stream()
+ .map(map -> new Tuple(map.get("LOGIN"), map.get("ONBOARDED"), map.get("UPDATED_AT")))
+ .collect(Collectors.toList()))
+ .containsExactlyInAnyOrder(expectedTuples);
+ }
+}
--- /dev/null
+CREATE TABLE "USERS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "LOGIN" VARCHAR(255),
+ "NAME" VARCHAR(200),
+ "EMAIL" VARCHAR(100),
+ "CRYPTED_PASSWORD" VARCHAR(40),
+ "SALT" VARCHAR(40),
+ "ACTIVE" BOOLEAN DEFAULT TRUE,
+ "SCM_ACCOUNTS" VARCHAR(4000),
+ "EXTERNAL_IDENTITY" VARCHAR(255),
+ "EXTERNAL_IDENTITY_PROVIDER" VARCHAR(100),
+ "IS_ROOT" BOOLEAN NOT NULL,
+ "USER_LOCAL" BOOLEAN,
+ "CREATED_AT" BIGINT,
+ "UPDATED_AT" BIGINT
+);
+CREATE UNIQUE INDEX "USERS_LOGIN" ON "USERS" ("LOGIN");
+CREATE INDEX "USERS_UPDATED_AT" ON "USERS" ("UPDATED_AT");
--- /dev/null
+CREATE TABLE "USERS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "LOGIN" VARCHAR(255),
+ "NAME" VARCHAR(200),
+ "EMAIL" VARCHAR(100),
+ "CRYPTED_PASSWORD" VARCHAR(40),
+ "SALT" VARCHAR(40),
+ "ACTIVE" BOOLEAN DEFAULT TRUE,
+ "SCM_ACCOUNTS" VARCHAR(4000),
+ "EXTERNAL_IDENTITY" VARCHAR(255),
+ "EXTERNAL_IDENTITY_PROVIDER" VARCHAR(100),
+ "IS_ROOT" BOOLEAN NOT NULL,
+ "USER_LOCAL" BOOLEAN,
+ "ONBOARDED" BOOLEAN,
+ "CREATED_AT" BIGINT,
+ "UPDATED_AT" BIGINT
+);
+CREATE UNIQUE INDEX "USERS_LOGIN" ON "USERS" ("LOGIN");
+CREATE INDEX "USERS_UPDATED_AT" ON "USERS" ("UPDATED_AT");
--- /dev/null
+CREATE TABLE "USERS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "LOGIN" VARCHAR(255),
+ "NAME" VARCHAR(200),
+ "EMAIL" VARCHAR(100),
+ "CRYPTED_PASSWORD" VARCHAR(40),
+ "SALT" VARCHAR(40),
+ "ACTIVE" BOOLEAN DEFAULT TRUE,
+ "SCM_ACCOUNTS" VARCHAR(4000),
+ "EXTERNAL_IDENTITY" VARCHAR(255),
+ "EXTERNAL_IDENTITY_PROVIDER" VARCHAR(100),
+ "IS_ROOT" BOOLEAN NOT NULL,
+ "USER_LOCAL" BOOLEAN,
+ "ONBOARDED" BOOLEAN,
+ "CREATED_AT" BIGINT,
+ "UPDATED_AT" BIGINT
+);
+CREATE UNIQUE INDEX "USERS_LOGIN" ON "USERS" ("LOGIN");
+CREATE INDEX "USERS_UPDATED_AT" ON "USERS" ("UPDATED_AT");
.setLogin("ada.lovelace")
.setEmail("ada.lovelace@noteg.com")
.setName("Ada Lovelace")
+ .setLocal(true)
.setScmAccounts(singletonList("al")));
logInAsSystemAdministrator();
import org.sonar.server.es.EsTester;
import org.sonar.server.issue.ws.AvatarResolverImpl;
import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.user.index.UserDoc;
import org.sonar.server.user.index.UserIndex;
import org.sonar.server.user.index.UserIndexDefinition;
import org.sonar.server.user.index.UserIndexer;
private WsTester ws = new WsTester(new UsersWs(new SearchAction(userSession, index, dbClient, new AvatarResolverImpl())));
@Test
- public void search_json_example() throws Exception {
+ public void test_json_example() throws Exception {
UserDto fmallet = db.users().insertUser(newUserDto("fmallet", "Freddy Mallet", "f@m.com")
.setActive(true)
.setLocal(true)
- .setScmAccounts(emptyList()));
+ .setScmAccounts(emptyList())
+ .setExternalIdentity("fmallet")
+ .setExternalIdentityProvider("sonarqube"));
UserDto simon = db.users().insertUser(newUserDto("sbrandhof", "Simon", "s.brandhof@company.tld")
.setActive(true)
.setLocal(false)
public void search_with_query() throws Exception {
loginAsSimpleUser();
injectUsers(5);
- UserDto user = db.users().insertUser(newUserDto("user-%_%-login", "user-name", "user@mail.com").setScmAccounts(singletonList("user1")));
- esTester.putDocuments(UserIndexDefinition.INDEX_TYPE_USER.getIndex(), UserIndexDefinition.INDEX_TYPE_USER.getType(),
- new UserDoc()
- .setActive(true)
- .setEmail(user.getEmail())
- .setLogin(user.getLogin())
- .setName(user.getName())
- .setCreatedAt(user.getCreatedAt())
- .setUpdatedAt(user.getUpdatedAt())
- .setScmAccounts(user.getScmAccountsAsList()));
+ UserDto user = db.users().insertUser(u -> u
+ .setLogin("user-%_%-login")
+ .setName("user-name")
+ .setEmail("user@mail.com")
+ .setLocal(true)
+ .setScmAccounts(singletonList("user1")));
+ userIndexer.indexOnStartup(null);
ws.newGetRequest("api/users", "search").setParam("q", "user-%_%-").execute().assertJson(getClass(), "user_one.json");
ws.newGetRequest("api/users", "search").setParam("q", "user@MAIL.com").execute().assertJson(getClass(), "user_one.json");
.setLogin("john")
.setName("John")
.setScmAccounts(newArrayList("jn"))
- .setActive(true);
- dbClient.userDao().insert(session, userDto)
+ .setActive(true)
+ .setLocal(true)
.setExternalIdentity("jo")
.setExternalIdentityProvider("sonarqube");
+ dbClient.userDao().insert(session, userDto);
session.commit();
userIndexer.index(userDto.getLogin());
}
login="simon"
name="Simon Brandhof"
email="simon.brandhof@sonarsource.com"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
<users id="2"
login="godin"
name="Evgeny Mandrikov"
email="evgeny.mandrikov@sonarsource.com"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
</dataset>
scm_accounts=" user_1 u1 "
created_at="1500000000000"
updated_at="1500000000000"
- is_root="[false]"/>
+ is_root="[false]"
+ onboarded="[true]"/>
</dataset>