Browse Source

SONAR-16139 Drop api/users/set_setting and related db table

tags/9.4.0.54424
Duarte Meneses 2 years ago
parent
commit
dc84e9f271
35 changed files with 113 additions and 1063 deletions
  1. 0
    1
      server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java
  2. 0
    2
      server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java
  3. 0
    7
      server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java
  4. 0
    2
      server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java
  5. 0
    9
      server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/PropertyNewValue.java
  6. 0
    79
      server/sonar-db-dao/src/main/java/org/sonar/db/user/UserPropertiesDao.java
  7. 0
    35
      server/sonar-db-dao/src/main/java/org/sonar/db/user/UserPropertiesMapper.java
  8. 0
    80
      server/sonar-db-dao/src/main/java/org/sonar/db/user/UserPropertyDto.java
  9. 0
    51
      server/sonar-db-dao/src/main/resources/org/sonar/db/user/UserPropertiesMapper.xml
  10. 0
    11
      server/sonar-db-dao/src/schema/schema-sq.ddl
  11. 0
    130
      server/sonar-db-dao/src/test/java/org/sonar/db/user/UserPropertiesDaoTest.java
  12. 0
    158
      server/sonar-db-dao/src/test/java/org/sonar/db/user/UserPropertiesDaoWithPersisterTest.java
  13. 0
    11
      server/sonar-db-dao/src/testFixtures/java/org/sonar/db/user/UserDbTester.java
  14. 0
    9
      server/sonar-db-dao/src/testFixtures/java/org/sonar/db/user/UserTesting.java
  15. 1
    0
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v94/DbVersion94.java
  16. 47
    0
      server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v94/DropUserPropertiesTable.java
  17. 50
    0
      server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v94/DropUserPropertiesTableTest.java
  18. 9
    0
      server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v94/DropUserPropertiesTableTest/schema.sql
  19. 0
    13
      server/sonar-webserver-auth/src/test/java/org/sonar/server/user/UserUpdaterCreateTest.java
  20. 0
    14
      server/sonar-webserver-auth/src/test/java/org/sonar/server/user/UserUpdaterReactivateTest.java
  21. 2
    14
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/CurrentAction.java
  22. 0
    1
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/DeactivateAction.java
  23. 0
    91
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/SetSettingAction.java
  24. 0
    1
      server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/UsersWsModule.java
  25. 2
    26
      server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/CurrentActionTest.java
  26. 0
    16
      server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/DeactivateActionTest.java
  27. 0
    130
      server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/SetSettingActionTest.java
  28. 1
    1
      server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/UsersWsModuleTest.java
  29. 0
    8
      sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java
  30. 0
    3
      sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java
  31. 0
    53
      sonar-ws/src/main/java/org/sonarqube/ws/client/userproperties/UserPropertiesService.java
  32. 0
    26
      sonar-ws/src/main/java/org/sonarqube/ws/client/userproperties/package-info.java
  33. 0
    65
      sonar-ws/src/main/java/org/sonarqube/ws/client/users/SetSettingRequest.java
  34. 0
    15
      sonar-ws/src/main/java/org/sonarqube/ws/client/users/UsersService.java
  35. 1
    1
      sonar-ws/src/main/protobuf/ws-users.proto

+ 0
- 1
server/sonar-db-core/src/main/java/org/sonar/db/version/SqTables.java View File

@@ -100,7 +100,6 @@ public final class SqTables {
"snapshots",
"users",
"user_dismissed_messages",
"user_properties",
"user_roles",
"user_tokens",
"webhooks",

+ 0
- 2
server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java View File

@@ -88,7 +88,6 @@ import org.sonar.db.user.SessionTokensDao;
import org.sonar.db.user.UserDao;
import org.sonar.db.user.UserDismissedMessagesDao;
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;
@@ -165,7 +164,6 @@ public class DaoModule extends Module {
UserDismissedMessagesDao.class,
UserGroupDao.class,
UserPermissionDao.class,
UserPropertiesDao.class,
UserTokenDao.class,
WebhookDao.class,
WebhookDeliveryDao.class);

+ 0
- 7
server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java View File

@@ -88,7 +88,6 @@ import org.sonar.db.user.SessionTokensDao;
import org.sonar.db.user.UserDao;
import org.sonar.db.user.UserDismissedMessagesDao;
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;
@@ -117,7 +116,6 @@ 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;
@@ -197,7 +195,6 @@ 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);
@@ -353,10 +350,6 @@ public class DbClient {
return userTokenDao;
}

