diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/EmailCommunicationService.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/EmailCommunicationService.java index d3775791b..20dfab94c 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/EmailCommunicationService.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/EmailCommunicationService.java @@ -2,4 +2,5 @@ public interface EmailCommunicationService { boolean sendPasswordResetEmail(String to, String token, String message); + boolean sendInvitationEmails(String[] to, String inviteLink, String message); } diff --git a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/EmailCommunicationServiceImpl.java b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/EmailCommunicationServiceImpl.java index e83ed917b..de09b45ac 100644 --- a/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/EmailCommunicationServiceImpl.java +++ b/server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/user/service/EmailCommunicationServiceImpl.java @@ -49,4 +49,32 @@ public boolean sendPasswordResetEmail(String to, String token, String message) { } + @Override + public boolean sendInvitationEmails(String[] to, String inviteLink, String message) { + try { + String subject = "You've been invited!"; + MimeMessage mimeMessage = javaMailSender.createMimeMessage(); + + MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true); + + mimeMessageHelper.setFrom(config.getNotificationsEmailSender()); + mimeMessageHelper.setTo(to); + mimeMessageHelper.setSubject(subject); + + // Construct the message with the invite link + String formattedMessage = String.format(message, inviteLink); + mimeMessageHelper.setText(formattedMessage, true); // Set HTML to true to allow links + + javaMailSender.send(mimeMessage); + + return true; + + } catch (Exception e) { + log.error("Failed to send mail to: {}, Exception: ", to, e); + return false; + } + + + } + } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java index 36815b323..3589aab52 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationController.java @@ -1,6 +1,7 @@ package org.lowcoder.api.authentication; -import lombok.RequiredArgsConstructor; +import java.util.List; + import org.lowcoder.api.authentication.dto.APIKeyRequest; import org.lowcoder.api.authentication.dto.AuthConfigRequest; import org.lowcoder.api.authentication.service.AuthenticationApiService; @@ -20,9 +21,9 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.server.ServerWebExchange; -import reactor.core.publisher.Mono; -import java.util.List; +import lombok.RequiredArgsConstructor; +import reactor.core.publisher.Mono; @RequiredArgsConstructor @RestController diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationEndpoints.java index 27baf9674..41a65d840 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/authentication/AuthenticationEndpoints.java @@ -1,7 +1,7 @@ package org.lowcoder.api.authentication; -import com.fasterxml.jackson.annotation.JsonView; -import io.swagger.v3.oas.annotations.Operation; +import java.util.List; + import org.lowcoder.api.authentication.dto.APIKeyRequest; import org.lowcoder.api.authentication.dto.AuthConfigRequest; import org.lowcoder.api.framework.view.ResponseView; @@ -13,11 +13,20 @@ import org.lowcoder.sdk.auth.AbstractAuthConfig; import org.lowcoder.sdk.config.JsonViews; import org.lowcoder.sdk.constants.AuthSourceConstants; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.server.ServerWebExchange; -import reactor.core.publisher.Mono; -import java.util.List; +import com.fasterxml.jackson.annotation.JsonView; + +import io.swagger.v3.oas.annotations.Operation; +import reactor.core.publisher.Mono; @RestController @RequestMapping(value = {NewUrl.CUSTOM_AUTH}) @@ -159,4 +168,5 @@ public Mono> linkAccountWithThirdParty( */ public record FormLoginRequest(String loginId, String password, boolean register, String source, String authId) { } -} +} + diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/InvitationController.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/InvitationController.java index b83c6efc7..eeda519e2 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/InvitationController.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/InvitationController.java @@ -7,6 +7,8 @@ import org.lowcoder.api.framework.view.ResponseView; import org.lowcoder.api.home.SessionUserService; import org.lowcoder.api.usermanagement.view.InvitationVO; +import org.lowcoder.domain.user.service.EmailCommunicationService; +import org.lowcoder.sdk.config.CommonConfig; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; @@ -24,6 +26,12 @@ public class InvitationController implements InvitationEndpoints @Autowired private SessionUserService sessionUserService; + @Autowired + private EmailCommunicationService emailCommunicationService; + + @Autowired + private CommonConfig config; + @Override public Mono> create(@RequestParam String orgId) { return invitationApiService.create(orgId) @@ -50,4 +58,13 @@ public Mono> inviteUser(@PathVariable String invitationId) { ); } + @Override + public Mono> sendInvitationEmails(InviteEmailRequest req) { + return invitationApiService.create(req.orgId()).map(invitation -> + emailCommunicationService.sendInvitationEmails(req.emails(), + config.getLowcoderPublicUrl() + "/invite/" + invitation.getInviteCode(), + "You have been invited to join our platform. Click here to accept the invitation: %s")) + .map(ResponseView::success); + } + } diff --git a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/InvitationEndpoints.java b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/InvitationEndpoints.java index a1c3ba8db..906cbbf7f 100644 --- a/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/InvitationEndpoints.java +++ b/server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/usermanagement/InvitationEndpoints.java @@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -46,5 +47,20 @@ public interface InvitationEndpoints ) @GetMapping("/{invitationId}/invite") public Mono> inviteUser(@PathVariable String invitationId); + + @Operation( + tags = TAG_INVITATION_MANAGEMENT, + operationId = "sendInvitationEmails", + summary = "Send invitation emails", + description = "Send invitation emails to the specified addresses" + ) + @PostMapping("/email/invite") + public Mono> sendInvitationEmails(@RequestBody InviteEmailRequest req); + /** + * @param emails email addresses to send the invitation to + * @param inviteLink the link to be included in the email + */ + public record InviteEmailRequest(String[] emails, String orgId) { + } }