Minor improvements to invitation email templates (#29498)
Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
parent
51522248a3
commit
b5a854b68e
8 changed files with 33 additions and 15 deletions
|
@ -18,6 +18,7 @@
|
|||
package org.keycloak.email;
|
||||
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.models.OrganizationModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.provider.Provider;
|
||||
|
@ -77,7 +78,7 @@ public interface EmailTemplateProvider extends Provider {
|
|||
|
||||
void sendVerifyEmail(String link, long expirationInMinutes) throws EmailException;
|
||||
|
||||
void sendOrgInviteEmail(String link, long expirationInMinutes) throws EmailException;
|
||||
void sendOrgInviteEmail(OrganizationModel organization, String link, long expirationInMinutes) throws EmailException;
|
||||
|
||||
void sendEmailUpdateConfirmation(String link, long expirationInMinutes, String address) throws EmailException;
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.keycloak.events.EventType;
|
|||
import org.keycloak.forms.login.freemarker.model.UrlBean;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakUriInfo;
|
||||
import org.keycloak.models.OrganizationModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||
|
@ -163,10 +164,11 @@ public class FreeMarkerEmailTemplateProvider implements EmailTemplateProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void sendOrgInviteEmail(String link, long expirationInMinutes) throws EmailException {
|
||||
public void sendOrgInviteEmail(OrganizationModel organization, String link, long expirationInMinutes) throws EmailException {
|
||||
Map<String, Object> attributes = new HashMap<>(this.attributes);
|
||||
addLinkInfoIntoAttributes(link, expirationInMinutes, attributes);
|
||||
send("orgInviteSubject", "org-invite.ftl", attributes);
|
||||
attributes.put("organization", organization);
|
||||
send("orgInviteSubject", List.of(organization.getName()), "org-invite.ftl", attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -110,7 +110,7 @@ public class OrganizationInvitationResource {
|
|||
session.getProvider(EmailTemplateProvider.class)
|
||||
.setRealm(realm)
|
||||
.setUser(user)
|
||||
.sendOrgInviteEmail(link, TimeUnit.SECONDS.toMinutes(tokenExpiration));
|
||||
.sendOrgInviteEmail(organization, link, TimeUnit.SECONDS.toMinutes(tokenExpiration));
|
||||
} catch (EmailException e) {
|
||||
ServicesLogger.LOGGER.failedToSendEmail(e);
|
||||
throw ErrorResponse.error("Failed to send invite email", Status.INTERNAL_SERVER_ERROR);
|
||||
|
|
|
@ -118,6 +118,7 @@ public class OrganizationMemberResource {
|
|||
}
|
||||
|
||||
@Path("invite-user")
|
||||
@POST
|
||||
public Response inviteUser(String email) {
|
||||
return new OrganizationInvitationResource(session, organization, adminEvent).inviteUser(email);
|
||||
}
|
||||
|
|
|
@ -19,12 +19,14 @@ package org.keycloak.testsuite.organization.admin;
|
|||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.jboss.arquillian.graphene.page.Page;
|
||||
|
@ -33,8 +35,6 @@ import org.junit.Test;
|
|||
import org.keycloak.admin.client.resource.OrganizationResource;
|
||||
import org.keycloak.common.Profile.Feature;
|
||||
import org.keycloak.common.util.UriUtils;
|
||||
import org.keycloak.cookie.CookieProvider;
|
||||
import org.keycloak.cookie.CookieScope;
|
||||
import org.keycloak.cookie.CookieType;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
|
@ -46,6 +46,7 @@ import org.keycloak.testsuite.pages.InfoPage;
|
|||
import org.keycloak.testsuite.pages.RegisterPage;
|
||||
import org.keycloak.testsuite.util.GreenMailRule;
|
||||
import org.keycloak.testsuite.util.MailUtils;
|
||||
import org.keycloak.testsuite.util.MailUtils.EmailBody;
|
||||
import org.keycloak.testsuite.util.UserBuilder;
|
||||
|
||||
@EnableFeature(Feature.ORGANIZATION)
|
||||
|
@ -71,7 +72,7 @@ public class OrganizationInvitationLinkTest extends AbstractOrganizationTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testInviteExistingUser() throws IOException {
|
||||
public void testInviteExistingUser() throws IOException, MessagingException {
|
||||
UserRepresentation user = UserBuilder.create()
|
||||
.username("invited")
|
||||
.email("invited@myemail.com")
|
||||
|
@ -88,7 +89,9 @@ public class OrganizationInvitationLinkTest extends AbstractOrganizationTest {
|
|||
|
||||
MimeMessage message = greenMail.getLastReceivedMessage();
|
||||
Assert.assertNotNull(message);
|
||||
String link = MailUtils.getPasswordResetEmailLink(message);
|
||||
Assert.assertEquals("Invitation to join the " + organizationName + " organization", message.getSubject());
|
||||
EmailBody body = MailUtils.getBody(message);
|
||||
String link = MailUtils.getLink(body.getHtml());
|
||||
driver.navigate().to(link.trim());
|
||||
// not yet a member
|
||||
Assert.assertFalse(organization.members().getAll().stream().anyMatch(actual -> user.getId().equals(actual.getId())));
|
||||
|
@ -100,7 +103,7 @@ public class OrganizationInvitationLinkTest extends AbstractOrganizationTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testInviteNewUserRegistration() throws IOException {
|
||||
public void testInviteNewUserRegistration() throws IOException, MessagingException {
|
||||
UserRepresentation user = UserBuilder.create()
|
||||
.username("invitedUser")
|
||||
.email("inviteduser@email")
|
||||
|
@ -112,7 +115,14 @@ public class OrganizationInvitationLinkTest extends AbstractOrganizationTest {
|
|||
|
||||
MimeMessage message = greenMail.getLastReceivedMessage();
|
||||
Assert.assertNotNull(message);
|
||||
String link = MailUtils.getPasswordResetEmailLink(message);
|
||||
Assert.assertEquals("Invitation to join the " + organizationName + " organization", message.getSubject());
|
||||
EmailBody body = MailUtils.getBody(message);
|
||||
String link = MailUtils.getLink(body.getHtml());
|
||||
String text = body.getHtml();
|
||||
assertTrue(text.contains("<p>You were invited to join the " + organizationName + " organization. Click the link below to join. </p>"));
|
||||
assertTrue(text.contains("<a href=\"" + link + "\" rel=\"nofollow\">Link to join the organization</a></p>"));
|
||||
assertTrue(text.contains("Link to join the organization"));
|
||||
assertTrue(text.contains("<p>If you dont want to join the organization, just ignore this message.</p>"));
|
||||
String orgToken = UriUtils.parseQueryParameters(link, false).values().stream().map(strings -> strings.get(0)).findFirst().orElse(null);
|
||||
Assert.assertNotNull(orgToken);
|
||||
driver.navigate().to(link.trim());
|
||||
|
@ -144,7 +154,8 @@ public class OrganizationInvitationLinkTest extends AbstractOrganizationTest {
|
|||
|
||||
MimeMessage message = greenMail.getLastReceivedMessage();
|
||||
Assert.assertNotNull(message);
|
||||
String link = MailUtils.getPasswordResetEmailLink(message);
|
||||
EmailBody body = MailUtils.getBody(message);
|
||||
String link = MailUtils.getLink(body.getHtml());
|
||||
String orgToken = UriUtils.parseQueryParameters(link, false).values().stream().map(strings -> strings.get(0)).findFirst().orElse(null);
|
||||
Assert.assertNotNull(orgToken);
|
||||
driver.navigate().to(link.trim());
|
||||
|
@ -173,7 +184,8 @@ public class OrganizationInvitationLinkTest extends AbstractOrganizationTest {
|
|||
setTimeOffset((int) TimeUnit.DAYS.toSeconds(1));
|
||||
MimeMessage message = greenMail.getLastReceivedMessage();
|
||||
Assert.assertNotNull(message);
|
||||
String link = MailUtils.getPasswordResetEmailLink(message);
|
||||
EmailBody body = MailUtils.getBody(message);
|
||||
String link = MailUtils.getLink(body.getHtml());
|
||||
String orgToken = UriUtils.parseQueryParameters(link, false).values().stream().map(strings -> strings.get(0)).findFirst().orElse(null);
|
||||
Assert.assertNotNull(orgToken);
|
||||
driver.navigate().to(link.trim());
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<@layout.emailLayout>
|
||||
${kcSanitize(msg("orgInviteBodyHtml", link, linkExpiration, realmName, linkExpirationFormatter(linkExpiration)))?no_esc}
|
||||
${kcSanitize(msg("orgInviteBodyHtml", link, linkExpiration, realmName, organization.name, linkExpirationFormatter(linkExpiration)))?no_esc}
|
||||
</@layout.emailLayout>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
emailVerificationSubject=Verify email
|
||||
emailVerificationBody=Someone has created a {2} account with this email address. If this was you, click the link below to verify your email address\n\n{0}\n\nThis link will expire within {3}.\n\nIf you didn''t create this account, just ignore this message.
|
||||
emailVerificationBodyHtml=<p>Someone has created a {2} account with this email address. If this was you, click the link below to verify your email address</p><p><a href="{0}">Link to e-mail address verification</a></p><p>This link will expire within {3}.</p><p>If you didn''t create this account, just ignore this message.</p>
|
||||
orgInviteBodyHtml=<p>Someone has invited your account {2} account to join their keycloak organization! Click the link below to join. </p><p><a href="{0}">Link to join the organization</a></p><p>This link will expire within {3}.</p><p>If you don't want to join the organization, just ignore this message.</p>
|
||||
orgInviteSubject=Invitation to join the {0} organization
|
||||
orgInviteBody=You were invited to join the "{3}" organization. Click the link below to join.\n\n{0}\n\nThis link will expire within {4}.\n\nIf you don't want to join the organization, just ignore this message.
|
||||
orgInviteBodyHtml=<p>You were invited to join the {3} organization. Click the link below to join. </p><p><a href="{0}">Link to join the organization</a></p><p>This link will expire within {4}.</p><p>If you don't want to join the organization, just ignore this message.</p>
|
||||
emailUpdateConfirmationSubject=Verify new email
|
||||
emailUpdateConfirmationBody=To update your {2} account with email address {1}, click the link below\n\n{0}\n\nThis link will expire within {3}.\n\nIf you don''t want to proceed with this modification, just ignore this message.
|
||||
emailUpdateConfirmationBodyHtml=<p>To update your {2} account with email address {1}, click the link below</p><p><a href="{0}">{0}</a></p><p>This link will expire within {3}.</p><p>If you don''t want to proceed with this modification, just ignore this message.</p>
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
<#ftl output_format="plainText">
|
||||
${kcSanitize(msg("orgInviteBodyHtml", link, linkExpiration, realmName, linkExpirationFormatter(linkExpiration)))}
|
||||
${kcSanitize(msg("orgInviteBody", link, linkExpiration, realmName, organization.name, linkExpirationFormatter(linkExpiration)))}
|
||||
|
|
Loading…
Reference in a new issue