public UserPropertiesDao userPropertiesDao() {
return userPropertiesDao;
}

public GroupMembershipDao groupMembershipDao() {
return groupMembershipDao;
}

+ 0
- 2
server/sonar-db-dao/src/main/java/org/sonar/db/MyBatis.java View File

@@ -151,7 +151,6 @@ 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;
@@ -307,7 +306,6 @@ public class MyBatis {
UserGroupMapper.class,
UserMapper.class,
UserPermissionMapper.class,
UserPropertiesMapper.class,
UserTokenMapper.class,
WebhookMapper.class,
WebhookDeliveryMapper.class

+ 0
- 9
server/sonar-db-dao/src/main/java/org/sonar/db/audit/model/PropertyNewValue.java View File

@@ -22,7 +22,6 @@ package org.sonar.db.audit.model;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.db.property.PropertyDto;
import org.sonar.db.user.UserPropertyDto;

public class PropertyNewValue extends NewValue {
private String propertyKey;
@@ -48,14 +47,6 @@ public class PropertyNewValue extends NewValue {
@Nullable
private String qualifier;

public PropertyNewValue(UserPropertyDto userPropertyDto, @Nullable String login) {
this.propertyKey = userPropertyDto.getKey();
this.userUuid = userPropertyDto.getUserUuid();
this.userLogin = login;

setValue(propertyKey, userPropertyDto.getValue());
}

public PropertyNewValue(PropertyDto propertyDto, @Nullable String userLogin, @Nullable String componentKey, @Nullable String componentName, @Nullable String qualifier) {
this.propertyKey = propertyDto.getKey();
this.userUuid = propertyDto.getUserUuid();

+ 0
- 79
server/sonar-db-dao/src/main/java/org/sonar/db/user/UserPropertiesDao.java View File

@@ -1,79 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2022 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 javax.annotation.Nullable;
import org.sonar.api.utils.System2;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.Dao;
import org.sonar.db.DbSession;
import org.sonar.db.audit.AuditPersister;
import org.sonar.db.audit.model.PropertyNewValue;

public class UserPropertiesDao implements Dao {

private final System2 system2;
private final UuidFactory uuidFactory;
private final AuditPersister auditPersister;

public UserPropertiesDao(System2 system2, UuidFactory uuidFactory, AuditPersister auditPersister) {
this.system2 = system2;
this.uuidFactory = uuidFactory;
this.auditPersister = auditPersister;
}

public List<UserPropertyDto> selectByUser(DbSession session, UserDto user) {
return mapper(session).selectByUserUuid(user.getUuid());
}

public UserPropertyDto insertOrUpdate(DbSession session, UserPropertyDto dto, @Nullable String login) {
long now = system2.now();
boolean isUpdate = true;
if (mapper(session).update(dto, now) == 0) {
mapper(session).insert(dto.setUuid(uuidFactory.create()), now);
isUpdate = false;
}

if (isUpdate) {
auditPersister.updateProperty(session, new PropertyNewValue(dto, login), true);
} else {
auditPersister.addProperty(session, new PropertyNewValue(dto, login), true);
}

return dto;
}

public void deleteByUser(DbSession session, UserDto user) {
List<UserPropertyDto> userProperties = selectByUser(session, user);
int deletedRows = mapper(session).deleteByUserUuid(user.getUuid());

if (deletedRows > 0) {
userProperties.stream()
.filter(p -> auditPersister.isTrackedProperty(p.getKey()))
.forEach(p -> auditPersister.deleteProperty(session, new PropertyNewValue(p, user.getLogin()), true));
}
}

private static UserPropertiesMapper mapper(DbSession session) {
return session.getMapper(UserPropertiesMapper.class);
}

}

+ 0
- 35
server/sonar-db-dao/src/main/java/org/sonar/db/user/UserPropertiesMapper.java View File

@@ -1,35 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2022 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);

int deleteByUserUuid(@Param("userUuid") String userUuid);

}

+ 0
- 80
server/sonar-db-dao/src/main/java/org/sonar/db/user/UserPropertyDto.java View File

@@ -1,80 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2022 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
- 51
server/sonar-db-dao/src/main/resources/org/sonar/db/user/UserPropertiesMapper.xml View File

@@ -1,51 +0,0 @@
<?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>

+ 0
- 11
server/sonar-db-dao/src/schema/schema-sq.ddl View File

@@ -942,17 +942,6 @@ CREATE UNIQUE INDEX "UNIQ_USER_DISMISSED_MESSAGES" ON "USER_DISMISSED_MESSAGES"(
CREATE INDEX "UDM_PROJECT_UUID" ON "USER_DISMISSED_MESSAGES"("PROJECT_UUID" NULLS FIRST);
CREATE INDEX "UDM_MESSAGE_TYPE" ON "USER_DISMISSED_MESSAGES"("MESSAGE_TYPE" NULLS FIRST);

CREATE TABLE "USER_PROPERTIES"(
"UUID" CHARACTER VARYING(40) NOT NULL,
"USER_UUID" CHARACTER VARYING(255) NOT NULL,
"KEE" CHARACTER VARYING(100) NOT NULL,
"TEXT_VALUE" CHARACTER VARYING(4000) NOT NULL,
"CREATED_AT" BIGINT NOT NULL,
"UPDATED_AT" BIGINT NOT NULL
);
ALTER TABLE "USER_PROPERTIES" ADD CONSTRAINT "PK_USER_PROPERTIES" PRIMARY KEY("UUID");
CREATE UNIQUE INDEX "USER_PROPERTIES_USER_UUID_KEE" ON "USER_PROPERTIES"("USER_UUID" NULLS FIRST, "KEE" NULLS FIRST);

CREATE TABLE "USER_ROLES"(
"UUID" CHARACTER VARYING(40) NOT NULL,
"ROLE" CHARACTER VARYING(64) NOT NULL,

+ 0
- 130
server/sonar-db-dao/src/test/java/org/sonar/db/user/UserPropertiesDaoTest.java View File

@@ -1,130 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2022 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.impl.utils.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"),
user.getLogin());

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"),
user.getLogin());

system2.setNow(2_000_000_000_000L);
underTest.insertOrUpdate(db.getSession(), new UserPropertyDto()
.setUserUuid(user.getUuid())
.setKey("a_key")
.setValue("new_value"),
user.getLogin());

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);
}
}

