Skip to content

Commit

Permalink
Merge branch 'main' into delete-saas
Browse files Browse the repository at this point in the history
  • Loading branch information
Mathieu Anderson authored Jan 23, 2024
2 parents e5dee40 + b9bd01c commit 0a151ec
Show file tree
Hide file tree
Showing 17 changed files with 206 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,22 @@ describe("ConsumerOffsetValues.tsx", () => {
it("does not call getConsumerOffsets on load", () => {
expect(mockGetConsumerOffsets).not.toHaveBeenCalled();
});

it("renders correct initial state", () => {
const fetchButton = screen.getByRole("button", {
name: "Fetch the consumer offsets of the current subscription",
name: "Fetch the consumer offset lag of the current subscription",
});
const offsetsText = screen.getByText("Fetch offsets to display data.");
const offsetLagText = screen.getByText("Fetch offset lag to display data.");

expect(fetchButton).toBeEnabled();
expect(offsetsText).toBeVisible();
expect(offsetLagText).toBeVisible();
});
it("renders Consumer offsets when clicking Fetch offsets button (one partition)", async () => {

it("renders Consumer offset lag when clicking Fetch offset lag button (one partition)", async () => {
mockGetConsumerOffsets.mockResolvedValue(testOffsetsDataOnePartition);

const fetchButton = screen.getByRole("button", {
name: "Fetch the consumer offsets of the current subscription",
name: "Fetch the consumer offset lag of the current subscription",
});

await userEvent.click(fetchButton);
Expand All @@ -82,16 +84,17 @@ describe("ConsumerOffsetValues.tsx", () => {
expect(offsets).toBeVisible();

const refetchButton = screen.getByRole("button", {
name: "Refetch the consumer offsets of the current subscription",
name: "Refetch the consumer offset lag of the current subscription",
});

expect(refetchButton).toBeEnabled();
});
it("renders Consumer offsets when clicking Fetch offsets button (two partitions)", async () => {

it("renders Consumer offset lag when clicking Fetch offset lag button (two partitions)", async () => {
mockGetConsumerOffsets.mockResolvedValue(testOffsetsDataTwoPartitions);

const fetchButton = screen.getByRole("button", {
name: "Fetch the consumer offsets of the current subscription",
name: "Fetch the consumer offset lag of the current subscription",
});

await userEvent.click(fetchButton);
Expand All @@ -106,26 +109,27 @@ describe("ConsumerOffsetValues.tsx", () => {
expect(offsetsPartitionTwo).toBeVisible();

const refetchButton = screen.getByRole("button", {
name: "Refetch the consumer offsets of the current subscription",
name: "Refetch the consumer offset lag of the current subscription",
});

expect(refetchButton).toBeEnabled();
});
it("renders no data message when clicking Fetch offsets button (no data)", async () => {

it("renders no data message when clicking Fetch offset lag button (no data)", async () => {
mockGetConsumerOffsets.mockResolvedValue(testOffsetsNoData);

const fetchButton = screen.getByRole("button", {
name: "Fetch the consumer offsets of the current subscription",
name: "Fetch the consumer offset lag of the current subscription",
});

await userEvent.click(fetchButton);

const noOffsets = screen.getByText("No offsets are currently retained.");
const noOffsets = screen.getByText("No offset lag is currently retained.");

expect(noOffsets).toBeVisible();

const refetchButton = screen.getByRole("button", {
name: "Refetch the consumer offsets of the current subscription",
name: "Refetch the consumer offset lag of the current subscription",
});

expect(refetchButton).toBeEnabled();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ const ConsumerOffsetsValues = ({
<Grid.Item>
{!shouldFetch && (
<Typography.Default htmlTag="dd">
Fetch offsets to display data.
Fetch offset lag to display data.
</Typography.Default>
)}
<Box.Flex flexDirection="column">
{offsetsData.length === 0 && offsetsDataFetched && (
<Typography.Default htmlTag="dd">
No offsets are currently retained.
No offset lag is currently retained.
</Typography.Default>
)}
{isFetching ? (
Expand All @@ -80,7 +80,7 @@ const ConsumerOffsetsValues = ({
Render as many skeletons as partitions for refetch */}
{(offsetsData.length === 0 ? ["skeleton"] : offsetsData).map(
(_, index) => {
return <Skeleton key={index} height={22} width={350} />;
return <Skeleton key={index} height={22} width={200} />;
}
)}
</Box.Flex>
Expand Down Expand Up @@ -112,10 +112,10 @@ const ConsumerOffsetsValues = ({
loading={isFetching}
aria-label={`${
shouldFetch ? "Refetch" : "Fetch"
} the consumer offsets of the current subscription`}
} the consumer offset lag of the current subscription`}
icon={refreshIcon}
>
{shouldFetch ? "Refetch" : "Fetch"} offsets
{shouldFetch ? "Refetch" : "Fetch"} offset lag
</Button.Secondary>
</Grid.Item>
</Grid>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ describe("TopicSubscriptionsDetailsModal.tsx", () => {
cleanup();
});

it("does not fetch data for Consumer offsets on load", async () => {
it("does not fetch data for Consumer offset lag on load", async () => {
expect(mockGetConsumerOffsets).not.toHaveBeenCalled();
});

Expand Down Expand Up @@ -195,7 +195,7 @@ describe("TopicSubscriptionsDetailsModal.tsx", () => {
findDefinition(defaultPropsAiven.serviceAccountData.password)
).toBeVisible();

expect(screen.queryByText("Consumer offsets")).not.toBeInTheDocument();
expect(screen.queryByText("Consumer offset lag")).not.toBeInTheDocument();
});
});

Expand All @@ -215,7 +215,7 @@ describe("TopicSubscriptionsDetailsModal.tsx", () => {
cleanup();
});

it("does not fetch data for Consumer offsets on load", async () => {
it("does not fetch data for Consumer offset lag on load", async () => {
expect(mockGetConsumerOffsets).not.toHaveBeenCalled();
});

Expand Down Expand Up @@ -261,17 +261,17 @@ describe("TopicSubscriptionsDetailsModal.tsx", () => {
findDefinition(defaultPropsNonAiven.selectedSubscription.acl_ip)
).toBeVisible();

expect(findTerm("Consumer offsets")).toBeVisible();
expect(findDefinition("Fetch offsets to display data.")).toBeVisible();
expect(findTerm("Consumer offset lag")).toBeVisible();
expect(findDefinition("Fetch offset lag to display data.")).toBeVisible();

expect(
screen.queryByText("Service account password")
).not.toBeInTheDocument();
});

it("fetches Consumer offsets data when Fetch offset button is clicked", async () => {
it("fetches Consumer offset lag data when Fetch offset button is clicked", async () => {
const fetchButton = screen.getByRole("button", {
name: "Fetch the consumer offsets of the current subscription",
name: "Fetch the consumer offset lag of the current subscription",
});

await userEvent.click(fetchButton);
Expand Down Expand Up @@ -310,7 +310,7 @@ describe("TopicSubscriptionsDetailsModal.tsx", () => {
jest.resetAllMocks();
});

it("does not fetch data for Consumer offsets on load", async () => {
it("does not fetch data for Consumer offset lag on load", async () => {
expect(mockGetConsumerOffsets).not.toHaveBeenCalled();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ const TopicSubscriptionsDetailsModal = ({
<Grid.Item xs={2}>
<Box.Flex flexDirection={"column"}>
<Typography.SmallStrong htmlTag={"dt"} color={"grey-60"}>
Consumer offsets
Consumer offset lag
</Typography.SmallStrong>
<ConsumerOffsetsValues
setError={(error: string) =>
Expand Down
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 @@ -60,4 +60,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
2 changes: 1 addition & 1 deletion core/src/main/resources/static/assets/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -10279,7 +10279,7 @@ Layouts
.page-wrapper {
background: #eef5f9;
padding-bottom: 60px;
padding-top: 60px;
padding-top: 85px;
}

/*******************
Expand Down
Loading

0 comments on commit 0a151ec

Please sign in to comment.