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.population.PopulationContextHelper;
055import org.ametys.core.util.I18nUtils;
056import org.ametys.core.util.mail.SendMailHelper;
057import org.ametys.plugins.core.user.UserHelper;
058import org.ametys.plugins.repository.AmetysObjectIterable;
059import org.ametys.plugins.repository.provider.RequestAttributeWorkspaceSelector;
060import org.ametys.plugins.workspaces.members.MembersWorkspaceModule.Invitation;
061import org.ametys.plugins.workspaces.project.ProjectManager;
062import org.ametys.plugins.workspaces.project.modules.WorkspaceModuleExtensionPoint;
063import org.ametys.plugins.workspaces.project.objects.Project;
064import org.ametys.plugins.workspaces.project.rights.ProjectRightHelper;
065import org.ametys.runtime.i18n.I18nizableText;
066import org.ametys.runtime.i18n.I18nizableTextParameter;
067import org.ametys.runtime.plugin.component.AbstractLogEnabled;
068import org.ametys.runtime.plugin.component.PluginAware;
069import org.ametys.web.WebConstants;
070import org.ametys.web.WebHelper;
071import org.ametys.web.repository.page.Page;
072import org.ametys.web.repository.page.Zone;
073import org.ametys.web.repository.page.ZoneItem;
074import org.ametys.web.repository.page.ZoneItem.ZoneType;
075import org.ametys.web.repository.site.Site;
076import org.ametys.web.repository.site.SiteManager;
077import org.ametys.web.usermanagement.UserManagementException;
078import org.ametys.web.usermanagement.UserSignUpConfiguration;
079import org.ametys.web.usermanagement.UserSignupManager;
080
081import com.google.common.collect.Iterables;
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     * @throws IllegalAccessException If the user cannot execute this operation
173     */
174    public Map<String, Object> inviteEmails(String projectName, List<String> emails, Map<String, String> allowedProfileByModule) throws UserManagementException, IllegalAccessException, NotUniqueUserException
175    {
176        Request request = ContextHelper.getRequest(_context);
177        String siteName = WebHelper.getSiteName(request);
178        String sitemapLanguage = (String) request.getAttribute(WebConstants.REQUEST_ATTR_SITEMAP_NAME);
179        
180        Project project = _projectManager.getProject(projectName);
181        Map<String, String> emailConfiguration = _getInvitationEmailConfiguration(project, sitemapLanguage);
182        String mailSubject = emailConfiguration.get("subject");
183        String mailBody = emailConfiguration.get("bodyText");
184        
185        return inviteEmails(projectName, siteName, sitemapLanguage, emails, allowedProfileByModule, mailSubject, mailBody);
186    }
187    /**
188     * Invite emails to be member of a project
189     * @param projectName The project name
190     * @param siteName The site name
191     * @param lang the current language
192     * @param emails The emails
193     * @param allowedProfileByModule the allowed profiles by module
194     * @param mailSubject The subject of mail
195     * @param mailBody The body of mail
196     * @return The result
197     * @throws UserManagementException if failed to invit user
198     * @throws NotUniqueUserException if many users match the given email
199     * @throws IllegalAccessException If the user cannot execute this operation
200     */
201    @Callable
202    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
203    {
204        Map<String, Object> result = new HashMap<>();
205        
206        result.put("existing-users", new ArrayList<Map<String, Object>>());
207        result.put("email-success", new ArrayList<String>());
208        result.put("email-error", new ArrayList<String>());
209        
210        Project project = _projectManager.getProject(projectName);
211        if (project != null)
212        {
213            MembersWorkspaceModule module = _moduleEP.getModule(MembersWorkspaceModule.MEMBERS_MODULE_ID);
214            if (module != null && _projectManager.isModuleActivated(project, module.getId()))
215            {
216                if (!_projectRightsHelper.canAddMember(project))
217                {
218                    throw new IllegalAccessException("User '" + _currentUserProvider.getUser() + "' tried to send invitations without sufficient right."); 
219                }
220                
221                String catalogSiteName = _projectManager.getCatalogSiteName();
222                
223                String userDirectoryAsStr = _getUserDirectoryForSignup(result, catalogSiteName, lang);
224                if (userDirectoryAsStr != null)
225                {
226                    String populationId = StringUtils.substringBeforeLast(userDirectoryAsStr, "#");
227                    String userDirectoryId = StringUtils.substringAfterLast(userDirectoryAsStr, "#");
228                    
229                    for (String email : emails)
230                    {
231                        try
232                        {
233                            if (!_signupManager.userExists(email, catalogSiteName))
234                            {
235                                _signupManager.temporarySignup(siteName, lang, email, populationId, userDirectoryId);
236                                
237                                // Whatever or not the mail has already been invited, re-created the invitation
238                                if (_addOrUpdateInvitation(project, catalogSiteName, module, email, allowedProfileByModule, populationId, userDirectoryId, mailSubject, mailBody))
239                                {
240                                    @SuppressWarnings("unchecked")
241                                    List<String> emailSuccess = (List<String>) result.get("email-success");
242                                    emailSuccess.add(email);
243                                    
244                                }
245                                else
246                                {
247                                    @SuppressWarnings("unchecked")
248                                    List<String> emailErrors = (List<String>) result.get("email-error");
249                                    emailErrors.add(email);
250                                }
251                            }
252                            else
253                            {
254                                User user = _getUser(catalogSiteName, email);
255                                
256                                Map<String, Object> user2json = _userHelper.user2json(user, true);
257                                
258                                @SuppressWarnings("unchecked")
259                                List<Map<String, Object>> existingUsers = (List<Map<String, Object>>) result.get("existing-users");
260                                existingUsers.add(user2json);
261                            }
262                        }
263                        catch (UserManagementException e)
264                        {
265                            getLogger().error("Cannot invite " + email, e);
266                            @SuppressWarnings("unchecked")
267                            List<String> emailErrors = (List<String>) result.get("email-error");
268                            emailErrors.add(email);
269                        }
270                    }
271                    
272                    @SuppressWarnings("unchecked")
273                    List<String> emailSuccess = (List<String>) result.get("email-success");
274                    if (emailSuccess.size() == emails.size())
275                    {
276                        result.put("success", true);
277                    }
278                }
279            }
280        }
281        else
282        {
283            result.put("success", false);
284            result.put("unknown-project", projectName);
285        }
286        
287        return result;
288    }
289    
290    private User _getUser(String siteName, String email) throws NotUniqueUserException
291    {
292        Set<String> populations = _populationContextHelper.getUserPopulationsOnContexts(Arrays.asList("/sites/" + siteName, "/sites-fo/" + siteName), false);
293        for (String population : populations)
294        {
295            User user = _userManager.getUser(population, email);
296            if (user == null)
297            {
298                user = _userManager.getUserByEmail(population, email);
299            }
300            
301            if (user != null)
302            {
303                return user;
304            }
305        }
306        
307        return null;
308    }
309    
310    /**
311     * Get the configuration to invite users by emails
312     * @param projectName The current project
313     * @param lang the current language
314     * @return the configuration for email invitations
315     */
316    @Callable
317    public Map<String, Object> getInvitationConfiguration(String projectName, String lang)
318    {
319        Project project = _projectManager.getProject(projectName);
320        
321        Map<String, Object> config = new HashMap<>();
322        
323        // Check the configuration is valid for invitations
324        String catalogSiteName = _projectManager.getCatalogSiteName();
325        if (_getUserDirectoryForSignup(config, catalogSiteName, lang) == null)
326        {
327            config.remove("success");
328            config.put("allowed", false); 
329            return config;
330        }
331        
332        // Check the current user has right to invite users
333        if (!_projectRightsHelper.canAddMember(project))
334        {
335            config.put("allowed", false); 
336            config.put("error", "no-right"); 
337            return config;
338        }
339        
340        config.put("allowed", true);
341        config.put("email", _getInvitationEmailConfiguration(project, lang));
342        config.put("rights", _projectRightsHelper.getProjectRightsData(projectName)); 
343        
344        return config;
345    }
346    
347    private Map<String, String> _getInvitationEmailConfiguration(Project project, String lang)
348    {
349        Map<String, String> emailConfig = new HashMap<>();
350        
351        Map<String, I18nizableTextParameter> i18nparams = new HashMap<>();
352        i18nparams.put("projectTitle", new I18nizableText(project.getTitle()));
353        i18nparams.put("projectUrl", new I18nizableText(Iterables.getFirst(_projectManager.getProjectUrls(project), StringUtils.EMPTY)));
354        i18nparams.put("nbDays", new I18nizableText(String.valueOf(_signupConfig.getTokenValidity())));
355        i18nparams.put("nbDays", new I18nizableText(String.valueOf(_signupConfig.getTokenValidity())));
356        
357        String catalogSiteName = _projectManager.getCatalogSiteName();
358        Site catalogSite = _siteManager.getSite(catalogSiteName);
359        i18nparams.put("catalogSiteTitle", new I18nizableText(catalogSite.getTitle()));
360        i18nparams.put("catalogSiteUrl", new I18nizableText(catalogSite.getUrl()));
361        
362        Page signupPage = _getSignupPage(_projectManager.getCatalogSiteName(), lang);
363        if (signupPage != null)
364        {
365            String signupUri = ResolveURIComponent.resolve("page", signupPage.getId(), false, true) + "?email=${email}&token=${token}";
366            i18nparams.put("signupUri", new I18nizableText(signupUri));
367        }
368        
369        String subject = getSubjectForInvitationEmail(i18nparams, lang);
370        if (subject != null)
371        {
372            emailConfig.put("subject", subject);
373        }
374        String bodyTxt = getTextBodyForInvitationEmail(i18nparams, lang);
375        if (bodyTxt != null)
376        {
377            emailConfig.put("bodyText", bodyTxt);
378        }
379        String bodyHtml = getHtmlBodyForInvitationEmail(i18nparams, lang);
380        if (bodyHtml != null)
381        {
382            emailConfig.put("bodyHtml", bodyHtml);
383        }
384        
385        return emailConfig;
386    }
387
388    private Page _getSignupPage(String catalogSiteName, String lang)
389    {
390
391        Page signupPage = _signupManager.getSignupPage(catalogSiteName, lang);
392
393        if (signupPage == null)
394        {
395            signupPage = _signupManager.getSignupPage(catalogSiteName, "en");
396        }
397        
398        if (signupPage == null)
399        {
400            Map<String, Language> availableLanguages = _languagesManager.getAvailableLanguages();
401            for (Language availableLanguage : availableLanguages.values())
402            {
403                if (signupPage == null)
404                {
405                    signupPage = _signupManager.getSignupPage(catalogSiteName, availableLanguage.getCode());
406                }
407            }
408        }
409        return signupPage;
410    }
411    
412    private void _sendInvitationMail (String catalogSiteName, String email, String populationId, String userDirectoryId, String mailSubject, String mailBodyTpl) throws UserManagementException
413    {
414        String bodyTxt = mailBodyTpl;
415        
416        String encodedEmail;
417        try
418        {
419            encodedEmail = URLEncoder.encode(email, "UTF-8");
420        }
421        catch (UnsupportedEncodingException e)
422        {
423            // Should never happen.
424            throw new UserManagementException("Encoding error while sending a sign-up confirmation e-mail.", e);
425        }
426
427        String token = _signupManager.getToken(catalogSiteName, email, populationId, userDirectoryId);
428        
429        bodyTxt = StringUtils.replace(bodyTxt, __MAIL_PROJECT_TOKEN_PATTERN, token);
430        bodyTxt = StringUtils.replace(bodyTxt, __MAIL_PROJECT_EMAIL_PATTERN, encodedEmail);
431        
432        getLogger().debug("Sending signup invitation e-mail to {}", email);
433        
434        Site site = _siteManager.getSite(catalogSiteName);
435        String from = site.getValue("site-mail-from");
436
437        try
438        {
439            // Send the e-mail.
440            SendMailHelper.newMail()
441                          .withSubject(mailSubject)
442                          .withTextBody(bodyTxt)
443                          .withSender(from)
444                          .withRecipient(email)
445                          .sendMail();
446        }
447        catch (MessagingException | IOException e)
448        {
449            throw new UserManagementException("Error sending the sign-up confirmation mail.", e);
450        }
451    }
452    
453    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
454    {
455        try
456        {
457            // First remove invitation if exists
458            module.removeInvitation(project, email);
459            
460            // Add invitations with temporary rights
461            module.addInvitation(project, new Date(), email, _currentUserProvider.getUser(), allowedProfileByModules);
462            
463            project.saveChanges();
464
465            _sendInvitationMail(catalogSiteName, email, populationId, userDirectoryId, mailSubject, mailBody);
466            
467            return true;
468        }
469        catch (RepositoryException e)
470        {
471            getLogger().error("Fail to store invitation for email " + email, e);
472            return false;
473        }
474    }
475    
476    private String _getUserDirectoryForSignup(Map<String, Object> result, String catalogSiteName, String lang)
477    {
478        if (catalogSiteName == null)
479        {
480            getLogger().error("The catalog's site name is not configured. User invitations can not be activated.");
481            result.put("success", false);
482            result.put("error", "invalid-configuration");
483            return null;
484        }
485        
486        if (!_signupManager.isPublicSignupAllowed(catalogSiteName))
487        {
488            getLogger().warn("Public signup is disabled for the catalog's site.");
489            result.put("success", false);
490            return null;
491        }
492        
493        Page signupPage = _getSignupPage(catalogSiteName, lang);
494        if (signupPage == null)
495        {
496            getLogger().error("The catalog's site does not contain the signup service for language " + lang + ". User invitations can not be activated.");
497            result.put("success", false);
498            result.put("error", "invalid-configuration");
499            return null;
500        }
501        
502        String userDirectoryAsStr = _getUserDirectoryForSignup(signupPage);
503        if (StringUtils.isEmpty(userDirectoryAsStr))
504        {
505            getLogger().error("There is no user directory configured for users signup. Please check the sign up service of catalog's site.");
506            result.put("success", false);
507            result.put("error", "invalid-configuration");
508            return null;
509        }
510        
511        return userDirectoryAsStr;
512            
513    }
514    
515    private String _getUserDirectoryForSignup(Page signupPage)
516    {
517        for (Zone zone : signupPage.getZones())
518        {
519            try (AmetysObjectIterable<? extends ZoneItem> zoneItems = zone.getZoneItems())
520            {
521                for (ZoneItem zoneItem : zoneItems)
522                {
523                    if (zoneItem.getType() == ZoneType.SERVICE && zoneItem.getServiceId().equals("org.ametys.web.service.UserSignup"))
524                    {
525                        return zoneItem.getServiceParameters().getValue("userdirectory");
526                    }
527                }
528            }
529        }
530        
531        return null;
532        
533    }
534    
535    /**
536     * Add user as member of all project where it has been invited
537     * @param user the new user
538     */
539    public void createMemberFromInvitations(User user)
540    {
541        Request request = ContextHelper.getRequest(_context);
542        String currentWorkspace = RequestAttributeWorkspaceSelector.getForcedWorkspace(request);
543        
544        try
545        {
546            // Force default workspace
547            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, "default");
548            
549            MembersWorkspaceModule memberModule = (MembersWorkspaceModule) _moduleEP.getExtension(MembersWorkspaceModule.MEMBERS_MODULE_ID);
550            
551            List<Invitation> invitations = memberModule.getInvitations(user.getEmail());
552            
553            for (Invitation invitation : invitations)
554            {
555                Map<String, String> allowedProfileByModules = invitation.getAllowedProfileByModules();
556                String projectName = invitation.getProjectName();
557                
558                Project project = _projectManager.getProject(projectName);
559                
560                
561                _projectMemberManager.addOrUpdateProjectMember(project, user.getIdentity(), allowedProfileByModules);
562                
563                // Notify author that invitation was accepted
564                UserIdentity author = invitation.getAuthor();
565                sendInvitationAcceptedMail(project, _userManager.getUser(author), user);
566                
567                try
568                {
569                    // Remove invitation
570                    memberModule.removeInvitation(project, invitation.getEmail());
571                }
572                catch (RepositoryException e)
573                {
574                    getLogger().error("Failed to remove invitation " + invitation, e);
575                }
576            }
577        }
578        finally 
579        {
580            // Restore current workspace
581            RequestAttributeWorkspaceSelector.setForcedWorkspace(request, currentWorkspace);
582        }
583    
584    }
585    
586    /**
587     * Send email to the user who initiated the invitation
588     * @param project The project
589     * @param invitAuthor The author of invitation
590     * @param newMember The new member
591     */
592    protected void sendInvitationAcceptedMail(Project project, User invitAuthor, User newMember)
593    {
594        if (invitAuthor != null)
595        {
596            Site site = project.getSites().iterator().next();
597            String from = site.getValue("site-mail-from");
598            String email = invitAuthor.getEmail();
599            
600            if (StringUtils.isNotEmpty(email))
601            {
602                // Prepare mail.
603                Map<String, I18nizableTextParameter> i18nParams = new HashMap<>();
604                i18nParams.put("projectTitle", new I18nizableText(project.getTitle()));
605                i18nParams.put("projectUrl", new I18nizableText(Iterables.getFirst(_projectManager.getProjectUrls(project), StringUtils.EMPTY)));
606                i18nParams.put("newMember", new I18nizableText(newMember.getFullName()));
607                i18nParams.put("newMemberMail", new I18nizableText(newMember.getEmail()));
608                
609                Set<Page> memberPages = _projectManager.getModulePages(project, MembersWorkspaceModule.MEMBERS_MODULE_ID);
610                if (!memberPages.isEmpty())
611                {
612                    Page page = memberPages.iterator().next();
613                    i18nParams.put("membersPageUri", new I18nizableText(ResolveURIComponent.resolve("page", page.getId(), false, true)));
614                }
615
616                String subject = getSubjectForInvitationAcceptedEmail(i18nParams, null);
617                String textBody = getTextBodyForInvitationAcceptedEmail(i18nParams, null);
618                String htmlBody = getHtmlBodyForInvitationAcceptedEmail(i18nParams, null);
619
620                try
621                {
622                    // Send the e-mail.
623                    SendMailHelper.newMail()
624                                  .withSubject(subject)
625                                  .withHTMLBody(htmlBody)
626                                  .withTextBody(textBody)
627                                  .withSender(from)
628                                  .withRecipient(email)
629                                  .sendMail();
630                }
631                catch (MessagingException | IOException e)
632                {
633                    getLogger().error("Error sending the invitation accepted email.", e);
634                }
635            }
636        }
637    }
638    
639    /**
640     * The email subject for invitation by email
641     * @param defaultI18nParams The default i18n parameters
642     * @param language the language
643     * @return the email subject for invitation by email
644     */
645    public String getSubjectForInvitationEmail (Map<String, I18nizableTextParameter> defaultI18nParams , String language)
646    {
647        if (StringUtils.isNotBlank(_subjectKeyForInvitation))
648        {
649            return _i18nUtils.translate(_getI18nizableText(_subjectKeyForInvitation, defaultI18nParams), language);
650        }
651        
652        return null;
653    }
654
655    /**
656     * The email text body for invitation by email
657     * @param defaultI18nParams The default i18n parameters with :
658     * siteName the site name
659     * email the mail
660     * token the token
661     * confirmUri the confirmation uri
662     * siteTitle the site title
663     * siteUrl the site url
664     * @param language the language
665     * @return the email text for invitation by email
666     */
667    public String getTextBodyForInvitationEmail(Map<String, I18nizableTextParameter> defaultI18nParams, String language)
668    {
669        if (StringUtils.isNotBlank(_textBodyKeyForInvitation))
670        {
671            return _i18nUtils.translate(_getI18nizableText(_textBodyKeyForInvitation, defaultI18nParams), language);
672        }
673        
674        return null;
675    }
676
677    /**
678     * The email html body for invitation by email
679     * @param defaultI18nParams The default i18n parameters with :
680     * siteName the site name
681     * email the mail
682     * token the token
683     * confirmUri the confirmation uri
684     * siteTitle the site title
685     * siteUrl the site url
686     * @param language the language
687     * @return the email html for invitation by email
688     */
689    public String getHtmlBodyForInvitationEmail(Map<String, I18nizableTextParameter> defaultI18nParams, String language)
690    {
691        if (StringUtils.isNotBlank(_htmlBodyKeyForInvitation))
692        {
693            return _i18nUtils.translate(_getI18nizableText(_htmlBodyKeyForInvitation, defaultI18nParams), language);
694        }
695        
696        return null;
697    }
698    
699    /**
700     * The email subject for invitation by email
701     * @param defaultI18nParams The default i18n parameters
702     * @param language the language
703     * @return the email subject for invitation by email
704     */
705    public String getSubjectForInvitationAcceptedEmail (Map<String, I18nizableTextParameter> defaultI18nParams , String language)
706    {
707        if (StringUtils.isNotBlank(_subjectKeyForInvitationAccepted))
708        {
709            return _i18nUtils.translate(_getI18nizableText(_subjectKeyForInvitationAccepted, defaultI18nParams), language);
710        }
711        
712        return null;
713    }
714    
715    /**
716     * The email text body for invitation by email
717     * @param defaultI18nParams The default i18n parameters with :
718     * @param language the language
719     * @return the email text for invitation by email
720     */
721    public String getTextBodyForInvitationAcceptedEmail(Map<String, I18nizableTextParameter> defaultI18nParams, String language)
722    {
723        if (StringUtils.isNotBlank(_textBodyKeyForInvitationAccepted))
724        {
725            return _i18nUtils.translate(_getI18nizableText(_textBodyKeyForInvitationAccepted, defaultI18nParams), language);
726        }
727        
728        return null;
729    }
730    
731    /**
732     * The email html body for invitation by email
733     * @param defaultI18nParams The default i18n parameters with :
734     * @param language the language
735     * @return the email html for invitation by email
736     */
737    public String getHtmlBodyForInvitationAcceptedEmail(Map<String, I18nizableTextParameter> defaultI18nParams, String language)
738    {
739        if (StringUtils.isNotBlank(_htmlBodyKeyForInvitationAccepted))
740        {
741            return _i18nUtils.translate(_getI18nizableText(_htmlBodyKeyForInvitationAccepted, defaultI18nParams), language);
742        }
743        
744        return null;
745    }
746    
747    /**
748     * Get the {@link I18nizableText} from the configured key and i18n parameters
749     * @param fullI18nKey the configured i18n key
750     * @param i18nParams the i18n parameters
751     * @return the i18nizable text
752     */
753    protected I18nizableText _getI18nizableText(String fullI18nKey, Map<String, I18nizableTextParameter> i18nParams)
754    {
755        String catalogue = StringUtils.contains(fullI18nKey, ":") ? StringUtils.substringBefore(fullI18nKey, ":") : "plugin." + _pluginName;
756        String i18nKey = StringUtils.contains(fullI18nKey, ":") ? StringUtils.substringAfter(fullI18nKey, ":") : fullI18nKey;
757        
758        return new I18nizableText(catalogue, i18nKey, i18nParams);
759    }
760    
761}