+ 0
- 158
server/sonar-db-dao/src/test/java/org/sonar/db/user/UserPropertiesDaoWithPersisterTest.java View File

@@ -1,158 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2022 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 org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.db.DbTester;
import org.sonar.db.audit.AuditPersister;
import org.sonar.db.audit.model.PropertyNewValue;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

public class UserPropertiesDaoWithPersisterTest {
private static final long NOW = 1_500_000_000_000L;
private static final String SECURED_PROPERTY_KEY = "a_key.secured";
private static final String PROPERTY_KEY = "a_key";

private final AuditPersister auditPersister = mock(AuditPersister.class);
private ArgumentCaptor<PropertyNewValue> newValueCaptor = ArgumentCaptor.forClass(PropertyNewValue.class);

private TestSystem2 system2 = new TestSystem2().setNow(NOW);

@Rule
public DbTester db = DbTester.create(system2, auditPersister);

private UserPropertiesDao underTest = db.getDbClient().userPropertiesDao();

@Test
public void insertTrackedUserPropertyIsPersisted() {
UserDto user = db.users().insertUser();

verify(auditPersister).addUser(eq(db.getSession()), any());

UserPropertyDto userSetting = underTest.insertOrUpdate(db.getSession(), new UserPropertyDto()
.setUserUuid(user.getUuid())
.setKey(PROPERTY_KEY)
.setValue("a_value"),
user.getLogin());

verify(auditPersister).addProperty(eq(db.getSession()), newValueCaptor.capture(), eq(true));
assertThat(newValueCaptor.getValue())
.extracting(PropertyNewValue::getPropertyKey, PropertyNewValue::getPropertyValue, PropertyNewValue::getUserUuid,
PropertyNewValue::getUserLogin)
.containsExactly(userSetting.getKey(), userSetting.getValue(), user.getUuid(), user.getLogin());

}

@Test
public void insertTrackedAndSecuredUserPropertyIsPersisted() {
UserDto user = db.users().insertUser();

verify(auditPersister).addUser(eq(db.getSession()), any());

UserPropertyDto userSetting = underTest.insertOrUpdate(db.getSession(), new UserPropertyDto()
.setUserUuid(user.getUuid())
.setKey(SECURED_PROPERTY_KEY)
.setValue("a_value"),
user.getLogin());

verify(auditPersister).addProperty(eq(db.getSession()), newValueCaptor.capture(), eq(true));
PropertyNewValue newValue = newValueCaptor.getValue();
assertThat(newValue)
.extracting(PropertyNewValue::getPropertyKey, PropertyNewValue::getPropertyValue, PropertyNewValue::getUserUuid,
PropertyNewValue::getUserLogin)
.containsExactly(userSetting.getKey(), null, user.getUuid(), user.getLogin());
assertThat(newValue.toString()).doesNotContain("propertyValue");
}

@Test
public void updateTrackedUserPropertyIsPersisted() {
UserDto user = db.users().insertUser();
underTest.insertOrUpdate(db.getSession(), new UserPropertyDto()
.setUserUuid(user.getUuid())
.setKey(PROPERTY_KEY)
.setValue("old_value"),
user.getLogin());
system2.setNow(2_000_000_000_000L);
UserPropertyDto userSetting = underTest.insertOrUpdate(db.getSession(), new UserPropertyDto()
.setUserUuid(user.getUuid())
.setKey(PROPERTY_KEY)
.setValue("new_value"),
user.getLogin());

verify(auditPersister).addUser(eq(db.getSession()), any());
verify(auditPersister).addProperty(eq(db.getSession()), any(), eq(true));
verify(auditPersister).updateProperty(eq(db.getSession()), newValueCaptor.capture(), eq(true));
assertThat(newValueCaptor.getValue())
.extracting(PropertyNewValue::getPropertyKey, PropertyNewValue::getPropertyValue, PropertyNewValue::getUserUuid,
PropertyNewValue::getUserLogin)
.containsExactly(userSetting.getKey(), userSetting.getValue(), user.getUuid(), user.getLogin());
}

@Test
public void deleteTrackedUserPropertyIsPersisted() {
when(auditPersister.isTrackedProperty(PROPERTY_KEY)).thenReturn(true);
when(auditPersister.isTrackedProperty(SECURED_PROPERTY_KEY)).thenReturn(false);

UserDto user = db.users().insertUser();
UserPropertyDto userSetting = underTest.insertOrUpdate(db.getSession(), new UserPropertyDto()
.setUserUuid(user.getUuid())
.setKey(PROPERTY_KEY)
.setValue("a_value"),
user.getLogin());
underTest.insertOrUpdate(db.getSession(), new UserPropertyDto()
.setUserUuid(user.getUuid())
.setKey(SECURED_PROPERTY_KEY)
.setValue("another_value"),
user.getLogin());
underTest.deleteByUser(db.getSession(), user);

verify(auditPersister).addUser(eq(db.getSession()), any());
verify(auditPersister, times(2)).addProperty(eq(db.getSession()), any(), eq(true));
verify(auditPersister).isTrackedProperty(PROPERTY_KEY);
verify(auditPersister).isTrackedProperty(SECURED_PROPERTY_KEY);
verify(auditPersister).deleteProperty(eq(db.getSession()), newValueCaptor.capture(), eq(true));
verifyNoMoreInteractions(auditPersister);
assertThat(newValueCaptor.getValue())
.extracting(PropertyNewValue::getPropertyKey, PropertyNewValue::getPropertyValue, PropertyNewValue::getUserUuid,
PropertyNewValue::getUserLogin)
.containsExactly(userSetting.getKey(), userSetting.getValue(), user.getUuid(), user.getLogin());
}

@Test
public void deleteTrackedUserPropertyWithoutAffectedRowsIsNotPersisted() {
UserDto user = db.users().insertUser();

underTest.deleteByUser(db.getSession(), user);

verify(auditPersister).addUser(eq(db.getSession()), any());
verifyNoMoreInteractions(auditPersister);
}
}

