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.UnsupportedEncodingException; 019import java.net.URLEncoder; 020import java.util.ArrayList; 021import java.util.Arrays; 022import java.util.Date; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026import java.util.Set; 027 028import javax.jcr.RepositoryException; 029import javax.mail.MessagingException; 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.transformation.xslt.ResolveURIComponent; 046import org.ametys.core.ui.Callable; 047import org.ametys.core.user.CurrentUserProvider; 048import org.ametys.core.user.User; 049import org.ametys.core.user.UserIdentity; 050import org.ametys.core.user.UserManager; 051import org.ametys.core.user.directory.NotUniqueUserException; 052import org.ametys.core.user.population.PopulationContextHelper; 053import org.ametys.core.util.I18nUtils; 054import org.ametys.core.util.mail.SendMailHelper; 055import org.ametys.plugins.core.user.UserHelper; 056import org.ametys.plugins.repository.AmetysObjectIterable; 057import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector; 058import org.ametys.plugins.workspaces.members.MembersWorkspaceModule.Invitation; 059import org.ametys.plugins.workspaces.project.ProjectManager; 060import org.ametys.plugins.workspaces.project.modules.WorkspaceModuleExtensionPoint; 061import org.ametys.plugins.workspaces.project.objects.Project; 062import org.ametys.plugins.workspaces.project.rights.ProjectRightHelper; 063import org.ametys.runtime.i18n.I18nizableText; 064import org.ametys.runtime.plugin.component.AbstractLogEnabled; 065import org.ametys.runtime.plugin.component.PluginAware; 066import org.ametys.web.repository.page.Page; 067import org.ametys.web.repository.page.Zone; 068import org.ametys.web.repository.page.ZoneItem; 069import org.ametys.web.repository.page.ZoneItem.ZoneType; 070import org.ametys.web.repository.site.Site; 071import org.ametys.web.repository.site.SiteManager; 072import org.ametys.web.usermanagement.UserManagementException; 073import org.ametys.web.usermanagement.UserSignUpConfiguration; 074import org.ametys.web.usermanagement.UserSignupManager; 075 076import com.google.common.collect.Iterables; 077 078/** 079 * Helper for invitations by email 080 * 081 */ 082public class ProjectInvitationHelper extends AbstractLogEnabled implements Serviceable, Component, Configurable, PluginAware, Contextualizable 083{ 084 /** The role */ 085 public static final String ROLE = ProjectInvitationHelper.class.getName(); 086 087 private static final String __MAIL_PROJECT_EMAIL_PATTERN = "${email}"; 088 private static final String __MAIL_PROJECT_TOKEN_PATTERN = "${token}"; 089 090 private ProjectManager _projectManager; 091 private UserSignUpConfiguration _signupConfig; 092 private UserSignupManager _signupManager; 093 private SiteManager _siteManager; 094 private WorkspaceModuleExtensionPoint _moduleEP; 095 private CurrentUserProvider _currentUserProvider; 096 private UserManager _userManager; 097 private UserHelper _userHelper; 098 private ProjectRightHelper _projectRightsHelper; 099 private ProjectMemberManager _projectMemberManager; 100 private PopulationContextHelper _populationContextHelper; 101 102 private String _subjectKeyForInvitation; 103 private String _textBodyKeyForInvitation; 104 private String _htmlBodyKeyForInvitation; 105 private String _subjectKeyForInvitationAccepted; 106 private String _textBodyKeyForInvitationAccepted; 107 private String _htmlBodyKeyForInvitationAccepted; 108 109 private I18nUtils _i18nUtils; 110 111 private String _pluginName; 112 113 private Context _context; 114 115 116 public void setPluginInfo(String pluginName, String featureName, String id) 117 { 118 _pluginName = pluginName; 119 } 120 121 public void contextualize(Context context) throws ContextException 122 { 123 _context = context; 124 } 125 126 @Override 127 public void service(ServiceManager serviceManager) throws ServiceException 128 { 129 _projectManager = (ProjectManager) serviceManager.lookup(ProjectManager.ROLE); 130 _projectRightsHelper = (ProjectRightHelper) serviceManager.lookup(ProjectRightHelper.ROLE); 131 _projectMemberManager = (ProjectMemberManager) serviceManager.lookup(ProjectMemberManager.ROLE); 132 _signupConfig = (UserSignUpConfiguration) serviceManager.lookup(UserSignUpConfiguration.ROLE); 133 _signupManager = (UserSignupManager) serviceManager.lookup(UserSignupManager.ROLE); 134 _siteManager = (SiteManager) serviceManager.lookup(SiteManager.ROLE); 135 _moduleEP = (WorkspaceModuleExtensionPoint) serviceManager.lookup(WorkspaceModuleExtensionPoint.ROLE); 136 _currentUserProvider = (CurrentUserProvider) serviceManager.lookup(CurrentUserProvider.ROLE); 137 _userManager = (UserManager) serviceManager.lookup(UserManager.ROLE); 138 _userHelper = (UserHelper) serviceManager.lookup(UserHelper.ROLE); 139 _i18nUtils = (I18nUtils) serviceManager.lookup(I18nUtils.ROLE); 140 _populationContextHelper = (PopulationContextHelper) serviceManager.lookup(PopulationContextHelper.ROLE); 141 } 142 143 @Override 144 public void configure(Configuration configuration) throws ConfigurationException 145 { 146 _subjectKeyForInvitation = configuration.getChild("invitation-email-subject").getValue(null); 147 _textBodyKeyForInvitation = configuration.getChild("invitation-email-text-body").getValue(null); 148 _htmlBodyKeyForInvitation = configuration.getChild("invitation-email-html-body").getValue(null); 149 150 _subjectKeyForInvitationAccepted = configuration.getChild("invitation-accepted-email-subject").getValue(null); 151 _textBodyKeyForInvitationAccepted = configuration.getChild("invitation-accepted-email-text-body").getValue(null); 152 _htmlBodyKeyForInvitationAccepted = configuration.getChild("invitation-accepted-email-html-body").getValue(null); 153 } 154 155 156 /** 157 * Invite emails to be member of a project 158 * @param projectName The project name 159 * @param siteName The site name 160 * @param lang the current language 161 * @param emails The emails 162 * @param allowedProfileByModule the allowed profiles by module 163 * @param mailSubject The subject of mail 164 * @param mailBody The body of mail 165 * @return The result 166 * @throws UserManagementException if failed to invit user 167 * @throws NotUniqueUserException if many users match the given email 168 * @throws IllegalAccessException If the user cannot execute this operation 169 */ 170 @Callable 171 public Map<String, Object> inviteEmails(String projectName, String siteName, String lang, List<String> emails, Map<String, String> allowedProfileByModule, String mailSubject, String mailBody) throws UserManagementException, IllegalAccessException, NotUniqueUserException 172 { 173 Map<String, Object> result = new HashMap<>(); 174 175 result.put("existing-users", new ArrayList<Map<String, Object>>()); 176 result.put("email-success", new ArrayList<String>()); 177 result.put("email-error", new ArrayList<String>()); 178 179 Project project = _projectManager.getProject(projectName); 180 if (project != null) 181 { 182 MembersWorkspaceModule module = _moduleEP.getModule(MembersWorkspaceModule.MEMBERS_MODULE_ID); 183 if (module != null && _projectManager.isModuleActivated(project, module.getId())) 184 { 185 if (!_projectRightsHelper.canAddMember(project)) 186 { 187 throw new IllegalAccessException("User '" + _currentUserProvider.getUser() + "' tried to send invitations without sufficient right."); 188 } 189 190 String catalogSiteName = _projectManager.getCatalogSiteName(); 191 192 String userDirectoryAsStr = _getUserDirectoryForSignup(result, catalogSiteName, lang); 193 if (userDirectoryAsStr != null) 194 { 195 String populationId = StringUtils.substringBeforeLast(userDirectoryAsStr, "#"); 196 String userDirectoryId = StringUtils.substringAfterLast(userDirectoryAsStr, "#"); 197 198 for (String email : emails) 199 { 200 try 201 { 202 if (!_signupManager.userExists(email, catalogSiteName)) 203 { 204 _signupManager.temporarySignup(siteName, lang, email, populationId, userDirectoryId); 205 206 // Whatever or not the mail has already been invited, re-created the invitation 207 if (_addOrUpdateInvitation(project, catalogSiteName, module, email, allowedProfileByModule, populationId, userDirectoryId, mailSubject, mailBody)) 208 { 209 @SuppressWarnings("unchecked") 210 List<String> emailSuccess = (List<String>) result.get("email-success"); 211 emailSuccess.add(email); 212 213 } 214 else 215 { 216 @SuppressWarnings("unchecked") 217 List<String> emailErrors = (List<String>) result.get("email-error"); 218 emailErrors.add(email); 219 } 220 } 221 else 222 { 223 User user = _getUser(catalogSiteName, email); 224 225 Map<String, Object> user2json = _userHelper.user2json(user, true); 226 227 @SuppressWarnings("unchecked") 228 List<Map<String, Object>> existingUsers = (List<Map<String, Object>>) result.get("existing-users"); 229 existingUsers.add(user2json); 230 } 231 } 232 catch (UserManagementException e) 233 { 234 getLogger().error("Cannot invite " + email, e); 235 @SuppressWarnings("unchecked") 236 List<String> emailErrors = (List<String>) result.get("email-error"); 237 emailErrors.add(email); 238 } 239 } 240 241 @SuppressWarnings("unchecked") 242 List<String> emailSuccess = (List<String>) result.get("email-success"); 243 if (emailSuccess.size() == emails.size()) 244 { 245 result.put("success", true); 246 } 247 } 248 } 249 } 250 else 251 { 252 result.put("success", false); 253 result.put("unknown-project", projectName); 254 } 255 256 return result; 257 } 258 259 private User _getUser(String siteName, String email) throws NotUniqueUserException 260 { 261 Set<String> populations = _populationContextHelper.getUserPopulationsOnContexts(Arrays.asList("/sites/" + siteName, "/sites-fo/" + siteName), false); 262 for (String population : populations) 263 { 264 User user = _userManager.getUser(population, email); 265 if (user == null) 266 { 267 user = _userManager.getUserByEmail(population, email); 268 } 269 270 if (user != null) 271 { 272 return user; 273 } 274 } 275 276 return null; 277 } 278 279 /** 280 * Get the configuration to invite users by emails 281 * @param projectName The current project 282 * @param lang the current language 283 * @return the configuration for email invitations 284 */ 285 @Callable 286 public Map<String, Object> getInvitationConfiguration(String projectName, String lang) 287 { 288 Project project = _projectManager.getProject(projectName); 289 290 Map<String, Object> config = new HashMap<>(); 291 292 // Check the configuration is valid for invitations 293 String catalogSiteName = _projectManager.getCatalogSiteName(); 294 if (_getUserDirectoryForSignup(config, catalogSiteName, lang) == null) 295 { 296 config.remove("success"); 297 config.put("allowed", false); 298 return config; 299 } 300 301 // Check the current user has right to invite users 302 if (!_projectRightsHelper.canAddMember(project)) 303 { 304 config.put("allowed", false); 305 config.put("error", "no-right"); 306 return config; 307 } 308 309 config.put("allowed", true); 310 config.put("email", _getInvitationEmailConfiguration(project, lang)); 311 config.put("rights", _projectRightsHelper.getProjectRightsData(projectName)); 312 313 return config; 314 } 315 316 private Map<String, Object> _getInvitationEmailConfiguration(Project project, String lang) 317 { 318 Map<String, Object> emailConfig = new HashMap<>(); 319 320 Map<String, I18nizableText> i18nparams = new HashMap<>(); 321 i18nparams.put("projectTitle", new I18nizableText(project.getTitle())); 322 i18nparams.put("projectUrl", new I18nizableText(Iterables.getFirst(_projectManager.getProjectUrls(project), StringUtils.EMPTY))); 323 i18nparams.put("nbDays", new I18nizableText(String.valueOf(_signupConfig.getTokenValidity()))); 324 i18nparams.put("nbDays", new I18nizableText(String.valueOf(_signupConfig.getTokenValidity()))); 325 326 String catalogSiteName = _projectManager.getCatalogSiteName(); 327 Site catalogSite = _siteManager.getSite(catalogSiteName); 328 i18nparams.put("catalogSiteTitle", new I18nizableText(catalogSite.getTitle())); 329 i18nparams.put("catalogSiteUrl", new I18nizableText(catalogSite.getUrl())); 330 331 Page signupPage = _signupManager.getSignupPage(_projectManager.getCatalogSiteName(), lang); 332 if (signupPage != null) 333 { 334 String signupUri = ResolveURIComponent.resolve("page", signupPage.getId(), false, true) + "?email=${email}&token=${token}"; 335 i18nparams.put("signupUri", new I18nizableText(signupUri)); 336 } 337 338 String subject = getSubjectForInvitationEmail(i18nparams, lang); 339 if (subject != null) 340 { 341 emailConfig.put("subject", subject); 342 } 343 String bodyTxt = getTextBodyForInvitationEmail(i18nparams, lang); 344 if (bodyTxt != null) 345 { 346 emailConfig.put("bodyText", bodyTxt); 347 } 348 String bodyHtml = getHtmlBodyForInvitationEmail(i18nparams, lang); 349 if (bodyHtml != null) 350 { 351 emailConfig.put("bodyHtml", bodyHtml); 352 } 353 354 return emailConfig; 355 } 356 357 private void _sendInvitationMail (String catalogSiteName, String email, String populationId, String userDirectoryId, String mailSubject, String mailBodyTpl) throws UserManagementException 358 { 359 String bodyTxt = mailBodyTpl; 360 361 String encodedEmail; 362 try 363 { 364 encodedEmail = URLEncoder.encode(email, "UTF-8"); 365 } 366 catch (UnsupportedEncodingException e) 367 { 368 // Should never happen. 369 throw new UserManagementException("Encoding error while sending a sign-up confirmation e-mail.", e); 370 } 371 372 String token = _signupManager.getToken(catalogSiteName, email, populationId, userDirectoryId); 373 374 bodyTxt = StringUtils.replace(bodyTxt, __MAIL_PROJECT_TOKEN_PATTERN, token); 375 bodyTxt = StringUtils.replace(bodyTxt, __MAIL_PROJECT_EMAIL_PATTERN, encodedEmail); 376 377 getLogger().debug("Sending signup invitation e-mail to {}", email); 378 379 Site site = _siteManager.getSite(catalogSiteName); 380 String from = site.getValue("site-mail-from"); 381 382 try 383 { 384 // Send the e-mail. 385 SendMailHelper.sendMail(mailSubject, null, bodyTxt, email, from); 386 } 387 catch (MessagingException e) 388 { 389 throw new UserManagementException("Error sending the sign-up confirmation mail.", e); 390 } 391 } 392 393 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 394 { 395 try 396 { 397 // First remove invitation if exists 398 module.removeInvitation(project, email); 399 400 // Add invitations with temporary rights 401 module.addInvitation(project, new Date(), email, _currentUserProvider.getUser(), allowedProfileByModules); 402 403 project.saveChanges(); 404 405 _sendInvitationMail(catalogSiteName, email, populationId, userDirectoryId, mailSubject, mailBody); 406 407 return true; 408 } 409 catch (RepositoryException e) 410 { 411 getLogger().error("Fail to store invitation for email " + email, e); 412 return false; 413 } 414 } 415 416 private String _getUserDirectoryForSignup(Map<String, Object> result, String catalogSiteName, String lang) 417 { 418 if (catalogSiteName == null) 419 { 420 getLogger().error("The catalog's site name is not configured. User invitations can not be activated."); 421 result.put("success", false); 422 result.put("error", "invalid-configuration"); 423 return null; 424 } 425 426 Page signupPage = _signupManager.getSignupPage(catalogSiteName, lang); 427 if (signupPage == null) 428 { 429 getLogger().error("The catalog's site does not contain the signup service for language " + lang + ". User invitations can not be activated."); 430 result.put("success", false); 431 result.put("error", "invalid-configuration"); 432 return null; 433 } 434 435 String userDirectoryAsStr = _getUserDirectoryForSignup(signupPage); 436 if (StringUtils.isEmpty(userDirectoryAsStr)) 437 { 438 getLogger().error("There is no user directory configured for users signup. Please check the sign up service of catalog's site."); 439 result.put("success", false); 440 result.put("error", "invalid-configuration"); 441 return null; 442 } 443 444 return userDirectoryAsStr; 445 446 } 447 448 private String _getUserDirectoryForSignup(Page signupPage) 449 { 450 for (Zone zone : signupPage.getZones()) 451 { 452 for (ZoneItem zoneItem : zone.getZoneItems()) 453 { 454 if (zoneItem.getType() == ZoneType.SERVICE && zoneItem.getServiceId().equals("org.ametys.web.service.UserSignup")) 455 { 456 return zoneItem.getServiceParameters().getValue("userdirectory"); 457 } 458 } 459 } 460 461 return null; 462 463 } 464 465 /** 466 * Add user as member of all project where it has been invited 467 * @param user the new user 468 */ 469 public void createMemberFromInvitations(User user) 470 { 471 Request request = ContextHelper.getRequest(_context); 472 String currentWorkspace = RequestAttributeWorkspaceSelector.getForcedWorkspace(request); 473 474 try 475 { 476 // Force default workspace 477 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, "default"); 478 479 MembersWorkspaceModule memberModule = (MembersWorkspaceModule) _moduleEP.getExtension(MembersWorkspaceModule.MEMBERS_MODULE_ID); 480 481 List<Invitation> invitations = memberModule.getInvitations(user.getEmail()); 482 483 for (Invitation invitation : invitations) 484 { 485 Map<String, String> allowedProfileByModules = invitation.getAllowedProfileByModules(); 486 String projectName = invitation.getProjectName(); 487 488 Project project = _projectManager.getProject(projectName); 489 490 // Create new member 491 JCRProjectMember member = _projectMemberManager.getOrCreateProjectMember(project, user.getIdentity()); 492 493 // Set member's rights 494 _projectMemberManager.setMemberProfiles(allowedProfileByModules, member, project, true); 495 496 project.saveChanges(); 497 498 // Notify author that invitation was accepted 499 UserIdentity author = invitation.getAuthor(); 500 sendInvitationAcceptedMail(project, _userManager.getUser(author), user); 501 502 try 503 { 504 // Remove invitation 505 memberModule.removeInvitation(project, invitation.getEmail()); 506 } 507 catch (RepositoryException e) 508 { 509 getLogger().error("Failed to remove invitation " + invitation, e); 510 } 511 } 512 } 513 finally 514 { 515 // Restore current workspace 516 RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWorkspace); 517 } 518 519 } 520 521 /** 522 * Send email to the user who initiated the invitation 523 * @param project The project 524 * @param invitAuthor The author of invitation 525 * @param newMember The new member 526 */ 527 protected void sendInvitationAcceptedMail(Project project, User invitAuthor, User newMember) 528 { 529 if (invitAuthor != null) 530 { 531 Site site = project.getSites().iterator().next(); 532 String from = site.getValue("site-mail-from"); 533 String email = invitAuthor.getEmail(); 534 535 if (StringUtils.isNotEmpty(email)) 536 { 537 // Prepare mail. 538 Map<String, I18nizableText> i18nParams = new HashMap<>(); 539 i18nParams.put("projectTitle", new I18nizableText(project.getTitle())); 540 i18nParams.put("projectUrl", new I18nizableText(Iterables.getFirst(_projectManager.getProjectUrls(project), StringUtils.EMPTY))); 541 i18nParams.put("newMember", new I18nizableText(newMember.getFullName())); 542 i18nParams.put("newMemberMail", new I18nizableText(newMember.getEmail())); 543 544 AmetysObjectIterable<Page> memberPages = _projectManager.getModulePages(project, MembersWorkspaceModule.MEMBERS_MODULE_ID, null); 545 if (memberPages.getSize() > 0) 546 { 547 Page page = memberPages.iterator().next(); 548 i18nParams.put("membersPageUri", new I18nizableText(ResolveURIComponent.resolve("page", page.getId(), false, true))); 549 } 550 551 String subject = getSubjectForInvitationAcceptedEmail(i18nParams, null); 552 String textBody = getTextBodyForInvitationAcceptedEmail(i18nParams, null); 553 String htmlBody = getHtmlBodyForInvitationAcceptedEmail(i18nParams, null); 554 555 try 556 { 557 // Send the e-mail. 558 SendMailHelper.sendMail(subject, htmlBody, textBody, email, from); 559 } 560 catch (MessagingException e) 561 { 562 getLogger().error("Error sending the invitation accepted email.", e); 563 } 564 } 565 } 566 } 567 568 /** 569 * The email subject for invitation by email 570 * @param defaultI18nParams The default i18n parameters 571 * @param language the language 572 * @return the email subject for invitation by email 573 */ 574 public String getSubjectForInvitationEmail (Map<String, I18nizableText> defaultI18nParams , String language) 575 { 576 if (StringUtils.isNotBlank(_subjectKeyForInvitation)) 577 { 578 return _i18nUtils.translate(_getI18nizableText(_subjectKeyForInvitation, defaultI18nParams), language); 579 } 580 581 return null; 582 } 583 584 /** 585 * The email text body for invitation by email 586 * @param defaultI18nParams The default i18n parameters with : 587 * siteName the site name 588 * email the mail 589 * token the token 590 * confirmUri the confirmation uri 591 * siteTitle the site title 592 * siteUrl the site url 593 * @param language the language 594 * @return the email text for invitation by email 595 */ 596 public String getTextBodyForInvitationEmail(Map<String, I18nizableText> defaultI18nParams, String language) 597 { 598 if (StringUtils.isNotBlank(_textBodyKeyForInvitation)) 599 { 600 return _i18nUtils.translate(_getI18nizableText(_textBodyKeyForInvitation, defaultI18nParams), language); 601 } 602 603 return null; 604 } 605 606 /** 607 * The email html body for invitation by email 608 * @param defaultI18nParams The default i18n parameters with : 609 * siteName the site name 610 * email the mail 611 * token the token 612 * confirmUri the confirmation uri 613 * siteTitle the site title 614 * siteUrl the site url 615 * @param language the language 616 * @return the email html for invitation by email 617 */ 618 public String getHtmlBodyForInvitationEmail(Map<String, I18nizableText> defaultI18nParams, String language) 619 { 620 if (StringUtils.isNotBlank(_htmlBodyKeyForInvitation)) 621 { 622 return _i18nUtils.translate(_getI18nizableText(_htmlBodyKeyForInvitation, defaultI18nParams), language); 623 } 624 625 return null; 626 } 627 628 /** 629 * The email subject for invitation by email 630 * @param defaultI18nParams The default i18n parameters 631 * @param language the language 632 * @return the email subject for invitation by email 633 */ 634 public String getSubjectForInvitationAcceptedEmail (Map<String, I18nizableText> defaultI18nParams , String language) 635 { 636 if (StringUtils.isNotBlank(_subjectKeyForInvitationAccepted)) 637 { 638 return _i18nUtils.translate(_getI18nizableText(_subjectKeyForInvitationAccepted, defaultI18nParams), language); 639 } 640 641 return null; 642 } 643 644 /** 645 * The email text body for invitation by email 646 * @param defaultI18nParams The default i18n parameters with : 647 * @param language the language 648 * @return the email text for invitation by email 649 */ 650 public String getTextBodyForInvitationAcceptedEmail(Map<String, I18nizableText> defaultI18nParams, String language) 651 { 652 if (StringUtils.isNotBlank(_textBodyKeyForInvitationAccepted)) 653 { 654 return _i18nUtils.translate(_getI18nizableText(_textBodyKeyForInvitationAccepted, defaultI18nParams), language); 655 } 656 657 return null; 658 } 659 660 /** 661 * The email html body for invitation by email 662 * @param defaultI18nParams The default i18n parameters with : 663 * @param language the language 664 * @return the email html for invitation by email 665 */ 666 public String getHtmlBodyForInvitationAcceptedEmail(Map<String, I18nizableText> defaultI18nParams, String language) 667 { 668 if (StringUtils.isNotBlank(_htmlBodyKeyForInvitationAccepted)) 669 { 670 return _i18nUtils.translate(_getI18nizableText(_htmlBodyKeyForInvitationAccepted, defaultI18nParams), language); 671 } 672 673 return null; 674 } 675 676 /** 677 * Get the {@link I18nizableText} from the configured key and i18n parameters 678 * @param fullI18nKey the configured i18n key 679 * @param i18nParams the i18n parameters 680 * @return the i18nizable text 681 */ 682 protected I18nizableText _getI18nizableText(String fullI18nKey, Map<String, I18nizableText> i18nParams) 683 { 684 String catalogue = StringUtils.contains(fullI18nKey, ":") ? StringUtils.substringBefore(fullI18nKey, ":") : "plugin." + _pluginName; 685 String i18nKey = StringUtils.contains(fullI18nKey, ":") ? StringUtils.substringAfter(fullI18nKey, ":") : fullI18nKey; 686 687 return new I18nizableText(catalogue, i18nKey, i18nParams); 688 } 689 690}