Преглед изворни кода

render messages before delivery via delegate

tags/v0.9.4^0
Jonathan Cobb пре 4 година
родитељ
комит
e7af641599
19 измењених фајлова са 234 додато и 155 уклоњено
  1. +0
    -7
      bubble-server/pom.xml
  2. +3
    -0
      bubble-server/src/main/java/bubble/cloud/DelegatedCloudServiceDriverBase.java
  3. +46
    -34
      bubble-server/src/main/java/bubble/cloud/NoopCloud.java
  4. +2
    -0
      bubble-server/src/main/java/bubble/cloud/auth/AuthenticationDriver.java
  5. +27
    -0
      bubble-server/src/main/java/bubble/cloud/auth/DelegatedAuthDriverBase.java
  6. +12
    -2
      bubble-server/src/main/java/bubble/cloud/auth/RenderedMessage.java
  7. +5
    -0
      bubble-server/src/main/java/bubble/cloud/authenticator/TOTPAuthenticatorDriver.java
  8. +7
    -10
      bubble-server/src/main/java/bubble/cloud/authenticator/delegate/DelegatedAuthenticatorDriver.java
  9. +35
    -0
      bubble-server/src/main/java/bubble/cloud/email/EmailServiceDriver.java
  10. +2
    -1
      bubble-server/src/main/java/bubble/cloud/email/RenderedEmail.java
  11. +7
    -31
      bubble-server/src/main/java/bubble/cloud/email/SmtpEmailDriver.java
  12. +12
    -14
      bubble-server/src/main/java/bubble/cloud/email/delegate/DelegatedEmailDriver.java
  13. +30
    -0
      bubble-server/src/main/java/bubble/cloud/sms/SmsServiceDriver.java
  14. +6
    -23
      bubble-server/src/main/java/bubble/cloud/sms/SmsServiceDriverBase.java
  15. +11
    -7
      bubble-server/src/main/java/bubble/cloud/sms/delegate/DelegatedSmsDriver.java
  16. +5
    -8
      bubble-server/src/main/java/bubble/notify/auth/AuthDriverNotification.java
  17. +9
    -3
      bubble-server/src/main/java/bubble/notify/auth/DelegatedAuthNotificationHandlerBase.java
  18. +1
    -1
      bubble-server/src/main/resources/META-INF/bubble/bubble.properties
  19. +14
    -14
      bubble-server/src/test/resources/models/tests/auth/forgot_password.json

+ 0
- 7
bubble-server/pom.xml Прегледај датотеку

@@ -259,13 +259,6 @@
<scope>test</scope>
</dependency>

<!--<dependency>-->
<!--<groupId>org.cobbzilla</groupId>-->
<!--<artifactId>wizard-server-test</artifactId>-->
<!--<version>1.0.0-SNAPSHOT</version>-->
<!--</dependency>-->
<!-- https://mvnrepository.com/artifact/io.swagger/swagger-jersey2-jaxrs -->

<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jersey2-jaxrs</artifactId>


+ 3
- 0
bubble-server/src/main/java/bubble/cloud/DelegatedCloudServiceDriverBase.java Прегледај датотеку

@@ -8,7 +8,9 @@ import bubble.dao.cloud.BubbleNodeDAO;
import bubble.model.cloud.BubbleNode;
import bubble.model.cloud.CloudCredentials;
import bubble.model.cloud.CloudService;
import bubble.server.BubbleConfiguration;
import bubble.service.notify.NotificationService;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;

import static bubble.model.cloud.CloudCredentials.PARAM_DELEGATE_NODE;
@@ -18,6 +20,7 @@ public abstract class DelegatedCloudServiceDriverBase extends CloudServiceDriver

protected CloudService cloud;

@Autowired @Getter protected BubbleConfiguration configuration;
@Autowired protected BubbleNodeDAO nodeDAO;
@Autowired protected NotificationService notificationService;



+ 46
- 34
bubble-server/src/main/java/bubble/cloud/NoopCloud.java Прегледај датотеку

@@ -5,11 +5,13 @@
package bubble.cloud;

import bubble.cloud.auth.AuthenticationDriver;
import bubble.cloud.auth.RenderedMessage;
import bubble.cloud.compute.ComputeNodeSize;
import bubble.cloud.compute.ComputeNodeSizeType;
import bubble.cloud.compute.ComputeServiceDriver;
import bubble.cloud.dns.DnsServiceDriver;
import bubble.cloud.email.EmailServiceDriver;
import bubble.cloud.email.RenderedEmail;
import bubble.cloud.geoCode.GeoCodeResult;
import bubble.cloud.geoCode.GeoCodeServiceDriver;
import bubble.cloud.geoLocation.GeoLocateServiceDriver;
@@ -48,7 +50,17 @@ public class NoopCloud implements
public static final String NOOP_CLOUD = NoopCloud.class.getName();

@Override public boolean send(Account account, AccountMessage message, AccountContact contact) {
if (log.isDebugEnabled()) log.debug("send( account="+ account + ")");
if (log.isDebugEnabled()) log.debug("send(account=" + account + ")");
return false;
}

@Override public RenderedEmail renderMessage(Account account, AccountMessage message, AccountContact contact) {
if (log.isDebugEnabled()) log.debug("renderMessage(account=" + account + ")");
return null;
}