+ 0
- 11
server/sonar-db-dao/src/testFixtures/java/org/sonar/db/user/UserDbTester.java View File

@@ -122,17 +122,6 @@ public class UserDbTester {
return Optional.ofNullable(dbClient.userDao().selectByExternalLoginAndIdentityProvider(db.getSession(), login, identityProvider));
}

// USER SETTINGS

@SafeVarargs
public final UserPropertyDto insertUserSetting(UserDto user, Consumer<UserPropertyDto>... populators) {
UserPropertyDto dto = UserTesting.newUserSettingDto(user);
stream(populators).forEach(p -> p.accept(dto));
dbClient.userPropertiesDao().insertOrUpdate(db.getSession(), dto, user.getLogin());
db.commit();
return dto;
}

// GROUPS

public GroupDto insertGroup(String name) {

+ 0
- 9
server/sonar-db-dao/src/testFixtures/java/org/sonar/db/user/UserTesting.java View File

@@ -20,7 +20,6 @@
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;
@@ -86,12 +85,4 @@ 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));
}
}

+ 1
- 0
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v94/DbVersion94.java View File

@@ -31,6 +31,7 @@ public class DbVersion94 implements DbVersion {
.add(6303, "Drop unused Issues Column ISSUE_ATTRIBUTES", DropIssuesAttributesIssueColumn.class)
.add(6304, "Create table 'SCANNER_ANALYSIS_CACHE", CreateScannerAnalysisCacheTable.class)
.add(6305, "Issue warning for users using SHA1 hash method", SelectUsersWithSha1HashMethod.class)
.add(6306, "Drop table 'user_properties'", DropUserPropertiesTable.class)
;
}
}

