From 3bd0252b723472cc1a627c05bb0309c21d7926d8 Mon Sep 17 00:00:00 2001 From: Jonathan Cobb Date: Sun, 5 Jan 2020 14:09:29 -0500 Subject: [PATCH] add model setup endpoint --- .../src/main/java/bubble/ApiConstants.java | 2 ++ .../java/bubble/dao/account/AccountDAO.java | 3 ++ .../bubble/dao/cloud/BubbleNetworkDAO.java | 7 +++++ .../java/bubble/model/account/Account.java | 5 ++-- .../java/bubble/model/app/RuleDriver.java | 12 +++++--- .../bubble/model/cloud/BubbleNetwork.java | 6 ++-- .../bubble/resources/account/MeResource.java | 28 +++++++++++++++++-- .../bubble/server/BubbleConfiguration.java | 13 +++++++-- .../service/boot/BubbleModelSetupService.java | 24 ++++++++++++++++ .../post_auth/ResourceMessages.properties | 9 ++++++ .../src/main/resources/spring-db-filter.xml | 2 +- bubble-web | 2 +- utils/cobbzilla-utils | 2 +- utils/cobbzilla-wizard | 2 +- 14 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 bubble-server/src/main/java/bubble/service/boot/BubbleModelSetupService.java diff --git a/bubble-server/src/main/java/bubble/ApiConstants.java b/bubble-server/src/main/java/bubble/ApiConstants.java index 7233d0ef..e2186ac3 100644 --- a/bubble-server/src/main/java/bubble/ApiConstants.java +++ b/bubble-server/src/main/java/bubble/ApiConstants.java @@ -129,6 +129,7 @@ public class ApiConstants { public static final String EP_TAGS = "/tags"; public static final String EP_NODES = "/nodes"; public static final String EP_DEVICES = "/devices"; + public static final String EP_MODEL = "/model"; public static final String EP_VPN = "/vpn"; public static final String EP_PAYMENT_METHOD = "/paymentMethod"; public static final String EP_PAYMENT_METHODS = PAYMENT_METHODS_ENDPOINT; @@ -241,4 +242,5 @@ public class ApiConstants { .orElseThrow((Supplier) () -> invalidEx("err."+e.getSimpleName()+".invalid", "Invalid "+e.getSimpleName()+": "+v, v)); } + } diff --git a/bubble-server/src/main/java/bubble/dao/account/AccountDAO.java b/bubble-server/src/main/java/bubble/dao/account/AccountDAO.java index 47430b51..27a32ba1 100644 --- a/bubble-server/src/main/java/bubble/dao/account/AccountDAO.java +++ b/bubble-server/src/main/java/bubble/dao/account/AccountDAO.java @@ -33,6 +33,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import static bubble.ApiConstants.getRemoteHost; import static bubble.model.account.AccountTemplate.copyTemplateObjects; import static bubble.model.account.AutoUpdatePolicy.EMPTY_AUTO_UPDATE_POLICY; +import static bubble.server.BubbleConfiguration.getDEFAULT_LOCALE; import static java.util.concurrent.TimeUnit.MINUTES; import static org.cobbzilla.util.daemon.ZillaRuntime.daemon; import static org.cobbzilla.wizard.model.IdentifiableBase.CTIME_ASC; @@ -71,6 +72,8 @@ public class AccountDAO extends AbstractCRUDDAO implements SqlViewSearc } @Override public Object preCreate(Account account) { + if (!account.hasLocale()) account.setLocale(getDEFAULT_LOCALE()); + final ValidationResult result = account.validateName(); if (result.isInvalid()) throw invalidEx(result); diff --git a/bubble-server/src/main/java/bubble/dao/cloud/BubbleNetworkDAO.java b/bubble-server/src/main/java/bubble/dao/cloud/BubbleNetworkDAO.java index fbef0d53..e6795ab7 100644 --- a/bubble-server/src/main/java/bubble/dao/cloud/BubbleNetworkDAO.java +++ b/bubble-server/src/main/java/bubble/dao/cloud/BubbleNetworkDAO.java @@ -19,6 +19,8 @@ import java.io.IOException; import java.util.List; import java.util.stream.Collectors; +import static bubble.server.BubbleConfiguration.getDEFAULT_LOCALE; + @Repository @Slf4j public class BubbleNetworkDAO extends AccountOwnedEntityDAO { @@ -31,6 +33,11 @@ public class BubbleNetworkDAO extends AccountOwnedEntityDAO { @Autowired private SelfNodeService selfNodeService; @Autowired private BubbleConfiguration configuration; + @Override public Object preCreate(BubbleNetwork network) { + if (!network.hasLocale()) network.setLocale(getDEFAULT_LOCALE()); + return super.preCreate(network); + } + @Override public BubbleNetwork postUpdate(BubbleNetwork network, Object context) { if (selfNodeService.getThisNetwork().getUuid().equals(network.getUuid())) { selfNodeService.refreshThisNetwork(); diff --git a/bubble-server/src/main/java/bubble/model/account/Account.java b/bubble-server/src/main/java/bubble/model/account/Account.java index 5d1dcce9..847c5b09 100644 --- a/bubble-server/src/main/java/bubble/model/account/Account.java +++ b/bubble-server/src/main/java/bubble/model/account/Account.java @@ -35,7 +35,7 @@ import java.util.List; import java.util.regex.Pattern; import static bubble.ApiConstants.ACCOUNTS_ENDPOINT; -import static bubble.ApiConstants.DEFAULT_LOCALE; +import static bubble.server.BubbleConfiguration.getDEFAULT_LOCALE; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import static org.cobbzilla.util.daemon.ZillaRuntime.*; @@ -116,7 +116,8 @@ public class Account extends IdentifiableBase implements TokenPrincipal, SqlView @ECSearchable @ECField(type=EntityFieldType.locale, index=50) @Size(max=20, message="err.locale.length") @Type(type=ENCRYPTED_STRING) @Column(columnDefinition="varchar("+(20+ENC_PAD)+") NOT NULL") - @Getter @Setter private String locale = DEFAULT_LOCALE; + @Getter @Setter private String locale = getDEFAULT_LOCALE(); + public boolean hasLocale () { return !empty(locale); } @ECSearchable @ECField(index=60) @Getter @Setter private Boolean admin = false; diff --git a/bubble-server/src/main/java/bubble/model/app/RuleDriver.java b/bubble-server/src/main/java/bubble/model/app/RuleDriver.java index d6ab2103..26a42f1b 100644 --- a/bubble-server/src/main/java/bubble/model/app/RuleDriver.java +++ b/bubble-server/src/main/java/bubble/model/app/RuleDriver.java @@ -17,11 +17,15 @@ import org.cobbzilla.wizard.model.SemanticVersion; import org.cobbzilla.wizard.model.entityconfig.annotations.*; import org.cobbzilla.wizard.validation.HasValue; -import javax.persistence.*; +import javax.persistence.Column; +import javax.persistence.Embedded; +import javax.persistence.Entity; +import javax.persistence.Transient; import java.util.Locale; -import static bubble.ApiConstants.*; -import static bubble.ApiConstants.DEFAULT_LOCALE; +import static bubble.ApiConstants.DRIVERS_ENDPOINT; +import static bubble.ApiConstants.EP_DRIVERS; +import static bubble.server.BubbleConfiguration.getDEFAULT_LOCALE; import static org.cobbzilla.util.io.StreamUtil.stream2string; import static org.cobbzilla.util.json.JsonUtil.json; import static org.cobbzilla.util.reflect.ReflectionUtil.copy; @@ -98,7 +102,7 @@ public class RuleDriver extends IdentifiableBase implements AccountTemplate { @Transient @Getter @Setter private AppRuleDriverDescriptor descriptor; public AppRuleDriverDescriptor getDescriptor(Locale locale) { - final String localeString = locale != null ? locale.toString() : DEFAULT_LOCALE; + final String localeString = locale != null ? locale.toString() : getDEFAULT_LOCALE(); final AppRuleDriverDescriptor localized; final String prefix = driverClass.replace(".", "/"); try { diff --git a/bubble-server/src/main/java/bubble/model/cloud/BubbleNetwork.java b/bubble-server/src/main/java/bubble/model/cloud/BubbleNetwork.java index f6243e9f..64150f99 100644 --- a/bubble-server/src/main/java/bubble/model/cloud/BubbleNetwork.java +++ b/bubble-server/src/main/java/bubble/model/cloud/BubbleNetwork.java @@ -28,8 +28,9 @@ import static bubble.ApiConstants.EP_NETWORKS; import static bubble.ApiConstants.ROOT_NETWORK_UUID; import static bubble.model.cloud.BubbleDomain.DOMAIN_NAME_MAXLEN; import static bubble.model.cloud.BubbleNetworkState.created; -import static bubble.ApiConstants.DEFAULT_LOCALE; +import static bubble.server.BubbleConfiguration.getDEFAULT_LOCALE; import static org.cobbzilla.util.daemon.ZillaRuntime.die; +import static org.cobbzilla.util.daemon.ZillaRuntime.empty; import static org.cobbzilla.util.reflect.ReflectionUtil.copy; import static org.cobbzilla.wizard.model.crypto.EncryptedTypes.ENCRYPTED_STRING; import static org.cobbzilla.wizard.model.crypto.EncryptedTypes.ENC_PAD; @@ -107,7 +108,8 @@ public class BubbleNetwork extends IdentifiableBase implements HasNetwork, HasBu @ECSearchable @ECField(type=EntityFieldType.locale, index=90) @Size(max=20, message="err.locale.length") @Type(type=ENCRYPTED_STRING) @Column(columnDefinition="varchar("+(20+ENC_PAD)+") NOT NULL") - @Getter @Setter private String locale = DEFAULT_LOCALE; + @Getter @Setter private String locale = getDEFAULT_LOCALE(); + public boolean hasLocale () { return !empty(locale); } // A unicode timezone alias from: cobbzilla-utils/src/main/resources/org/cobbzilla/util/time/unicode-timezones.xml // All unicode aliases are guaranteed to map to a Linux timezone and a Java timezone diff --git a/bubble-server/src/main/java/bubble/resources/account/MeResource.java b/bubble-server/src/main/java/bubble/resources/account/MeResource.java index 11fe34de..9dbf5537 100644 --- a/bubble-server/src/main/java/bubble/resources/account/MeResource.java +++ b/bubble-server/src/main/java/bubble/resources/account/MeResource.java @@ -19,10 +19,13 @@ import bubble.resources.notify.SentNotificationsResource; import bubble.server.BubbleConfiguration; import bubble.service.account.StandardAccountMessageService; import bubble.service.account.download.AccountDownloadService; +import bubble.service.boot.BubbleModelSetupService; import bubble.service.cloud.StandardNetworkService; import com.fasterxml.jackson.databind.JsonNode; import lombok.Cleanup; import lombok.extern.slf4j.Slf4j; +import org.cobbzilla.util.io.FileUtil; +import org.cobbzilla.util.io.TempDir; import org.cobbzilla.util.string.LocaleUtil; import org.cobbzilla.wizard.auth.ChangePasswordRequest; import org.cobbzilla.wizard.client.ApiClientBase; @@ -32,6 +35,7 @@ import org.cobbzilla.wizard.client.script.ApiRunnerListenerStreamLogger; import org.cobbzilla.wizard.client.script.ApiScript; import org.cobbzilla.wizard.model.HashedPassword; import org.glassfish.grizzly.http.server.Request; +import org.glassfish.jersey.media.multipart.FormDataParam; import org.glassfish.jersey.server.ContainerRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -39,13 +43,16 @@ import org.springframework.stereotype.Service; import javax.ws.rs.*; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.io.StringWriter; import java.util.Locale; import static bubble.ApiConstants.*; +import static org.cobbzilla.util.daemon.ZillaRuntime.empty; import static org.cobbzilla.util.daemon.ZillaRuntime.errorString; -import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; -import static org.cobbzilla.util.http.HttpContentTypes.TEXT_PLAIN; +import static org.cobbzilla.util.http.HttpContentTypes.*; import static org.cobbzilla.util.json.JsonUtil.json; import static org.cobbzilla.wizard.resources.ResourceUtil.*; @@ -282,4 +289,21 @@ public class MeResource { return ok(networkService.listLaunchStatuses(caller.getUuid())); } + @Autowired private BubbleModelSetupService modelSetupService; + + @POST @Path(EP_MODEL) + @Consumes(MULTIPART_FORM_DATA) + public Response uploadModel(@Context Request req, + @Context ContainerRequest ctx, + @FormDataParam("file") InputStream in, + @FormDataParam("name") String name) throws IOException { + final Account caller = userPrincipal(ctx); + if (empty(name)) return invalid("err.name.required"); + + @Cleanup final TempDir temp = new TempDir(); + final File modelFile = new File(temp, name); + FileUtil.toFileOrDie(modelFile, in); + return ok(modelSetupService.setupModel(caller, modelFile)); + } + } diff --git a/bubble-server/src/main/java/bubble/server/BubbleConfiguration.java b/bubble-server/src/main/java/bubble/server/BubbleConfiguration.java index b72f2ea3..7ad901f4 100644 --- a/bubble-server/src/main/java/bubble/server/BubbleConfiguration.java +++ b/bubble-server/src/main/java/bubble/server/BubbleConfiguration.java @@ -136,11 +136,20 @@ public class BubbleConfiguration extends PgRestServerConfiguration return bubbleJar; } + private static final AtomicReference _DEFAULT_LOCALE = new AtomicReference<>(); + public static String getDEFAULT_LOCALE() { return _DEFAULT_LOCALE.get(); } + @Setter private String defaultLocale = DEFAULT_LOCALE; public String getDefaultLocale () { - if (!empty(defaultLocale)) return defaultLocale; + if (!empty(defaultLocale)) { + if (_DEFAULT_LOCALE.get() == null) _DEFAULT_LOCALE.set(defaultLocale); + return defaultLocale; + } final String[] allLocales = getAllLocales(); - if (ArrayUtils.contains(allLocales, DEFAULT_LOCALE)) return DEFAULT_LOCALE; + if (ArrayUtils.contains(allLocales, DEFAULT_LOCALE)) { + if (_DEFAULT_LOCALE.get() == null) _DEFAULT_LOCALE.set(DEFAULT_LOCALE); + return DEFAULT_LOCALE; + } return allLocales[0]; } diff --git a/bubble-server/src/main/java/bubble/service/boot/BubbleModelSetupService.java b/bubble-server/src/main/java/bubble/service/boot/BubbleModelSetupService.java new file mode 100644 index 00000000..d1e6e156 --- /dev/null +++ b/bubble-server/src/main/java/bubble/service/boot/BubbleModelSetupService.java @@ -0,0 +1,24 @@ +package bubble.service.boot; + +import bubble.model.account.HasAccount; +import bubble.server.BubbleConfiguration; +import lombok.Getter; +import org.cobbzilla.wizard.ModelSetupService; +import org.cobbzilla.wizard.model.Identifiable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import static bubble.ApiConstants.ENTITY_CONFIGS_ENDPOINT; + +@Service +public class BubbleModelSetupService extends ModelSetupService { + + @Getter @Autowired private BubbleConfiguration configuration; + + @Override protected String getEntityConfigsEndpoint() { return ENTITY_CONFIGS_ENDPOINT; } + + @Override protected void setOwner(Identifiable account, Identifiable entity) { + if (entity instanceof HasAccount) ((HasAccount) entity).setAccount(account.getUuid()); + } + +} diff --git a/bubble-server/src/main/resources/message_templates/en_US/server/post_auth/ResourceMessages.properties b/bubble-server/src/main/resources/message_templates/en_US/server/post_auth/ResourceMessages.properties index 3389d0d4..2f996f4b 100644 --- a/bubble-server/src/main/resources/message_templates/en_US/server/post_auth/ResourceMessages.properties +++ b/bubble-server/src/main/resources/message_templates/en_US/server/post_auth/ResourceMessages.properties @@ -29,6 +29,11 @@ label_menu_logout_icon=fa fa-sign-out-alt # Model Setup fields form_title_model_setup=System Objects field_label_entity_type=Object Type +button_label_upload_model=Upload Objects +field_label_upload_file=Objects File +field_description_upload_file=Must be a valid ZIP or TGZ archive file. +button_label_save_upload_model=Upload +button_label_close_upload_model=Cancel button_label_add_entity=Add New button_label_close_add_entity=Cancel button_label_save_add_entity=Save @@ -446,3 +451,7 @@ err.user.noContact=No contact information provided for user err.value.required=Value is required err.version.mismatch=Version in URL does not match version in object err.write.failed=Write operation failed for key +err.entity.classInFilename.invalid=Type of object could not be determined from filename. The part before the first dot or underscore should be a valid type name +err.entity.filenameExtension.invalid=The object file must be a JSON file containing one or more objects, or a Model Archive File (ending in .zip, .tar.gz, or .tgz) containing a manifest and corresponding object files. +err.entity.fileZipFormat.invalid=The Model Archive File was not in a readable format +err.entity.manifest.required=No manifest.json file was found within the Model Archive File diff --git a/bubble-server/src/main/resources/spring-db-filter.xml b/bubble-server/src/main/resources/spring-db-filter.xml index 35c9fd7e..18d264ae 100644 --- a/bubble-server/src/main/resources/spring-db-filter.xml +++ b/bubble-server/src/main/resources/spring-db-filter.xml @@ -21,7 +21,7 @@ - + diff --git a/bubble-web b/bubble-web index 5f88f3d5..fbb91b5d 160000 --- a/bubble-web +++ b/bubble-web @@ -1 +1 @@ -Subproject commit 5f88f3d53b4170f0183f65c83568b4b1756b6715 +Subproject commit fbb91b5da57408b03ce1c34de4e4d98da226ba13 diff --git a/utils/cobbzilla-utils b/utils/cobbzilla-utils index d6f4b31c..d7ebbd7a 160000 --- a/utils/cobbzilla-utils +++ b/utils/cobbzilla-utils @@ -1 +1 @@ -Subproject commit d6f4b31cda97819212ba2ff6b4ca34e9536d3a9a +Subproject commit d7ebbd7a8c490dae4c804425bdd83466220a69c8 diff --git a/utils/cobbzilla-wizard b/utils/cobbzilla-wizard index a1e5163c..fb35a1d4 160000 --- a/utils/cobbzilla-wizard +++ b/utils/cobbzilla-wizard @@ -1 +1 @@ -Subproject commit a1e5163cb506eab58296a04298694d9a4cf99230 +Subproject commit fb35a1d4e1ab1755365db87deef54b77f02cb369