Commit d41ee4c2 by jhrabal

templates

parent 45b9c4f9
-- default admin user
insert into APP_ROLE (ID, NAME) values (1, 'ADMIN');
insert into APP_USER (ID, EMAIL, FIRST_NAME, LAST_NAME, PASSWORD, PASSWORD_SALT) VAlUES (1, 'janhrabal@seznam.cz', 'Jan', 'Hrabal', 'NKz1rz7kSEBXFGbolvEhdomvcDQYmD0IKGADVpuoxL1ztsE1NAnOMvbiSkvc3vwLQvBdPHw449XzgRderNJc9MMnnMTEgJdl3S6dtBGiEYDRHK19toXdwttfaDrXewjyZBJkzy7CxE/BOad4XkiTreIFAUGRedK9TGZ+RWbrJ2KIRrkSX3H1J2eT7HLF8bblkxz2qhjsF5s0k37e3sFI0xAdyCy6qAYS4/MW4WYQ3o0YyZc4krGE2k3y9kfPxWEh/favQKoFIX92ZkRh6ZIXNF7i4oUBl1pcg6r5ykCT83IAWm9avM768NEitEVOx0V8P0PQ2WxGA3n7nicKmwYjow==', 'GACR2Rea1kIhZAlImqK8HauZwTah5eMyKiTzr9HDriryN92YkE5UkWe3Gn7oRLkKEftaNfEfa2Ujj18Rrsed2a6QN69UZCkpRHnwgoBp5ckOOaC6s4undHSjYZW5rJx8CuKXTJpO1TS1LlsjwCyir8oA2gGm480jgGwOefm+r2s=');
insert into APP_USER (ID, EMAIL, FIRST_NAME, LAST_NAME, PASSWORD, PASSWORD_SALT, LOCALE, TIMEZONE_ID) VAlUES (1, 'janhrabal@seznam.cz', 'Jan', 'Hrabal', 'NKz1rz7kSEBXFGbolvEhdomvcDQYmD0IKGADVpuoxL1ztsE1NAnOMvbiSkvc3vwLQvBdPHw449XzgRderNJc9MMnnMTEgJdl3S6dtBGiEYDRHK19toXdwttfaDrXewjyZBJkzy7CxE/BOad4XkiTreIFAUGRedK9TGZ+RWbrJ2KIRrkSX3H1J2eT7HLF8bblkxz2qhjsF5s0k37e3sFI0xAdyCy6qAYS4/MW4WYQ3o0YyZc4krGE2k3y9kfPxWEh/favQKoFIX92ZkRh6ZIXNF7i4oUBl1pcg6r5ykCT83IAWm9avM768NEitEVOx0V8P0PQ2WxGA3n7nicKmwYjow==', 'GACR2Rea1kIhZAlImqK8HauZwTah5eMyKiTzr9HDriryN92YkE5UkWe3Gn7oRLkKEftaNfEfa2Ujj18Rrsed2a6QN69UZCkpRHnwgoBp5ckOOaC6s4undHSjYZW5rJx8CuKXTJpO1TS1LlsjwCyir8oA2gGm480jgGwOefm+r2s=', 'en', 'UTC');
insert into APP_USER_ROLE (USER_ID, ROLE_ID) values (1, 1);
-- default templates
insert into TEMPLATE (ID, CODE, TEMPLATE) values (1, 'email.layout', '{{content}}');
insert into TEMPLATE (ID, CODE, TEMPLATE) values (2, 'email.signup.subject', 'Welcome to ...');
insert into TEMPLATE (ID, CODE, TEMPLATE) values (3, 'email.signup.text', 'Welcome to ...');
insert into TEMPLATE (ID, CODE, TEMPLATE) values (4, 'email.signup.html', 'Welcome to ...');
insert into TEMPLATE (ID, CODE, TEMPLATE) values (5, 'email.password.subject', 'Password subject');
insert into TEMPLATE (ID, CODE, TEMPLATE) values (6, 'email.password.text', 'Password text {{token}}');
insert into TEMPLATE (ID, CODE, TEMPLATE) values (7, 'email.password.html', 'Password HTML');
......@@ -78,6 +78,9 @@ CREATE TABLE APP_USER (
FIRST_NAME VARCHAR(250),
LAST_NAME VARCHAR(250),
TIMEZONE_ID VARCHAR(50),
LOCALE VARCHAR(50),
CONSTRAINT PK_APP_USER PRIMARY KEY(ID)
);
CREATE INDEX APP_USER_EMAIL_IDX ON APP_USER(lower(EMAIL));
......@@ -170,18 +173,18 @@ CREATE TABLE EMAIL_ATTACHMENT (
CREATE INDEX EMAIL_ATTACHMENT_IDX ON EMAIL_ATTACHMENT(EMAIL_ID);
-- CUSTOMIZABLE TEMPLATES
CREATE TABLE CUSTOMIZABLE_TEMPLATE (
-- TEMPLATES
CREATE TABLE TEMPLATE (
ID INT8 NOT NULL,
CODE VARCHAR(250),
NAME VARCHAR(100),
TEMPLATE TEXT,
CONSTRAINT PK_CUSTOMIZABLE_TEMPLATE PRIMARY KEY(ID)
CONSTRAINT PK_TEMPLATE PRIMARY KEY(ID)
);
CREATE INDEX CUSTOMIZABLE_TEMPLATE_CODE_IDX ON CUSTOMIZABLE_TEMPLATE(CODE);
CREATE INDEX TEMPLATE_CODE_IDX ON TEMPLATE(CODE);
CREATE TABLE CUSTOMIZABLE_TEMPLATE_LABEL (
......@@ -197,7 +200,7 @@ CREATE TABLE CUSTOMIZABLE_TEMPLATE_LABEL (
POSITION NUMERIC(19,0),
CONSTRAINT PK_CUSTOMIZABLE_TEMPLATE_LABEL PRIMARY KEY(ID),
CONSTRAINT FK_CUSTOMIZABLE_TEMPLATE_LABEL_TEMPLATE FOREIGN KEY (TEMPLATE_ID) REFERENCES CUSTOMIZABLE_TEMPLATE(ID)
CONSTRAINT FK_CUSTOMIZABLE_TEMPLATE_LABEL_TEMPLATE FOREIGN KEY (TEMPLATE_ID) REFERENCES TEMPLATE(ID)
);
CREATE INDEX CUSTOMIZABLE_TEMPLATE_LABEL_TEMPLATE_IDX ON CUSTOMIZABLE_TEMPLATE_LABEL(TEMPLATE_ID);
......
package com.jh.boot.security;
import com.jh.boot.security.model.AppUser;
import com.jh.boot.security.model.ResetPasswordToken;
public interface AuthServiceListener {
void registerUser(AppUser user);
void generateResetToken(AppUser user);
void generateResetToken(AppUser user, ResetPasswordToken token);
}
......@@ -66,6 +66,12 @@ public class AppUser extends AbstractIdEntity {
)
private Set<AppRole> roles;
@Column(name = "LOCALE")
private String locale;
@Column(name = "TIMEZONE_ID")
private String timezone;
/**
* Gets the email.
*
......@@ -200,4 +206,20 @@ public class AppUser extends AbstractIdEntity {
this.roles = roles;
}
public String getLocale() {
return locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
public String getTimezone() {
return timezone;
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}
}
......@@ -82,7 +82,7 @@ public class AppUserAuthService implements AuthService {
appUserRepository.saveResetPasswordToken(token);
if (authListeners != null) {
authListeners.forEach(al -> al.generateResetToken(user));
authListeners.forEach(al -> al.generateResetToken(user, token));
}
return token.getToken();
......
package com.jh.boot.security.utils;
import java.io.StringWriter;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import com.jh.boot.email.Email;
import com.jh.boot.email.EmailRecipient;
import com.jh.boot.email.EmailService;
import com.jh.boot.email.RecipientType;
import com.jh.boot.security.AuthServiceListener;
import com.jh.boot.security.model.AppUser;
import com.jh.boot.security.model.ResetPasswordToken;
import com.jh.boot.template.TemplateService;
//TODO make it configurable
public class TemplateEmailAuthServiceListener implements AuthServiceListener {
@Autowired
......@@ -23,31 +27,60 @@ public class TemplateEmailAuthServiceListener implements AuthServiceListener {
@Autowired
private TemplateService templateService;
@Value("${security.auth.template.signup:security.auth.signup}")
@Value("${template.email.layout:email.layout}")
private String layoutTemplateCode;
@Value("${template.email.signup.subject:email.signup.subject}")
private String signupSubjectCode;
@Value("${template.email.signup.text:template.email.signup.text}")
private String signupTemplateCode;
@Value("${security.auth.template.signup.html:security.auth.signup.html}")
@Value("${template.email.signup.html:template.email.signup.html}")
private String signupTemplateHtmlCode;
@Value("${security.auth.template.resetPassword:security.auth.resetPassword}")
private String resetPasswordTemplateCode;
@Value("${template.email.password.subject:email.password.subject}")
private String passwordSubjectCode;
@Value("${template.email.password.text:email.password.text}")
private String passwordTemplateCode;
@Value("${template.email.password.html:email.password.html}")
private String passwordTemplateHtmlCode;
@Override
public void registerUser(AppUser user) {
StringWriter sw = new StringWriter();
templateService.evaluate(sw, signupTemplateCode, Collections.singletonMap("user", user), Locale.ENGLISH);
Email email = new Email();
email.setText(sw.toString());
emailService.sendEmail(email);
sendEmail(signupSubjectCode, signupTemplateCode, signupTemplateHtmlCode, user, Collections.singletonMap("user", user));
}
@Override
public void generateResetToken(AppUser user) {
StringWriter sw = new StringWriter();
templateService.evaluate(sw, resetPasswordTemplateCode, Collections.singletonMap("user", user), Locale.ENGLISH);
public void generateResetToken(AppUser user, ResetPasswordToken token) {
Map<String, Object> data = new HashMap<>();
data.put("user", user);
data.put("token", token.getToken());
sendEmail(passwordSubjectCode, passwordTemplateCode, passwordTemplateHtmlCode, user, data);
}
protected void sendEmail(String subject, String content, String html, AppUser user, Map<String, Object> data) {
Locale locale = new Locale(user.getLocale());
subject = templateService.evaluate(subject, data, locale);
content = templateService.evaluate(content, data, locale);
html = templateService.evaluate(html, data, locale);
//is layout defined?
String layout = templateService.evaluate(layoutTemplateCode, Collections.singletonMap("content", html), locale);
Email email = new Email();
email.setRecipients(Collections.singleton(new EmailRecipient(user.getEmail(), RecipientType.TO)));
email.setSubject(subject);
email.setText(content);
email.setHtml(StringUtils.hasText(layout) ? layout : html);
emailService.sendEmail(email);
}
}
package com.jh.boot.template;
import org.springframework.context.annotation.Bean;
import com.jh.common.template.handlebars.HandlebarsTemplateService;
public class JhTemplateConfig {
@Bean
public TemplateLoader templateLoader() {
return null;
}
@Bean
public TemplateService templateService() {
HandlebarsTemplateService service = new HandlebarsTemplateService();
service.setTemplateLoader(templateLoader());
return service;
}
}
......@@ -3,12 +3,11 @@ package com.jh.boot.template;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Transient;
import com.jh.boot.jpa.AbstractIdEntity;
@Entity
@Table(name = "CUSTOMIZABLE_TEMPLATE")
@Table(name = "TEMPLATE")
public class Template extends AbstractIdEntity {
@Column(name = "CODE")
......@@ -20,10 +19,6 @@ public class Template extends AbstractIdEntity {
@Column(name = "TEMPLATE")
private String template;
// @Column(name = "TRANSLATE_NAME")
@Transient
private Boolean translateName;
public Template() {
super();
}
......@@ -57,13 +52,4 @@ public class Template extends AbstractIdEntity {
this.template = template;
}
public Boolean getTranslateName() {
return translateName;
}
public void setTranslateName(Boolean translateName) {
this.translateName = translateName;
}
}
......@@ -3,6 +3,6 @@ package com.jh.boot.template;
public interface TemplateLoader {
String loadTemplate(String code);
Template loadTemplate(String code);
}
package com.jh.boot.template;
import java.io.Writer;
import java.util.Locale;
import java.util.Map;
public interface TemplateService {
void evaluate(Writer writer, String templateCode, Map<String, Object> data, Locale locale);
String evaluate(String templateCode, Map<String, Object> data, Locale locale);
}
package com.jh.boot.template.customizable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import com.jh.boot.template.Template;
import com.jh.boot.template.TemplateLoader;
......@@ -11,12 +12,9 @@ public class CustomizableTemplateLoader implements TemplateLoader {
private CustomizableLabelsRepository repository;
@Override
public String loadTemplate(String code) {
Template t = repository.fetchTemplate(code);
if (t == null) {
return null;
}
return t.getTemplate();
@Transactional
public Template loadTemplate(String code) {
return repository.fetchTemplate(code);
}
}
package com.jh.boot.template.customizable;
import java.io.Writer;
import java.io.StringWriter;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
......@@ -21,7 +21,7 @@ public class CustomizableTemplateService implements TemplateService {
@Override
public void evaluate(Writer writer, String templateCode, Map<String, Object> data, Locale locale) {
public String evaluate(String templateCode, Map<String, Object> data, Locale locale) {
if (data == null) {
data = Collections.emptyMap();
}
......@@ -30,7 +30,11 @@ public class CustomizableTemplateService implements TemplateService {
data = new HashMap<String, Object>(data);
data.put("labels", labels);
StringWriter writer = new StringWriter();
engine.evaluate(writer, templateCode, data);
return writer.toString();
}
}
......@@ -157,12 +157,13 @@ public class HandlebarsTemplateEngine implements TemplateEngine {
Template template = useCache ? templateCache.get(name) : null;
if (template == null) {
String s = templateLoader.loadTemplate(templateCode);
if (s == null) {
throw new RuntimeException(String.format("Template %s not found", templateCode));
com.jh.boot.template.Template t = templateLoader.loadTemplate(templateCode);
if (t == null) {
// throw new RuntimeException(String.format("Template %s not found", templateCode));
return; //TODO log warning
}
try {
template = handlebars.compileInline(s);
template = handlebars.compileInline(t.getTemplate());
} catch (IOException e) {
throw new RuntimeException("Cannot evaluate template", e);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment