Skip to content

Commit

Permalink
Add promotion persmission (#2182)
Browse files Browse the repository at this point in the history
* Add promotion persmission

Signed-off-by: muralibasani <[email protected]>

* Validate checks

Signed-off-by: muralibasani <[email protected]>

* Updating permission validation

Signed-off-by: muralibasani <[email protected]>

* Validation for topic create requests

Signed-off-by: muralibasani <[email protected]>

* Validation for topic create requests

Signed-off-by: muralibasani <[email protected]>

* Validation for topic create requests

Signed-off-by: muralibasani <[email protected]>

* Validation for topic create requests

Signed-off-by: muralibasani <[email protected]>

* Update text

Signed-off-by: muralibasani <[email protected]>

* Update text

Signed-off-by: muralibasani <[email protected]>

* Limiting users on FE as well

Signed-off-by: muralibasani <[email protected]>

* Button disabled with hover text

Signed-off-by: muralibasani <[email protected]>

---------

Signed-off-by: muralibasani <[email protected]>
Co-authored-by: muralibasani <[email protected]>
Co-authored-by: Aindriú Lavelle <[email protected]>
  • Loading branch information
3 people authored Jan 22, 2024
1 parent 5a10be7 commit 0ccca58
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 6 deletions.
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);

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

0 comments on commit 0ccca58

Please sign in to comment.