+ 47
- 0
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v94/DropUserPropertiesTable.java View File

@@ -0,0 +1,47 @@
/*
* SonarQube
* Copyright (C) 2009-2022 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.v94;

import java.sql.SQLException;
import org.sonar.db.Database;
import org.sonar.db.DatabaseUtils;
import org.sonar.server.platform.db.migration.sql.DropTableBuilder;
import org.sonar.server.platform.db.migration.step.DdlChange;

public class DropUserPropertiesTable extends DdlChange {
private static final String TABLE_NAME = "user_properties";

public DropUserPropertiesTable(Database db) {
super(db);
}

@Override
public void execute(Context context) throws SQLException {
if (tableExists()) {
context.execute(new DropTableBuilder(getDialect(), TABLE_NAME).build());
}
}

private boolean tableExists() throws SQLException {
try (var connection = getDatabase().getDataSource().getConnection()) {
return DatabaseUtils.tableExists(TABLE_NAME, connection);
}
}
}

+ 50
- 0
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v94/DropUserPropertiesTableTest.java View File

@@ -0,0 +1,50 @@
/*
* SonarQube
* Copyright (C) 2009-2022 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.v94;

import java.sql.SQLException;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.db.CoreDbTester;

public class DropUserPropertiesTableTest {
private static final String TABLE_NAME = "user_properties";

@Rule
public final CoreDbTester db = CoreDbTester.createForSchema(DropUserPropertiesTableTest.class, "schema.sql");

private final DropUserPropertiesTable underTest = new DropUserPropertiesTable(db.database());

@Test
public void migration_should_drop_table() throws SQLException {
db.assertTableExists(TABLE_NAME);
underTest.execute();
db.assertTableDoesNotExist(TABLE_NAME);
}

@Test
public void migration_should_be_reentrant() throws SQLException {
db.assertTableExists(TABLE_NAME);
underTest.execute();
// re-entrant
underTest.execute();
db.assertTableDoesNotExist(TABLE_NAME);
}
}

+ 9
- 0
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v94/DropUserPropertiesTableTest/schema.sql View File

@@ -0,0 +1,9 @@
CREATE TABLE "USER_PROPERTIES"(
"UUID" CHARACTER VARYING(40) NOT NULL,
"USER_UUID" CHARACTER VARYING(255) NOT NULL,
"KEE" CHARACTER VARYING(100) NOT NULL,
"TEXT_VALUE" CHARACTER VARYING(4000) NOT NULL,
"CREATED_AT" BIGINT NOT NULL,
"UPDATED_AT" BIGINT NOT NULL
);
ALTER TABLE "USER_PROPERTIES" ADD CONSTRAINT "PK_USER_PROPERTIES" PRIMARY KEY("UUID");

+ 0
- 13
server/sonar-webserver-auth/src/test/java/org/sonar/server/user/UserUpdaterCreateTest.java View File

@@ -293,19 +293,6 @@ public class UserUpdaterCreateTest {
assertThat(dbClient.userDao().selectByLogin(session, "user").isOnboarded()).isFalse();
}

@Test
public void does_not_set_notifications_readDate_setting_when_creating_user_when_not_on() {
createDefaultGroup();

UserDto user = underTest.createAndCommit(db.getSession(), NewUser.builder()
.setLogin("userLogin")
.setName("UserName")
.build(), u -> {
});

assertThat(dbClient.userPropertiesDao().selectByUser(session, user)).isEmpty();
}

@Test
public void create_user_and_index_other_user() {
createDefaultGroup();

+ 0
- 14
server/sonar-webserver-auth/src/test/java/org/sonar/server/user/UserUpdaterReactivateTest.java View File

@@ -267,20 +267,6 @@ public class UserUpdaterReactivateTest {
assertThat(dbClient.userDao().selectByLogin(session, user.getLogin()).isOnboarded()).isFalse();
}

@Test
public void does_not_set_notifications_readDate_setting_when_reactivating_user() {
createDefaultGroup();
UserDto user = db.users().insertDisabledUser();

underTest.reactivateAndCommit(db.getSession(), user, NewUser.builder()
.setLogin(user.getLogin())
.setName(user.getName())
.build(), u -> {
});

assertThat(dbClient.userPropertiesDao().selectByUser(session, user)).isEmpty();
}

@Test
public void fail_to_reactivate_user_when_login_already_exists() {
createDefaultGroup();

+ 2
- 14
server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/CurrentAction.java View File

@@ -28,7 +28,6 @@ import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService.NewController;
import org.sonar.core.platform.EditionProvider;
import org.sonar.core.platform.PlatformEditionProvider;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.BranchDto;
@@ -51,11 +50,11 @@ import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang.StringUtils.EMPTY;
import static org.sonar.api.web.UserRole.USER;
import static org.sonar.server.ws.WsUtils.writeProtobuf;
import static org.sonarqube.ws.Users.CurrentWsResponse.Permissions;
import static org.sonarqube.ws.Users.CurrentWsResponse.newBuilder;
import static org.sonarqube.ws.Users.CurrentWsResponse.HomepageType.APPLICATION;
import static org.sonarqube.ws.Users.CurrentWsResponse.HomepageType.PORTFOLIO;
import static org.sonarqube.ws.Users.CurrentWsResponse.HomepageType.PROJECT;
import static org.sonarqube.ws.Users.CurrentWsResponse.Permissions;
import static org.sonarqube.ws.Users.CurrentWsResponse.newBuilder;
import static org.sonarqube.ws.client.user.UsersWsParameters.ACTION_CURRENT;

public class CurrentAction implements UsersWsAction {
@@ -120,7 +119,6 @@ public class CurrentAction implements UsersWsAction {
.setPermissions(Permissions.newBuilder().addAllGlobal(getGlobalPermissions()).build())
.setHomepage(buildHomepage(dbSession, user))
.setShowOnboardingTutorial(!user.isOnboarded())
.addAllSettings(loadUserSettings(dbSession, user))
.setUsingSonarLintConnectedMode(user.getLastSonarlintConnectionDate() != null)
.setSonarLintAdSeen(user.isSonarlintAdSeen());
ofNullable(emptyToNull(user.getEmail())).ifPresent(builder::setEmail);
@@ -224,16 +222,6 @@ 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;
}

+ 0
- 1
server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/DeactivateAction.java View File

@@ -92,7 +92,6 @@ public class DeactivateAction implements UsersWsAction {
dbClient.userPermissionDao().deleteByUserUuid(dbSession, user);
dbClient.permissionTemplateDao().deleteUserPermissionsByUserUuid(dbSession, userUuid, user.getLogin());
dbClient.qProfileEditUsersDao().deleteByUser(dbSession, user);
dbClient.userPropertiesDao().deleteByUser(dbSession, user);
dbClient.almPatDao().deleteByUser(dbSession, user);
dbClient.sessionTokensDao().deleteByUser(dbSession, user);
dbClient.userDismissedMessagesDao().deleteByUser(dbSession, user);

+ 0
- 91
server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/SetSettingAction.java View File

@@ -1,91 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2022 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(
"tutorials.jenkins.skipBitbucketPreReqs",
"notifications.optOut");

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),
userSession.getLogin());
dbSession.commit();
}
}

}

+ 0
- 1
server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/UsersWsModule.java View File

@@ -40,7 +40,6 @@ public class UsersWsModule extends Module {
UserJsonWriter.class,
SetHomepageAction.class,
HomepageTypesImpl.class,
SetSettingAction.class,
UpdateIdentityProviderAction.class);

}

+ 2
- 26
server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/CurrentActionTest.java View File

@@ -19,7 +19,6 @@
*/
package org.sonar.server.user.ws;

