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

Issue email to all approvers #1258

Merged
merged 4 commits into from
May 19, 2023
Merged
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
@@ -35,7 +35,6 @@
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.swing.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
19 changes: 18 additions & 1 deletion core/src/main/java/io/aiven/klaw/service/EmailService.java
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import lombok.extern.slf4j.Slf4j;
@@ -71,10 +72,21 @@ public class EmailService {
+ "\t</tr>\n"
+ "</table></html>";

@Async("notificationsThreadPool")
public void sendSimpleMessage(
String to, String cc, String subject, String text, int tenantId, String loginUrl) {

sendSimpleMessage(to, cc, null, subject, text, tenantId, loginUrl);
}

@Async("notificationsThreadPool")
public void sendSimpleMessage(
String to,
String cc,
List<String> bcc,
String subject,
String text,
int tenantId,
String loginUrl) {
String emailNotificationsEnabled =
manageDatabase.getKwPropertyValue(EMAIL_NOTIFICATIONS_ENABLED_KEY, DEFAULT_TENANT_ID);
try {
@@ -83,6 +95,11 @@ public void sendSimpleMessage(
if (cc != null) {
message.setRecipients(Message.RecipientType.CC, cc);
}
if (bcc != null && !bcc.isEmpty()) {
for (String bccAddress : bcc) {
message.setRecipients(Message.RecipientType.BCC, bccAddress);
}
}

message.setSubject(subject);
Address address = new InternetAddress(noReplyMailId);
74 changes: 68 additions & 6 deletions core/src/main/java/io/aiven/klaw/service/MailUtils.java
Original file line number Diff line number Diff line change
@@ -9,7 +9,10 @@
import io.aiven.klaw.helpers.UtilMethods;
import io.aiven.klaw.model.enums.ApiResultStatus;
import io.aiven.klaw.model.enums.MailType;
import io.aiven.klaw.model.enums.PermissionType;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@@ -109,19 +112,22 @@ void sendMail(
getUserName(SecurityContextHolder.getContext().getAuthentication().getPrincipal()))
.getTenantId();
loadKwProps(tenantId);

Boolean requiresApproval = false;
switch (mailType) {
case TOPIC_CREATE_REQUESTED -> {
formattedStr = String.format(topicRequestMail, "'" + topicName + "'");
subject = "Create Topic Request";
requiresApproval = true;
}
case TOPIC_DELETE_REQUESTED -> {
formattedStr = String.format(topicDeleteRequestMail, "'" + topicName + "'");
subject = "Delete Topic Request";
requiresApproval = true;
}
case TOPIC_CLAIM_REQUESTED -> {
formattedStr = String.format(topicClaimRequestMail, "'" + topicName + "'");
subject = "Claim Topic Request";
requiresApproval = true;
}
case TOPIC_REQUEST_APPROVED -> {
formattedStr = String.format(topicRequestApproved, "'" + topicName + "'");
@@ -135,10 +141,12 @@ void sendMail(
case ACL_REQUESTED -> {
formattedStr = String.format(aclRequestMail, "'" + acl + "'", "'" + topicName + "'");
subject = "New Acl Request";
requiresApproval = true;
}
case ACL_DELETE_REQUESTED -> {
formattedStr = String.format(aclDeleteRequestMail, "'" + acl + "'", "'" + topicName + "'");
subject = "Acl Delete Request";
requiresApproval = true;
}
case ACL_REQUEST_APPROVED -> {
formattedStr = String.format(aclRequestApproved, "'" + acl + "'", "'" + topicName + "'");
@@ -157,9 +165,25 @@ void sendMail(
formattedStr = "Acl Request processing failed : " + acl + ", " + topicName;
subject = "Request processing failed.";
}
case CONNECTOR_CLAIM_REQUESTED,
CONNECTOR_REQUEST_DENIED,
CONNECTOR_DELETE_REQUESTED,
SCHEMA_REQUESTED -> {
// all remaining requests that require approvals are grouped here.
requiresApproval = true;
}
}

sendMail(username, dbHandle, formattedStr, subject, false, null, tenantId, loginUrl);
sendMail(
username,
dbHandle,
formattedStr,
subject,
false,
requiresApproval,
null,
tenantId,
loginUrl);
}

void sendMail(String username, String pwd, HandleDbRequests dbHandle, String loginUrl) {
@@ -174,7 +198,7 @@ void sendMail(String username, String pwd, HandleDbRequests dbHandle, String log
formattedStr = String.format(newUserAdded, username, pwd);
subject = "Access to Klaw";

sendMail(username, dbHandle, formattedStr, subject, false, null, tenantId, loginUrl);
sendMail(username, dbHandle, formattedStr, subject, false, false, null, tenantId, loginUrl);
}

void sendMailResetPwd(
@@ -255,6 +279,7 @@ void sendMailRegisteredUserSaas(
formattedStr,
subject,
true,
false,
registerUserInfo.getMailid(),
tenantId,
loginUrl);
@@ -296,6 +321,7 @@ void sendMailRegisteredUser(
formattedStr,
subject,
true,
false,
registerUserInfo.getMailid(),
tenantId,
loginUrl);
@@ -340,6 +366,7 @@ private void sendMail(
String formattedStr,
String subject,
boolean registrationRequest,
boolean requiresApproval,
String otherMailId,
int tenantId,
String loginUrl) {
@@ -349,6 +376,8 @@ private void sendMail(
String emailId;

String emailIdTeam = null;
Integer teamId = null;
List<String> allApprovers = null;
try {
if (registrationRequest) {
emailId = otherMailId;
@@ -358,14 +387,19 @@ private void sendMail(

try {
List<Team> allTeams = dbHandle.getAllTeamsOfUsers(username, tenantId);
if (!allTeams.isEmpty()) emailIdTeam = allTeams.get(0).getTeammail();
if (!allTeams.isEmpty()) {
emailIdTeam = allTeams.get(0).getTeammail();
teamId = allTeams.get(0).getTeamId();
}
} catch (Exception e) {
log.error("Exception :", e);
}

if (requiresApproval) {
allApprovers = getAllUsersWithPermissionToApproveRequest(tenantId, username, teamId);
}
if (emailId != null) {
emailService.sendSimpleMessage(
emailId, emailIdTeam, subject, formattedStr, tenantId, loginUrl);
emailId, emailIdTeam, allApprovers, subject, formattedStr, tenantId, loginUrl);
} else {
log.error("Email id not found. Notification not sent !!");
}
@@ -417,6 +451,34 @@ public String getEmailAddressFromUsername(String username) {
}
}

private List<String> getAllUsersWithPermissionToApproveRequest(
int tenantId, String username, Integer teamId) {

Map<String, List<String>> rolesToPermissions =
manageDatabase.getRolesPermissionsPerTenant(tenantId);

List<String> roles = new ArrayList<>();

rolesToPermissions.forEach(
(k, v) -> {
if (v.contains(PermissionType.APPROVE_ALL_REQUESTS_TEAMS.name())) {
roles.add(k);
}
});

// Prevent duplicates only show from the correct tenant, that is not the usernae of the
// requestor and that is not on the same team as they have already received that email.
return manageDatabase.selectAllCachedUserInfo().stream()
.filter(
user ->
user.getTenantId() == tenantId
&& !user.getUsername().equals(username)
&& roles.contains(user.getRole())
&& (teamId == null || !user.getTeamId().equals(teamId)))
.map(u -> u.getMailid())
.toList();
}

public String sendMailToSaasAdmin(int tenantId, String userName, String period, String loginUrl) {
String mailtext =
"Tenant extension : Tenant " + tenantId + " username " + userName + " period " + period;
111 changes: 101 additions & 10 deletions core/src/test/java/io/aiven/klaw/service/MailUtilsTest.java
Original file line number Diff line number Diff line change
@@ -7,16 +7,21 @@

import io.aiven.klaw.config.ManageDatabase;
import io.aiven.klaw.dao.UserInfo;
import io.aiven.klaw.helpers.HandleDbRequests;
import io.aiven.klaw.helpers.KwConstants;
import io.aiven.klaw.helpers.db.rdbms.HandleDbRequestsJdbc;
import io.aiven.klaw.model.enums.MailType;
import io.aiven.klaw.model.enums.PermissionType;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@@ -25,7 +30,9 @@ public class MailUtilsTest {
public static final String LOGIN_URL = "https://localhost:9097";
@Mock UserDetails userDetails;

@Mock HandleDbRequests handleDbRequests;
// @Mock HandleDbRequests handleDbRequests;

@Mock HandleDbRequestsJdbc handleDbRequestsJdbc;

@Mock EmailService emailService;

@@ -36,6 +43,11 @@ public class MailUtilsTest {
@BeforeEach
public void setUp() throws Exception {
// mailService = new MailUtils();
when(manageDatabase.getHandleDbRequests()).thenReturn(handleDbRequestsJdbc);
when(handleDbRequestsJdbc.getUsersInfo(eq("james")))
.thenReturn(createUserInfo("James", "USER"));
when(manageDatabase.getRolesPermissionsPerTenant(eq(101)))
.thenReturn(getRolesToPermissionsMap());
}

@Test
@@ -45,13 +57,11 @@ public void getUserDetails() {}
public void resetPasswordEmail_noCCTeam() throws InterruptedException {

String username = "Octopus";
UserInfo info = new UserInfo();
info.setUsername(username);
info.setMailid("Octopus.klaw@mailid");
UserInfo info = createUserInfo(username, "USER");
when(manageDatabase.selectAllCachedUserInfo()).thenReturn(List.of(info));
when(manageDatabase.getKwPropertyValue(eq("klaw.mail.passwordreset.content"), eq(101)))
.thenReturn(KwConstants.MAIL_PASSWORDRESET_CONTENT);
mailService.sendMailResetPwd(username, "KlawPassword", handleDbRequests, 101, LOGIN_URL);
mailService.sendMailResetPwd(username, "KlawPassword", handleDbRequestsJdbc, 101, LOGIN_URL);

Thread.sleep(1000);
Mockito.verify(emailService, timeout(1000).times(1))
@@ -63,15 +73,96 @@ public void resetPasswordEmail_noCCTeam() throws InterruptedException {
public void resetPasswordEmail_noSuchUser() {

String username = "Octopus";
UserInfo info = new UserInfo();
info.setUsername("Octi");
info.setMailid("Octi.klaw@mailid");
UserInfo info = createUserInfo("Octi", "USER");
when(manageDatabase.selectAllCachedUserInfo()).thenReturn(List.of(info));
when(manageDatabase.getKwPropertyValue(eq("klaw.mail.passwordreset.content"), eq(101)))
.thenReturn(KwConstants.MAIL_PASSWORDRESET_CONTENT);
mailService.sendMailResetPwd(username, "KlawPassword", handleDbRequests, 101, LOGIN_URL);
mailService.sendMailResetPwd(username, "KlawPassword", handleDbRequestsJdbc, 101, LOGIN_URL);
Mockito.verify(emailService, timeout(1000).times(0))
.sendSimpleMessage(
eq(info.getMailid()), eq(null), anyString(), anyString(), eq(101), eq(LOGIN_URL));
}

@Test
@WithMockUser(
username = "james",
authorities = {"USER"})
public void sendMailWith_NoBCC() {
String username = "James";
when(manageDatabase.selectAllCachedUserInfo())
.thenReturn(List.of(createUserInfo(username, "USER"), createUserInfo("Tom", "ADMIN")));
when(manageDatabase.getKwPropertyValue(eq("klaw.mail.aclrequestapproval.content"), eq(101)))
.thenReturn(KwConstants.MAIL_ACLREQUESTAPPROVAL_CONTENT);

mailService.sendMail(
"TopicOne",
"AclOne",
null,
username,
handleDbRequestsJdbc,
MailType.ACL_REQUEST_APPROVED,
LOGIN_URL);

Mockito.verify(emailService, timeout(1000).times(1))
.sendSimpleMessage(
anyString(), eq(null), eq(null), anyString(), anyString(), eq(101), eq(LOGIN_URL));
}

@Test
@WithMockUser(
username = "james",
authorities = {"USER"})
public void sendMailWith_BCC() {

String username = "James";
when(manageDatabase.selectAllCachedUserInfo())
.thenReturn(List.of(createUserInfo(username, "USER"), createUserInfo("Tom", "ADMIN")));
when(manageDatabase.getKwPropertyValue(eq("klaw.mail.topicrequest.content"), eq(101)))
.thenReturn(KwConstants.MAIL_TOPICREQUEST_CONTENT);

mailService.sendMail(
"TopicOne",
"AclOne",
null,
username,
handleDbRequestsJdbc,
MailType.TOPIC_CREATE_REQUESTED,
LOGIN_URL);

Mockito.verify(emailService, timeout(1000).times(1))
.sendSimpleMessage(
anyString(),
eq(null),
eq(List.of("Tom.klaw@mailid")),
anyString(),
anyString(),
eq(101),
eq(LOGIN_URL));
}

private Map<String, List<String>> getRolesToPermissionsMap() {

List<String> user = List.of(PermissionType.APPROVE_TOPICS.name());

List<String> admin =
List.of(
PermissionType.APPROVE_TOPICS.name(), PermissionType.APPROVE_ALL_REQUESTS_TEAMS.name());

return new HashMap<>() {
{
put("USER", user);
put("ADMIN", admin);
}
};
}

private static UserInfo createUserInfo(String username, String role) {
UserInfo info = new UserInfo();
info.setUsername(username);
info.setMailid(username + ".klaw@mailid");
info.setTenantId(101);
info.setTeamId(10);
info.setRole(role);
return info;
}
}