Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ void logConfigAtStartup(@Observes Startup event) {

Map<String, Object> config = new TreeMap<>();
config.put(DEFAULT_TEMPLATE, isDefaultTemplateEnabled());
config.put(drawerToggle, isDrawerEnabled());
config.put(drawerToggle, isDrawerEnabled(null));
config.put(EMAILS_ONLY_MODE, isEmailsOnlyModeEnabled());
config.put(ERRATA_MIGRATION_BATCH_SIZE, getErrataMigrationBatchSize());
config.put(KESSEL_DOMAIN, kesselDomain);
Expand All @@ -162,9 +162,10 @@ public boolean isDefaultTemplateEnabled() {
return defaultTemplateEnabled;
}

public boolean isDrawerEnabled() {
public boolean isDrawerEnabled(String orgId) {
if (unleashEnabled) {
return unleash.isEnabled(drawerToggle, false);
UnleashContext unleashContext = buildUnleashContextWithOrgId(orgId);
return unleash.isEnabled(drawerToggle, unleashContext, false);
} else {
return drawerEnabled;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ public List<EventTypeEmailSubscription> getEmailSubscriptionByEventType(String o
.setParameter("userId", username)
.setParameter("bundleName", bundleName)
.setParameter("applicationName", applicationName)
.setParameter("subscriptionTypes", getAvailableTypes())
.setParameter("subscriptionTypes", getAvailableTypes(orgId))
.getResultList();
}

Expand All @@ -162,12 +162,12 @@ public List<EventTypeEmailSubscription> getEmailSubscriptionsPerEventTypeForUser
return entityManager.createQuery(query, EventTypeEmailSubscription.class)
.setParameter("orgId", orgId)
.setParameter("userId", username)
.setParameter("subscriptionTypes", getAvailableTypes())
.setParameter("subscriptionTypes", getAvailableTypes(orgId))
.getResultList();
}

private List<SubscriptionType> getAvailableTypes() {
if (backendConfig.isDrawerEnabled()) {
private List<SubscriptionType> getAvailableTypes(String orgId) {
if (backendConfig.isDrawerEnabled(orgId)) {
return List.of(INSTANT, DAILY, DRAWER);
} else {
return List.of(INSTANT, DAILY);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ private Template findTemplate(UUID id, String notFoundMessage) {
return template;
}

public boolean isSubscriptionTypeSupported(final UUID eventTypeId, final SubscriptionType subscriptionType) {
public boolean isSubscriptionTypeSupported(final UUID eventTypeId, final SubscriptionType subscriptionType, final String orgId) {
try {
switch (subscriptionType) {
case DAILY:
Expand All @@ -358,7 +358,7 @@ public boolean isSubscriptionTypeSupported(final UUID eventTypeId, final Subscri
break;
case DRAWER:
checkIfExistDrawerTemplateByEventType(eventTypeId);
return backendConfig.isDrawerEnabled();
return backendConfig.isDrawerEnabled(orgId);
default:
Log.infof("Subscription type %s not checked", subscriptionType);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public Page<DrawerEntryPayload> getDrawerEntries(@Context SecurityContext securi
LocalDateTime start = LocalDateTime.now();
List<DrawerEntryPayload> drawerEntries = new ArrayList<>();
Long count = 0L;
if (backendConfig.isDrawerEnabled()) {
if (backendConfig.isDrawerEnabled(orgId)) {
count = drawerRepository.count(orgId, username, bundleIds, appIds, eventTypeIds, startDate, endDate, readStatus);
if (count > 0) {
drawerEntries = drawerRepository.getNotifications(orgId, username, bundleIds, appIds, eventTypeIds, startDate, endDate, readStatus, query);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,15 +302,15 @@ private void addApplicationStructureDetails(final SettingsValuesByEventType sett
private boolean isTemplateSupported(String bundleName, String applicationName, EventType eventType, SubscriptionType subscriptionType, final String orgId) {
boolean supported;
if (backendConfig.isUseCommonTemplateModuleForUserPrefApisToggle()) {
if (!backendConfig.isDrawerEnabled() && subscriptionType == DRAWER) {
if (!backendConfig.isDrawerEnabled(orgId) && subscriptionType == DRAWER) {
supported = false;
} else {
boolean canUseTemplateBetaVersion = backendConfig.isUseBetaTemplatesEnabled(orgId);
TemplateDefinition templateDefinition = getTemplateDefinition(bundleName, applicationName, eventType.getName(), subscriptionType, canUseTemplateBetaVersion);
supported = templateService.isValidTemplateDefinition(templateDefinition);
}
} else {
supported = templateRepository.isSubscriptionTypeSupported(eventType.getId(), subscriptionType);
supported = templateRepository.isSubscriptionTypeSupported(eventType.getId(), subscriptionType, orgId);
}
return supported;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.redhat.cloud.notifications.db.repositories;

import com.redhat.cloud.notifications.TestLifecycleManager;
import com.redhat.cloud.notifications.config.BackendConfig;
import com.redhat.cloud.notifications.db.DbIsolatedTest;
import com.redhat.cloud.notifications.db.ResourceHelpers;
import com.redhat.cloud.notifications.models.AggregationEmailTemplate;
Expand All @@ -9,6 +10,7 @@
import com.redhat.cloud.notifications.models.EventType;
import com.redhat.cloud.notifications.models.InstantEmailTemplate;
import com.redhat.cloud.notifications.models.Template;
import io.quarkus.test.InjectMock;
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
Expand All @@ -17,9 +19,15 @@

import java.util.UUID;

import static com.redhat.cloud.notifications.TestConstants.DEFAULT_ORG_ID;
import static com.redhat.cloud.notifications.models.SubscriptionType.DAILY;
import static com.redhat.cloud.notifications.models.SubscriptionType.DRAWER;
import static com.redhat.cloud.notifications.models.SubscriptionType.INSTANT;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;

@QuarkusTest
@QuarkusTestResource(TestLifecycleManager.class)
Expand All @@ -31,6 +39,9 @@ public class TemplateRepositoryTest extends DbIsolatedTest {
@Inject
TemplateRepository templateRepository;

@InjectMock
BackendConfig backendConfig;

private Bundle bundle;
private Application app1;
private Application app2;
Expand Down Expand Up @@ -89,17 +100,40 @@ private void assertIsSubscriptionTypeSupported(boolean app1Instant, boolean app1
boolean app2Daily, boolean unknownAppInstant, boolean unknownAppDaily) {

// bundle / app-1 / event-type-1
assertEquals(app1Instant, templateRepository.isSubscriptionTypeSupported(eventType1.getId(), INSTANT));
assertEquals(false, templateRepository.isSubscriptionTypeSupported(eventType2.getId(), INSTANT));
assertEquals(app1Daily, templateRepository.isSubscriptionTypeSupported(eventType1.getId(), DAILY));
assertEquals(app1Daily, templateRepository.isSubscriptionTypeSupported(eventType2.getId(), DAILY));
assertEquals(app1Instant, templateRepository.isSubscriptionTypeSupported(eventType1.getId(), INSTANT, DEFAULT_ORG_ID));
assertEquals(false, templateRepository.isSubscriptionTypeSupported(eventType2.getId(), INSTANT, DEFAULT_ORG_ID));
assertEquals(app1Daily, templateRepository.isSubscriptionTypeSupported(eventType1.getId(), DAILY, DEFAULT_ORG_ID));
assertEquals(app1Daily, templateRepository.isSubscriptionTypeSupported(eventType2.getId(), DAILY, DEFAULT_ORG_ID));

// bundle / app-2 / event-type-2
assertEquals(app2Instant, templateRepository.isSubscriptionTypeSupported(app2eventType1.getId(), INSTANT));
assertEquals(app2Daily, templateRepository.isSubscriptionTypeSupported(app2eventType1.getId(), DAILY));
assertEquals(app2Instant, templateRepository.isSubscriptionTypeSupported(app2eventType1.getId(), INSTANT, DEFAULT_ORG_ID));
assertEquals(app2Daily, templateRepository.isSubscriptionTypeSupported(app2eventType1.getId(), DAILY, DEFAULT_ORG_ID));

// unknown-bundle / unknown-app
assertEquals(unknownAppInstant, templateRepository.isSubscriptionTypeSupported(UUID.randomUUID(), INSTANT));
assertEquals(unknownAppDaily, templateRepository.isSubscriptionTypeSupported(UUID.randomUUID(), DAILY));
assertEquals(unknownAppInstant, templateRepository.isSubscriptionTypeSupported(UUID.randomUUID(), INSTANT, DEFAULT_ORG_ID));
assertEquals(unknownAppDaily, templateRepository.isSubscriptionTypeSupported(UUID.randomUUID(), DAILY, DEFAULT_ORG_ID));
}

@Test
void testIsSubscriptionTypeSupportedOrgSpecific() {
final String ORG_WITH_DRAWER_ENABLED = "org-with-drawer-enabled";
final String ORG_WITH_DRAWER_DISABLED = "org-with-drawer-disabled";

when(backendConfig.isDrawerEnabled(eq(ORG_WITH_DRAWER_ENABLED))).thenReturn(true);
when(backendConfig.isDrawerEnabled(eq(ORG_WITH_DRAWER_DISABLED))).thenReturn(false);
when(backendConfig.isDefaultTemplateEnabled()).thenReturn(false);

// Create drawer template
resourceHelpers.createDrawerTemplate(bundle.getName(), app1.getName(), eventType1.getName());

// Verify drawer supported for org-with-drawer-enabled
assertTrue(templateRepository.isSubscriptionTypeSupported(
eventType1.getId(), DRAWER, ORG_WITH_DRAWER_ENABLED
), "Drawer should be supported for org-with-drawer-enabled");

// Verify drawer NOT supported for org-with-drawer-disabled
assertFalse(templateRepository.isSubscriptionTypeSupported(
eventType1.getId(), DRAWER, ORG_WITH_DRAWER_DISABLED
), "Drawer should NOT be supported for org-with-drawer-disabled");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
import static java.time.ZoneOffset.UTC;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;

@QuarkusTest
Expand All @@ -62,7 +64,7 @@ public class DrawerResourceTest extends DbIsolatedTest {

@Test
void testMultiplePages() {
when(backendConfig.isDrawerEnabled()).thenReturn(true);
when(backendConfig.isDrawerEnabled(anyString())).thenReturn(true);
final String USERNAME = "user-1";
Header defaultIdentityHeader = mockRbac(DEFAULT_ACCOUNT_ID, DEFAULT_ORG_ID, USERNAME, FULL_ACCESS);

Expand Down Expand Up @@ -102,7 +104,7 @@ void testMultiplePages() {

@Test
void testFilters() {
when(backendConfig.isDrawerEnabled()).thenReturn(true);
when(backendConfig.isDrawerEnabled(anyString())).thenReturn(true);
Bundle createdBundle = resourceHelpers.createBundle("test-drawer-event-resource-bundle");
Bundle createdBundle2 = resourceHelpers.createBundle("test-drawer-event-resource-bundle2");
Application createdApplication = resourceHelpers.createApplication(createdBundle.getId(), "test-drawer-event-resource-application");
Expand Down Expand Up @@ -205,7 +207,8 @@ void testFilters() {

@Transactional
void createDrawerNotification(String userId, Event createdEvent) {
DrawerNotification notificationDrawer = new DrawerNotification(DEFAULT_ORG_ID, userId, entityManager.find(Event.class, createdEvent.getId()));
Event event = entityManager.find(Event.class, createdEvent.getId());
DrawerNotification notificationDrawer = new DrawerNotification(event.getOrgId(), userId, event);
notificationDrawer.setCreated(createdEvent.getCreated());
entityManager.persist(notificationDrawer);
}
Expand Down Expand Up @@ -302,4 +305,59 @@ private static void assertLinks(Map<String, String> links, String... expectedKey
assertTrue(links.containsKey(key));
}
}

@Test
void testDrawerNotificationsOrgSpecific() {
final String ORG_WITH_DRAWER_ENABLED = "org-with-drawer-enabled";
final String ORG_WITH_DRAWER_DISABLED = "org-with-drawer-disabled";
final String ANOTHER_ORG_WITH_DRAWER_ENABLED = "another-org-with-drawer-enabled";
final String USERNAME = "user-test";

when(backendConfig.isDrawerEnabled(eq(ORG_WITH_DRAWER_ENABLED))).thenReturn(true);
when(backendConfig.isDrawerEnabled(eq(ORG_WITH_DRAWER_DISABLED))).thenReturn(false);
when(backendConfig.isDrawerEnabled(eq(ANOTHER_ORG_WITH_DRAWER_ENABLED))).thenReturn(true);

Bundle bundle = resourceHelpers.createBundle("bundle-org-test");
Application app = resourceHelpers.createApplication(bundle.getId(), "app-org-test");
EventType eventType = resourceHelpers.createEventType(app.getId(), "event-type-org-test");

// Create events for all three orgs with the SAME username
// This tests data isolation - ensuring orgs can't see each other's data
Event eventOrg1 = createEvent("account-1", ORG_WITH_DRAWER_ENABLED, bundle, app, eventType,
LocalDateTime.now(UTC), Severity.LOW);
Event eventOrg2 = createEvent("account-2", ORG_WITH_DRAWER_DISABLED, bundle, app, eventType,
LocalDateTime.now(UTC), Severity.MODERATE);
Event eventOrg3 = createEvent("account-3", ANOTHER_ORG_WITH_DRAWER_ENABLED, bundle, app, eventType,
LocalDateTime.now(UTC), Severity.IMPORTANT);

// Create drawer notifications for the same user across all orgs
createDrawerNotification(USERNAME, eventOrg1);
createDrawerNotification(USERNAME, eventOrg2);
createDrawerNotification(USERNAME, eventOrg3);

// Test Org 1: should see only their own notification (Severity.LOW), not Org 3's data
Header headerOrg1 = mockRbac("account-1", ORG_WITH_DRAWER_ENABLED, USERNAME, FULL_ACCESS);
Page<DrawerEntryPayload> pageOrg1 = getDrawerEntries(headerOrg1, null, null, null,
null, null, null, null, null, null);
assertEquals(1, pageOrg1.getMeta().getCount(),
"Org 1 should see exactly 1 notification (their own), not cross-org data");
assertEquals("LOW", pageOrg1.getData().get(0).getSeverity(),
"Org 1 should see their own event with Severity.LOW");

// Test Org 2: drawer disabled, should see 0 entries
Header headerOrg2 = mockRbac("account-2", ORG_WITH_DRAWER_DISABLED, USERNAME, FULL_ACCESS);
Page<DrawerEntryPayload> pageOrg2 = getDrawerEntries(headerOrg2, null, null, null,
null, null, null, null, null, null);
assertEquals(0, pageOrg2.getMeta().getCount(),
"Org 2 with drawer disabled should see 0 notifications");

// Test Org 3: should see only their own notification (Severity.HIGH), proving data isolation
Header headerOrg3 = mockRbac("account-3", ANOTHER_ORG_WITH_DRAWER_ENABLED, USERNAME, FULL_ACCESS);
Page<DrawerEntryPayload> pageOrg3 = getDrawerEntries(headerOrg3, null, null, null,
null, null, null, null, null, null);
assertEquals(1, pageOrg3.getMeta().getCount(),
"Org 3 should see exactly 1 notification (their own), proving org isolation");
assertEquals("IMPORTANT", pageOrg3.getData().get(0).getSeverity(),
"Org 3 should see their own event with Severity.IMPORTANT, not Org 1's data");
}
}
Loading
Loading