import java.util.Collections;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.resources.Qualifiers;
@@ -42,7 +41,6 @@ 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.assertThatThrownBy;
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.GlobalPermission.ADMINISTER_QUALITY_PROFILES;
@@ -103,9 +101,8 @@ public class CurrentActionTest {

assertThat(response)
.extracting(CurrentWsResponse::getIsLoggedIn, CurrentWsResponse::getLogin, CurrentWsResponse::getName, CurrentWsResponse::hasAvatar, CurrentWsResponse::getLocal,
CurrentWsResponse::getExternalIdentity, CurrentWsResponse::getExternalProvider, CurrentWsResponse::getSettingsList,
CurrentWsResponse::getUsingSonarLintConnectedMode, CurrentWsResponse::getSonarLintAdSeen)
.containsExactly(true, "obiwan.kenobi", "Obiwan Kenobi", false, true, "obiwan", "sonarqube", Collections.emptyList(), false, false);
CurrentWsResponse::getExternalIdentity, CurrentWsResponse::getExternalProvider, CurrentWsResponse::getUsingSonarLintConnectedMode, CurrentWsResponse::getSonarLintAdSeen)
.containsExactly(true, "obiwan.kenobi", "Obiwan Kenobi", false, true, "obiwan", "sonarqube", false, false);
assertThat(response.hasEmail()).isFalse();
assertThat(response.getScmAccountsList()).isEmpty();
assertThat(response.getGroupsList()).isEmpty();
@@ -148,27 +145,6 @@ public class CurrentActionTest {
assertThat(response.getPermissions().getGlobalList()).containsOnly("profileadmin", "scan");
}

