001/* 002 * Copyright 2018 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.workspaces.members; 017 018import java.io.IOException; 019import java.io.UnsupportedEncodingException; 020import java.net.URLEncoder; 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.Date; 024import java.util.HashMap; 025import java.util.List; 026import java.util.Map; 027import java.util.Set; 028 029import javax.jcr.RepositoryException; 030 031import org.apache.avalon.framework.component.Component; 032import org.apache.avalon.framework.configuration.Configurable; 033import org.apache.avalon.framework.configuration.Configuration; 034import org.apache.avalon.framework.configuration.ConfigurationException; 035import org.apache.avalon.framework.context.Context; 036import org.apache.avalon.framework.context.ContextException; 037import org.apache.avalon.framework.context.Contextualizable; 038import org.apache.avalon.framework.service.ServiceException; 039import org.apache.avalon.framework.service.ServiceManager; 040import org.apache.avalon.framework.service.Serviceable; 041import org.apache.cocoon.components.ContextHelper; 042import org.apache.cocoon.environment.Request; 043import org.apache.commons.lang3.StringUtils; 044 045import org.ametys.cms.languages.Language; 046import org.ametys.cms.languages.LanguagesManager; 047import org.ametys.cms.transformation.xslt.ResolveURIComponent; 048import org.ametys.core.ui.Callable; 049import org.ametys.core.user.CurrentUserProvider; 050import org.ametys.core.user.User; 051import org.ametys.core.user.UserIdentity; 052import org.ametys.core.user.UserManager; 053import org.ametys.core.user.directory.NotUniqueUserException; 054import org.ametys.core.user.directory.UserDirectory; 055import org.ametys.core.user.population.PopulationContextHelper; 056import org.ametys.core.util.I18nUtils; 057import org.ametys.core.util.mail.SendMailHelper; 058import org.ametys.plugins.core.user.UserHelper; 059import org.ametys.plugins.repository.AmetysObjectIterable; 060import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector; 061import org.ametys.plugins.workspaces.members.MembersWorkspaceModule.Invitation; 062import org.ametys.plugins.workspaces.project.ProjectManager; 063import org.ametys.plugins.workspaces.project.modules.WorkspaceModuleExtensionPoint; 064import org.ametys.plugins.workspaces.project.objects.Project; 065import org.ametys.plugins.workspaces.project.rights.ProjectRightHelper; 066import org.ametys.runtime.authentication.AccessDeniedException; 067import org.ametys.runtime.i18n.I18nizableText; 068import org.ametys.runtime.i18n.I18nizableTextParameter; 069import org.ametys.runtime.plugin.component.AbstractLogEnabled; 070import org.ametys.runtime.plugin.component.PluginAware; 071import org.ametys.web.WebConstants; 072import org.ametys.web.WebHelper; 073import org.ametys.web.repository.page.Page; 074import org.ametys.web.repository.page.Zone; 075import org.ametys.web.repository.page.ZoneItem; 076import org.ametys.web.repository.site.Site; 077import org.ametys.web.repository.site.SiteManager; 078import org.ametys.web.usermanagement.UserManagementException; 079import org.ametys.web.usermanagement.UserManagementException.StatusError; 080import org.ametys.web.usermanagement.UserSignUpConfiguration; 081import org.ametys.web.usermanagement.UserSignupManager; 082 083import jakarta.mail.MessagingException; 084 085/** 086 * Helper for invitations by email 087 * 088 */ 089public class ProjectInvitationHelper extends AbstractLogEnabled implements Serviceable, Component, Configurable, PluginAware, Contextualizable 090{ 091 /** The role */ 092 public static final String ROLE = ProjectInvitationHelper.class.getName(); 093 094 private static final String __MAIL_PROJECT_EMAIL_PATTERN = "${email}"; 095 private static final String __MAIL_PROJECT_TOKEN_PATTERN = "${token}"; 096 097 private ProjectManager _projectManager; 098 private UserSignUpConfiguration _signupConfig; 099 private UserSignupManager _signupManager; 100 private SiteManager _siteManager; 101 private WorkspaceModuleExtensionPoint _moduleEP; 102 private CurrentUserProvider _currentUserProvider; 103 private UserManager _userManager; 104 private UserHelper _userHelper; 105 private ProjectRightHelper _projectRightsHelper; 106 private ProjectMemberManager _projectMemberManager; 107 private PopulationContextHelper _populationContextHelper; 108 private LanguagesManager _languagesManager; 109 110 private String _subjectKeyForInvitation; 111 private String _textBodyKeyForInvitation; 112 private String _htmlBodyKeyForInvitation; 113 private String _subjectKeyForInvitationAccepted; 114 private String _textBodyKeyForInvitationAccepted; 115 private String _htmlBodyKeyForInvitationAccepted; 116 117 private I18nUtils _i18nUtils; 118 119 private String _pluginName; 120 121 private Context _context; 122 123 124 public void setPluginInfo(String pluginName, String featureName, String id) 125 { 126 _pluginName = pluginName; 127 } 128 129 public void contextualize(Context context) throws ContextException 130 { 131 _context = context; 132 } 133 134 @Override 135 public void service(ServiceManager serviceManager) throws ServiceException 136 { 137 _projectManager = (ProjectManager) serviceManager.lookup(ProjectManager.ROLE); 138 _projectRightsHelper = (ProjectRightHelper) serviceManager.lookup(ProjectRightHelper.ROLE); 139 _projectMemberManager = (ProjectMemberManager) serviceManager.lookup(ProjectMemberManager.ROLE); 140 _signupConfig = (UserSignUpConfiguration) serviceManager.lookup(UserSignUpConfiguration.ROLE); 141 _signupManager = (UserSignupManager) serviceManager.lookup(UserSignupManager.ROLE); 142 _siteManager = (SiteManager) serviceManager.lookup(SiteManager.ROLE); 143 _moduleEP = (WorkspaceModuleExtensionPoint) serviceManager.lookup(WorkspaceModuleExtensionPoint.ROLE); 144 _currentUserProvider = (CurrentUserProvider) serviceManager.lookup(CurrentUserProvider.ROLE); 145 _userManager = (UserManager) serviceManager.lookup(UserManager.ROLE); 146 _userHelper = (UserHelper) serviceManager.lookup(UserHelper.ROLE); 147 _i18nUtils = (I18nUtils) serviceManager.lookup(I18nUtils.ROLE); 148 _populationContextHelper = (PopulationContextHelper) serviceManager.lookup(PopulationContextHelper.ROLE); 149 _languagesManager = (LanguagesManager) serviceManager.lookup(LanguagesManager.ROLE); 150 } 151 152 @Override 153 public void configure(Configuration configuration) throws ConfigurationException 154 { 155 _subjectKeyForInvitation = configuration.getChild("invitation-email-subject").getValue(null); 156 _textBodyKeyForInvitation = configuration.getChild("invitation-email-text-body").getValue(null); 157 _htmlBodyKeyForInvitation = configuration.getChild("invitation-email-html-body").getValue(null); 158 159 _subjectKeyForInvitationAccepted = configuration.getChild("invitation-accepted-email-subject").getValue(null); 160 _textBodyKeyForInvitationAccepted = configuration.getChild("invitation-accepted-email-text-body").getValue(null); 161 _htmlBodyKeyForInvitationAccepted = configuration.getChild("invitation-accepted-email-html-body").getValue(null); 162 } 163 164 /** 165 * Invite emails to be member of a project 166 * @param projectName The project name 167 * @param emails The emails 168 * @param allowedProfileByModule the allowed profiles by module 169 * @return The result 170 * @throws UserManagementException if failed to invit user 171 * @throws NotUniqueUserException if many users match the given email 172 */ 173 public Map<String, Object> inviteEmails(String projectName, List<String> emails, Map<String, String> allowedProfileByModule) throws UserManagementException, NotUniqueUserException 174 { 175 Request request = ContextHelper.getRequest(_context); 176 String siteName = WebHelper.getSiteName(request); 177 String sitemapLanguage = (String) request.getAttribute(WebConstants.REQUEST_ATTR_SITEMAP_NAME); 178 179 Project project = _projectManager.getProject(projectName); 180 Map<String, String> emailConfiguration = _getInvitationEmailConfiguration(project, sitemapLanguage); 181 String mailSubject = emailConfiguration.get("subject"); 182 String mailBody = emailConfiguration.get("bodyText"); 183 184 return inviteEmails(projectName, siteName, sitemapLanguage, emails, allowedProfileByModule, mailSubject, mailBody); 185 } 186 /** 187 * Invite emails to be member of a project 188 * @param projectName The project name 189 * @param siteName The site name 190 * @param lang the current language 191 * @param emails The emails 192 * @param allowedProfileByModule the allowed profiles by module 193 * @param mailSubject The subject of mail 194 * @param mailBody The body of mail 195 * @return The result 196 * @throws UserManagementException if failed to invit user 197 * @throws NotUniqueUserException if many users match the given email 198 */ 199 @Callable 200 public Map<String, Object> inviteEmails(String projectName, String siteName, String lang, List<String> emails, Map<String, String> allowedProfileByModule, String mailSubject, String mailBody) throws UserManagementException, NotUniqueUserException 201 { 202 Map<String, Object> result = new HashMap<>(); 203 204 result.put("existing-users", new ArrayList<Map<String, Object>>()); 205 result.put("email-success", new ArrayList<String>()); 206 result.put("email-error", new ArrayList<String>()); 207 208 Project project = _projectManager.getProject(projectName); 209 if (project != null) 210 { 211 MembersWorkspaceModule module = _moduleEP.getModule(MembersWorkspaceModule.MEMBERS_MODULE_ID); 212 if (module != null && _projectManager.isModuleActivated(project, module.getId())) 213 { 214 if (!_projectRightsHelper.canAddMember(project)) 215 { 216 throw new AccessDeniedException("User '" + _currentUserProvider.getUser() + "' tried to send invitations without sufficient right."); 217 } 218 219 String catalogSiteName = _projectManager.getCatalogSiteName(); 220 221 UserDirectory userDirectory = _getUserDirectoryForSignup(result, catalogSiteName, lang); 222 if (userDirectory != null) 223 { 224 String populationId = userDirectory.getPopulationId(); 225 String userDirectoryId = userDirectory.getId(); 226 227 for (String email : emails) 228 { 229 try 230 { 231 _signupManager.inviteToSignup(catalogSiteName, lang, email, populationId, userDirectoryId, null, null, false, false, false); 232 233 if (_addOrUpdateInvitation(project, catalogSiteName, module, email, allowedProfileByModule, populationId, userDirectoryId, mailSubject, mailBody)) 234 { 235 @SuppressWarnings("unchecked") 236 List<String> emailSuccess = (List<String>) result.get("email-success"); 237 emailSuccess.add(email); 238 239 } 240 } 241 catch (UserManagementException e) 242 { 243 switch (e.getStatusError()) 244 { 245 case USER_ALREADY_EXISTS: 246 User user = _getUser(catalogSiteName, email); 247 248 Map<String, Object> user2json = _userHelper.user2json(user, true); 249 250 @SuppressWarnings("unchecked") 251 List<Map<String, Object>> existingUsers = (List<Map<String, Object>>) result.get("existing-users"); 252 existingUsers.add(user2json); 253 break; 254 255 case TEMP_USER_ALREADY_EXISTS: 256 // if mail has already been invited, re-created the invitation 257 if (_addOrUpdateInvitation(project, catalogSiteName, module, email, allowedProfileByModule, populationId, userDirectoryId, mailSubject, mailBody)) 258 { 259 @SuppressWarnings("unchecked") 260 List<String> emailSuccess = (List<String>) result.get("email-success"); 261 emailSuccess.add(email); 262 263 } 264 break; 265 266 default: 267 getLogger().error("Cannot invite " + email, e); 268 @SuppressWarnings("unchecked") 269 List<String> emailErrors = (List<String>) result.get("email-error"); 270 emailErrors.add(email); 271 break; 272 } 273 } 274 } 275 276 @SuppressWarnings("unchecked") 277 List<String> emailSuccess = (List<String>) result.get("email-success"); 278 if (emailSuccess.size() == emails.size()) 279 { 280 result.put("success", true); 281 } 282 } 283 } 284 } 285 else 286 { 287 result.put("success", false); 288 result.put("unknown-project", projectName); 289 } 290 291 return result; 292 } 293 294 private User _getUser(String siteName, String email) throws NotUniqueUserException 295 { 296 Set<String> populations = _populationContextHelper.getUserPopulationsOnContexts(Arrays.asList("/sites/" + siteName, "/sites-fo/" + siteName), false); 297 for (String population : populations) 298 { 299 User user = _userManager.getUser(population, email); 300 if (user == null) 301 { 302 user = _userManager.getUserByEmail(population, email); 303 } 304 305 if (user != null) 306 { 307 return user; 308 } 309 } 310 311 return null; 312 } 313 314 /** 315 * Get the configuration to invite users by emails 316 * @param projectName The current project 317 * @param lang the current language 318 * @return the configuration for email invitations 319 */ 320 @Callable 321 public Map<String, Object> getInvitationConfiguration(String projectName, String lang) 322 { 323 Project project = _projectManager.getProject(projectName); 324 325 Map<String, Object> config = new HashMap<>(); 326 327 // Check the configuration is valid for invitations 328 String catalogSiteName = _projectManager.getCatalogSiteName(); 329 if (_getUserDirectoryForSignup(config, catalogSiteName, lang) == null) 330 { 331 config.remove("success"); 332 config.put("allowed", false); 333 return config; 334 } 335 336 // Check the current user has right to invite users 337 if (!_projectRightsHelper.canAddMember(project)) 338 { 339 config.put("allowed", false); 340 config.put("error", "no-right"); 341 return config; 342 } 343 344 config.put("allowed", true); 345 config.put("email", _getInvitationEmailConfiguration(project, lang)); 346 config.put("rights", _projectRightsHelper.getProjectRightsData(projectName)); 347 348 return config; 349 } 350 351 private Map<String, String> _getInvitationEmailConfiguration(Project project, String lang) 352 { 353 Map<String, String> emailConfig = new HashMap<>(); 354 355 Map<String, I18nizableTextParameter> i18nparams = new HashMap<>(); 356 i18nparams.put("projectTitle", new I18nizableText(project.getTitle())); 357 i18nparams.put("projectUrl", new I18nizableText(_projectManager.getProjectUrl(project, StringUtils.EMPTY))); 358 i18nparams.put("nbDays", new I18nizableText(String.valueOf(_signupConfig.getTokenValidity()))); 359 i18nparams.put("nbDays", new I18nizableText(String.valueOf(_signupConfig.getTokenValidity()))); 360 361 String catalogSiteName = _projectManager.getCatalogSiteName(); 362 Site catalogSite = _siteManager.getSite(catalogSiteName); 363 i18nparams.put("catalogSiteTitle", new I18nizableText(catalogSite.getTitle())); 364 i18nparams.put("catalogSiteUrl", new I18nizableText(catalogSite.getUrl())); 365 366 Page signupPage = _getSignupPage(_projectManager.getCatalogSiteName(), lang); 367 if (signupPage != null) 368 { 369 String signupUri = ResolveURIComponent.resolve("page", signupPage.getId(), false, true) + "?email=${email}&token=${token}"; 370 i18nparams.put("signupUri", new I18nizableText(signupUri)); 371 } 372 373 String subject = getSubjectForInvitationEmail(i18nparams, lang); 374 if (subject != null) 375 { 376 emailConfig.put("subject", subject); 377 } 378 String bodyTxt = getTextBodyForInvitationEmail(i18nparams, lang); 379 if (bodyTxt != null) 380 { 381 emailConfig.put("bodyText", bodyTxt); 382 } 383 String bodyHtml = getHtmlBodyForInvitationEmail(i18nparams, lang); 384 if (bodyHtml != null) 385 { 386 emailConfig.put("bodyHtml", bodyHtml); 387 } 388 389 return emailConfig; 390 } 391 392 private Page _getSignupPage(String catalogSiteName, String lang) 393 { 394 Page signupPage = _signupManager.getSignupPage(catalogSiteName, lang); 395 396 if (signupPage == null) 397 { 398 signupPage = _signupManager.getSignupPage(catalogSiteName, "en"); 399 } 400 401 if (signupPage == null) 402 { 403 Map<String, Language> availableLanguages = _languagesManager.getAvailableLanguages(); 404 for (Language availableLanguage : availableLanguages.values()) 405 { 406 if (signupPage == null) 407 { 408 signupPage = _signupManager.getSignupPage(catalogSiteName, availableLanguage.getCode()); 409 } 410 } 411 } 412 return signupPage; 413 } 414 415 private void _sendInvitationMail (String catalogSiteName, String email, String populationId, String userDirectoryId, String mailSubject, String mailBodyTpl) throws UserManagementException 416 { 417 String bodyTxt = mailBodyTpl; 418 419 String encodedEmail; 420 try 421 { 422 encodedEmail = URLEncoder.encode(email, "UTF-8"); 423 } 424 catch (UnsupportedEncodingException e) 425 { 426 // Should never happen. 427 throw new UserManagementException("Encoding error while sending a sign-up confirmation e-mail.", StatusError.MAIL_ERROR, e); 428 } 429 430 String token = _signupManager.getToken(catalogSiteName, email, populationId, userDirectoryId); 431 432 bodyTxt = StringUtils.replace(bodyTxt, __MAIL_PROJECT_TOKEN_PATTERN, token); 433 bodyTxt = StringUtils.replace(bodyTxt, __MAIL_PROJECT_EMAIL_PATTERN, encodedEmail); 434 435 getLogger().debug("Sending signup invitation e-mail to {}", email); 436 437 Site site = _siteManager.getSite(catalogSiteName); 438 String from = site.getValue("site-mail-from"); 439 440 try 441 { 442 List<String> errorReport = new ArrayList<>(); 443 444 // Send the e-mail. 445 SendMailHelper.newMail() 446 .withSubject(mailSubject) 447 .withTextBody(bodyTxt) 448 .withSender(from) 449 .withRecipient(email) 450 .withErrorReport(errorReport) 451 .sendMail(); 452 453 if (errorReport.contains(email)) 454 { 455 throw new UserManagementException("Error sending the sign-up confirmation mail.", StatusError.MAIL_ERROR); 456 } 457 } 458 catch (MessagingException | IOException e) 459 { 460 throw new UserManagementException("Error sending the sign-up confirmation mail.", StatusError.MAIL_ERROR, e); 461 } 462 } 463 464 private boolean _addOrUpdateInvitation(Project project, String catalogSiteName, MembersWorkspaceModule module, String email, Map<String, String> allowedProfileByModules, String populationId, String userDirectoryId, String mailSubject, String mailBody) throws UserManagementException 465 { 466 try 467 { 468 // First remove invitation if exists 469 module.removeInvitation(project, email); 470 471 // Add invitations with temporary rights 472 module.addInvitation(project, new Date(), email, _currentUserProvider.getUser(), allowedProfileByModules); 473 474 project.saveChanges(); 475 476 _sendInvitationMail(catalogSiteName, email, populationId, userDirectoryId, mailSubject, mailBody); 477 478 return true; 479 } 480 catch (RepositoryException e) 481 { 482 getLogger().error("Fail to store invitation for email " + email, e); 483 return false; 484 } 485 } 486 487 private UserDirectory _getUserDirectoryForSignup(Map<String, Object> result, String catalogSiteName, String lang) 488 { 489 if (catalogSiteName == null) 490 { 491 getLogger().error("The catalog's site name is not configured. User invitations can not be activated."); 492 result.put("success", false); 493 result.put("error", "invalid-configuration"); 494 return null; 495 } 496 497 if (!_signupManager.isSignupAllowed(catalogSiteName)) 498 { 499 getLogger().warn("Signup is disabled for the catalog's site."); 500 result.put("success", false); 501 return null; 502 } 503 504 Page signupPage = _getSignupPage(catalogSiteName, lang); 505 if (signupPage == null) 506 { 507 getLogger().error("The catalog's site does not contain the signup service for language " + lang + ". User invitations can not be activated."); 508 result.put("success", false); 509 result.put("error", "invalid-configuration"); 510 return null; 511 } 512 513 UserDirectory userDirectory = _getUserDirectoryForSignup(signupPage); 514 if (userDirectory == null) 515 { 516 getLogger().error("There is no user directory configured for users signup. Please check the sign up service of catalog's site."); 517 result.put("success", false); 518 result.put("error", "invalid-configuration"); 519 return null; 520 } 521 522 return userDirectory; 523 524 } 525 526 private UserDirectory _getUserDirectoryForSignup(Page signupPage) 527 { 528 for (Zone zone : signupPage.getZones()) 529 { 530 try (AmetysObjectIterable<? extends ZoneItem> zoneItems = zone.getZoneItems()) 531 { 532 for (ZoneItem zoneItem : zoneItems) 533 { 534 UserDirectory userDirectory = _signupManager.getUserDirectory(zoneItem); 535 if (userDirectory != null) 536 { 537 return userDirectory; 538 } 539 } 540 } 541 } 542 543 return null; 544 545 } 546 547 /** 548 * Add user as member of all project where it has been invited 549 * @param user the new user 550 */ 551 public void createMemberFromInvitations(User user) 552 { 553 Request request = ContextHelper.getRequest(_context); 554 String currentWorkspace = RequestAttributeWorkspaceSelector.getForcedWorkspace(request); 555 556 try 557 { 558 // Force default workspace 559 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, "default"); 560 561 MembersWorkspaceModule memberModule = (MembersWorkspaceModule) _moduleEP.getExtension(MembersWorkspaceModule.MEMBERS_MODULE_ID); 562 563 List<Invitation> invitations = memberModule.getInvitations(user.getEmail()); 564 565 for (Invitation invitation : invitations) 566 { 567 Map<String, String> allowedProfileByModules = invitation.getAllowedProfileByModules(); 568 String projectName = invitation.getProjectName(); 569 570 Project project = _projectManager.getProject(projectName); 571 572 _projectMemberManager.addOrUpdateProjectMember(project, user.getIdentity(), allowedProfileByModules, invitation.getAuthor()); 573 574 // Notify author that invitation was accepted 575 UserIdentity author = invitation.getAuthor(); 576 sendInvitationAcceptedMail(project, _userManager.getUser(author), user); 577 578 try 579 { 580 // Remove invitation 581 memberModule.removeInvitation(project, invitation.getEmail()); 582 } 583 catch (RepositoryException e) 584 { 585 getLogger().error("Failed to remove invitation " + invitation, e); 586 } 587 } 588 } 589 finally 590 { 591 // Restore current workspace 592 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWorkspace); 593 } 594 595 } 596 597 /** 598 * Send email to the user who initiated the invitation 599 * @param project The project 600 * @param invitAuthor The author of invitation 601 * @param newMember The new member 602 */ 603 protected void sendInvitationAcceptedMail(Project project, User invitAuthor, User newMember) 604 { 605 if (invitAuthor != null) 606 { 607 Site site = project.getSite(); 608 String from = site.getValue("site-mail-from"); 609 String email = invitAuthor.getEmail(); 610 611 if (StringUtils.isNotEmpty(email)) 612 { 613 // Prepare mail. 614 Map<String, I18nizableTextParameter> i18nParams = new HashMap<>(); 615 i18nParams.put("projectTitle", new I18nizableText(project.getTitle())); 616 i18nParams.put("projectUrl", new I18nizableText(_projectManager.getProjectUrl(project, StringUtils.EMPTY))); 617 i18nParams.put("newMember", new I18nizableText(newMember.getFullName())); 618 i18nParams.put("newMemberMail", new I18nizableText(newMember.getEmail())); 619 620 Set<Page> memberPages = _projectManager.getModulePages(project, MembersWorkspaceModule.MEMBERS_MODULE_ID); 621 if (!memberPages.isEmpty()) 622 { 623 Page page = memberPages.iterator().next(); 624 i18nParams.put("membersPageUri", new I18nizableText(ResolveURIComponent.resolve("page", page.getId(), false, true))); 625 } 626 627 String subject = getSubjectForInvitationAcceptedEmail(i18nParams, null); 628 String textBody = getTextBodyForInvitationAcceptedEmail(i18nParams, null); 629 String htmlBody = getHtmlBodyForInvitationAcceptedEmail(i18nParams, null); 630 631 try 632 { 633 // Send the e-mail. 634 SendMailHelper.newMail() 635 .withSubject(subject) 636 .withHTMLBody(htmlBody) 637 .withTextBody(textBody) 638 .withSender(from) 639 .withRecipient(email) 640 .sendMail(); 641 } 642 catch (MessagingException | IOException e) 643 { 644 getLogger().error("Error sending the invitation accepted email.", e); 645 } 646 } 647 } 648 } 649 650 /** 651 * The email subject for invitation by email 652 * @param defaultI18nParams The default i18n parameters 653 * @param language the language 654 * @return the email subject for invitation by email 655 */ 656 public String getSubjectForInvitationEmail (Map<String, I18nizableTextParameter> defaultI18nParams , String language) 657 { 658 if (StringUtils.isNotBlank(_subjectKeyForInvitation)) 659 { 660 return _i18nUtils.translate(_getI18nizableText(_subjectKeyForInvitation, defaultI18nParams), language); 661 } 662 663 return null; 664 } 665 666 /** 667 * The email text body for invitation by email 668 * @param defaultI18nParams The default i18n parameters with : 669 * siteName the site name 670 * email the mail 671 * token the token 672 * confirmUri the confirmation uri 673 * siteTitle the site title 674 * siteUrl the site url 675 * @param language the language 676 * @return the email text for invitation by email 677 */ 678 public String getTextBodyForInvitationEmail(Map<String, I18nizableTextParameter> defaultI18nParams, String language) 679 { 680 if (StringUtils.isNotBlank(_textBodyKeyForInvitation)) 681 { 682 return _i18nUtils.translate(_getI18nizableText(_textBodyKeyForInvitation, defaultI18nParams), language); 683 } 684 685 return null; 686 } 687 688 /** 689 * The email html body for invitation by email 690 * @param defaultI18nParams The default i18n parameters with : 691 * siteName the site name 692 * email the mail 693 * token the token 694 * confirmUri the confirmation uri 695 * siteTitle the site title 696 * siteUrl the site url 697 * @param language the language 698 * @return the email html for invitation by email 699 */ 700 public String getHtmlBodyForInvitationEmail(Map<String, I18nizableTextParameter> defaultI18nParams, String language) 701 { 702 if (StringUtils.isNotBlank(_htmlBodyKeyForInvitation)) 703 { 704 return _i18nUtils.translate(_getI18nizableText(_htmlBodyKeyForInvitation, defaultI18nParams), language); 705 } 706 707 return null; 708 } 709 710 /** 711 * The email subject for invitation by email 712 * @param defaultI18nParams The default i18n parameters 713 * @param language the language 714 * @return the email subject for invitation by email 715 */ 716 public String getSubjectForInvitationAcceptedEmail (Map<String, I18nizableTextParameter> defaultI18nParams , String language) 717 { 718 if (StringUtils.isNotBlank(_subjectKeyForInvitationAccepted)) 719 { 720 return _i18nUtils.translate(_getI18nizableText(_subjectKeyForInvitationAccepted, defaultI18nParams), language); 721 } 722 723 return null; 724 } 725 726 /** 727 * The email text body for invitation by email 728 * @param defaultI18nParams The default i18n parameters with : 729 * @param language the language 730 * @return the email text for invitation by email 731 */ 732 public String getTextBodyForInvitationAcceptedEmail(Map<String, I18nizableTextParameter> defaultI18nParams, String language) 733 { 734 if (StringUtils.isNotBlank(_textBodyKeyForInvitationAccepted)) 735 { 736 return _i18nUtils.translate(_getI18nizableText(_textBodyKeyForInvitationAccepted, defaultI18nParams), language); 737 } 738 739 return null; 740 } 741 742 /** 743 * The email html body for invitation by email 744 * @param defaultI18nParams The default i18n parameters with : 745 * @param language the language 746 * @return the email html for invitation by email 747 */ 748 public String getHtmlBodyForInvitationAcceptedEmail(Map<String, I18nizableTextParameter> defaultI18nParams, String language) 749 { 750 if (StringUtils.isNotBlank(_htmlBodyKeyForInvitationAccepted)) 751 { 752 return _i18nUtils.translate(_getI18nizableText(_htmlBodyKeyForInvitationAccepted, defaultI18nParams), language); 753 } 754 755 return null; 756 } 757 758 /** 759 * Get the {@link I18nizableText} from the configured key and i18n parameters 760 * @param fullI18nKey the configured i18n key 761 * @param i18nParams the i18n parameters 762 * @return the i18nizable text 763 */ 764 protected I18nizableText _getI18nizableText(String fullI18nKey, Map<String, I18nizableTextParameter> i18nParams) 765 { 766 String catalogue = StringUtils.contains(fullI18nKey, ":") ? StringUtils.substringBefore(fullI18nKey, ":") : "plugin." + _pluginName; 767 String i18nKey = StringUtils.contains(fullI18nKey, ":") ? StringUtils.substringAfter(fullI18nKey, ":") : fullI18nKey; 768 769 return new I18nizableText(catalogue, i18nKey, i18nParams); 770 } 771 772}