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