@Override public boolean send(RenderedMessage renderedMessage) {
if (log.isDebugEnabled()) log.debug("send(renderedMessage=" + renderedMessage + ")");
return false;
}

@@ -58,42 +70,42 @@ public class NoopCloud implements
}

@Override public boolean _write(String fromNode, String key, InputStream data, StorageMetadata metadata, String requestId) throws IOException {
if (log.isDebugEnabled()) log.debug("_write( fromNode="+ fromNode + ")");
if (log.isDebugEnabled()) log.debug("_write(fromNode=" + fromNode + ")");
return false;
}

@Override public boolean canWrite(String fromNode, String toNode, String key) {
if (log.isDebugEnabled()) log.debug("canWrite( fromNode="+ fromNode + ")");
if (log.isDebugEnabled()) log.debug("canWrite(fromNode=" + fromNode + ")");
return false;
}

@Override public boolean delete(String fromNode, String uri) {
if (log.isDebugEnabled()) log.debug("delete( fromNode="+ fromNode + ")");
if (log.isDebugEnabled()) log.debug("delete(fromNode=" + fromNode + ")");
return false;
}

@Override public boolean deleteNetwork(String networkUuid) throws IOException {
if (log.isDebugEnabled()) log.debug("deleteNetwork( networkUuid="+ networkUuid + ")");
if (log.isDebugEnabled()) log.debug("deleteNetwork(networkUuid=" + networkUuid + ")");
return false;
}

@Override public boolean rekey(String fromNode, CloudService newCloud) throws IOException {
if (log.isDebugEnabled()) log.debug("rekey( fromNode="+ fromNode + ")");
if (log.isDebugEnabled()) log.debug("rekey(fromNode=" + fromNode + ")");
return false;
}

@Override public StorageListing list(String fromNode, String prefix) throws IOException {
if (log.isDebugEnabled()) log.debug("list( fromNode="+ fromNode + ")");
if (log.isDebugEnabled()) log.debug("list(fromNode=" + fromNode + ")");
return null;
}

@Override public StorageListing listNext(String fromNode, String listingId) throws IOException {
if (log.isDebugEnabled()) log.debug("listNext( fromNode="+ fromNode + ")");
if (log.isDebugEnabled()) log.debug("listNext(fromNode=" + fromNode + ")");
return null;
}

@Override public void setConfig(JsonNode json, CloudService cloudService) {
if (log.isDebugEnabled()) log.debug("setConfig( json="+ json + ")");
if (log.isDebugEnabled()) log.debug("setConfig(json=" + json + ")");

}

@@ -103,7 +115,7 @@ public class NoopCloud implements
}

@Override public void setCredentials(CloudCredentials creds) {
if (log.isDebugEnabled()) log.debug("setCredentials( creds="+ creds + ")");
if (log.isDebugEnabled()) log.debug("setCredentials(creds=" + creds + ")");

}

@@ -113,17 +125,17 @@ public class NoopCloud implements
}

@Override public boolean _exists(String fromNode, String key) throws IOException {
if (log.isDebugEnabled()) log.debug("_exists( fromNode="+ fromNode + ")");
if (log.isDebugEnabled()) log.debug("_exists(fromNode=" + fromNode + ")");
return false;
}

@Override public StorageMetadata readMetadata(String fromNode, String key) {
if (log.isDebugEnabled()) log.debug("readMetadata( fromNode="+ fromNode + ")");
if (log.isDebugEnabled()) log.debug("readMetadata(fromNode=" + fromNode + ")");
return null;
}

@Override public InputStream _read(String fromNode, String key) throws IOException {
if (log.isDebugEnabled()) log.debug("_read( fromNode="+ fromNode + ")");
if (log.isDebugEnabled()) log.debug("_read(fromNode=" + fromNode + ")");
return null;
}

@@ -133,77 +145,77 @@ public class NoopCloud implements
}

@Override public PaymentValidationResult validate(AccountPaymentMethod paymentMethod) {
if (log.isDebugEnabled()) log.debug("validate( paymentMethod="+ paymentMethod + ")");
if (log.isDebugEnabled()) log.debug("validate(paymentMethod=" + paymentMethod + ")");
return null;
}

@Override public boolean authorize(BubblePlan plan, String accountPlanUuid, String billUuid, AccountPaymentMethod paymentMethod) {
if (log.isDebugEnabled()) log.debug("authorize( plan="+ plan + ")");
if (log.isDebugEnabled()) log.debug("authorize(plan=" + plan + ")");
return false;
}

@Override public boolean cancelAuthorization(BubblePlan plan, String accountPlanUuid, AccountPaymentMethod paymentMethod) {
if (log.isDebugEnabled()) log.debug("cancelAuthorization( plan="+ plan + ")");
if (log.isDebugEnabled()) log.debug("cancelAuthorization(plan=" + plan + ")");
return false;
}

@Override public boolean purchase(String accountPlanUuid, String paymentMethodUuid, String billUuid) {
if (log.isDebugEnabled()) log.debug("purchase( accountPlanUuid="+ accountPlanUuid + ")");
if (log.isDebugEnabled()) log.debug("purchase(accountPlanUuid=" + accountPlanUuid + ")");
return false;
}

