@@ -115,13 +115,13 @@ public class ComputeEngineContainerImplTest { | |||
); | |||
assertThat(picoContainer.getParent().getParent().getComponentAdapters()).hasSize( | |||
CONTAINER_ITSELF | |||
+ 19 // MigrationConfigurationModule | |||
+ 20 // MigrationConfigurationModule | |||
+ 17 // level 2 | |||
); | |||
assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize( | |||
COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION | |||
+ 26 // level 1 | |||
+ 59 // content of DaoModule | |||
+ 60 // content of DaoModule | |||
+ 3 // content of EsModule | |||
+ 54 // content of CorePropertyDefinitions | |||
+ 1 // StopFlagContainer |
@@ -108,6 +108,7 @@ public final class SqTables { | |||
"schema_migrations", | |||
"snapshots", | |||
"users", | |||
"user_properties", | |||
"user_roles", | |||
"user_tokens", | |||
"webhooks", |
@@ -936,3 +936,15 @@ CREATE TABLE "ORGANIZATION_ALM_BINDINGS" ( | |||
); | |||
CREATE UNIQUE INDEX "ORG_ALM_BINDINGS_ORG" ON "ORGANIZATION_ALM_BINDINGS" ("ORGANIZATION_UUID"); | |||
CREATE UNIQUE INDEX "ORG_ALM_BINDINGS_INSTALL" ON "ORGANIZATION_ALM_BINDINGS" ("ALM_APP_INSTALL_UUID"); | |||
CREATE TABLE "USER_PROPERTIES" ( | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"USER_UUID" VARCHAR(255) NOT NULL, | |||
"KEE" VARCHAR(100) NOT NULL, | |||
"TEXT_VALUE" VARCHAR(4000) NOT NULL, | |||
"CREATED_AT" BIGINT NOT NULL, | |||
"UPDATED_AT" BIGINT NOT NULL, | |||
CONSTRAINT "PK_USER_PROPERTIES" PRIMARY KEY ("UUID") | |||
); | |||
CREATE UNIQUE INDEX "USER_PROPERTIES_USER_UUID_KEE" ON "USER_PROPERTIES" ("USER_UUID", "KEE"); |
@@ -79,6 +79,7 @@ import org.sonar.db.user.GroupMembershipDao; | |||
import org.sonar.db.user.RoleDao; | |||
import org.sonar.db.user.UserDao; | |||
import org.sonar.db.user.UserGroupDao; | |||
import org.sonar.db.user.UserPropertiesDao; | |||
import org.sonar.db.user.UserTokenDao; | |||
import org.sonar.db.webhook.WebhookDao; | |||
import org.sonar.db.webhook.WebhookDeliveryDao; | |||
@@ -144,6 +145,7 @@ public class DaoModule extends Module { | |||
UserDao.class, | |||
UserGroupDao.class, | |||
UserPermissionDao.class, | |||
UserPropertiesDao.class, | |||
UserTokenDao.class, | |||
WebhookDao.class, | |||
WebhookDeliveryDao.class)); |
@@ -77,6 +77,7 @@ import org.sonar.db.user.GroupMembershipDao; | |||
import org.sonar.db.user.RoleDao; | |||
import org.sonar.db.user.UserDao; | |||
import org.sonar.db.user.UserGroupDao; | |||
import org.sonar.db.user.UserPropertiesDao; | |||
import org.sonar.db.user.UserTokenDao; | |||
import org.sonar.db.webhook.WebhookDao; | |||
import org.sonar.db.webhook.WebhookDeliveryDao; | |||
@@ -103,6 +104,7 @@ public class DbClient { | |||
private final UserDao userDao; | |||
private final UserGroupDao userGroupDao; | |||
private final UserTokenDao userTokenDao; | |||
private final UserPropertiesDao userPropertiesDao; | |||
private final GroupMembershipDao groupMembershipDao; | |||
private final RoleDao roleDao; | |||
private final GroupPermissionDao groupPermissionDao; | |||
@@ -172,6 +174,7 @@ public class DbClient { | |||
userDao = getDao(map, UserDao.class); | |||
userGroupDao = getDao(map, UserGroupDao.class); | |||
userTokenDao = getDao(map, UserTokenDao.class); | |||
userPropertiesDao = getDao(map, UserPropertiesDao.class); | |||
groupMembershipDao = getDao(map, GroupMembershipDao.class); | |||
roleDao = getDao(map, RoleDao.class); | |||
groupPermissionDao = getDao(map, GroupPermissionDao.class); | |||
@@ -301,6 +304,10 @@ public class DbClient { | |||
return userTokenDao; | |||
} | |||
public UserPropertiesDao userPropertiesDao() { | |||
return userPropertiesDao; | |||
} | |||
public GroupMembershipDao groupMembershipDao() { | |||
return groupMembershipDao; | |||
} |
@@ -131,6 +131,7 @@ import org.sonar.db.user.UserDto; | |||
import org.sonar.db.user.UserGroupDto; | |||
import org.sonar.db.user.UserGroupMapper; | |||
import org.sonar.db.user.UserMapper; | |||
import org.sonar.db.user.UserPropertiesMapper; | |||
import org.sonar.db.user.UserTokenCount; | |||
import org.sonar.db.user.UserTokenDto; | |||
import org.sonar.db.user.UserTokenMapper; | |||
@@ -261,6 +262,7 @@ public class MyBatis implements Startable { | |||
UserGroupMapper.class, | |||
UserMapper.class, | |||
UserPermissionMapper.class, | |||
UserPropertiesMapper.class, | |||
UserTokenMapper.class, | |||
WebhookMapper.class, | |||
WebhookDeliveryMapper.class |
@@ -0,0 +1,58 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.db.user; | |||
import java.util.List; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.core.util.UuidFactory; | |||
import org.sonar.db.Dao; | |||
import org.sonar.db.DbSession; | |||
public class UserPropertiesDao implements Dao { | |||
private final System2 system2; | |||
private final UuidFactory uuidFactory; | |||
public UserPropertiesDao(System2 system2, UuidFactory uuidFactory) { | |||
this.system2 = system2; | |||
this.uuidFactory = uuidFactory; | |||
} | |||
public List<UserPropertyDto> selectByUser(DbSession session, UserDto user) { | |||
return mapper(session).selectByUserUuid(user.getUuid()); | |||
} | |||
public UserPropertyDto insertOrUpdate(DbSession session, UserPropertyDto dto) { | |||
long now = system2.now(); | |||
if (mapper(session).update(dto, now) == 0) { | |||
mapper(session).insert(dto.setUuid(uuidFactory.create()), now); | |||
} | |||
return dto; | |||
} | |||
public void deleteByUser(DbSession session, UserDto user) { | |||
mapper(session).deleteByUserUuid(user.getUuid()); | |||
} | |||
private static UserPropertiesMapper mapper(DbSession session) { | |||
return session.getMapper(UserPropertiesMapper.class); | |||
} | |||
} |
@@ -0,0 +1,35 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.db.user; | |||
import java.util.List; | |||
import org.apache.ibatis.annotations.Param; | |||
public interface UserPropertiesMapper { | |||
List<UserPropertyDto> selectByUserUuid(@Param("userUuid") String userUuid); | |||
void insert(@Param("userProperty") UserPropertyDto userPropertyDto, @Param("now") long now); | |||
int update(@Param("userProperty") UserPropertyDto userPropertyDto, @Param("now") long now); | |||
void deleteByUserUuid(@Param("userUuid") String userUuid); | |||
} |
@@ -0,0 +1,80 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.db.user; | |||
public class UserPropertyDto { | |||
/** | |||
* Unique UUID identifier. Max size is 40. Can't be null. | |||
*/ | |||
private String uuid; | |||
/** | |||
* The UUID of the user the settings belongs to. Max size is 255. Can't be null. | |||
*/ | |||
private String userUuid; | |||
/** | |||
* The key of the settings. Max size is 100. Can't be null. | |||
*/ | |||
private String key; | |||
/** | |||
* The value of the settings. Max size is 4000. Can't be null. | |||
*/ | |||
private String value; | |||
public String getUuid() { | |||
return uuid; | |||
} | |||
UserPropertyDto setUuid(String uuid) { | |||
this.uuid = uuid; | |||
return this; | |||
} | |||
public String getUserUuid() { | |||
return userUuid; | |||
} | |||
public UserPropertyDto setUserUuid(String userUuid) { | |||
this.userUuid = userUuid; | |||
return this; | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
public UserPropertyDto setKey(String key) { | |||
this.key = key; | |||
return this; | |||
} | |||
public String getValue() { | |||
return value; | |||
} | |||
public UserPropertyDto setValue(String value) { | |||
this.value = value; | |||
return this; | |||
} | |||
} |
@@ -0,0 +1,51 @@ | |||
<?xml version="1.0" encoding="UTF-8" ?> | |||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd"> | |||
<mapper namespace="org.sonar.db.user.UserPropertiesMapper"> | |||
<sql id="userPropertiesColumns"> | |||
us.uuid as uuid, | |||
us.user_uuid as userUuid, | |||
us.kee as "key", | |||
us.text_value as "value" | |||
</sql> | |||
<select id="selectByUserUuid" parameterType="String" resultType="org.sonar.db.user.UserPropertyDto"> | |||
SELECT | |||
<include refid="userPropertiesColumns"/> | |||
FROM user_properties us | |||
WHERE us.user_uuid=#{userUuid} | |||
</select> | |||
<insert id="insert" parameterType="map" useGeneratedKeys="false"> | |||
INSERT INTO user_properties ( | |||
uuid, | |||
user_uuid, | |||
kee, | |||
text_value, | |||
created_at, | |||
updated_at | |||
) VALUES ( | |||
#{userProperty.uuid,jdbcType=VARCHAR}, | |||
#{userProperty.userUuid,jdbcType=VARCHAR}, | |||
#{userProperty.key,jdbcType=VARCHAR}, | |||
#{userProperty.value,jdbcType=VARCHAR}, | |||
#{now,jdbcType=BIGINT}, | |||
#{now,jdbcType=BIGINT} | |||
) | |||
</insert> | |||
<update id="update" parameterType="map"> | |||
UPDATE user_properties SET | |||
text_value = #{userProperty.value, jdbcType=VARCHAR}, | |||
updated_at = #{now,jdbcType=BIGINT} | |||
WHERE | |||
user_uuid = #{userProperty.userUuid, jdbcType=VARCHAR} | |||
AND kee = #{userProperty.key, jdbcType=VARCHAR} | |||
</update> | |||
<update id="deleteByUserUuid" parameterType="String"> | |||
DELETE FROM user_properties WHERE user_uuid=#{userUuid,jdbcType=VARCHAR} | |||
</update> | |||
</mapper> |
@@ -30,6 +30,6 @@ public class DaoModuleTest { | |||
public void verify_count_of_added_components() { | |||
ComponentContainer container = new ComponentContainer(); | |||
new DaoModule().configure(container); | |||
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 59); | |||
assertThat(container.size()).isEqualTo(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 60); | |||
} | |||
} |
@@ -23,12 +23,11 @@ import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.user.UserQuery; | |||
import org.sonar.api.utils.DateUtils; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.utils.internal.TestSystem2; | |||
import org.sonar.db.DatabaseUtils; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
@@ -42,15 +41,13 @@ import static java.util.Collections.emptyList; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.groups.Tuple.tuple; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.db.user.GroupTesting.newGroupDto; | |||
import static org.sonar.db.user.UserTesting.newUserDto; | |||
public class UserDaoTest { | |||
private static final long NOW = 1_500_000_000_000L; | |||
private System2 system2 = mock(System2.class); | |||
private TestSystem2 system2 = new TestSystem2().setNow(NOW); | |||
@Rule | |||
public DbTester db = DbTester.create(system2); | |||
@@ -59,11 +56,6 @@ public class UserDaoTest { | |||
private DbSession session = db.getSession(); | |||
private UserDao underTest = db.getDbClient().userDao(); | |||
@Before | |||
public void setUp() { | |||
when(system2.now()).thenReturn(NOW); | |||
} | |||
@Test | |||
public void selectByUuid() { | |||
UserDto user1 = db.users().insertUser(); | |||
@@ -363,11 +355,11 @@ public class UserDaoTest { | |||
public void countNewUsersSince() { | |||
assertThat(underTest.countNewUsersSince(session, 400L)).isEqualTo(0); | |||
when(system2.now()).thenReturn(100L); | |||
system2.setNow(100L); | |||
insertNonRootUser(newUserDto()); | |||
when(system2.now()).thenReturn(200L); | |||
system2.setNow(200L); | |||
insertNonRootUser(newUserDto()); | |||
when(system2.now()).thenReturn(300L); | |||
system2.setNow(300L); | |||
insertNonRootUser(newUserDto()); | |||
assertThat(underTest.countNewUsersSince(session, 50L)).isEqualTo(3); | |||
@@ -707,25 +699,25 @@ public class UserDaoTest { | |||
assertThat(underTest.selectByLogin(session, otherUser.getLogin()).isRoot()).isEqualTo(false); | |||
// does not fail when changing to same value | |||
when(system2.now()).thenReturn(15_000L); | |||
system2.setNow(15_000L); | |||
commit(() -> underTest.setRoot(session, login, false)); | |||
verifyRootAndUpdatedAt(login, false, 15_000L); | |||
verifyRootAndUpdatedAt(otherUser.getLogin(), false, otherUser.getUpdatedAt()); | |||
// change value | |||
when(system2.now()).thenReturn(26_000L); | |||
system2.setNow(26_000L); | |||
commit(() -> underTest.setRoot(session, login, true)); | |||
verifyRootAndUpdatedAt(login, true, 26_000L); | |||
verifyRootAndUpdatedAt(otherUser.getLogin(), false, otherUser.getUpdatedAt()); | |||
// does not fail when changing to same value | |||
when(system2.now()).thenReturn(37_000L); | |||
system2.setNow(37_000L); | |||
commit(() -> underTest.setRoot(session, login, true)); | |||
verifyRootAndUpdatedAt(login, true, 37_000L); | |||
verifyRootAndUpdatedAt(otherUser.getLogin(), false, otherUser.getUpdatedAt()); | |||
// change value back | |||
when(system2.now()).thenReturn(48_000L); | |||
system2.setNow(48_000L); | |||
commit(() -> underTest.setRoot(session, login, false)); | |||
verifyRootAndUpdatedAt(login, false, 48_000L); | |||
verifyRootAndUpdatedAt(otherUser.getLogin(), false, otherUser.getUpdatedAt()); |
@@ -44,6 +44,7 @@ import static org.sonar.db.permission.OrganizationPermission.ADMINISTER; | |||
import static org.sonar.db.user.GroupTesting.newGroupDto; | |||
import static org.sonar.db.user.UserTesting.newDisabledUser; | |||
import static org.sonar.db.user.UserTesting.newUserDto; | |||
import static org.sonar.db.user.UserTesting.newUserSettingDto; | |||
import static org.sonar.db.user.UserTokenTesting.newUserToken; | |||
public class UserDbTester { | |||
@@ -110,6 +111,17 @@ public class UserDbTester { | |||
return Optional.ofNullable(dbClient.userDao().selectByLogin(db.getSession(), login)); | |||
} | |||
// USER SETTINGS | |||
@SafeVarargs | |||
public final UserPropertyDto insertUserSetting(UserDto user, Consumer<UserPropertyDto>... populators) { | |||
UserPropertyDto dto = newUserSettingDto(user); | |||
stream(populators).forEach(p -> p.accept(dto)); | |||
dbClient.userPropertiesDao().insertOrUpdate(db.getSession(), dto); | |||
db.commit(); | |||
return dto; | |||
} | |||
// GROUPS | |||
public GroupDto insertGroup(OrganizationDto organization, String name) { |
@@ -0,0 +1,127 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.db.user; | |||
import java.util.List; | |||
import java.util.Map; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.utils.internal.TestSystem2; | |||
import org.sonar.db.DbTester; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.entry; | |||
public class UserPropertiesDaoTest { | |||
private static final long NOW = 1_500_000_000_000L; | |||
private TestSystem2 system2 = new TestSystem2().setNow(NOW); | |||
@Rule | |||
public DbTester db = DbTester.create(system2); | |||
private UserPropertiesDao underTest = db.getDbClient().userPropertiesDao(); | |||
@Test | |||
public void select_by_user() { | |||
UserDto user = db.users().insertUser(); | |||
UserPropertyDto userSetting1 = db.users().insertUserSetting(user); | |||
UserPropertyDto userSetting2 = db.users().insertUserSetting(user); | |||
UserDto anotherUser = db.users().insertUser(); | |||
UserPropertyDto userSetting3 = db.users().insertUserSetting(anotherUser); | |||
List<UserPropertyDto> results = underTest.selectByUser(db.getSession(), user); | |||
assertThat(results) | |||
.extracting(UserPropertyDto::getUuid) | |||
.containsExactlyInAnyOrder(userSetting1.getUuid(), userSetting2.getUuid()) | |||
.doesNotContain(userSetting3.getUuid()); | |||
} | |||
@Test | |||
public void insert() { | |||
UserDto user = db.users().insertUser(); | |||
UserPropertyDto userSetting = underTest.insertOrUpdate(db.getSession(), new UserPropertyDto() | |||
.setUserUuid(user.getUuid()) | |||
.setKey("a_key") | |||
.setValue("a_value")); | |||
Map<String, Object> map = db.selectFirst(db.getSession(), "select uuid as \"uuid\",\n" + | |||
" user_uuid as \"userUuid\",\n" + | |||
" kee as \"key\",\n" + | |||
" text_value as \"value\"," + | |||
" created_at as \"createdAt\",\n" + | |||
" updated_at as \"updatedAt\"" + | |||
" from user_properties"); | |||
assertThat(map).contains( | |||
entry("uuid", userSetting.getUuid()), | |||
entry("userUuid", user.getUuid()), | |||
entry("key", "a_key"), | |||
entry("value", "a_value"), | |||
entry("createdAt", NOW), | |||
entry("updatedAt", NOW)); | |||
} | |||
@Test | |||
public void update() { | |||
UserDto user = db.users().insertUser(); | |||
UserPropertyDto userProperty = underTest.insertOrUpdate(db.getSession(), new UserPropertyDto() | |||
.setUserUuid(user.getUuid()) | |||
.setKey("a_key") | |||
.setValue("old_value")); | |||
system2.setNow(2_000_000_000_000L); | |||
underTest.insertOrUpdate(db.getSession(), new UserPropertyDto() | |||
.setUserUuid(user.getUuid()) | |||
.setKey("a_key") | |||
.setValue("new_value")); | |||
Map<String, Object> map = db.selectFirst(db.getSession(), "select uuid as \"uuid\",\n" + | |||
" user_uuid as \"userUuid\",\n" + | |||
" kee as \"key\",\n" + | |||
" text_value as \"value\"," + | |||
" created_at as \"createdAt\",\n" + | |||
" updated_at as \"updatedAt\"" + | |||
" from user_properties"); | |||
assertThat(map).contains( | |||
entry("uuid", userProperty.getUuid()), | |||
entry("userUuid", user.getUuid()), | |||
entry("key", "a_key"), | |||
entry("value", "new_value"), | |||
entry("createdAt", NOW), | |||
entry("updatedAt", 2_000_000_000_000L)); | |||
} | |||
@Test | |||
public void delete_by_user() { | |||
UserDto user = db.users().insertUser(); | |||
db.users().insertUserSetting(user); | |||
db.users().insertUserSetting(user); | |||
UserDto anotherUser = db.users().insertUser(); | |||
db.users().insertUserSetting(anotherUser); | |||
underTest.deleteByUser(db.getSession(), user); | |||
assertThat(underTest.selectByUser(db.getSession(), user)).isEmpty(); | |||
assertThat(underTest.selectByUser(db.getSession(), anotherUser)).hasSize(1); | |||
} | |||
} |
@@ -20,6 +20,7 @@ | |||
package org.sonar.db.user; | |||
import javax.annotation.Nullable; | |||
import org.sonar.core.util.Uuids; | |||
import static java.util.Collections.singletonList; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | |||
@@ -87,4 +88,12 @@ public class UserTesting { | |||
.setCryptedPassword(null) | |||
.setSalt(null); | |||
} | |||
public static UserPropertyDto newUserSettingDto(UserDto user) { | |||
return new UserPropertyDto() | |||
.setUuid(Uuids.createFast()) | |||
.setUserUuid(user.getUuid()) | |||
.setKey(randomAlphanumeric(20)) | |||
.setValue(randomAlphanumeric(100)); | |||
} | |||
} |
@@ -39,6 +39,7 @@ import org.sonar.server.platform.db.migration.version.v72.DbVersion72; | |||
import org.sonar.server.platform.db.migration.version.v73.DbVersion73; | |||
import org.sonar.server.platform.db.migration.version.v74.DbVersion74; | |||
import org.sonar.server.platform.db.migration.version.v75.DbVersion75; | |||
import org.sonar.server.platform.db.migration.version.v76.DbVersion76; | |||
public class MigrationConfigurationModule extends Module { | |||
@Override | |||
@@ -61,6 +62,7 @@ public class MigrationConfigurationModule extends Module { | |||
DbVersion73.class, | |||
DbVersion74.class, | |||
DbVersion75.class, | |||
DbVersion76.class, | |||
// migration steps | |||
MigrationStepRegistryImpl.class, |
@@ -0,0 +1,58 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.v76; | |||
import java.sql.SQLException; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.SupportsBlueGreen; | |||
import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder; | |||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; | |||
@SupportsBlueGreen | |||
public class AddUniqueIndexInUserPropertiesTable extends DdlChange { | |||
private static final String TABLE_NAME = "user_properties"; | |||
public AddUniqueIndexInUserPropertiesTable(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
public void execute(Context context) throws SQLException { | |||
context.execute(new CreateIndexBuilder(getDialect()) | |||
.addColumn(newVarcharColumnDefBuilder() | |||
.setColumnName("user_uuid") | |||
.setIsNullable(false) | |||
.setLimit(255) | |||
.build()) | |||
.addColumn(newVarcharColumnDefBuilder() | |||
.setColumnName("kee") | |||
.setIsNullable(false) | |||
.setLimit(100) | |||
.build()) | |||
.setUnique(true) | |||
.setTable(TABLE_NAME) | |||
.setName("user_properties_user_uuid_kee") | |||
.build()); | |||
} | |||
} |
@@ -0,0 +1,94 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.v76; | |||
import java.sql.Connection; | |||
import java.sql.SQLException; | |||
import org.sonar.db.Database; | |||
import org.sonar.db.DatabaseUtils; | |||
import org.sonar.server.platform.db.migration.SupportsBlueGreen; | |||
import org.sonar.server.platform.db.migration.def.BigIntegerColumnDef; | |||
import org.sonar.server.platform.db.migration.def.VarcharColumnDef; | |||
import org.sonar.server.platform.db.migration.sql.CreateTableBuilder; | |||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||
import static org.sonar.server.platform.db.migration.def.BigIntegerColumnDef.newBigIntegerColumnDefBuilder; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_SIZE; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; | |||
@SupportsBlueGreen | |||
public class CreateUserPropertiesTable extends DdlChange { | |||
private static final String TABLE_NAME = "user_properties"; | |||
private static final VarcharColumnDef UUID_COLUMN = newVarcharColumnDefBuilder() | |||
.setColumnName("uuid") | |||
.setIsNullable(false) | |||
.setLimit(UUID_SIZE) | |||
.build(); | |||
private static final VarcharColumnDef USER_UUID_COLUMN = newVarcharColumnDefBuilder() | |||
.setColumnName("user_uuid") | |||
.setIsNullable(false) | |||
.setLimit(255) | |||
.build(); | |||
private static final VarcharColumnDef KEY_COLUMN = newVarcharColumnDefBuilder() | |||
.setColumnName("kee") | |||
.setIsNullable(false) | |||
.setLimit(100) | |||
.build(); | |||
private static final VarcharColumnDef TEXT_VALUE_COLUMN = newVarcharColumnDefBuilder() | |||
.setColumnName("text_value") | |||
.setIsNullable(false) | |||
.setLimit(4000) | |||
.build(); | |||
private static final BigIntegerColumnDef CREATED_AT_COLUMN = newBigIntegerColumnDefBuilder() | |||
.setColumnName("created_at") | |||
.setIsNullable(false) | |||
.build(); | |||
private static final BigIntegerColumnDef UPDATED_AT_COLUMN = newBigIntegerColumnDefBuilder() | |||
.setColumnName("updated_at") | |||
.setIsNullable(false) | |||
.build(); | |||
public CreateUserPropertiesTable(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
public void execute(Context context) throws SQLException { | |||
if (tableExists()) { | |||
return; | |||
} | |||
context.execute(new CreateTableBuilder(getDialect(), TABLE_NAME) | |||
.addPkColumn(UUID_COLUMN) | |||
.addColumn(USER_UUID_COLUMN) | |||
.addColumn(KEY_COLUMN) | |||
.addColumn(TEXT_VALUE_COLUMN) | |||
.addColumn(CREATED_AT_COLUMN) | |||
.addColumn(UPDATED_AT_COLUMN) | |||
.build()); | |||
} | |||
private boolean tableExists() throws SQLException { | |||
try (Connection connection = getDatabase().getDataSource().getConnection()) { | |||
return DatabaseUtils.tableExists(TABLE_NAME, connection); | |||
} | |||
} | |||
} |
@@ -0,0 +1,33 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.v76; | |||
import org.sonar.server.platform.db.migration.step.MigrationStepRegistry; | |||
import org.sonar.server.platform.db.migration.version.DbVersion; | |||
public class DbVersion76 implements DbVersion { | |||
@Override | |||
public void addSteps(MigrationStepRegistry registry) { | |||
registry | |||
.add(2500, "Create table USER_PROPERTIES", CreateUserPropertiesTable.class) | |||
.add(2501, "Add index in table USER_PROPERTIES", AddUniqueIndexInUserPropertiesTable.class); | |||
} | |||
} |
@@ -0,0 +1,24 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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. | |||
*/ | |||
@ParametersAreNonnullByDefault | |||
package org.sonar.server.platform.db.migration.version.v76; | |||
import javax.annotation.ParametersAreNonnullByDefault; | |||
@@ -37,7 +37,7 @@ public class MigrationConfigurationModuleTest { | |||
assertThat(container.getPicoContainer().getComponentAdapters()) | |||
.hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER | |||
// DbVersion classes | |||
+ 16 | |||
+ 17 | |||
// Others | |||
+ 3); | |||
} |
@@ -63,5 +63,4 @@ public class CreateOrganizationsAlmBindingsTableTest { | |||
db.assertUniqueIndex(TABLE, "org_alm_bindings_org", "organization_uuid"); | |||
db.assertUniqueIndex(TABLE, "org_alm_bindings_install", "alm_app_install_uuid"); | |||
} | |||
} |
@@ -0,0 +1,55 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.v76; | |||
import java.sql.SQLException; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.db.CoreDbTester; | |||
public class AddUniqueIndexInUserPropertiesTableTest { | |||
private static final String TABLE = "user_properties"; | |||
@Rule | |||
public final CoreDbTester db = CoreDbTester.createForSchema(AddUniqueIndexInUserPropertiesTableTest.class, "user_properties.sql"); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private AddUniqueIndexInUserPropertiesTable underTest = new AddUniqueIndexInUserPropertiesTable(db.database()); | |||
@Test | |||
public void creates_index() throws SQLException { | |||
underTest.execute(); | |||
db.assertUniqueIndex(TABLE, "user_properties_user_uuid_kee", "user_uuid", "kee"); | |||
} | |||
@Test | |||
public void migration_is_not_re_entrant() throws SQLException { | |||
underTest.execute(); | |||
expectedException.expect(IllegalStateException.class); | |||
underTest.execute(); | |||
} | |||
} |
@@ -0,0 +1,63 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.v76; | |||
import java.sql.SQLException; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.db.CoreDbTester; | |||
import static java.sql.Types.BIGINT; | |||
import static java.sql.Types.VARCHAR; | |||
public class CreateUserPropertiesTableTest { | |||
private static final String TABLE = "user_properties"; | |||
@Rule | |||
public final CoreDbTester db = CoreDbTester.createEmpty(); | |||
private CreateUserPropertiesTable underTest = new CreateUserPropertiesTable(db.database()); | |||
@Test | |||
public void creates_table() throws SQLException { | |||
underTest.execute(); | |||
checkTable(); | |||
} | |||
@Test | |||
public void migration_is_reentrant() throws SQLException { | |||
underTest.execute(); | |||
underTest.execute(); | |||
checkTable(); | |||
} | |||
private void checkTable() { | |||
db.assertPrimaryKey(TABLE, "pk_user_properties", "uuid"); | |||
db.assertColumnDefinition(TABLE, "uuid", VARCHAR, 40, false); | |||
db.assertColumnDefinition(TABLE, "user_uuid", VARCHAR, 255, false); | |||
db.assertColumnDefinition(TABLE, "kee", VARCHAR, 100, false); | |||
db.assertColumnDefinition(TABLE, "text_value", VARCHAR, 4000, false); | |||
db.assertColumnDefinition(TABLE, "created_at", BIGINT, null, false); | |||
db.assertColumnDefinition(TABLE, "updated_at", BIGINT, null, false); | |||
} | |||
} |
@@ -0,0 +1,41 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.v76; | |||
import org.junit.Test; | |||
import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMigrationCount; | |||
import static org.sonar.server.platform.db.migration.version.DbVersionTestUtils.verifyMinimumMigrationNumber; | |||
public class DbVersion76Test { | |||
private DbVersion76 underTest = new DbVersion76(); | |||
@Test | |||
public void migrationNumber_starts_at_2500() { | |||
verifyMinimumMigrationNumber(underTest, 2500); | |||
} | |||
@Test | |||
public void verify_migration_count() { | |||
verifyMigrationCount(underTest, 2); | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
CREATE TABLE "USER_PROPERTIES" ( | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"USER_UUID" VARCHAR(255) NOT NULL, | |||
"KEE" VARCHAR(100) NOT NULL, | |||
"TEXT_VALUE" VARCHAR(4000) NOT NULL, | |||
"CREATED_AT" BIGINT NOT NULL, | |||
"UPDATED_AT" BIGINT NOT NULL, | |||
CONSTRAINT "PK_USER_PROPERTIES" PRIMARY KEY ("UUID") | |||
); |
@@ -27,6 +27,7 @@ import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService.NewController; | |||
import org.sonar.core.platform.PluginRepository; | |||
import org.sonar.core.util.stream.MoreCollectors; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
@@ -125,7 +126,8 @@ public class CurrentAction implements UsersWsAction { | |||
.addAllScmAccounts(user.getScmAccountsAsList()) | |||
.setPermissions(Permissions.newBuilder().addAllGlobal(getGlobalPermissions()).build()) | |||
.setHomepage(buildHomepage(dbSession, user)) | |||
.setShowOnboardingTutorial(!user.isOnboarded()); | |||
.setShowOnboardingTutorial(!user.isOnboarded()) | |||
.addAllSettings(loadUserSettings(dbSession, user)); | |||
setNullable(emptyToNull(user.getEmail()), builder::setEmail); | |||
setNullable(emptyToNull(user.getEmail()), u -> builder.setAvatar(avatarResolver.create(user))); | |||
setNullable(user.getExternalLogin(), builder::setExternalIdentity); | |||
@@ -237,6 +239,16 @@ public class CurrentAction implements UsersWsAction { | |||
.build(); | |||
} | |||
private List<CurrentWsResponse.Setting> loadUserSettings(DbSession dbSession, UserDto user) { | |||
return dbClient.userPropertiesDao().selectByUser(dbSession, user) | |||
.stream() | |||
.map(dto -> CurrentWsResponse.Setting.newBuilder() | |||
.setKey(dto.getKey()) | |||
.setValue(dto.getValue()) | |||
.build()) | |||
.collect(MoreCollectors.toList()); | |||
} | |||
private static boolean noHomepageSet(UserDto user) { | |||
return user.getHomepageType() == null; | |||
} |
@@ -102,6 +102,7 @@ public class DeactivateAction implements UsersWsAction { | |||
dbClient.permissionTemplateDao().deleteUserPermissionsByUserId(dbSession, userId); | |||
dbClient.qProfileEditUsersDao().deleteByUser(dbSession, user); | |||
dbClient.organizationMemberDao().deleteByUserId(dbSession, userId); | |||
dbClient.userPropertiesDao().deleteByUser(dbSession, user); | |||
dbClient.userDao().deactivateUser(dbSession, user); | |||
userIndexer.commitAndIndex(dbSession, user); | |||
} |
@@ -0,0 +1,88 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.user.ws; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.user.UserPropertyDto; | |||
import org.sonar.server.user.UserSession; | |||
import static java.util.Objects.requireNonNull; | |||
public class SetSettingAction implements UsersWsAction { | |||
public static final String PARAM_KEY = "key"; | |||
public static final String PARAM_VALUE = "value"; | |||
private final DbClient dbClient; | |||
private final UserSession userSession; | |||
public SetSettingAction(DbClient dbClient, UserSession userSession) { | |||
this.dbClient = dbClient; | |||
this.userSession = userSession; | |||
} | |||
@Override | |||
public void define(WebService.NewController controller) { | |||
WebService.NewAction action = controller.createAction("set_setting") | |||
.setDescription("Update a setting value.<br>" + | |||
"Requires user to be authenticated") | |||
.setSince("7.6") | |||
.setInternal(true) | |||
.setPost(true) | |||
.setHandler(this); | |||
action.createParam(PARAM_KEY) | |||
.setRequired(true) | |||
.setMaximumLength(100) | |||
.setDescription("Setting key") | |||
.setPossibleValues("notifications.optOut", "notifications.readDate"); | |||
action.createParam(PARAM_VALUE) | |||
.setRequired(true) | |||
.setMaximumLength(4000) | |||
.setDescription("Setting value") | |||
.setExampleValue("true"); | |||
} | |||
@Override | |||
public void handle(Request request, Response response) throws Exception { | |||
userSession.checkLoggedIn(); | |||
String key = request.mandatoryParam(PARAM_KEY); | |||
String value = request.mandatoryParam(PARAM_VALUE); | |||
setUserSetting(key, value); | |||
response.noContent(); | |||
} | |||
private void setUserSetting(String key, String value) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
dbClient.userPropertiesDao().insertOrUpdate(dbSession, | |||
new UserPropertyDto() | |||
.setUserUuid(requireNonNull(userSession.getUuid(), "Authenticated user uuid cannot be null")) | |||
.setKey(key) | |||
.setValue(value)); | |||
dbSession.commit(); | |||
} | |||
} | |||
} |
@@ -38,6 +38,7 @@ public class UsersWsModule extends Module { | |||
UserJsonWriter.class, | |||
SkipOnboardingTutorialAction.class, | |||
SetHomepageAction.class, | |||
HomepageTypesImpl.class); | |||
HomepageTypesImpl.class, | |||
SetSettingAction.class); | |||
} | |||
} |
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.server.user.ws; | |||
import java.util.Collections; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
@@ -45,6 +46,7 @@ import org.sonarqube.ws.Users.CurrentWsResponse; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.mockito.Mockito.mock; | |||
import static org.sonar.api.web.UserRole.USER; | |||
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER; | |||
@@ -56,7 +58,7 @@ import static org.sonar.test.JsonAssert.assertJson; | |||
public class CurrentActionTest { | |||
@Rule | |||
public UserSessionRule userSessionRule = UserSessionRule.standalone(); | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
@Rule | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
@Rule | |||
@@ -70,7 +72,7 @@ public class CurrentActionTest { | |||
ResourceTypeTree.builder().addType(ResourceType.builder(Qualifiers.PROJECT).build()).build()})); | |||
private WsActionTester ws = new WsActionTester( | |||
new CurrentAction(userSessionRule, db.getDbClient(), TestDefaultOrganizationProvider.from(db), new AvatarResolverImpl(), homepageTypes, pluginRepository, permissionService)); | |||
new CurrentAction(userSession, db.getDbClient(), TestDefaultOrganizationProvider.from(db), new AvatarResolverImpl(), homepageTypes, pluginRepository, permissionService)); | |||
@Test | |||
public void return_user_info() { | |||
@@ -83,7 +85,7 @@ public class CurrentActionTest { | |||
.setExternalIdentityProvider("sonarqube") | |||
.setScmAccounts(newArrayList("obiwan:github", "obiwan:bitbucket")) | |||
.setOnboarded(false)); | |||
userSessionRule.logIn("obiwan.kenobi"); | |||
userSession.logIn(user); | |||
CurrentWsResponse response = call(); | |||
@@ -97,7 +99,7 @@ public class CurrentActionTest { | |||
@Test | |||
public void return_minimal_user_info() { | |||
db.users().insertUser(user -> user | |||
UserDto user = db.users().insertUser(u -> u | |||
.setLogin("obiwan.kenobi") | |||
.setName("Obiwan Kenobi") | |||
.setEmail(null) | |||
@@ -105,14 +107,14 @@ public class CurrentActionTest { | |||
.setExternalLogin("obiwan") | |||
.setExternalIdentityProvider("sonarqube") | |||
.setScmAccounts((String) null)); | |||
userSessionRule.logIn("obiwan.kenobi"); | |||
userSession.logIn(user); | |||
CurrentWsResponse response = call(); | |||
assertThat(response) | |||
.extracting(CurrentWsResponse::getIsLoggedIn, CurrentWsResponse::getLogin, CurrentWsResponse::getName, CurrentWsResponse::hasAvatar, CurrentWsResponse::getLocal, | |||
CurrentWsResponse::getExternalIdentity, CurrentWsResponse::getExternalProvider, CurrentWsResponse::hasPersonalOrganization) | |||
.containsExactly(true, "obiwan.kenobi", "Obiwan Kenobi", false, true, "obiwan", "sonarqube", false); | |||
CurrentWsResponse::getExternalIdentity, CurrentWsResponse::getExternalProvider, CurrentWsResponse::hasPersonalOrganization, CurrentWsResponse::getSettingsList) | |||
.containsExactly(true, "obiwan.kenobi", "Obiwan Kenobi", false, true, "obiwan", "sonarqube", false, Collections.emptyList()); | |||
assertThat(response.hasEmail()).isFalse(); | |||
assertThat(response.getScmAccountsList()).isEmpty(); | |||
assertThat(response.getGroupsList()).isEmpty(); | |||
@@ -121,10 +123,10 @@ public class CurrentActionTest { | |||
@Test | |||
public void convert_empty_email_to_null() { | |||
db.users().insertUser(user -> user | |||
UserDto user = db.users().insertUser(u -> u | |||
.setLogin("obiwan.kenobi") | |||
.setEmail("")); | |||
userSessionRule.logIn("obiwan.kenobi"); | |||
userSession.logIn(user); | |||
CurrentWsResponse response = call(); | |||
@@ -134,7 +136,7 @@ public class CurrentActionTest { | |||
@Test | |||
public void return_group_membership() { | |||
UserDto user = db.users().insertUser(); | |||
userSessionRule.logIn(user.getLogin()); | |||
userSession.logIn(user); | |||
db.users().insertMember(db.users().insertGroup(newGroupDto().setName("Jedi")), user); | |||
db.users().insertMember(db.users().insertGroup(newGroupDto().setName("Rebel")), user); | |||
@@ -146,8 +148,8 @@ public class CurrentActionTest { | |||
@Test | |||
public void return_permissions() { | |||
UserDto user = db.users().insertUser(); | |||
userSessionRule | |||
.logIn(user.getLogin()) | |||
userSession | |||
.logIn(user) | |||
// permissions on default organization | |||
.addPermission(SCAN, db.getDefaultOrganization()) | |||
.addPermission(ADMINISTER_QUALITY_PROFILES, db.getDefaultOrganization()) | |||
@@ -163,17 +165,38 @@ public class CurrentActionTest { | |||
public void return_personal_organization() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
UserDto user = db.users().insertUser(u -> u.setOrganizationUuid(organization.getUuid())); | |||
userSessionRule.logIn(user); | |||
userSession.logIn(user); | |||
CurrentWsResponse response = call(); | |||
assertThat(response.getPersonalOrganization()).isEqualTo(organization.getKey()); | |||
} | |||
@Test | |||
public void return_user_settings() { | |||
UserDto user = db.users().insertUser(); | |||
db.users().insertUserSetting(user, userSetting -> userSetting | |||
.setKey("notifications.readDate") | |||
.setValue("1234")); | |||
db.users().insertUserSetting(user, userSetting -> userSetting | |||
.setKey("notifications.optOut") | |||
.setValue("true")); | |||
db.commit(); | |||
userSession.logIn(user); | |||
CurrentWsResponse response = call(); | |||
assertThat(response.getSettingsList()) | |||
.extracting(CurrentWsResponse.Setting::getKey, CurrentWsResponse.Setting::getValue) | |||
.containsExactly( | |||
tuple("notifications.optOut", "true"), | |||
tuple("notifications.readDate", "1234")); | |||
} | |||
@Test | |||
public void fail_with_ISE_when_user_login_in_db_does_not_exist() { | |||
db.users().insertUser(usert -> usert.setLogin("another")); | |||
userSessionRule.logIn("obiwan.kenobi"); | |||
userSession.logIn("obiwan.kenobi"); | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage("User login 'obiwan.kenobi' cannot be found"); | |||
@@ -184,7 +207,7 @@ public class CurrentActionTest { | |||
@Test | |||
public void fail_with_ISE_when_personal_organization_does_not_exist() { | |||
UserDto user = db.users().insertUser(u -> u.setOrganizationUuid("Unknown")); | |||
userSessionRule.logIn(user); | |||
userSession.logIn(user); | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage("Organization uuid 'Unknown' does not exist"); | |||
@@ -194,7 +217,7 @@ public class CurrentActionTest { | |||
@Test | |||
public void anonymous() { | |||
userSessionRule | |||
userSession | |||
.anonymous() | |||
.addPermission(SCAN, db.getDefaultOrganization()) | |||
.addPermission(PROVISION_PROJECTS, db.getDefaultOrganization()); | |||
@@ -214,11 +237,6 @@ public class CurrentActionTest { | |||
@Test | |||
public void json_example() { | |||
ComponentDto componentDto = db.components().insertPrivateProject(u -> u.setUuid("UUID-of-the-death-star"), u -> u.setDbKey("death-star-key")); | |||
userSessionRule | |||
.logIn("obiwan.kenobi") | |||
.addPermission(SCAN, db.getDefaultOrganization()) | |||
.addPermission(ADMINISTER_QUALITY_PROFILES, db.getDefaultOrganization()) | |||
.addProjectPermission(USER, componentDto); | |||
UserDto obiwan = db.users().insertUser(user -> user | |||
.setLogin("obiwan.kenobi") | |||
.setName("Obiwan Kenobi") | |||
@@ -230,6 +248,11 @@ public class CurrentActionTest { | |||
.setOnboarded(true) | |||
.setHomepageType("PROJECT") | |||
.setHomepageParameter("UUID-of-the-death-star")); | |||
userSession | |||
.logIn(obiwan) | |||
.addPermission(SCAN, db.getDefaultOrganization()) | |||
.addPermission(ADMINISTER_QUALITY_PROFILES, db.getDefaultOrganization()) | |||
.addProjectPermission(USER, componentDto); | |||
db.users().insertMember(db.users().insertGroup(newGroupDto().setName("Jedi")), obiwan); | |||
db.users().insertMember(db.users().insertGroup(newGroupDto().setName("Rebel")), obiwan); | |||
@@ -20,7 +20,6 @@ | |||
package org.sonar.server.user.ws; | |||
import java.util.Optional; | |||
import java.util.function.Consumer; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
@@ -57,7 +56,6 @@ import static org.elasticsearch.index.query.QueryBuilders.boolQuery; | |||
import static org.elasticsearch.index.query.QueryBuilders.termQuery; | |||
import static org.sonar.api.web.UserRole.CODEVIEWER; | |||
import static org.sonar.api.web.UserRole.USER; | |||
import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN; | |||
import static org.sonar.db.organization.OrganizationTesting.newOrganizationDto; | |||
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER; | |||
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES; | |||
@@ -93,14 +91,14 @@ public class DeactivateActionTest { | |||
@Test | |||
public void deactivate_user_and_delete_his_related_data() { | |||
UserDto user = insertUser(u -> u | |||
UserDto user = db.users().insertUser(u -> u | |||
.setLogin("ada.lovelace") | |||
.setEmail("ada.lovelace@noteg.com") | |||
.setName("Ada Lovelace") | |||
.setScmAccounts(singletonList("al"))); | |||
logInAsSystemAdministrator(); | |||
deactivate(user.getLogin()).getInput(); | |||
deactivate(user.getLogin()); | |||
verifyThatUserIsDeactivated(user.getLogin()); | |||
assertThat(es.client().prepareSearch(UserIndexDefinition.INDEX_TYPE_USER) | |||
@@ -113,12 +111,12 @@ public class DeactivateActionTest { | |||
@Test | |||
public void deactivate_user_deletes_his_group_membership() { | |||
logInAsSystemAdministrator(); | |||
UserDto user = insertUser(); | |||
UserDto user = db.users().insertUser(); | |||
GroupDto group1 = db.users().insertGroup(); | |||
db.users().insertGroup(); | |||
db.users().insertMember(group1, user); | |||
deactivate(user.getLogin()).getInput(); | |||
deactivate(user.getLogin()); | |||
assertThat(db.getDbClient().groupMembershipDao().selectGroupIdsByUserId(dbSession, user.getId())).isEmpty(); | |||
} | |||
@@ -126,12 +124,12 @@ public class DeactivateActionTest { | |||
@Test | |||
public void deactivate_user_deletes_his_tokens() { | |||
logInAsSystemAdministrator(); | |||
UserDto user = insertUser(); | |||
UserDto user = db.users().insertUser(); | |||
db.users().insertToken(user); | |||
db.users().insertToken(user); | |||
db.commit(); | |||
deactivate(user.getLogin()).getInput(); | |||
deactivate(user.getLogin()); | |||
assertThat(db.getDbClient().userTokenDao().selectByUser(dbSession, user)).isEmpty(); | |||
} | |||
@@ -139,13 +137,13 @@ public class DeactivateActionTest { | |||
@Test | |||
public void deactivate_user_deletes_his_properties() { | |||
logInAsSystemAdministrator(); | |||
UserDto user = insertUser(); | |||
UserDto user = db.users().insertUser(); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
db.properties().insertProperty(newUserPropertyDto(user)); | |||
db.properties().insertProperty(newUserPropertyDto(user)); | |||
db.properties().insertProperty(newUserPropertyDto(user).setResourceId(project.getId())); | |||
deactivate(user.getLogin()).getInput(); | |||
deactivate(user.getLogin()); | |||
assertThat(db.getDbClient().propertiesDao().selectByQuery(PropertyQuery.builder().setUserId(user.getId()).build(), dbSession)).isEmpty(); | |||
assertThat(db.getDbClient().propertiesDao().selectByQuery(PropertyQuery.builder().setUserId(user.getId()).setComponentId(project.getId()).build(), dbSession)).isEmpty(); | |||
@@ -154,14 +152,14 @@ public class DeactivateActionTest { | |||
@Test | |||
public void deactivate_user_deletes_his_permissions() { | |||
logInAsSystemAdministrator(); | |||
UserDto user = insertUser(); | |||
UserDto user = db.users().insertUser(); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
db.users().insertPermissionOnUser(user, SCAN); | |||
db.users().insertPermissionOnUser(user, ADMINISTER_QUALITY_PROFILES); | |||
db.users().insertProjectPermissionOnUser(user, USER, project); | |||
db.users().insertProjectPermissionOnUser(user, CODEVIEWER, project); | |||
deactivate(user.getLogin()).getInput(); | |||
deactivate(user.getLogin()); | |||
assertThat(db.getDbClient().userPermissionDao().selectGlobalPermissionsOfUser(dbSession, user.getId(), db.getDefaultOrganization().getUuid())).isEmpty(); | |||
assertThat(db.getDbClient().userPermissionDao().selectProjectPermissionsOfUser(dbSession, user.getId(), project.getId())).isEmpty(); | |||
@@ -170,13 +168,13 @@ public class DeactivateActionTest { | |||
@Test | |||
public void deactivate_user_deletes_his_permission_templates() { | |||
logInAsSystemAdministrator(); | |||
UserDto user = insertUser(); | |||
UserDto user = db.users().insertUser(); | |||
PermissionTemplateDto template = db.permissionTemplates().insertTemplate(); | |||
PermissionTemplateDto anotherTemplate = db.permissionTemplates().insertTemplate(); | |||
db.permissionTemplates().addUserToTemplate(template.getId(), user.getId(), USER); | |||
db.permissionTemplates().addUserToTemplate(anotherTemplate.getId(), user.getId(), CODEVIEWER); | |||
deactivate(user.getLogin()).getInput(); | |||
deactivate(user.getLogin()); | |||
assertThat(db.getDbClient().permissionTemplateDao().selectUserPermissionsByTemplateId(dbSession, template.getId())).extracting(PermissionTemplateUserDto::getUserId).isEmpty(); | |||
assertThat(db.getDbClient().permissionTemplateDao().selectUserPermissionsByTemplateId(dbSession, anotherTemplate.getId())).extracting(PermissionTemplateUserDto::getUserId) | |||
@@ -186,11 +184,11 @@ public class DeactivateActionTest { | |||
@Test | |||
public void deactivate_user_deletes_his_qprofiles_permissions() { | |||
logInAsSystemAdministrator(); | |||
UserDto user = insertUser(); | |||
UserDto user = db.users().insertUser(); | |||
QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization()); | |||
db.qualityProfiles().addUserPermission(profile, user); | |||
deactivate(user.getLogin()).getInput(); | |||
deactivate(user.getLogin()); | |||
assertThat(db.getDbClient().qProfileEditUsersDao().exists(dbSession, profile, user)).isFalse(); | |||
} | |||
@@ -198,14 +196,14 @@ public class DeactivateActionTest { | |||
@Test | |||
public void deactivate_user_deletes_his_default_assignee_settings() { | |||
logInAsSystemAdministrator(); | |||
UserDto user = insertUser(); | |||
UserDto user = db.users().insertUser(); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto anotherProject = db.components().insertPrivateProject(); | |||
db.properties().insertProperty(new PropertyDto().setKey("sonar.issues.defaultAssigneeLogin").setValue(user.getLogin()).setResourceId(project.getId())); | |||
db.properties().insertProperty(new PropertyDto().setKey("sonar.issues.defaultAssigneeLogin").setValue(user.getLogin()).setResourceId(anotherProject.getId())); | |||
db.properties().insertProperty(new PropertyDto().setKey("other").setValue(user.getLogin()).setResourceId(anotherProject.getId())); | |||
deactivate(user.getLogin()).getInput(); | |||
deactivate(user.getLogin()); | |||
assertThat(db.getDbClient().propertiesDao().selectByQuery(PropertyQuery.builder().setKey("sonar.issues.defaultAssigneeLogin").build(), db.getSession())).isEmpty(); | |||
assertThat(db.getDbClient().propertiesDao().selectByQuery(PropertyQuery.builder().build(), db.getSession())).extracting(PropertyDto::getKey).containsOnly("other"); | |||
@@ -214,21 +212,36 @@ public class DeactivateActionTest { | |||
@Test | |||
public void deactivate_user_deletes_his_organization_membership() { | |||
logInAsSystemAdministrator(); | |||
UserDto user = insertUser(); | |||
UserDto user = db.users().insertUser(); | |||
OrganizationDto organization = db.organizations().insert(); | |||
db.organizations().addMember(organization, user); | |||
OrganizationDto anotherOrganization = db.organizations().insert(); | |||
db.organizations().addMember(anotherOrganization, user); | |||
deactivate(user.getLogin()).getInput(); | |||
deactivate(user.getLogin()); | |||
assertThat(dbClient.organizationMemberDao().select(db.getSession(), organization.getUuid(), user.getId())).isNotPresent(); | |||
assertThat(dbClient.organizationMemberDao().select(db.getSession(), anotherOrganization.getUuid(), user.getId())).isNotPresent(); | |||
} | |||
@Test | |||
public void deactivate_user_deletes_his_user_settings() { | |||
logInAsSystemAdministrator(); | |||
UserDto user = db.users().insertUser(); | |||
db.users().insertUserSetting(user); | |||
db.users().insertUserSetting(user); | |||
UserDto anotherUser = db.users().insertUser(); | |||
db.users().insertUserSetting(anotherUser); | |||
deactivate(user.getLogin()); | |||
assertThat(db.getDbClient().userPropertiesDao().selectByUser(dbSession, user)).isEmpty(); | |||
assertThat(db.getDbClient().userPropertiesDao().selectByUser(dbSession, anotherUser)).hasSize(1); | |||
} | |||
@Test | |||
public void cannot_deactivate_self() { | |||
UserDto user = createUser(); | |||
UserDto user = db.users().insertUser(); | |||
userSession.logIn(user.getLogin()).setSystemAdministrator(); | |||
expectedException.expect(BadRequestException.class); | |||
@@ -279,7 +292,7 @@ public class DeactivateActionTest { | |||
@Test | |||
public void fail_to_deactivate_last_administrator_of_default_organization() { | |||
UserDto admin = createUser(); | |||
UserDto admin = db.users().insertUser(); | |||
db.users().insertPermissionOnUser(admin, ADMINISTER); | |||
logInAsSystemAdministrator(); | |||
@@ -293,15 +306,15 @@ public class DeactivateActionTest { | |||
public void fail_to_deactivate_last_administrator_of_organization() { | |||
// user1 is the unique administrator of org1 and org2. | |||
// user1 and user2 are both administrators of org3 | |||
UserDto user1 = insertUser(u -> u.setLogin("test")); | |||
UserDto user1 = db.users().insertUser(u -> u.setLogin("test")); | |||
OrganizationDto org1 = db.organizations().insert(newOrganizationDto().setKey("org1")); | |||
OrganizationDto org2 = db.organizations().insert(newOrganizationDto().setKey("org2")); | |||
OrganizationDto org3 = db.organizations().insert(newOrganizationDto().setKey("org3")); | |||
db.users().insertPermissionOnUser(org1, user1, SYSTEM_ADMIN); | |||
db.users().insertPermissionOnUser(org2, user1, SYSTEM_ADMIN); | |||
db.users().insertPermissionOnUser(org3, user1, SYSTEM_ADMIN); | |||
UserDto user2 = createUser(); | |||
db.users().insertPermissionOnUser(org3, user2, SYSTEM_ADMIN); | |||
db.users().insertPermissionOnUser(org1, user1, ADMINISTER); | |||
db.users().insertPermissionOnUser(org2, user1, ADMINISTER); | |||
db.users().insertPermissionOnUser(org3, user1, ADMINISTER); | |||
UserDto user2 = db.users().insertUser(); | |||
db.users().insertPermissionOnUser(org3, user2, ADMINISTER); | |||
logInAsSystemAdministrator(); | |||
expectedException.expect(BadRequestException.class); | |||
@@ -312,8 +325,8 @@ public class DeactivateActionTest { | |||
@Test | |||
public void administrators_can_be_deactivated_if_there_are_still_other_administrators() { | |||
UserDto admin = createUser(); | |||
UserDto anotherAdmin = createUser(); | |||
UserDto admin = db.users().insertUser(); | |||
UserDto anotherAdmin = db.users().insertUser(); | |||
db.users().insertPermissionOnUser(admin, ADMINISTER); | |||
db.users().insertPermissionOnUser(anotherAdmin, ADMINISTER); | |||
db.commit(); | |||
@@ -334,7 +347,7 @@ public class DeactivateActionTest { | |||
@Test | |||
public void test_example() { | |||
UserDto user = insertUser(u -> u | |||
UserDto user = db.users().insertUser(u -> u | |||
.setLogin("ada.lovelace") | |||
.setEmail("ada.lovelace@noteg.com") | |||
.setName("Ada Lovelace") | |||
@@ -347,19 +360,6 @@ public class DeactivateActionTest { | |||
assertJson(json).isSimilarTo(ws.getDef().responseExampleAsString()); | |||
} | |||
private UserDto createUser() { | |||
return insertUser(); | |||
} | |||
@SafeVarargs | |||
private final UserDto insertUser(Consumer<UserDto>... populators) { | |||
UserDto user = db.users().insertUser(populators); | |||
db.users().insertToken(user); | |||
db.properties().insertProperties(new PropertyDto().setUserId(user.getId()).setKey("foo").setValue("bar")); | |||
userIndexer.commitAndIndex(dbSession, user); | |||
return user; | |||
} | |||
private void logInAsSystemAdministrator() { | |||
userSession.logIn().setSystemAdministrator(); | |||
} |
@@ -0,0 +1,130 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.user.ws; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.db.user.UserPropertyDto; | |||
import org.sonar.server.exceptions.UnauthorizedException; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.ws.WsActionTester; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
public class SetSettingActionTest { | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
@Rule | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
private WsActionTester ws = new WsActionTester(new SetSettingAction(db.getDbClient(), userSession)); | |||
@Test | |||
public void set_new_setting() { | |||
UserDto user = db.users().insertUser(); | |||
userSession.logIn(user); | |||
ws.newRequest() | |||
.setParam("key", "notifications.optOut") | |||
.setParam("value", "true") | |||
.execute(); | |||
assertThat(db.getDbClient().userPropertiesDao().selectByUser(db.getSession(), user)) | |||
.extracting(UserPropertyDto::getKey, UserPropertyDto::getValue) | |||
.containsExactlyInAnyOrder(tuple("notifications.optOut", "true")); | |||
} | |||
@Test | |||
public void update_existing_setting() { | |||
UserDto user = db.users().insertUser(); | |||
db.users().insertUserSetting(user, userSetting -> userSetting | |||
.setKey("notifications.optOut") | |||
.setValue("false")); | |||
userSession.logIn(user); | |||
ws.newRequest() | |||
.setParam("key", "notifications.optOut") | |||
.setParam("value", "true") | |||
.execute(); | |||
assertThat(db.getDbClient().userPropertiesDao().selectByUser(db.getSession(), user)) | |||
.extracting(UserPropertyDto::getKey, UserPropertyDto::getValue) | |||
.containsExactlyInAnyOrder(tuple("notifications.optOut", "true")); | |||
} | |||
@Test | |||
public void keep_existing_setting_when_setting_new_one() { | |||
UserDto user = db.users().insertUser(); | |||
db.users().insertUserSetting(user, userSetting -> userSetting | |||
.setKey("notifications.readDate") | |||
.setValue("1234")); | |||
userSession.logIn(user); | |||
ws.newRequest() | |||
.setParam("key", "notifications.optOut") | |||
.setParam("value", "true") | |||
.execute(); | |||
assertThat(db.getDbClient().userPropertiesDao().selectByUser(db.getSession(), user)) | |||
.extracting(UserPropertyDto::getKey, UserPropertyDto::getValue) | |||
.containsExactlyInAnyOrder( | |||
tuple("notifications.readDate", "1234"), | |||
tuple("notifications.optOut", "true")); | |||
} | |||
@Test | |||
public void fail_when_not_authenticated() { | |||
expectedException.expect(UnauthorizedException.class); | |||
ws.newRequest() | |||
.setParam("key", "notifications.optOut") | |||
.setParam("value", "true") | |||
.execute(); | |||
} | |||
@Test | |||
public void definition() { | |||
WebService.Action definition = ws.getDef(); | |||
assertThat(definition.key()).isEqualTo("set_setting"); | |||
assertThat(definition.isPost()).isTrue(); | |||
assertThat(definition.isInternal()).isTrue(); | |||
assertThat(definition.since()).isEqualTo("7.6"); | |||
assertThat(definition.params()) | |||
.extracting(WebService.Param::key, WebService.Param::isRequired, WebService.Param::maximumLength) | |||
.containsOnly( | |||
tuple("key", true, 100), | |||
tuple("value", true, 4000)); | |||
assertThat(definition.param("key").possibleValues()).containsExactlyInAnyOrder("notifications.optOut", "notifications.readDate"); | |||
} | |||
} |
@@ -29,6 +29,6 @@ public class UsersWsModuleTest { | |||
public void verify_count_of_added_components() { | |||
ComponentContainer container = new ComponentContainer(); | |||
new UsersWsModule().configure(container); | |||
assertThat(container.size()).isEqualTo(2 + 14); | |||
assertThat(container.size()).isEqualTo(2 + 15); | |||
} | |||
} |
@@ -0,0 +1,64 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.sonarqube.ws.client.users; | |||
import javax.annotation.Generated; | |||
/** | |||
* This is part of the internal API. | |||
* This is a POST request. | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/users/set_setting">Further information about this action online (including a response example)</a> | |||
* @since 7.6 | |||
*/ | |||
@Generated("sonar-ws-generator") | |||
public class SetSettingRequest { | |||
private String key; | |||
private String value; | |||
/** | |||
* This is a mandatory parameter. | |||
*/ | |||
public SetSettingRequest setKey(String key) { | |||
this.key = key; | |||
return this; | |||
} | |||
public String getKey() { | |||
return key; | |||
} | |||
/** | |||
* This is a mandatory parameter. | |||
* Possible values: | |||
* <ul> | |||
* <li>"notifications.optOut"</li> | |||
* <li>"notifications.readDate"</li> | |||
* </ul> | |||
*/ | |||
public SetSettingRequest setValue(String value) { | |||
this.value = value; | |||
return this; | |||
} | |||
public String getValue() { | |||
return value; | |||
} | |||
} |
@@ -22,15 +22,15 @@ package org.sonarqube.ws.client.users; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.Generated; | |||
import org.sonarqube.ws.MediaTypes; | |||
import org.sonarqube.ws.client.BaseService; | |||
import org.sonarqube.ws.client.GetRequest; | |||
import org.sonarqube.ws.client.PostRequest; | |||
import org.sonarqube.ws.client.WsConnector; | |||
import org.sonarqube.ws.Users.CreateWsResponse; | |||
import org.sonarqube.ws.Users.CurrentWsResponse; | |||
import org.sonarqube.ws.Users.GroupsWsResponse; | |||
import org.sonarqube.ws.Users.IdentityProvidersWsResponse; | |||
import org.sonarqube.ws.Users.SearchWsResponse; | |||
import org.sonarqube.ws.client.BaseService; | |||
import org.sonarqube.ws.client.GetRequest; | |||
import org.sonarqube.ws.client.PostRequest; | |||
import org.sonarqube.ws.client.WsConnector; | |||
/** | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/users">Further information about this web service online</a> | |||
@@ -172,6 +172,22 @@ public class UsersService extends BaseService { | |||
).content(); | |||
} | |||
/** | |||
* | |||
* This is part of the internal API. | |||
* This is a POST request. | |||
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/users/set_setting">Further information about this action online (including a response example)</a> | |||
* @since 7.6 | |||
*/ | |||
public void setSetting(SetSettingRequest request) { | |||
call( | |||
new PostRequest(path("set_setting")) | |||
.setParam("key", request.getKey()) | |||
.setParam("value", request.getValue()) | |||
.setMediaType(MediaTypes.JSON) | |||
).content(); | |||
} | |||
/** | |||
* | |||
* This is part of the internal API. |
@@ -110,6 +110,7 @@ message CurrentWsResponse { | |||
optional string avatar = 12; | |||
optional Homepage homepage = 13; | |||
optional string personalOrganization = 14; | |||
repeated Setting settings = 15; | |||
message Permissions { | |||
repeated string global = 1; | |||
@@ -133,4 +134,9 @@ message CurrentWsResponse { | |||
optional string organization = 3; | |||
optional string branch = 4; | |||
} | |||
message Setting { | |||
optional string key = 1; | |||
optional string value = 2; | |||
} | |||
} |