001package org.apache.archiva.redback.integration.mail;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import freemarker.template.Configuration;
023import org.apache.archiva.redback.configuration.UserConfiguration;
024import org.apache.archiva.redback.configuration.UserConfigurationKeys;
025import org.apache.archiva.redback.keys.AuthenticationKey;
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028import org.springframework.stereotype.Service;
029import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
030
031import javax.inject.Inject;
032import javax.inject.Named;
033import java.text.SimpleDateFormat;
034import java.util.HashMap;
035import java.util.Locale;
036import java.util.Map;
037
038/**
039 * Mail generator that uses freemarker templates.
040 *
041 * This implementation sets the following model values that can be used in templates:
042 * <ul>
043 *     <li>applicationUrl</li>
044 *     <li>urlPath</li>
045 *     <li>authKey</li>
046 *     <li>accountId</li>
047 *     <li>requestedOn</li>
048 *     <li>expiresOn</li>
049 * </ul>
050 *
051 * The additional template data is added for interpolation, if not <code>null</code>.
052 *
053 * This implementation is location enabled. That means, it will try to find templates in the following order:
054 * <ul>
055 *     <li><i>templateName</i>_<i>language</i>_<i>country</i>.ftl</li>
056 *     <li><i>templateName</i>_<i>language</i>.ftl</li>
057 *     <li><i>templateName</i>.ftl</li>
058 * </ul>
059 *
060 * The default encoding used for reading the template is UTF-8
061 *
062 * @author Martin Stockhammer <martin_s@apache.org>
063 */
064@Service( "mailGenerator#freemarker" )
065public class FreemarkerMailGenerator implements MailGenerator
066{
067    private Logger log = LoggerFactory.getLogger( FreemarkerMailGenerator.class );
068
069    public static final String DEFAULT_ENCODING = "UTF-8";
070
071    @Inject
072    @Named( value = "userConfiguration#default" )
073    private UserConfiguration config;
074
075    @Inject
076    Configuration freemarkerConfiguration;
077
078    private String encoding;
079
080    private String getEncoding( )
081    {
082        if ( this.encoding == null )
083        {
084            this.encoding = config.getString( UserConfigurationKeys.MAIL_TEMPLATE_ENCODING, DEFAULT_ENCODING );
085        }
086        return this.encoding;
087    }
088
089    private Locale getMailLocale() {
090        String localeString = config.getString( UserConfigurationKeys.MAIL_DEFAULT_LOCALE );
091        if (localeString == null || "".equals(localeString)) {
092            return Locale.getDefault( );
093        } else {
094            return Locale.forLanguageTag( localeString );
095        }
096    }
097
098    /**
099     *
100     * @param templateName the template name without extension
101     * @param locale the locale used to find the template file
102     * @param authkey the authentication key
103     * @param baseUrl the base url
104     * @param templateData additional template data, may be <code>null</code>
105     * @return the string generated from the template
106     */
107    @Override
108    public String generateMail( String templateName, Locale locale, AuthenticationKey authkey, String baseUrl,
109                                Map<String, Object> templateData )
110    {
111        Map<String, Object> context = createModel( authkey, baseUrl, templateData );
112        StringBuffer content = new StringBuffer( );
113        try
114        {
115            content.append( FreeMarkerTemplateUtils.processTemplateIntoString(
116                freemarkerConfiguration.getTemplate( templateName + ".ftl", locale, getEncoding( ) ), context ) );
117            return content.toString( );
118        }
119        catch ( Exception e )
120        {
121            log.error( "Could not parse the mail template {}: {}", templateName, e.getMessage( ), e );
122        }
123        return "";
124    }
125
126    @Override
127    public String generateMail( String templateName, AuthenticationKey authenticationKey, String baseUrl )
128    {
129        return generateMail( templateName, getMailLocale(), authenticationKey, baseUrl );
130    }
131
132    @Override
133    public String generateMail( String templateName, Locale locale, AuthenticationKey authenticationKey, String baseUrl )
134    {
135        return generateMail( templateName, locale, authenticationKey, baseUrl, null );
136    }
137
138    private Map<String, Object> createModel( AuthenticationKey authkey, String appUrl, Map<String, Object> templateData )
139    {
140        Map<String, Object> context = new HashMap<>( );
141        context.put( "applicationUrl", config.getString( UserConfigurationKeys.APPLICATION_URL, appUrl ) );
142
143        String feedback = config.getString( UserConfigurationKeys.EMAIL_FEEDBACK_PATH );
144
145        if ( feedback != null )
146        {
147            if ( feedback.startsWith( "/" ) )
148            {
149                feedback = appUrl + feedback;
150            }
151
152            context.put( "feedback", feedback );
153        }
154
155        context.put( "urlPath",
156            config.getString( UserConfigurationKeys.EMAIL_URL_PATH, "security/login!login.action" ) );
157
158        context.put( "authkey", authkey.getKey( ) );
159
160        context.put( "accountId", authkey.getForPrincipal( ) );
161
162        SimpleDateFormat dateformatter =
163            new SimpleDateFormat( config.getString( UserConfigurationKeys.APPLICATION_TIMESTAMP ), Locale.US );
164
165        context.put( "requestedOn", dateformatter.format( authkey.getDateCreated( ) ) );
166
167        if ( authkey.getDateExpires( ) != null )
168        {
169            context.put( "expiresOn", dateformatter.format( authkey.getDateExpires( ) ) );
170        }
171        else
172        {
173            context.put( "expiresOn", "(does not expire)" );
174        }
175
176        if (templateData!=null)
177        {
178            for ( Map.Entry<String, Object> entry : templateData.entrySet( ) )
179            {
180                context.put( entry.getKey( ), entry.getValue( ) );
181            }
182        }
183
184        return context;
185    }
186
187    public Configuration getFreemarkerConfiguration( )
188    {
189        return freemarkerConfiguration;
190    }
191
192    public void setFreemarkerConfiguration( Configuration freemarkerConfiguration )
193    {
194        this.freemarkerConfiguration = freemarkerConfiguration;
195    }
196
197    public UserConfiguration getConfig( )
198    {
199        return config;
200    }
201
202    public void setConfig( UserConfiguration config )
203    {
204        this.config = config;
205    }
206}