@Override public boolean refund(String accountPlanUuid) {
if (log.isDebugEnabled()) log.debug("refund( accountPlanUuid="+ accountPlanUuid + ")");
if (log.isDebugEnabled()) log.debug("refund(accountPlanUuid=" + accountPlanUuid + ")");
return false;
}

@Override public GeoTimeZone getTimezone(String lat, String lon) {
if (log.isDebugEnabled()) log.debug("getTimezone( lat="+ lat + ")");
if (log.isDebugEnabled()) log.debug("getTimezone(lat=" + lat + ")");
return null;
}

@Override public GeoLocation geolocate(String ip) {
if (log.isDebugEnabled()) log.debug("geolocate( ip="+ ip + ")");
if (log.isDebugEnabled()) log.debug("geolocate(ip=" + ip + ")");
return null;
}

@Override public GeoCodeResult lookup(GeoLocation location) {
if (log.isDebugEnabled()) log.debug("lookup( location="+ location + ")");
if (log.isDebugEnabled()) log.debug("lookup(location=" + location + ")");
return null;
}

@Override public Collection<DnsRecord> create(BubbleDomain domain) {
if (log.isDebugEnabled()) log.debug("create( domain="+ domain + ")");
if (log.isDebugEnabled()) log.debug("create(domain=" + domain + ")");
return null;
}

@Override public Collection<DnsRecord> setNetwork(BubbleNetwork network) {
if (log.isDebugEnabled()) log.debug("setNetwork( network="+ network + ")");
if (log.isDebugEnabled()) log.debug("setNetwork(network=" + network + ")");
return null;
}

@Override public Collection<DnsRecord> setNode(BubbleNode node) {
if (log.isDebugEnabled()) log.debug("setNode( node="+ node + ")");
if (log.isDebugEnabled()) log.debug("setNode(node=" + node + ")");
return null;
}

@Override public Collection<DnsRecord> deleteNode(BubbleNode node) {
if (log.isDebugEnabled()) log.debug("deleteNode( node="+ node + ")");
if (log.isDebugEnabled()) log.debug("deleteNode(node=" + node + ")");
return null;
}

@Override public DnsRecord update(DnsRecord record) {
if (log.isDebugEnabled()) log.debug("update( record="+ record + ")");
if (log.isDebugEnabled()) log.debug("update(record=" + record + ")");
return null;
}

@Override public DnsRecord remove(DnsRecord record) {
if (log.isDebugEnabled()) log.debug("remove( record="+ record + ")");
if (log.isDebugEnabled()) log.debug("remove(record=" + record + ")");
return null;
}

@Override public Collection<DnsRecord> list(DnsRecordMatch matcher) {
if (log.isDebugEnabled()) log.debug("list( matcher="+ matcher + ")");
if (log.isDebugEnabled()) log.debug("list(matcher=" + matcher + ")");
return null;
}

@@ -213,27 +225,27 @@ public class NoopCloud implements
}

@Override public ComputeNodeSize getSize(ComputeNodeSizeType type) {
if (log.isDebugEnabled()) log.debug("getSize( type="+ type + ")");
if (log.isDebugEnabled()) log.debug("getSize(type=" + type + ")");
return null;
}

@Override public BubbleNode start(BubbleNode node) throws Exception {
if (log.isDebugEnabled()) log.debug("start( node="+ node + ")");
if (log.isDebugEnabled()) log.debug("start(node=" + node + ")");
return null;
}

@Override public BubbleNode cleanupStart(BubbleNode node) throws Exception {
if (log.isDebugEnabled()) log.debug("cleanupStart( node="+ node + ")");
if (log.isDebugEnabled()) log.debug("cleanupStart(node=" + node + ")");
return null;
}

@Override public BubbleNode stop(BubbleNode node) throws Exception {
if (log.isDebugEnabled()) log.debug("stop( node="+ node + ")");
if (log.isDebugEnabled()) log.debug("stop(node=" + node + ")");
return null;
}

@Override public BubbleNode status(BubbleNode node) throws Exception {
if (log.isDebugEnabled()) log.debug("status( node="+ node + ")");
if (log.isDebugEnabled()) log.debug("status(node=" + node + ")");
return null;
}

@@ -243,7 +255,7 @@ public class NoopCloud implements
}

@Override public CloudRegion getRegion(String region) {
if (log.isDebugEnabled()) log.debug("getRegion( region="+ region + ")");
if (log.isDebugEnabled()) log.debug("getRegion(region=" + region + ")");
return null;
}
}

+ 2
- 0
bubble-server/src/main/java/bubble/cloud/auth/AuthenticationDriver.java Прегледај датотеку

