@@ -28,7 +28,10 @@ import static bubble.server.BubbleServer.isRestoreMode; | |||||
public class BubbleAuthFilter extends AuthFilter<Account> { | public class BubbleAuthFilter extends AuthFilter<Account> { | ||||
public static final Set<String> SKIP_AUTH_PREFIXES = new HashSet<>(Arrays.asList( | public static final Set<String> SKIP_AUTH_PREFIXES = new HashSet<>(Arrays.asList( | ||||
AUTH_ENDPOINT, ENTITY_CONFIGS_ENDPOINT, BUBBLE_MAGIC_ENDPOINT, MESSAGES_ENDPOINT, TIMEZONES_ENDPOINT, | |||||
AUTH_ENDPOINT, ENTITY_CONFIGS_ENDPOINT, | |||||
PLANS_ENDPOINT, PAYMENT_METHODS_ENDPOINT, | |||||
BUBBLE_MAGIC_ENDPOINT, | |||||
MESSAGES_ENDPOINT, TIMEZONES_ENDPOINT, | |||||
NOTIFY_ENDPOINT, FILTER_HTTP_ENDPOINT, DETECT_ENDPOINT | NOTIFY_ENDPOINT, FILTER_HTTP_ENDPOINT, DETECT_ENDPOINT | ||||
)); | )); | ||||
public static final Set<String> SKIP_AUTH_PATHS = new SingletonSet<>(AUTH_ENDPOINT); | public static final Set<String> SKIP_AUTH_PATHS = new SingletonSet<>(AUTH_ENDPOINT); | ||||
@@ -110,9 +110,18 @@ public class StripePaymentDriver extends PaymentDriverBase<StripePaymentDriverCo | |||||
final AccountPolicy policy = policyDAO.findSingleByAccount(accountPaymentMethod.getAccount()); | final AccountPolicy policy = policyDAO.findSingleByAccount(accountPaymentMethod.getAccount()); | ||||
if (policy == null) return new PaymentValidationResult("err.paymentInfo.emailRequired"); | if (policy == null) return new PaymentValidationResult("err.paymentInfo.emailRequired"); | ||||
final String email = policy.getFirstVerifiedEmail(); | |||||
if (email == null && policy.getFirstEmail() != null) { | |||||
return new PaymentValidationResult("err.paymentInfo.verifiedEmailRequired"); | |||||
final String email; | |||||
if (accountPaymentMethod.requireValidatedEmail()) { | |||||
email = policy.getFirstVerifiedEmail(); | |||||
if (email == null && policy.getFirstEmail() != null) { | |||||
return new PaymentValidationResult("err.paymentInfo.verifiedEmailRequired"); | |||||
} | |||||
} else { | |||||
email = policy.getFirstEmail(); | |||||
if (email == null) { | |||||
return new PaymentValidationResult("err.paymentInfo.verifiedEmailRequired"); | |||||
} | |||||
} | } | ||||
final Map<String, Object> customerParams = new HashMap<>(); | final Map<String, Object> customerParams = new HashMap<>(); | ||||
@@ -46,8 +46,6 @@ import static bubble.server.BubbleConfiguration.getDEFAULT_LOCALE; | |||||
import static java.lang.Thread.currentThread; | import static java.lang.Thread.currentThread; | ||||
import static java.util.concurrent.TimeUnit.MINUTES; | import static java.util.concurrent.TimeUnit.MINUTES; | ||||
import static org.cobbzilla.util.daemon.ZillaRuntime.daemon; | import static org.cobbzilla.util.daemon.ZillaRuntime.daemon; | ||||
import static org.cobbzilla.util.json.JsonUtil.COMPACT_MAPPER; | |||||
import static org.cobbzilla.util.json.JsonUtil.json; | |||||
import static org.cobbzilla.wizard.model.IdentifiableBase.CTIME_ASC; | import static org.cobbzilla.wizard.model.IdentifiableBase.CTIME_ASC; | ||||
import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx; | import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx; | ||||
@@ -257,11 +255,9 @@ public class AccountDAO extends AbstractCRUDDAO<Account> implements SqlViewSearc | |||||
return ((AppSiteDAO) dao).findByAccountAndAppAndId(accountUuid, apps.get(parentEntity.getApp()).getUuid(), parentEntity.getName()); | return ((AppSiteDAO) dao).findByAccountAndAppAndId(accountUuid, apps.get(parentEntity.getApp()).getUuid(), parentEntity.getName()); | ||||
} | } | ||||
@Override public AppSite preCreate(AppSite parentEntity, AppSite accountEntity) { | @Override public AppSite preCreate(AppSite parentEntity, AppSite accountEntity) { | ||||
log.info("CopyTemplate.AppSite.preCreate: site="+json(accountEntity, COMPACT_MAPPER)); | |||||
return accountEntity.setApp(apps.get(parentEntity.getApp()).getUuid()); | return accountEntity.setApp(apps.get(parentEntity.getApp()).getUuid()); | ||||
} | } | ||||
@Override public void postCreate(AppSite parentEntity, AppSite accountEntity) { | @Override public void postCreate(AppSite parentEntity, AppSite accountEntity) { | ||||
log.info("CopyTemplate.AppSite.postCreate: site="+json(accountEntity, COMPACT_MAPPER)); | |||||
sites.put(parentEntity.getUuid(), accountEntity); | sites.put(parentEntity.getUuid(), accountEntity); | ||||
} | } | ||||
}); | }); | ||||
@@ -27,6 +27,7 @@ public class AccountInitializer implements Runnable { | |||||
public static final int MAX_ACCOUNT_INIT_RETRIES = 3; | public static final int MAX_ACCOUNT_INIT_RETRIES = 3; | ||||
public static final long COPY_WAIT_TIME = SECONDS.toMillis(2); | public static final long COPY_WAIT_TIME = SECONDS.toMillis(2); | ||||
public static final long SEND_MESSAGE_WAIT_TIME = SECONDS.toMillis(1); | |||||
private Account account; | private Account account; | ||||
private AccountDAO accountDAO; | private AccountDAO accountDAO; | ||||
@@ -36,6 +37,15 @@ public class AccountInitializer implements Runnable { | |||||
private AtomicBoolean ready = new AtomicBoolean(false); | private AtomicBoolean ready = new AtomicBoolean(false); | ||||
public boolean ready() { return ready.get(); } | public boolean ready() { return ready.get(); } | ||||
private AtomicBoolean canSendAccountMessages = new AtomicBoolean(false); | |||||
public void setCanSendAccountMessages() { canSendAccountMessages.set(true); } | |||||
private AtomicBoolean abort = new AtomicBoolean(false); | |||||
public void setAbort () { abort.set(true); } | |||||
private AtomicBoolean completed = new AtomicBoolean(false); | |||||
public boolean completed () { return completed.get(); } | |||||
private AtomicReference<Exception> error = new AtomicReference<>(); | private AtomicReference<Exception> error = new AtomicReference<>(); | ||||
public Exception getError() { return error.get(); } | public Exception getError() { return error.get(); } | ||||
public boolean hasError () { return getError() != null; } | public boolean hasError () { return getError() != null; } | ||||
@@ -56,6 +66,14 @@ public class AccountInitializer implements Runnable { | |||||
sleep(COPY_WAIT_TIME, "waiting before copyTemplates"); | sleep(COPY_WAIT_TIME, "waiting before copyTemplates"); | ||||
accountDAO.copyTemplates(account, ready); | accountDAO.copyTemplates(account, ready); | ||||
while (!canSendAccountMessages.get() && !abort.get()) { | |||||
sleep(SEND_MESSAGE_WAIT_TIME, "waiting before sending welcome message"); | |||||
} | |||||
if (abort.get()) { | |||||
log.warn("aborting!"); | |||||
return; | |||||
} | |||||
if (account.hasPolicy() && account.getPolicy().hasAccountContacts()) { | if (account.hasPolicy() && account.getPolicy().hasAccountContacts()) { | ||||
messageDAO.sendVerifyRequest(account.getRemoteHost(), account, account.getPolicy().getAccountContacts()[0]); | messageDAO.sendVerifyRequest(account.getRemoteHost(), account, account.getPolicy().getAccountContacts()[0]); | ||||
} | } | ||||
@@ -82,6 +100,8 @@ public class AccountInitializer implements Runnable { | |||||
error.set(e); | error.set(e); | ||||
// todo: send to errbit | // todo: send to errbit | ||||
die("error: "+e, e); | die("error: "+e, e); | ||||
} finally { | |||||
completed.set(true); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -5,6 +5,7 @@ | |||||
package bubble.dao.bill; | package bubble.dao.bill; | ||||
import bubble.cloud.payment.PaymentServiceDriver; | import bubble.cloud.payment.PaymentServiceDriver; | ||||
import bubble.dao.account.AccountDAO; | |||||
import bubble.dao.account.AccountOwnedEntityDAO; | import bubble.dao.account.AccountOwnedEntityDAO; | ||||
import bubble.dao.cloud.BubbleNetworkDAO; | import bubble.dao.cloud.BubbleNetworkDAO; | ||||
import bubble.dao.cloud.CloudServiceDAO; | import bubble.dao.cloud.CloudServiceDAO; | ||||
@@ -39,6 +40,7 @@ public class AccountPlanDAO extends AccountOwnedEntityDAO<AccountPlan> { | |||||
public static final long PURCHASE_DELAY = SECONDS.toMillis(3); | public static final long PURCHASE_DELAY = SECONDS.toMillis(3); | ||||
@Autowired private BubblePlanDAO planDAO; | @Autowired private BubblePlanDAO planDAO; | ||||
@Autowired private AccountDAO accountDAO; | |||||
@Autowired private BillDAO billDAO; | @Autowired private BillDAO billDAO; | ||||
@Autowired private CloudServiceDAO cloudDAO; | @Autowired private CloudServiceDAO cloudDAO; | ||||
@Autowired private BubbleNetworkDAO networkDAO; | @Autowired private BubbleNetworkDAO networkDAO; | ||||
@@ -77,7 +79,7 @@ public class AccountPlanDAO extends AccountOwnedEntityDAO<AccountPlan> { | |||||
} | } | ||||
@Override public Object preCreate(AccountPlan accountPlan) { | @Override public Object preCreate(AccountPlan accountPlan) { | ||||
final ValidationResult errors = validateHostname(accountPlan); | |||||
final ValidationResult errors = validateHostname(accountPlan, accountDAO, networkDAO); | |||||
if (errors.isInvalid()) throw invalidEx(errors); | if (errors.isInvalid()) throw invalidEx(errors); | ||||
if (configuration.paymentsEnabled()) { | if (configuration.paymentsEnabled()) { | ||||
@@ -86,7 +86,8 @@ public class Account extends IdentifiableBaseParentEntity implements TokenPrinci | |||||
public static final String[] UPDATE_FIELDS = {"url", "description", "autoUpdatePolicy"}; | public static final String[] UPDATE_FIELDS = {"url", "description", "autoUpdatePolicy"}; | ||||
public static final String[] ADMIN_UPDATE_FIELDS = ArrayUtil.append(UPDATE_FIELDS, "suspended", "admin"); | public static final String[] ADMIN_UPDATE_FIELDS = ArrayUtil.append(UPDATE_FIELDS, "suspended", "admin"); | ||||
public static final String[] CREATE_FIELDS = ArrayUtil.append(ADMIN_UPDATE_FIELDS, "name", "referralCode", "termsAgreed"); | |||||
public static final String[] CREATE_FIELDS = ArrayUtil.append(ADMIN_UPDATE_FIELDS, | |||||
"name", "referralCode", "termsAgreed", "preferredPlan"); | |||||
public static final String ROOT_USERNAME = "root"; | public static final String ROOT_USERNAME = "root"; | ||||
public static final int NAME_MIN_LENGTH = 4; | public static final int NAME_MIN_LENGTH = 4; | ||||
@@ -191,6 +192,10 @@ public class Account extends IdentifiableBaseParentEntity implements TokenPrinci | |||||
return new ConstraintViolationBean("err.password.invalid", "Password must contain at least one letter, one number, and one special character"); | return new ConstraintViolationBean("err.password.invalid", "Password must contain at least one letter, one number, and one special character"); | ||||
} | } | ||||
@Column(length=UUID_MAXLEN) | |||||
@Getter @Setter private String preferredPlan; | |||||
public boolean hasPreferredPlan () { return !empty(preferredPlan); } | |||||
@Embedded @Getter @Setter private AutoUpdatePolicy autoUpdatePolicy; | @Embedded @Getter @Setter private AutoUpdatePolicy autoUpdatePolicy; | ||||
public boolean wantsNewStuff () { return autoUpdatePolicy != null && autoUpdatePolicy.newStuff(); } | public boolean wantsNewStuff () { return autoUpdatePolicy != null && autoUpdatePolicy.newStuff(); } | ||||
@@ -4,6 +4,7 @@ | |||||
*/ | */ | ||||
package bubble.model.account; | package bubble.model.account; | ||||
import bubble.model.bill.AccountPaymentMethod; | |||||
import lombok.Getter; | import lombok.Getter; | ||||
import lombok.Setter; | import lombok.Setter; | ||||
@@ -22,4 +23,6 @@ public class AccountRegistration extends Account { | |||||
@Getter @Setter private Boolean agreeToTerms = null; | @Getter @Setter private Boolean agreeToTerms = null; | ||||
public boolean agreeToTerms () { return agreeToTerms != null && agreeToTerms; } | public boolean agreeToTerms () { return agreeToTerms != null && agreeToTerms; } | ||||
@Getter @Setter private AccountPaymentMethod paymentMethodObject; | |||||
public boolean hasPaymentMethod () { return paymentMethodObject != null; } | |||||
} | } |
@@ -98,6 +98,9 @@ public class AccountPaymentMethod extends IdentifiableBase implements HasAccount | |||||
@JsonProperty @Override public long getCtime () { return super.getCtime(); } | @JsonProperty @Override public long getCtime () { return super.getCtime(); } | ||||
@Transient @Getter @Setter private transient Boolean requireValidatedEmail = null; | |||||
public boolean requireValidatedEmail() { return requireValidatedEmail == null || requireValidatedEmail; } | |||||
public ValidationResult validate(ValidationResult result, BubbleConfiguration configuration) { | public ValidationResult validate(ValidationResult result, BubbleConfiguration configuration) { | ||||
if (!hasPaymentMethodType()) { | if (!hasPaymentMethodType()) { | ||||
@@ -139,6 +142,7 @@ public class AccountPaymentMethod extends IdentifiableBase implements HasAccount | |||||
if (empty(getPaymentInfo())) { | if (empty(getPaymentInfo())) { | ||||
result.addViolation("err.paymentInfo.required"); | result.addViolation("err.paymentInfo.required"); | ||||
} else { | } else { | ||||
log.info("validate: starting validation of payment method with this.requireValidatedEmail="+requireValidatedEmail); | |||||
final PaymentValidationResult validationResult = paymentDriver.validate(this); | final PaymentValidationResult validationResult = paymentDriver.validate(this); | ||||
if (validationResult.hasErrors()) { | if (validationResult.hasErrors()) { | ||||
result.addAll(validationResult.getViolations()); | result.addAll(validationResult.getViolations()); | ||||
@@ -202,12 +202,15 @@ public class BubbleNetwork extends IdentifiableBase implements HasNetwork, HasBu | |||||
errors.addViolation("err.name.length"); | errors.addViolation("err.name.length"); | ||||
} else if (name.length() < NETWORK_NAME_MINLEN) { | } else if (name.length() < NETWORK_NAME_MINLEN) { | ||||
errors.addViolation("err.name.tooShort"); | errors.addViolation("err.name.tooShort"); | ||||
} else if (networkDAO.findByNameAndDomainUuid(name, request.getDomain()) != null) { | |||||
errors.addViolation("err.name.alreadyInUse"); | |||||
} else { | } else { | ||||
final Account acct = accountDAO.findByName(name); | |||||
if (acct != null && !acct.getUuid().equals(request.getAccount())) { | |||||
errors.addViolation("err.name.reservedForAccount"); | |||||
final BubbleNetwork network = networkDAO.findByNameAndDomainUuid(name, request.getDomain()); | |||||
if (network != null && !network.getUuid().equals(request.getNetwork())) { | |||||
errors.addViolation("err.name.alreadyInUse"); | |||||
} else { | |||||
final Account acct = accountDAO.findByName(name); | |||||
if (acct != null && !acct.getUuid().equals(request.getAccount())) { | |||||
errors.addViolation("err.name.reservedForAccount"); | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -111,20 +111,25 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned | |||||
public Response view(@Context ContainerRequest ctx, | public Response view(@Context ContainerRequest ctx, | ||||
@PathParam("id") String id) { | @PathParam("id") String id) { | ||||
final Account caller = userPrincipal(ctx); | |||||
final String accountUuid = getAccountUuid(ctx); | |||||
if (!caller.admin() && !caller.getUuid().equals(accountUuid)) return notFound(); | |||||
final Account caller = getAccountForViewById(ctx); | |||||
E found = find(ctx, id); | E found = find(ctx, id); | ||||
if (found == null) { | if (found == null) { | ||||
found = findAlternate(ctx, id); | found = findAlternate(ctx, id); | ||||
if (found == null) return notFound(id); | if (found == null) return notFound(id); | ||||
} | } | ||||
if (!found.getAccount().equals(caller.getUuid()) && !caller.admin()) return notFound(id); | |||||
if (caller != null && !found.getAccount().equals(caller.getUuid()) && !caller.admin()) return notFound(id); | |||||
return ok(populate(ctx, found)); | return ok(populate(ctx, found)); | ||||
} | } | ||||
public Account getAccountForViewById(ContainerRequest ctx) { | |||||
final Account caller = userPrincipal(ctx); | |||||
final String accountUuid = getAccountUuid(ctx); | |||||
if (!caller.admin() && !caller.getUuid().equals(accountUuid)) throw notFoundEx(); | |||||
return caller; | |||||
} | |||||
@PUT | @PUT | ||||
public Response create(@Context Request req, | public Response create(@Context Request req, | ||||
@Context ContainerRequest ctx, | @Context ContainerRequest ctx, | ||||
@@ -8,12 +8,15 @@ import bubble.dao.SessionDAO; | |||||
import bubble.dao.account.AccountDAO; | import bubble.dao.account.AccountDAO; | ||||
import bubble.dao.account.AccountPolicyDAO; | import bubble.dao.account.AccountPolicyDAO; | ||||
import bubble.dao.account.message.AccountMessageDAO; | import bubble.dao.account.message.AccountMessageDAO; | ||||
import bubble.dao.bill.AccountPaymentMethodDAO; | |||||
import bubble.dao.bill.BubblePlanDAO; | import bubble.dao.bill.BubblePlanDAO; | ||||
import bubble.dao.cloud.BubbleNodeDAO; | import bubble.dao.cloud.BubbleNodeDAO; | ||||
import bubble.dao.cloud.BubbleNodeKeyDAO; | import bubble.dao.cloud.BubbleNodeKeyDAO; | ||||
import bubble.model.CertType; | import bubble.model.CertType; | ||||
import bubble.model.account.*; | import bubble.model.account.*; | ||||
import bubble.model.account.message.*; | import bubble.model.account.message.*; | ||||
import bubble.model.bill.AccountPaymentMethod; | |||||
import bubble.model.bill.BubblePlan; | |||||
import bubble.model.boot.ActivationRequest; | import bubble.model.boot.ActivationRequest; | ||||
import bubble.model.cloud.BubbleNetwork; | import bubble.model.cloud.BubbleNetwork; | ||||
import bubble.model.cloud.BubbleNode; | import bubble.model.cloud.BubbleNode; | ||||
@@ -23,8 +26,8 @@ import bubble.model.cloud.notify.NotificationReceipt; | |||||
import bubble.model.device.BubbleDeviceType; | import bubble.model.device.BubbleDeviceType; | ||||
import bubble.model.device.Device; | import bubble.model.device.Device; | ||||
import bubble.server.BubbleConfiguration; | import bubble.server.BubbleConfiguration; | ||||
import bubble.service.account.StandardAuthenticatorService; | |||||
import bubble.service.account.StandardAccountMessageService; | import bubble.service.account.StandardAccountMessageService; | ||||
import bubble.service.account.StandardAuthenticatorService; | |||||
import bubble.service.backup.RestoreService; | import bubble.service.backup.RestoreService; | ||||
import bubble.service.bill.PromotionService; | import bubble.service.bill.PromotionService; | ||||
import bubble.service.boot.ActivationService; | import bubble.service.boot.ActivationService; | ||||
@@ -63,6 +66,8 @@ import static java.util.concurrent.TimeUnit.SECONDS; | |||||
import static org.cobbzilla.util.daemon.ZillaRuntime.*; | import static org.cobbzilla.util.daemon.ZillaRuntime.*; | ||||
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; | import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; | ||||
import static org.cobbzilla.util.http.HttpContentTypes.CONTENT_TYPE_ANY; | import static org.cobbzilla.util.http.HttpContentTypes.CONTENT_TYPE_ANY; | ||||
import static org.cobbzilla.util.json.JsonUtil.COMPACT_MAPPER; | |||||
import static org.cobbzilla.util.json.JsonUtil.json; | |||||
import static org.cobbzilla.util.string.LocaleUtil.currencyForLocale; | import static org.cobbzilla.util.string.LocaleUtil.currencyForLocale; | ||||
import static org.cobbzilla.util.system.Sleep.sleep; | import static org.cobbzilla.util.system.Sleep.sleep; | ||||
import static org.cobbzilla.wizard.resources.ResourceUtil.*; | import static org.cobbzilla.wizard.resources.ResourceUtil.*; | ||||
@@ -81,6 +86,7 @@ public class AuthResource { | |||||
@Autowired private SessionDAO sessionDAO; | @Autowired private SessionDAO sessionDAO; | ||||
@Autowired private ActivationService activationService; | @Autowired private ActivationService activationService; | ||||
@Autowired private AccountMessageDAO accountMessageDAO; | @Autowired private AccountMessageDAO accountMessageDAO; | ||||
@Autowired private AccountPaymentMethodDAO accountPaymentMethodDAO; | |||||
@Autowired private StandardAccountMessageService messageService; | @Autowired private StandardAccountMessageService messageService; | ||||
@Autowired private BubblePlanDAO planDAO; | @Autowired private BubblePlanDAO planDAO; | ||||
@Autowired private BubbleNodeDAO nodeDAO; | @Autowired private BubbleNodeDAO nodeDAO; | ||||
@@ -240,6 +246,11 @@ public class AuthResource { | |||||
} | } | ||||
} | } | ||||
if (request.hasPreferredPlan()) { | |||||
final BubblePlan plan = planDAO.findById(request.getPreferredPlan()); | |||||
if (plan == null) errors.addViolation("err.plan.notFound"); | |||||
} | |||||
if (errors.isInvalid()) return invalid(errors); | if (errors.isInvalid()) return invalid(errors); | ||||
final String parentUuid = thisNetwork.getTag(TAG_PARENT_ACCOUNT, thisNetwork.getAccount()); | final String parentUuid = thisNetwork.getTag(TAG_PARENT_ACCOUNT, thisNetwork.getAccount()); | ||||
@@ -249,12 +260,37 @@ public class AuthResource { | |||||
final Account account = accountDAO.newAccount(req, null, request, parent); | final Account account = accountDAO.newAccount(req, null, request, parent); | ||||
SimpleViolationException promoEx = null; | SimpleViolationException promoEx = null; | ||||
if (configuration.paymentsEnabled()) { | if (configuration.paymentsEnabled()) { | ||||
if (request.hasPaymentMethod()) { | |||||
final AccountPaymentMethod paymentMethodObject = request.getPaymentMethodObject(); | |||||
log.info("register: found AccountPaymentMethod at registration-time: " + json(paymentMethodObject, COMPACT_MAPPER)); | |||||
paymentMethodObject.setUuid(null); | |||||
paymentMethodObject.setAccount(account.getUuid()); | |||||
paymentMethodObject.setRequireValidatedEmail(false); | |||||
account.waitForAccountInit(); // payment clouds for user must exist before we can create the APM | |||||
final ValidationResult result = new ValidationResult(); | |||||
log.info("register: starting validation of payment method with requireValidatedEmail="+paymentMethodObject.requireValidatedEmail()); | |||||
paymentMethodObject.validate(result, configuration); | |||||
if (result.isInvalid()) { | |||||
account.getAccountInitializer().setAbort(); | |||||
final AccountPolicy policy = policyDAO.findSingleByAccount(account.getUuid()); | |||||
policyDAO.update(policy.setDeletionPolicy(AccountDeletionPolicy.full_delete)); | |||||
while (!account.getAccountInitializer().completed()) { | |||||
sleep(SECONDS.toMillis(1), "waiting for account initialization to complete before deleting"); | |||||
} | |||||
accountDAO.delete(account.getUuid()); | |||||
throw invalidEx(result); | |||||
} | |||||
log.info("register: creating AccountPaymentMethod upon registration: " + json(paymentMethodObject, COMPACT_MAPPER)); | |||||
final AccountPaymentMethod apm = accountPaymentMethodDAO.create(paymentMethodObject); | |||||
log.info("register: created AccountPaymentMethod upon registration: " + apm.getUuid()); | |||||
} | |||||
try { | try { | ||||
promoService.applyPromotions(account, request.getPromoCode(), currency); | promoService.applyPromotions(account, request.getPromoCode(), currency); | ||||
} catch (SimpleViolationException e) { | } catch (SimpleViolationException e) { | ||||
promoEx = e; | promoEx = e; | ||||
} | } | ||||
} | } | ||||
account.getAccountInitializer().setCanSendAccountMessages(); | |||||
return ok(account | return ok(account | ||||
.waitForAccountInit() | .waitForAccountInit() | ||||
.setPromoError(promoEx == null ? null : promoEx.getMessageTemplate()) | .setPromoError(promoEx == null ? null : promoEx.getMessageTemplate()) | ||||
@@ -5,6 +5,7 @@ | |||||
package bubble.resources.bill; | package bubble.resources.bill; | ||||
import bubble.cloud.CloudServiceType; | import bubble.cloud.CloudServiceType; | ||||
import bubble.dao.account.AccountDAO; | |||||
import bubble.dao.cloud.CloudServiceDAO; | import bubble.dao.cloud.CloudServiceDAO; | ||||
import bubble.model.account.Account; | import bubble.model.account.Account; | ||||
import bubble.model.bill.PaymentMethodType; | import bubble.model.bill.PaymentMethodType; | ||||
@@ -33,13 +34,16 @@ import static org.cobbzilla.wizard.resources.ResourceUtil.*; | |||||
public class AllPaymentMethodsResource { | public class AllPaymentMethodsResource { | ||||
@Autowired private CloudServiceDAO cloudDAO; | @Autowired private CloudServiceDAO cloudDAO; | ||||
@Autowired private AccountDAO accountDAO; | |||||
@Autowired private BubbleConfiguration configuration; | @Autowired private BubbleConfiguration configuration; | ||||
@GET | @GET | ||||
public Response listPaymentMethods(@Context ContainerRequest ctx, | public Response listPaymentMethods(@Context ContainerRequest ctx, | ||||
@QueryParam("type") PaymentMethodType type) { | @QueryParam("type") PaymentMethodType type) { | ||||
final Account account = userPrincipal(ctx); | |||||
final List<CloudService> allPaymentServices = cloudDAO.findByAccountAndType(account.getUuid(), CloudServiceType.payment); | |||||
final Account account = optionalUserPrincipal(ctx); | |||||
final List<CloudService> allPaymentServices = account != null | |||||
? cloudDAO.findByAccountAndType(account.getUuid(), CloudServiceType.payment) | |||||
: cloudDAO.findPublicTemplatesByType(accountDAO.getFirstAdmin().getUuid(), CloudServiceType.payment); | |||||
final Set<PaymentMethodType> typesFound = new HashSet<>(); | final Set<PaymentMethodType> typesFound = new HashSet<>(); | ||||
final List<CloudService> paymentServices = new ArrayList<>(); | final List<CloudService> paymentServices = new ArrayList<>(); | ||||
for (CloudService cloud : allPaymentServices) { | for (CloudService cloud : allPaymentServices) { | ||||
@@ -41,6 +41,11 @@ public class BubblePlansResource extends AccountOwnedResource<BubblePlan, Bubble | |||||
@Autowired private BubblePlanAppDAO planAppDAO; | @Autowired private BubblePlanAppDAO planAppDAO; | ||||
@Autowired private BubbleAppDAO appDAO; | @Autowired private BubbleAppDAO appDAO; | ||||
// allow unauthenticated users to read plans | |||||
@Override public Account getAccountForViewById(ContainerRequest ctx) { | |||||
return optionalUserPrincipal(ctx); | |||||
} | |||||
@Override protected BubblePlan setReferences(ContainerRequest ctx, Account caller, BubblePlan bubblePlan) { | @Override protected BubblePlan setReferences(ContainerRequest ctx, Account caller, BubblePlan bubblePlan) { | ||||
if (empty(bubblePlan.getChargeName())) throw invalidEx("err.chargeName.required"); | if (empty(bubblePlan.getChargeName())) throw invalidEx("err.chargeName.required"); | ||||
if (bubblePlan.getChargeName().length() > MAX_CHARGENAME_LEN) throw invalidEx("err.chargeName.length"); | if (bubblePlan.getChargeName().length() > MAX_CHARGENAME_LEN) throw invalidEx("err.chargeName.length"); | ||||
@@ -67,8 +72,12 @@ public class BubblePlansResource extends AccountOwnedResource<BubblePlan, Bubble | |||||
} | } | ||||
@Override protected BubblePlan populate(ContainerRequest ctx, BubblePlan plan) { | @Override protected BubblePlan populate(ContainerRequest ctx, BubblePlan plan) { | ||||
final Account account = optionalUserPrincipal(ctx); | |||||
final List<BubbleApp> apps = getAppsForPlan(plan); | final List<BubbleApp> apps = getAppsForPlan(plan); | ||||
plan.setApps(apps); | plan.setApps(apps); | ||||
if (account == null) { | |||||
plan.getApps().forEach(app -> app.setDataConfig(null)); | |||||
} | |||||
return super.populate(ctx, plan); | return super.populate(ctx, plan); | ||||
} | } | ||||
@@ -310,26 +310,6 @@ footprint_description_EU=Your Bubble will only run within European Union countri | |||||
footprint_name_Worldwide=World-wide | footprint_name_Worldwide=World-wide | ||||
footprint_description_Worldwide=Your Bubble can run anywhere in the world | footprint_description_Worldwide=Your Bubble can run anywhere in the world | ||||
# Payment methods | |||||
payment_description_credit=Credit or Debit Card | |||||
payment_description_code=Invitation Code | |||||
payment_description_free=FREE! | |||||
message_payment_not_supported=This system is not configured to handle payments of this type | |||||
# Invite code payment fields | |||||
field_payment_invite_code=Invitation Code | |||||
button_label_submit_invite_code=Use Invite Code | |||||
message_verified_invite_code=Invite Code Successfully Verified | |||||
# Free payment fields | |||||
button_label_submit_free_pay=Click here to use the FREE payment method | |||||
message_verified_free_pay=Free Payment Successfully Applied | |||||
# Credit payment fields | |||||
field_payment_card_number=Credit or Debit Card | |||||
button_label_submit_card=Verify Card | |||||
message_verified_card=Card Successfully Verified | |||||
# Launch progress meter: pre-launch (standard) ticks | # Launch progress meter: pre-launch (standard) ticks | ||||
meter_tick_confirming_network_lock=Confirming network lock | meter_tick_confirming_network_lock=Confirming network lock | ||||
meter_tick_validating_node_network_and_plan=Verifying settings for Bubble | meter_tick_validating_node_network_and_plan=Verifying settings for Bubble | ||||
@@ -268,6 +268,8 @@ form_title_register=Register | |||||
field_label_contactType=Contact Type | field_label_contactType=Contact Type | ||||
field_label_email=Email | field_label_email=Email | ||||
field_label_promoCode=Beta Invite Code | field_label_promoCode=Beta Invite Code | ||||
message_request_promoCode=Don't have an invite code? Request one here. | |||||
message_request_promoCode_link=https://bubblev.com/beta | |||||
field_label_sms=SMS Phone | field_label_sms=SMS Phone | ||||
field_label_agreeToTerms=By checking this box, you agree to our <a target="_blank" rel="noopener" href="https://bubblev.com/pages/privacy">Privacy Policy</a> and <a target="_blank" rel="noopener" href="https://bubblev.com/pages/terms">Terms of Service</a>. | field_label_agreeToTerms=By checking this box, you agree to our <a target="_blank" rel="noopener" href="https://bubblev.com/pages/privacy">Privacy Policy</a> and <a target="_blank" rel="noopener" href="https://bubblev.com/pages/terms">Terms of Service</a>. | ||||
message_login_agreeToTerms=By logging in, you agree to the <a target="_blank" rel="noopener" href="https://bubblev.com/pages/privacy">Privacy Policy</a> and <a target="_blank" rel="noopener" href="https://bubblev.com/pages/terms">Terms of Service</a>. | message_login_agreeToTerms=By logging in, you agree to the <a target="_blank" rel="noopener" href="https://bubblev.com/pages/privacy">Privacy Policy</a> and <a target="_blank" rel="noopener" href="https://bubblev.com/pages/terms">Terms of Service</a>. | ||||
@@ -278,6 +280,8 @@ field_label_paymentMethod=Payment Method | |||||
field_label_newPaymentMethod=Add a Payment Method | field_label_newPaymentMethod=Add a Payment Method | ||||
field_label_existingPaymentMethod=Payment Method | field_label_existingPaymentMethod=Payment Method | ||||
err_noPaymentMethods=No payment methods are configured. Contact the administrator of this system. | err_noPaymentMethods=No payment methods are configured. Contact the administrator of this system. | ||||
err.paymentMethod.required=Payment information is required | |||||
err.plan.notFound=Plan not found | |||||
button_label_login=Login | button_label_login=Login | ||||
button_label_register=Register | button_label_register=Register | ||||
button_label_forgotPassword=Forgot Password | button_label_forgotPassword=Forgot Password | ||||
@@ -287,6 +291,26 @@ form_title_forgotPassword=Forgot Password | |||||
button_label_resetPassword=Request Password Reset | button_label_resetPassword=Request Password Reset | ||||
message_resetPassword_sent=Password Reset Message Successfully Sent | message_resetPassword_sent=Password Reset Message Successfully Sent | ||||
# Payment methods | |||||
payment_description_credit=Credit or Debit Card | |||||
payment_description_code=Invitation Code | |||||
payment_description_free=FREE! | |||||
message_payment_not_supported=This system is not configured to handle payments of this type | |||||
# Invite code payment fields | |||||
field_payment_invite_code=Invitation Code | |||||
button_label_submit_invite_code=Use Invite Code | |||||
message_verified_invite_code=Invite Code Successfully Verified | |||||
# Free payment fields | |||||
button_label_submit_free_pay=Click here to use the FREE payment method | |||||
message_verified_free_pay=Free Payment Successfully Applied | |||||
# Credit payment fields | |||||
field_payment_card_number=Credit or Debit Card | |||||
button_label_submit_card=Verify Card | |||||
message_verified_card=Card Successfully Verified | |||||
# Change Password / Set Password pages | # Change Password / Set Password pages | ||||
form_title_change_password=Change Password | form_title_change_password=Change Password | ||||
form_title_set_password=Set Password | form_title_set_password=Set Password | ||||
@@ -1 +1 @@ | |||||
Subproject commit 2da83c231b0a07b723ba60e33e2e1a540311cceb | |||||
Subproject commit 372ad8a74fddeab1cb174685bd7f2cde919ac48e |