Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add promotion persmission #2182

Merged
merged 15 commits into from
Jan 22, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package io.aiven.klaw.dao.migration;

import static io.aiven.klaw.helpers.KwConstants.KLAW_OPTIONAL_PERMISSION_NEW_TOPIC_CREATION_KEY;
import static io.aiven.klaw.model.enums.PermissionType.APPROVE_TOPICS_CREATE;

import io.aiven.klaw.config.ManageDatabase;
import io.aiven.klaw.dao.KwProperties;
import io.aiven.klaw.dao.UserInfo;
import io.aiven.klaw.helpers.db.rdbms.InsertDataJdbc;
import io.aiven.klaw.helpers.db.rdbms.SelectDataJdbc;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

@DataMigration(version = "2.8.0", order = 4)
@Slf4j
@Configuration // Spring will automatically scan and instantiate this class for retrieval.
public class MigrateData2x8x0 {

@Autowired private InsertDataJdbc insertDataJdbc;
@Autowired private SelectDataJdbc selectDataJdbc;

@Autowired private ManageDatabase manageDatabase;

public MigrateData2x8x0() {}

@MigrationRunner()
public boolean migrate() {
log.info(
"Start to migrate 2.8.0 data. Add new server property "
+ KLAW_OPTIONAL_PERMISSION_NEW_TOPIC_CREATION_KEY);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor correction klaw.extra.permission.topic.promote. ->klaw.extra.permission.topic.create

List<UserInfo> allUserInfo = selectDataJdbc.selectAllUsersAllTenants();
Set<Integer> tenantIds =
allUserInfo.stream().map(UserInfo::getTenantId).collect(Collectors.toSet());

for (int tenantId : tenantIds) {
List<KwProperties> kwPropertiesList = selectDataJdbc.selectAllKwPropertiesPerTenant(tenantId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry just realised it's probably worth putting a check in here to only update it if it does not already exist?

if (kwPropertiesList.stream()
.noneMatch(
kwProperties ->
kwProperties
.getKwKey()
.equals(KLAW_OPTIONAL_PERMISSION_NEW_TOPIC_CREATION_KEY))) {
KwProperties kwProperties38 =
new KwProperties(
KLAW_OPTIONAL_PERMISSION_NEW_TOPIC_CREATION_KEY,
tenantId,
"false",
"Enforce extra permission " + APPROVE_TOPICS_CREATE + " to create new topics");
kwPropertiesList.add(kwProperties38);

insertDataJdbc.insertDefaultKwProperties(List.of(kwProperties38));
manageDatabase.loadEnvMapForOneTenant(tenantId);
manageDatabase.loadKwPropsPerOneTenant(null, tenantId);
}
}

return true;
}
}
5 changes: 5 additions & 0 deletions core/src/main/java/io/aiven/klaw/error/KlawErrorMessages.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.aiven.klaw.error;

import static io.aiven.klaw.model.enums.PermissionType.APPROVE_TOPICS_CREATE;

public class KlawErrorMessages {

public static final String ACTIVE_DIRECTORY_ERR_CODE_101 = "AD101";
Expand Down Expand Up @@ -346,6 +348,9 @@ public class KlawErrorMessages {
public static final String TOPICS_ERR_115 =
"PartitionId cannot be empty or less than zero. Number of Offsets cannot be less than zero.";

public static final String TOPICS_ERR_116 =
"Please check if permission " + APPROVE_TOPICS_CREATE + " is assigned to you.";

// Topic Validation
public static final String TOPICS_VLD_ERR_101 =
"Failure. Invalid Topic request type. Possible Value : Create/Promote";
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/java/io/aiven/klaw/helpers/KwConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public class KwConstants {
public static final String CLUSTER_CONN_URL_KEY = "klaw.clusterapi.url";
public static final String EMAIL_NOTIFICATIONS_ENABLED_KEY = "klaw.mail.notifications.enable";

public static final String KLAW_OPTIONAL_PERMISSION_NEW_TOPIC_CREATION_KEY =
"klaw.extra.permission.topic.create";

public static final String USER_ROLE = "USER";

public static final String REQUESTOR_SUBSCRIPTIONS = "requestor_subscriptions";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public enum PermissionType {

REQUEST_CREATE_OPERATIONAL_CHANGES("To request for Operational changes"),
APPROVE_TOPICS("To approve topics requests"),
APPROVE_TOPICS_CREATE("To approve topic create requests"),
APPROVE_SUBSCRIPTIONS("To approve producer or consumer subscriptions"),
APPROVE_SCHEMAS("To approve schemas"),
APPROVE_CONNECTORS("To approve kafka connectors"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,6 @@ public class AuthenticationInfo {
@NotNull private String myteamtopics;
@NotNull private String myOrgTopics;
@NotNull private String googleFeedbackFormLink;
@NotNull private String klawOptionalPermissionNewTopicCreationEnabled;
@NotNull private String klawOptionalPermissionNewTopicCreation;
}
13 changes: 13 additions & 0 deletions core/src/main/java/io/aiven/klaw/service/DefaultDataService.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package io.aiven.klaw.service;

import static io.aiven.klaw.helpers.KwConstants.KLAW_OPTIONAL_PERMISSION_NEW_TOPIC_CREATION_KEY;
import static io.aiven.klaw.model.enums.PermissionType.APPROVE_TOPICS_CREATE;

import io.aiven.klaw.dao.*;
import io.aiven.klaw.helpers.KwConstants;
import io.aiven.klaw.helpers.db.rdbms.HandleDbRequestsJdbc;
Expand Down Expand Up @@ -302,6 +305,16 @@ public List<KwProperties> createDefaultProperties(int tenantId, String mailId) {
KwConstants.MAIL_TOPICUPDATEREQUEST_CONTENT,
"Email notification body for a new Topic Update Request");
kwPropertiesList.add(kwProperties37);

KwProperties kwProperties38 =
new KwProperties(
KLAW_OPTIONAL_PERMISSION_NEW_TOPIC_CREATION_KEY,
tenantId,
"false",
"Enforce extra permission "
+ APPROVE_TOPICS_CREATE
+ " to allow users to create new topics");
kwPropertiesList.add(kwProperties38);
return kwPropertiesList;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
import static io.aiven.klaw.error.KlawErrorMessages.TOPICS_ERR_113;
import static io.aiven.klaw.error.KlawErrorMessages.TOPICS_ERR_114;
import static io.aiven.klaw.error.KlawErrorMessages.TOPICS_ERR_115;
import static io.aiven.klaw.error.KlawErrorMessages.TOPICS_ERR_116;
import static io.aiven.klaw.error.KlawErrorMessages.TOPICS_VLD_ERR_121;
import static io.aiven.klaw.helpers.KwConstants.KLAW_OPTIONAL_PERMISSION_NEW_TOPIC_CREATION_KEY;
import static io.aiven.klaw.helpers.KwConstants.ORDER_OF_TOPIC_ENVS;
import static io.aiven.klaw.helpers.UtilMethods.updateEnvStatus;
import static io.aiven.klaw.service.MailUtils.MailType.TOPIC_CLAIM_REQUESTED;
Expand Down Expand Up @@ -706,14 +708,23 @@ public ApiResponse deleteTopicRequests(String topicId) throws KlawException {
*/
public ApiResponse approveTopicRequests(String topicId) throws KlawException {
log.info("approveTopicRequests {}", topicId);
if (commonUtilsService.isNotAuthorizedUser(getPrincipal(), PermissionType.APPROVE_TOPICS)) {
return ApiResponse.NOT_AUTHORIZED;
}

String userName = getUserName();
int tenantId = commonUtilsService.getTenantId(userName);
TopicRequest topicRequest = getTopicRequestFromTopicId(Integer.parseInt(topicId), tenantId);

String isOptionalExtraPermissionForPromote =
manageDatabase.getKwPropertyValue(
KLAW_OPTIONAL_PERMISSION_NEW_TOPIC_CREATION_KEY, tenantId);
if (topicRequest.getRequestOperationType().equals(RequestOperationType.CREATE.value)
&& Boolean.parseBoolean(isOptionalExtraPermissionForPromote)
&& commonUtilsService.isNotAuthorizedUser(
getPrincipal(), PermissionType.APPROVE_TOPICS_CREATE)) {
return ApiResponse.notOk(ApiResultStatus.NOT_AUTHORIZED.value + ". " + TOPICS_ERR_116);
} else if (commonUtilsService.isNotAuthorizedUser(
getPrincipal(), PermissionType.APPROVE_TOPICS)) {
return ApiResponse.NOT_AUTHORIZED;
}

ApiResponse validationResponse = validateTopicRequest(topicRequest, userName);
if (!validationResponse.isSuccess()) {
return validationResponse;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static io.aiven.klaw.error.KlawErrorMessages.*;
import static io.aiven.klaw.helpers.KwConstants.APPROVER_SUBSCRIPTIONS;
import static io.aiven.klaw.helpers.KwConstants.CORAL_INDEX_FILE_PATH;
import static io.aiven.klaw.helpers.KwConstants.KLAW_OPTIONAL_PERMISSION_NEW_TOPIC_CREATION_KEY;
import static io.aiven.klaw.helpers.KwConstants.REQUESTOR_SUBSCRIPTIONS;
import static io.aiven.klaw.model.enums.AuthenticationType.ACTIVE_DIRECTORY;
import static io.aiven.klaw.model.enums.RolesType.SUPERADMIN;
Expand Down Expand Up @@ -599,6 +600,20 @@ public AuthenticationInfo getAuth() {
broadCastText += " Announcement : " + broadCastTextGlobal;
}

String isOptionalExtraPermissionForTopicCreateEnabled =
manageDatabase.getKwPropertyValue(
KLAW_OPTIONAL_PERMISSION_NEW_TOPIC_CREATION_KEY, tenantId);

authenticationInfo.setKlawOptionalPermissionNewTopicCreationEnabled(
isOptionalExtraPermissionForTopicCreateEnabled);

if (commonUtilsService.isNotAuthorizedUser(
getPrincipal(), PermissionType.APPROVE_TOPICS_CREATE)) {
authenticationInfo.setKlawOptionalPermissionNewTopicCreation("false");
} else {
authenticationInfo.setKlawOptionalPermissionNewTopicCreation("true");
}

UserInfo userInfo = manageDatabase.getHandleDbRequests().getUsersInfo(userName);
authenticationInfo.setCanSwitchTeams("" + userInfo.isSwitchTeams());

Expand Down
34 changes: 33 additions & 1 deletion core/src/main/resources/templates/execTopics.html
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,40 @@ <h4 class="card-title">Topic Approvals</h4></td>
<tr>
<td align="left"><h3 class="card-title">Topic : {{ topicRequest.topicname }}</h3></td>
<td align="right" ng-show="topicRequest.requestStatus == 'CREATED' && userlogged != topicRequest.requestor">
<button type="button" ng-click="execTopicRequestUp(topicRequest.topicid);" class="btn btn-success btn-circle"><i class="fa fa-check"></i>

<button type="button"
ng-show="topicRequest.requestOperationType === 'CREATE' &&
dashboardDetails.klawOptionalPermissionNewTopicCreationEnabled == 'false'"
ng-click="execTopicRequestUp(topicRequest.topicid);"
class="btn btn-success btn-circle">
<i class="fa fa-check"></i>
</button>

<button type="button"
ng-show="topicRequest.requestOperationType === 'CREATE' &&
dashboardDetails.klawOptionalPermissionNewTopicCreationEnabled == 'true' &&
dashboardDetails.klawOptionalPermissionNewTopicCreation == 'true'"
ng-click="execTopicRequestUp(topicRequest.topicid);"
class="btn btn-success btn-circle">
<i class="fa fa-check"></i>
</button>

<button type="button"
ng-show="topicRequest.requestOperationType === 'CREATE' &&
dashboardDetails.klawOptionalPermissionNewTopicCreationEnabled === 'true' &&
dashboardDetails.klawOptionalPermissionNewTopicCreation === 'false'"
ng-click="execTopicRequestUp(topicRequest.topicid);"
class="btn btn-success btn-circle" disabled
title="You do not have permission to approve this request">
<i class="fa fa-check"></i>
</button>

<button type="button" ng-show="topicRequest.requestOperationType !== 'CREATE'"
ng-click="execTopicRequestUp(topicRequest.topicid);"
class="btn btn-success btn-circle">
<i class="fa fa-check"></i>
</button>

<button type="button" ng-click="execTopicRequestReject(topicRequest.topicid);" class="btn btn-danger btn-circle"><i class="fa fa-times"></i>
</button>
</td>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public void CheckAllProdDataMigrationClassesHaveAMigrationRunner() {
Reflections reflections = new Reflections(PROD_PACKAGE_TO_SCAN);
Set<Class<?>> classes = reflections.getTypesAnnotatedWith(DataMigration.class);
// When adding a new package you will need to increment this by 1.
assertThat(classes.size()).isEqualTo(4);
assertThat(classes.size()).isEqualTo(5);
Set<Integer> uniqueOrder = new HashSet<>();
// Check Order Numbers are correctly assigned
classes.forEach(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.aiven.klaw.service;

import static io.aiven.klaw.error.KlawErrorMessages.TOPICS_VLD_ERR_121;
import static io.aiven.klaw.helpers.KwConstants.KLAW_OPTIONAL_PERMISSION_NEW_TOPIC_CREATION_KEY;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
Expand Down Expand Up @@ -1670,6 +1671,26 @@ public void getTopicsWithPatternFilterOneResult() throws KlawNotAuthorizedExcept
assertThat(topicsList.get(0)).hasSize(1);
}

@Test
@Order(59)
public void approvePromoteTopicRequests() throws KlawException {
int topicId = 1001;
TopicRequest topicRequest = getTopicRequest(TOPIC_1);
topicRequest.setRequestOperationType(RequestOperationType.CREATE.value);

when(commonUtilsService.isNotAuthorizedUser("userDetails", PermissionType.APPROVE_TOPICS))
.thenReturn(false);
when(commonUtilsService.isNotAuthorizedUser(
"userDetails", PermissionType.APPROVE_TOPICS_CREATE))
.thenReturn(true);
when(handleDbRequests.getTopicRequestsForTopic(anyInt(), anyInt())).thenReturn(topicRequest);
when(manageDatabase.getKwPropertyValue(KLAW_OPTIONAL_PERMISSION_NEW_TOPIC_CREATION_KEY, 0))
.thenReturn("true");

ApiResponse apiResponse1 = topicControllerService.approveTopicRequests(topicId + "");
assertThat(apiResponse1.getMessage()).contains(ApiResponse.NOT_AUTHORIZED.getMessage());
}

private List<MessageSchema> getSchemas(int number) {
List<MessageSchema> schemas = new ArrayList<>();
for (int i = 0; i < number; i++) {
Expand Down