@@ -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<RuntimeException>) () -> | |||
invalidEx("err."+e.getSimpleName()+".invalid", "Invalid "+e.getSimpleName()+": "+v, v)); | |||
} | |||
} |
@@ -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<Account> 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); | |||
@@ -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<BubbleNetwork> { | |||
@@ -31,6 +33,11 @@ public class BubbleNetworkDAO extends AccountOwnedEntityDAO<BubbleNetwork> { | |||
@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(); | |||
@@ -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; | |||
@@ -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 { | |||
@@ -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 | |||
@@ -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)); | |||
} | |||
} |
@@ -136,11 +136,20 @@ public class BubbleConfiguration extends PgRestServerConfiguration | |||
return bubbleJar; | |||
} | |||
private static final AtomicReference<String> _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]; | |||
} | |||
@@ -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()); | |||
} | |||
} |
@@ -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 |
@@ -21,7 +21,7 @@ | |||
<!-- RedisService --> | |||
<context:component-scan base-package="org.cobbzilla.wizard.cache.redis"/> | |||
<!-- only load the model, DAOs and mocks of certain services --> | |||
<!-- only load the modelFile, DAOs and mocks of certain services --> | |||
<context:component-scan base-package="bubble.model"/> | |||
<context:component-scan base-package="bubble.dao"> | |||
<context:exclude-filter type="regex" expression="bubble.dao.SessionDAO"/> | |||
@@ -1 +1 @@ | |||
Subproject commit 5f88f3d53b4170f0183f65c83568b4b1756b6715 | |||
Subproject commit fbb91b5da57408b03ce1c34de4e4d98da226ba13 |
@@ -1 +1 @@ | |||
Subproject commit d6f4b31cda97819212ba2ff6b4ca34e9536d3a9a | |||
Subproject commit d7ebbd7a8c490dae4c804425bdd83466220a69c8 |
@@ -1 +1 @@ | |||
Subproject commit a1e5163cb506eab58296a04298694d9a4cf99230 | |||
Subproject commit fb35a1d4e1ab1755365db87deef54b77f02cb369 |