@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)
.containsExactlyInAnyOrder(
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"));

+ 0
- 16
server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/DeactivateActionTest.java View File

@@ -221,22 +221,6 @@ public class DeactivateActionTest {
assertThat(db.getDbClient().propertiesDao().selectByQuery(PropertyQuery.builder().build(), db.getSession())).extracting(PropertyDto::getKey).containsOnly("other");
}

@Test
public void deactivate_user_deletes_their_user_settings() {
createAdminUser();
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 deactivate_user_deletes_their_qgate_permissions() {
createAdminUser();

+ 0
- 130
server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/SetSettingActionTest.java View File

@@ -1,130 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2022 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.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.assertThatThrownBy;
import static org.assertj.core.api.Assertions.tuple;

public class SetSettingActionTest {

@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() {
assertThatThrownBy(() -> {
ws.newRequest()
.setParam("key", "notifications.optOut")
.setParam("value", "true")
.execute();
})
.isInstanceOf(UnauthorizedException.class);
}

@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(
"tutorials.jenkins.skipBitbucketPreReqs",
"notifications.optOut");
}

}

+ 1
- 1
server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/UsersWsModuleTest.java View File

@@ -30,6 +30,6 @@ public class UsersWsModuleTest {
public void verify_count_of_added_components() {
ListContainer container = new ListContainer();
new UsersWsModule().configure(container);
assertThat(container.getAddedObjects()).hasSize(16);
assertThat(container.getAddedObjects()).hasSize(15);
}
}

+ 0
- 8
sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java View File

@@ -69,7 +69,6 @@ import org.sonarqube.ws.client.system.SystemService;
import org.sonarqube.ws.client.timemachine.TimemachineService;
import org.sonarqube.ws.client.updatecenter.UpdatecenterService;
import org.sonarqube.ws.client.usergroups.UserGroupsService;
import org.sonarqube.ws.client.userproperties.UserPropertiesService;
import org.sonarqube.ws.client.users.UsersService;
import org.sonarqube.ws.client.usertokens.UserTokensService;
import org.sonarqube.ws.client.views.ViewsService;
@@ -133,7 +132,6 @@ class DefaultWsClient implements WsClient {
private final TimemachineService timemachineService;
private final UpdatecenterService updatecenterService;
private final UserGroupsService userGroupsService;
private final UserPropertiesService userPropertiesService;
private final UserTokensService userTokensService;
private final UsersService usersService;
private final ViewsService viewsService;
@@ -192,7 +190,6 @@ class DefaultWsClient implements WsClient {
this.timemachineService = new TimemachineService(wsConnector);
this.updatecenterService = new UpdatecenterService(wsConnector);
this.userGroupsService = new UserGroupsService(wsConnector);
this.userPropertiesService = new UserPropertiesService(wsConnector);
this.userTokensService = new UserTokensService(wsConnector);
this.usersService = new UsersService(wsConnector);
this.viewsService = new ViewsService(wsConnector);
@@ -444,11 +441,6 @@ class DefaultWsClient implements WsClient {
return userGroupsService;
}

@Override
public UserPropertiesService userProperties() {
return userPropertiesService;
}

@Override
public UserTokensService userTokens() {
return userTokensService;

+ 0
- 3
sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java View File

@@ -69,7 +69,6 @@ import org.sonarqube.ws.client.system.SystemService;
import org.sonarqube.ws.client.timemachine.TimemachineService;
import org.sonarqube.ws.client.updatecenter.UpdatecenterService;
import org.sonarqube.ws.client.usergroups.UserGroupsService;
import org.sonarqube.ws.client.userproperties.UserPropertiesService;
import org.sonarqube.ws.client.users.UsersService;
import org.sonarqube.ws.client.usertokens.UserTokensService;
import org.sonarqube.ws.client.views.ViewsService;
@@ -189,8 +188,6 @@ public interface WsClient {

UserGroupsService userGroups();

UserPropertiesService userProperties();

UserTokensService userTokens();

UsersService users();

+ 0
- 53
sonar-ws/src/main/java/org/sonarqube/ws/client/userproperties/UserPropertiesService.java View File

@@ -1,53 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2022 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.userproperties;

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.WsConnector;

/**
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/user_properties">Further information about this web service online</a>
*/
@Generated("sonar-ws-generator")
public class UserPropertiesService extends BaseService {

public UserPropertiesService(WsConnector wsConnector) {
super(wsConnector, "api/user_properties");
}

/**
*
* This is part of the internal API.
* This is a GET request.
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/user_properties/index">Further information about this action online (including a response example)</a>
* @since 2.6
* @deprecated since 6.3
*/
@Deprecated
public String index() {
return call(
new GetRequest(path("index"))
.setMediaType(MediaTypes.JSON)
).content();
}
}

+ 0
- 26
sonar-ws/src/main/java/org/sonarqube/ws/client/userproperties/package-info.java View File

@@ -1,26 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2022 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
@Generated("sonar-ws-generator")
package org.sonarqube.ws.client.userproperties;

import javax.annotation.ParametersAreNonnullByDefault;
import javax.annotation.Generated;


+ 0
- 65
sonar-ws/src/main/java/org/sonarqube/ws/client/users/SetSettingRequest.java View File

@@ -1,65 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2022 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>"tutorials.jenkins.skipBitbucketPreReqs"</li>
* <li>"notifications.optOut"</li>
* <li>"notifications.readDate"</li>
* </ul>
*/
public SetSettingRequest setValue(String value) {
this.value = value;
return this;
}

public String getValue() {
return value;
}
}

+ 0
- 15
sonar-ws/src/main/java/org/sonarqube/ws/client/users/UsersService.java View File

@@ -167,21 +167,6 @@ public class UsersService extends BaseService {
.setMediaType(MediaTypes.JSON)).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.

+ 1
- 1
sonar-ws/src/main/protobuf/ws-users.proto View File

@@ -110,7 +110,7 @@ message CurrentWsResponse {
optional bool showOnboardingTutorial = 11;
optional string avatar = 12;
optional Homepage homepage = 13;
repeated Setting settings = 15;
reserved 15; // settings removed
optional bool usingSonarLintConnectedMode = 16;
optional bool sonarLintAdSeen = 17;


Loading…
Cancel
Save