@@ -46,6 +46,8 @@ public interface AuthenticationDriver extends CloudServiceDriver {

boolean send(Account account, AccountMessage message, AccountContact contact);

boolean send(RenderedMessage renderedMessage);

@Override default boolean test () { return true; }

default Map<String, Object> buildContext(Account account, AccountMessage message, AccountContact contact) {


+ 27
- 0
bubble-server/src/main/java/bubble/cloud/auth/DelegatedAuthDriverBase.java Прегледај датотеку

@@ -5,8 +5,14 @@
package bubble.cloud.auth;

import bubble.cloud.DelegatedCloudServiceDriverBase;
import bubble.model.cloud.BubbleNode;
import bubble.model.cloud.CloudService;
import bubble.model.cloud.notify.NotificationType;
import bubble.notify.auth.AuthDriverNotification;
import bubble.notify.email.EmailDriverNotification;
import com.fasterxml.jackson.databind.JsonNode;

import static org.cobbzilla.util.json.JsonUtil.json;

public abstract class DelegatedAuthDriverBase extends DelegatedCloudServiceDriverBase implements AuthenticationDriver {

@@ -14,4 +20,25 @@ public abstract class DelegatedAuthDriverBase extends DelegatedCloudServiceDrive

protected AuthDriverNotification notification(AuthDriverNotification n) { return n.setAuthService(cloud.getDelegated()); }

protected abstract NotificationType getSendNotificationType();

protected abstract Class<? extends RenderedMessage> getRenderedMessageClass();

protected abstract String getDefaultTemplatePath();

@Override public String getTemplatePath() {
final JsonNode driverConfig = cloud.getDriverConfig();
return driverConfig != null && driverConfig.has("templatePath")
? driverConfig.get("templatePath").textValue()
: getDefaultTemplatePath();
}

@Override public boolean send(RenderedMessage message) {
final BubbleNode delegate = getDelegateNode();
if (!configuration.testMode()) message.getCtx().clear();
return notificationService.notifySync(delegate, getSendNotificationType(), notification(new EmailDriverNotification()
.setRenderedMessage(json(json(message), JsonNode.class))
.setRenderedMessageClass(getRenderedMessageClass().getName())));
}

}

+ 12
- 2
bubble-server/src/main/java/bubble/cloud/auth/RenderedMessage.java Прегледај датотеку

@@ -18,6 +18,8 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;

import static bubble.ApiConstants.ALWAYS_TRUE;
import static org.cobbzilla.util.daemon.ZillaRuntime.die;
import static org.cobbzilla.util.json.JsonUtil.json;

public interface RenderedMessage {

@@ -27,9 +29,10 @@ public interface RenderedMessage {
Comparator<RenderedMessage> SORT_CTIME_ASC = Comparator.comparingLong(RenderedMessage::getCtime);

Map<String, Object> getCtx();

long getCtime();

default <T> T del(String key) { getCtx().remove(key); return (T) this; }
default <T> T del(String key) { if (getCtx() != null) getCtx().remove(key); return (T) this; }

default boolean hasContext(String key, String val) {
if (getCtx() == null) return false;
@@ -42,7 +45,14 @@ public interface RenderedMessage {
}
}

@JsonIgnore default AccountMessage getAccountMessage() { return (AccountMessage) getCtx().get("message"); }
@JsonIgnore default AccountMessage getAccountMessage() {
final Object obj = getCtx() == null ? null : getCtx().get("message");
if (obj == null) return null;
if (obj instanceof AccountMessage) return (AccountMessage) obj;
if (obj instanceof Map) return json(json(obj), AccountMessage.class);
return die("getAccountMessage: unrecognized 'message' object: "+obj);
}

@JsonIgnore default AccountMessageType getMessageType() { return getAccountMessage().getMessageType(); }
@JsonIgnore default AccountAction getAction() { return getAccountMessage().getAction(); }
@JsonIgnore default ActionTarget getTarget() { return getAccountMessage().getTarget(); }


+ 5
- 0
bubble-server/src/main/java/bubble/cloud/authenticator/TOTPAuthenticatorDriver.java Прегледај датотеку

@@ -4,6 +4,7 @@
*/
package bubble.cloud.authenticator;

import bubble.cloud.auth.RenderedMessage;
import bubble.dao.account.AccountPolicyDAO;
import bubble.model.account.Account;
import bubble.model.account.AccountContact;
@@ -11,6 +12,8 @@ import bubble.model.account.message.AccountMessage;
import bubble.service.account.StandardAccountMessageService;
import org.springframework.beans.factory.annotation.Autowired;

import static org.cobbzilla.util.daemon.ZillaRuntime.notSupported;

public class TOTPAuthenticatorDriver implements AuthenticatorServiceDriver {

@Override public boolean disableDelegation() { return true; }
@@ -23,4 +26,6 @@ public class TOTPAuthenticatorDriver implements AuthenticatorServiceDriver {
return true;
}

@Override public boolean send(RenderedMessage renderedMessage) { return notSupported("send"); }

}

+ 7
- 10
bubble-server/src/main/java/bubble/cloud/authenticator/delegate/DelegatedAuthenticatorDriver.java Прегледај датотеку

@@ -5,26 +5,23 @@
package bubble.cloud.authenticator.delegate;

import bubble.cloud.auth.DelegatedAuthDriverBase;
import bubble.cloud.auth.RenderedMessage;
import bubble.cloud.authenticator.AuthenticatorServiceDriver;
import bubble.model.account.Account;
import bubble.model.account.AccountContact;
import bubble.model.account.message.AccountMessage;
import bubble.model.cloud.BubbleNode;
import bubble.model.cloud.CloudService;
import bubble.notify.authenticator.AuthenticatorDriverNotification;
import bubble.model.cloud.notify.NotificationType;

import static bubble.model.cloud.notify.NotificationType.authenticator_driver_send;
import static org.cobbzilla.util.daemon.ZillaRuntime.notSupported;

public class DelegatedAuthenticatorDriver extends DelegatedAuthDriverBase implements AuthenticatorServiceDriver {

public DelegatedAuthenticatorDriver(CloudService cloud) { super(cloud); }

@Override public boolean send(Account account, AccountMessage message, AccountContact contact) {
final BubbleNode delegate = getDelegateNode();
return notificationService.notifySync(delegate, authenticator_driver_send, notification(new AuthenticatorDriverNotification()
.setAccount(account)
.setMessage(message)
.setContact(contact)));
}
@Override protected String getDefaultTemplatePath() { return notSupported("getDefaultTemplatePath"); }
@Override protected NotificationType getSendNotificationType() { return notSupported("getSendNotificationType"); }
@Override protected Class<? extends RenderedMessage> getRenderedMessageClass() { return notSupported("getRenderedMessageClass"); }
@Override public boolean send(Account account, AccountMessage message, AccountContact contact) { return notSupported("send"); }

}

+ 35
- 0
bubble-server/src/main/java/bubble/cloud/email/EmailServiceDriver.java Прегледај датотеку

@@ -6,9 +6,44 @@ package bubble.cloud.email;

import bubble.cloud.CloudServiceType;
import bubble.cloud.auth.AuthenticationDriver;
import bubble.model.account.Account;
import bubble.model.account.AccountContact;
import bubble.model.account.message.AccountMessage;
import bubble.server.BubbleConfiguration;

import java.util.Map;

public interface EmailServiceDriver extends AuthenticationDriver {

@Override default CloudServiceType getType() { return CloudServiceType.email; }

static boolean send(EmailServiceDriver driver, Account account, AccountMessage message, AccountContact contact) {
final RenderedEmail email = driver.renderMessage(account, message, contact);
return driver.send(email);
}

default RenderedEmail renderMessage(Account account, AccountMessage message, AccountContact contact) {
return renderMessage(account, message, contact, getConfiguration(), getTemplatePath());
}

static RenderedEmail renderMessage(Account account, AccountMessage message, AccountContact contact,
BubbleConfiguration configuration, String templatePath) {
final Map<String, Object> ctx = AuthenticationDriver.buildContext(account, message, contact, configuration);

final RenderedEmail email = new RenderedEmail(ctx);
email.setToEmail(contact.getInfo());
email.setToName(account.getName());
email.setFromEmail(AuthenticationDriver.render("fromEmail", ctx, message, configuration, templatePath));
email.setFromName(AuthenticationDriver.render("fromName", ctx, message, configuration, templatePath));
email.setSubject(AuthenticationDriver.render("subject", ctx, message, configuration, templatePath));
email.setMessage(AuthenticationDriver.render("message", ctx, message, configuration, templatePath));
try {
email.setHtmlMessage(AuthenticationDriver.render("htmlMessage", ctx, message, configuration, templatePath));
} catch (Exception e) {
log.debug("Error loading htmlMessage for "+message.templateName("htmlMessage")+": "+e);
}
return email;
}


}

+ 2
- 1
bubble-server/src/main/java/bubble/cloud/email/RenderedEmail.java Прегледај датотеку

@@ -8,6 +8,7 @@ import bubble.cloud.auth.RenderedMessage;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.cobbzilla.mail.SimpleEmailMessage;

import java.util.Map;
@@ -16,7 +17,7 @@ import static java.util.UUID.randomUUID;
import static org.cobbzilla.util.daemon.ZillaRuntime.now;
import static org.cobbzilla.util.reflect.ReflectionUtil.copy;

@NoArgsConstructor
@NoArgsConstructor @Accessors(chain=true)
public class RenderedEmail extends SimpleEmailMessage implements RenderedMessage {

@Getter private long ctime = now();


+ 7
- 31
bubble-server/src/main/java/bubble/cloud/email/SmtpEmailDriver.java Прегледај датотеку

@@ -5,7 +5,7 @@
package bubble.cloud.email;

import bubble.cloud.CloudServiceDriverBase;
import bubble.cloud.auth.AuthenticationDriver;
import bubble.cloud.auth.RenderedMessage;
import bubble.cloud.email.mock.MockMailSender;
import bubble.model.account.Account;
import bubble.model.account.AccountContact;
@@ -13,12 +13,9 @@ import bubble.model.account.message.AccountMessage;
import bubble.server.BubbleConfiguration;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.mail.SimpleEmailMessage;
import org.cobbzilla.mail.sender.SmtpMailSender;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Map;

@Slf4j
public class SmtpEmailDriver extends CloudServiceDriverBase<EmailDriverConfig> implements EmailServiceDriver {

@@ -42,40 +39,19 @@ public class SmtpEmailDriver extends CloudServiceDriverBase<EmailDriverConfig> i
}

@Override public boolean send(Account account, AccountMessage message, AccountContact contact) {
return EmailServiceDriver.send(this, account, message, contact);
}

@Override public boolean send(RenderedMessage email) {
try {
final SimpleEmailMessage email = renderMessage(account, message, contact);
log.debug("send: sending message "+getSender().getClass().getName()+": "+email);
getSender().send(email);
getSender().send((RenderedEmail) email);
return true;
} catch (Exception e) {
log.error("send failed: "+e);
return false;
}
return true;
}

@Override public String getTemplatePath() { return config.getTemplatePath(); }

public SimpleEmailMessage renderMessage(Account account, AccountMessage message, AccountContact contact) {
return renderMessage(account, message, contact, configuration, getTemplatePath());
}

public static SimpleEmailMessage renderMessage(Account account, AccountMessage message, AccountContact contact,
BubbleConfiguration configuration, String templatePath) {
final Map<String, Object> ctx = AuthenticationDriver.buildContext(account, message, contact, configuration);

final SimpleEmailMessage email = new RenderedEmail(ctx);
email.setToEmail(contact.getInfo());
email.setToName(account.getName());
email.setFromEmail(AuthenticationDriver.render("fromEmail", ctx, message, configuration, templatePath));
email.setFromName(AuthenticationDriver.render("fromName", ctx, message, configuration, templatePath));
email.setSubject(AuthenticationDriver.render("subject", ctx, message, configuration, templatePath));
email.setMessage(AuthenticationDriver.render("message", ctx, message, configuration, templatePath));
try {
email.setHtmlMessage(AuthenticationDriver.render("htmlMessage", ctx, message, configuration, templatePath));
} catch (Exception e) {
log.debug("Error loading htmlMessage for "+message.templateName("htmlMessage")+": "+e);
}
return email;
}

}

+ 12
- 14
bubble-server/src/main/java/bubble/cloud/email/delegate/DelegatedEmailDriver.java Прегледај датотеку

@@ -5,22 +5,20 @@
package bubble.cloud.email.delegate;

import bubble.cloud.auth.DelegatedAuthDriverBase;
import bubble.cloud.auth.RenderedMessage;
import bubble.cloud.email.EmailDriverConfig;
import bubble.cloud.email.EmailServiceDriver;
import bubble.cloud.email.RenderedEmail;
import bubble.cloud.email.mock.MockMailSender;
import bubble.model.account.Account;
import bubble.model.account.AccountContact;
import bubble.model.account.message.AccountMessage;
import bubble.model.cloud.BubbleNode;
import bubble.model.cloud.CloudService;
import bubble.notify.email.EmailDriverNotification;
import bubble.server.BubbleConfiguration;
import lombok.Getter;
import bubble.model.cloud.notify.NotificationType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.mail.EmailException;
import org.springframework.beans.factory.annotation.Autowired;

import static bubble.cloud.email.EmailDriverConfig.DEFAULT_TEMPLATE_PATH;
import static bubble.cloud.email.SmtpEmailDriver.renderMessage;
import static bubble.model.cloud.notify.NotificationType.email_driver_send;
import static org.cobbzilla.mail.sender.SmtpMailSender.isTestDomain;
import static org.cobbzilla.util.daemon.ZillaRuntime.die;
@@ -32,25 +30,25 @@ public class DelegatedEmailDriver extends DelegatedAuthDriverBase implements Ema

private final MockMailSender mockMailSender = new MockMailSender();

@Getter @Autowired private BubbleConfiguration configuration;

@Override public boolean send(Account account, AccountMessage message, AccountContact contact) {
if (isTestDomain(contact.getInfo())) return sendToMock(account, message, contact);
final BubbleNode delegate = getDelegateNode();
return notificationService.notifySync(delegate, email_driver_send, notification(new EmailDriverNotification()
.setAccount(account)
.setMessage(message)
.setContact(contact)));
return EmailServiceDriver.send(this, account, message, contact);
}

public boolean sendToMock(Account account, AccountMessage message, AccountContact contact) {
try {
log.info("send: sending to MockMailSender: "+message);
mockMailSender.send(renderMessage(account, message, contact, getConfiguration(), DEFAULT_TEMPLATE_PATH));
mockMailSender.send(EmailServiceDriver.renderMessage(account, message, contact, getConfiguration(), DEFAULT_TEMPLATE_PATH));
} catch (EmailException e) {
return die("send: "+e, e);
}
return true;
}

@Override protected String getDefaultTemplatePath() { return EmailDriverConfig.DEFAULT_TEMPLATE_PATH; }

@Override public NotificationType getSendNotificationType() { return email_driver_send; }

@Override protected Class<? extends RenderedMessage> getRenderedMessageClass() { return RenderedEmail.class; }

}

+ 30
- 0
bubble-server/src/main/java/bubble/cloud/sms/SmsServiceDriver.java Прегледај датотеку

@@ -6,9 +6,39 @@ package bubble.cloud.sms;

import bubble.cloud.CloudServiceType;
import bubble.cloud.auth.AuthenticationDriver;
import bubble.model.account.Account;
import bubble.model.account.AccountContact;
import bubble.model.account.message.AccountMessage;
import org.cobbzilla.util.string.LocaleUtil;

import java.util.Map;

import static bubble.cloud.auth.SmsAuthFieldHandler.formatPhoneForCountry;
import static org.cobbzilla.util.daemon.ZillaRuntime.die;

public interface SmsServiceDriver extends AuthenticationDriver {

@Override default CloudServiceType getType() { return CloudServiceType.sms; }

static boolean send(SmsServiceDriver driver, Account account, AccountMessage message, AccountContact contact) {
final String info = contact.getInfo();
final int colonPos = info.indexOf(':');
if (colonPos == -1 || colonPos == info.length()-1) return die("send: invalid number: "+ info);

final String country = info.substring(0, colonPos);
final String toPhone = formatPhoneForCountry(country, info.substring(colonPos+1));
final String prefix = LocaleUtil.getPhoneCode(country);
if (prefix == null) return die("send: no telephone prefix found for country: "+country);

final String dest = "+" + prefix + toPhone;
final Map<String, Object> ctx = driver.buildContext(account, message, contact);
final String text = driver.render("message", ctx, message);

final RenderedSms renderedSms = new RenderedSms(ctx)
.setToNumber(dest)
.setText(text);

return driver.send(renderedSms);
}

}

+ 6
- 23
bubble-server/src/main/java/bubble/cloud/sms/SmsServiceDriverBase.java Прегледај датотеку

@@ -4,6 +4,7 @@
*/
package bubble.cloud.sms;

import bubble.cloud.auth.RenderedMessage;
import bubble.model.account.Account;
import bubble.model.account.AccountContact;
import bubble.model.account.message.AccountMessage;
@@ -13,12 +14,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.util.string.LocaleUtil;

import java.util.Map;

import static bubble.cloud.auth.SmsAuthFieldHandler.formatPhoneForCountry;
import static org.cobbzilla.util.daemon.ZillaRuntime.die;
import static org.cobbzilla.util.json.JsonUtil.json;
import static org.cobbzilla.util.reflect.ReflectionUtil.getFirstTypeParam;

@@ -40,24 +36,11 @@ public abstract class SmsServiceDriverBase<T extends SmsConfig> implements SmsSe
protected abstract boolean deliver(RenderedSms sms);

@Override public boolean send(Account account, AccountMessage message, AccountContact contact) {

final String info = contact.getInfo();
final int colonPos = info.indexOf(':');
if (colonPos == -1 || colonPos == info.length()-1) return die("send: invalid number: "+ info);

final String country = info.substring(0, colonPos);
final String toPhone = formatPhoneForCountry(country, info.substring(colonPos+1));
final String prefix = LocaleUtil.getPhoneCode(country);
if (prefix == null) return die("send: no telephone prefix found for country: "+country);

final String dest = "+" + prefix + toPhone;
final Map<String, Object> ctx = buildContext(account, message, contact);
final String text = render("message", ctx, message);

return deliver(new RenderedSms(ctx)
.setFromNumber(getFromPhone())
.setToNumber(dest)
.setText(text));
return SmsServiceDriver.send(this, account, message, contact);
}

@Override public boolean send(RenderedMessage renderedMessage) {
final RenderedSms sms = (RenderedSms) renderedMessage;
return deliver(sms.setFromNumber(getFromPhone()));
}
}

+ 11
- 7
bubble-server/src/main/java/bubble/cloud/sms/delegate/DelegatedSmsDriver.java Прегледај датотеку

@@ -5,13 +5,15 @@
package bubble.cloud.sms.delegate;

import bubble.cloud.auth.DelegatedAuthDriverBase;
import bubble.cloud.auth.RenderedMessage;
import bubble.cloud.sms.RenderedSms;
import bubble.cloud.sms.SmsConfig;
import bubble.cloud.sms.SmsServiceDriver;
import bubble.model.account.Account;
import bubble.model.account.AccountContact;
import bubble.model.account.message.AccountMessage;
import bubble.model.cloud.BubbleNode;
import bubble.model.cloud.CloudService;
import bubble.notify.email.EmailDriverNotification;
import bubble.model.cloud.notify.NotificationType;

import static bubble.model.cloud.notify.NotificationType.sms_driver_send;

@@ -20,11 +22,13 @@ public class DelegatedSmsDriver extends DelegatedAuthDriverBase implements SmsSe
public DelegatedSmsDriver(CloudService cloud) { super(cloud); }

@Override public boolean send(Account account, AccountMessage message, AccountContact contact) {
final BubbleNode delegate = getDelegateNode();
return notificationService.notifySync(delegate, sms_driver_send, notification(new EmailDriverNotification()
.setAccount(account)
.setMessage(message)
.setContact(contact)));
return SmsServiceDriver.send(this, account, message, contact);
}

@Override protected String getDefaultTemplatePath() { return SmsConfig.DEFAULT_TEMPLATE_PATH; }

@Override protected NotificationType getSendNotificationType() { return sms_driver_send; }

@Override protected Class<? extends RenderedMessage> getRenderedMessageClass() { return RenderedSms.class; }

}

+ 5
- 8
bubble-server/src/main/java/bubble/notify/auth/AuthDriverNotification.java Прегледај датотеку

@@ -4,25 +4,22 @@
*/
package bubble.notify.auth;

import bubble.model.account.Account;
import bubble.model.account.AccountContact;
import bubble.model.account.message.AccountMessage;
import bubble.notify.SynchronousNotification;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

import static org.cobbzilla.util.daemon.ZillaRuntime.hashOf;
import static org.cobbzilla.util.json.JsonUtil.json;

@Accessors(chain=true)
public class AuthDriverNotification extends SynchronousNotification {

@Getter @Setter private String authService;
@Getter @Setter private Account account;
@Getter @Setter private AccountMessage message;
@Getter @Setter private AccountContact contact;
@Getter @Setter private JsonNode renderedMessage;
@Getter @Setter private String renderedMessageClass;

@Getter(lazy=true) private final String cacheKey
= hashOf(authService, account != null ? account.getUuid() : null, message != null ? message.getCacheKey() : null, contact != null ? contact.getCacheKey() : null);
@Getter(lazy=true) private final String cacheKey = hashOf(authService, renderedMessage != null ? json(renderedMessage) : null);

}

+ 9
- 3
bubble-server/src/main/java/bubble/notify/auth/DelegatedAuthNotificationHandlerBase.java Прегледај датотеку

@@ -5,6 +5,7 @@
package bubble.notify.auth;

import bubble.cloud.auth.AuthenticationDriver;
import bubble.cloud.auth.RenderedMessage;
import bubble.dao.cloud.BubbleNodeDAO;
import bubble.dao.cloud.CloudServiceDAO;
import bubble.model.cloud.BubbleNode;
@@ -17,12 +18,15 @@ import org.springframework.beans.factory.annotation.Autowired;

import static org.cobbzilla.util.daemon.ZillaRuntime.die;
import static org.cobbzilla.util.json.JsonUtil.json;
import static org.cobbzilla.util.reflect.ReflectionUtil.forName;

public abstract class DelegatedAuthNotificationHandlerBase extends DelegatedNotificationHandlerBase {

@Autowired private BubbleNodeDAO nodeDAO;
@Autowired private CloudServiceDAO cloudDAO;

protected abstract NotificationType getResponseType();

@Override public void handleNotification(ReceivedNotification n) {
final BubbleNode sender = nodeDAO.findByUuid(n.getFromNode());
if (sender == null) die("sender not found: "+n.getFromNode());
@@ -31,11 +35,13 @@ public abstract class DelegatedAuthNotificationHandlerBase extends DelegatedNoti
final CloudService authService = cloudDAO.findByUuid(notification.getAuthService());

final AuthenticationDriver driver = authService.getAuthenticationDriver(configuration);
final boolean sent = driver.send(notification.getAccount(), notification.getMessage(), notification.getContact());

final Class<? extends RenderedMessage> renderedMessageClass = forName(notification.getRenderedMessageClass());
final RenderedMessage renderedMessage = json(notification.getRenderedMessage(), renderedMessageClass);

final boolean sent = driver.send(renderedMessage);

notifySender(getResponseType(), n.getNotificationId(), sender, sent);
}

protected abstract NotificationType getResponseType();

}

+ 1
- 1
bubble-server/src/main/resources/META-INF/bubble/bubble.properties Прегледај датотеку

@@ -1 +1 @@
bubble.version=0.9.3
bubble.version=0.9.4

+ 14
- 14
bubble-server/src/test/resources/models/tests/auth/forgot_password.json Прегледај датотеку

@@ -50,9 +50,9 @@
"response": {
"store": "smsInbox",
"check": [
{"condition": "'{{json.[0].ctx.message.messageType}}' == 'request'"},
{"condition": "'{{json.[0].ctx.message.action}}' == 'verify'"},
{"condition": "'{{json.[0].ctx.message.target}}' == 'account'"}
{"condition": "'{{json.[0].ctx.message.messageType}}' === 'request'"},
{"condition": "'{{json.[0].ctx.message.action}}' === 'verify'"},
{"condition": "'{{json.[0].ctx.message.target}}' === 'account'"}
]
}
},
@@ -89,10 +89,10 @@
"response": {
"store": "emailInbox",
"check": [
{"condition": "json.length == 1"},
{"condition": "'{{json.[0].ctx.message.messageType}}' == 'request'"},
{"condition": "'{{json.[0].ctx.message.action}}' == 'password'"},
{"condition": "'{{json.[0].ctx.message.target}}' == 'account'"}
{"condition": "json.length === 1"},
{"condition": "'{{json.[0].ctx.message.messageType}}' === 'request'"},
{"condition": "'{{json.[0].ctx.message.action}}' === 'password'"},
{"condition": "'{{json.[0].ctx.message.target}}' === 'account'"}
]
}
},
@@ -106,10 +106,10 @@
"response": {
"store": "smsInbox",
"check": [
{"condition": "json.length == 1"},
{"condition": "'{{json.[0].ctx.message.messageType}}' == 'request'"},
{"condition": "'{{json.[0].ctx.message.action}}' == 'password'"},
{"condition": "'{{json.[0].ctx.message.target}}' == 'account'"}
{"condition": "json.length === 1"},
{"condition": "'{{json.[0].ctx.message.messageType}}' === 'request'"},
{"condition": "'{{json.[0].ctx.message.action}}' === 'password'"},
{"condition": "'{{json.[0].ctx.message.target}}' === 'account'"}
]
}
},
@@ -143,8 +143,8 @@
"response": {
"check": [
{"condition": "json.getMultifactorAuth() != null"},
{"condition": "json.getMultifactorAuth().length == 1"},
{"condition": "json.getMultifactorAuth()[0].getType().name() == 'sms'"}
{"condition": "json.getMultifactorAuth().length === 1"},
{"condition": "json.getMultifactorAuth()[0].getType().name() === 'sms'"}
]
}
},
@@ -197,7 +197,7 @@
"comment": "view current user",
"request": { "uri": "me" },
"response": {
"check": [ {"condition": "json.getName() == '{{userAccount.name}}'"} ]
"check": [ {"condition": "json.getName() === '{{userAccount.name}}'"} ]
}
}
]

Loading…
Откажи
Сачувај