Selaa lähdekoodia

implement seaching across all entities

tags/v0.1.6
Jonathan Cobb 5 vuotta sitten
vanhempi
commit
9f3c5946f2
33 muutettua tiedostoa jossa 370 lisäystä ja 104 poistoa
  1. +4
    -2
      bubble-server/src/main/java/bubble/ApiConstants.java
  2. +1
    -2
      bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocateServiceDriverBase.java
  3. +2
    -0
      bubble-server/src/main/java/bubble/model/account/Account.java
  4. +6
    -4
      bubble-server/src/main/java/bubble/model/account/message/AccountMessage.java
  5. +10
    -0
      bubble-server/src/main/java/bubble/model/app/AppData.java
  6. +10
    -0
      bubble-server/src/main/java/bubble/model/app/AppMatcher.java
  7. +8
    -0
      bubble-server/src/main/java/bubble/model/app/AppRule.java
  8. +7
    -0
      bubble-server/src/main/java/bubble/model/app/AppSite.java
  9. +7
    -0
      bubble-server/src/main/java/bubble/model/app/BubbleApp.java
  10. +9
    -0
      bubble-server/src/main/java/bubble/model/app/RuleDriver.java
  11. +12
    -0
      bubble-server/src/main/java/bubble/model/bill/AccountPayment.java
  12. +6
    -4
      bubble-server/src/main/java/bubble/model/bill/AccountPaymentMethod.java
  13. +13
    -0
      bubble-server/src/main/java/bubble/model/bill/AccountPlan.java
  14. +12
    -0
      bubble-server/src/main/java/bubble/model/bill/Bill.java
  15. +14
    -0
      bubble-server/src/main/java/bubble/model/bill/BubblePlan.java
  16. +7
    -0
      bubble-server/src/main/java/bubble/model/cloud/AnsibleRole.java
  17. +7
    -1
      bubble-server/src/main/java/bubble/model/cloud/BubbleBackup.java
  18. +1
    -0
      bubble-server/src/main/java/bubble/model/cloud/BubbleDomain.java
  19. +1
    -0
      bubble-server/src/main/java/bubble/model/cloud/BubbleFootprint.java
  20. +2
    -1
      bubble-server/src/main/java/bubble/model/cloud/BubbleNetwork.java
  21. +4
    -2
      bubble-server/src/main/java/bubble/model/cloud/BubbleNode.java
  22. +7
    -1
      bubble-server/src/main/java/bubble/model/cloud/BubbleNodeKey.java
  23. +1
    -0
      bubble-server/src/main/java/bubble/model/cloud/CloudService.java
  24. +9
    -0
      bubble-server/src/main/java/bubble/model/cloud/notify/NotificationBase.java
  25. +2
    -4
      bubble-server/src/main/java/bubble/model/cloud/notify/ReceivedNotification.java
  26. +2
    -4
      bubble-server/src/main/java/bubble/model/cloud/notify/SentNotification.java
  27. +1
    -1
      bubble-server/src/main/java/bubble/resources/EntityConfigsResource.java
  28. +74
    -0
      bubble-server/src/main/java/bubble/resources/IdentityResource.java
  29. +121
    -0
      bubble-server/src/main/java/bubble/resources/SearchResource.java
  30. +0
    -76
      bubble-server/src/main/java/bubble/resources/account/MeResource.java
  31. +8
    -0
      bubble-server/src/test/java/bubble/test/dev/DevServerTest.java
  32. +1
    -1
      utils/cobbzilla-utils
  33. +1
    -1
      utils/cobbzilla-wizard

+ 4
- 2
bubble-server/src/main/java/bubble/ApiConstants.java Näytä tiedosto

@@ -31,6 +31,8 @@ import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx;
@Slf4j
public class ApiConstants {

public static final int MAX_SEARCH_PAGE = 50;

@Getter(lazy=true) private static final String bubbleDefaultDomain = initDefaultDomain();
private static String initDefaultDomain() {
final File f = new File(HOME_DIR, ".BUBBLE_DEFAULT_DOMAIN");
@@ -149,14 +151,14 @@ public class ApiConstants {
public static final String EP_RESTORE = "/restore";
public static final String EP_KEYS = "/keys";
public static final String EP_STATUS = "/status";
public static final String EP_ID = "/id";
public static final String EP_SEARCH = "/search";
public static final String EP_FORK = "/fork";

public static final String DETECT_ENDPOINT = "/detect";
public static final String EP_LOCALE = "/locale";
public static final String EP_TIMEZONE = "/timezone";

public static final String ID_ENDPOINT = "/id";
public static final String SEARCH_ENDPOINT = "/search";
public static final String DEBUG_ENDPOINT = "/debug";
public static final String BUBBLE_MAGIC_ENDPOINT = "/.bubble";
public static final String EP_ASSETS = "/assets";


+ 1
- 2
bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocateServiceDriverBase.java Näytä tiedosto

@@ -26,7 +26,6 @@ import static org.cobbzilla.util.daemon.ZillaRuntime.die;
import static org.cobbzilla.util.daemon.ZillaRuntime.hashOf;
import static org.cobbzilla.util.io.FileUtil.*;
import static org.cobbzilla.util.json.JsonUtil.json;
import static org.cobbzilla.util.security.ShaUtil.sha256_hex;
import static org.cobbzilla.wizard.cache.redis.RedisService.EX;

@Slf4j
@@ -75,7 +74,7 @@ public abstract class GeoLocateServiceDriverBase<T> extends CloudServiceDriverBa
final HttpRequestBean request = new HttpRequestBean(urlWithLicense).setHeaders(headers);
final HttpMeta meta = HttpUtil.getHeadMetadata(request);

final String uniq = sha256_hex(hashOf(url, headers));
final String uniq = hashOf(url, headers);
final String dbKey = "dbcache_" + uniq;
final File dbFile = cloudDataDAO.getFile(cloud.getUuid(), dbKey);
if (!meta.shouldRefresh(dbFile)) return dbFile; // we are current!


+ 2
- 0
bubble-server/src/main/java/bubble/model/account/Account.java Näytä tiedosto

@@ -41,6 +41,7 @@ import static org.cobbzilla.util.system.Sleep.sleep;
import static org.cobbzilla.util.time.TimeUtil.formatDuration;
import static org.cobbzilla.wizard.model.crypto.EncryptedTypes.ENCRYPTED_STRING;
import static org.cobbzilla.wizard.model.crypto.EncryptedTypes.ENC_PAD;
import static org.cobbzilla.wizard.model.entityconfig.annotations.ECForeignKeySearchDepth.none;
import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx;

@ECType(root=true) @ECTypeURIs(listFields={"name", "url", "description", "admin", "suspended"}, isDeleteDefined=false)
@@ -56,6 +57,7 @@ import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx;
@ECTypeChild(type=BubbleNode.class, backref="account"),
@ECTypeChild(type=SentNotification.class, backref="account")
})
@ECSearchDepth(fkDepth=none)
@Entity @NoArgsConstructor @Accessors(chain=true) @Slf4j
public class Account extends IdentifiableBase implements TokenPrincipal, SqlViewSearchResult {



+ 6
- 4
bubble-server/src/main/java/bubble/model/account/message/AccountMessage.java Näytä tiedosto

@@ -11,10 +11,7 @@ import lombok.ToString;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.wizard.model.IdentifiableBase;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECForeignKey;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECIndex;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECIndexes;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECType;
import org.cobbzilla.wizard.model.entityconfig.annotations.*;
import org.hibernate.annotations.Type;

import javax.persistence.*;
@@ -49,21 +46,26 @@ public class AccountMessage extends IdentifiableBase implements HasAccount {
public boolean hasContact () { return !empty(contact); }
public boolean isSameContact (String uuid) { return hasContact() && contact.equals(uuid); }

@ECSearchable(filter=true)
@ECIndex @Column(length=UUID_MAXLEN, nullable=false, updatable=false)
@Getter @Setter private String name;

@ECSearchable(filter=true)
@Size(max=100, message="err.remoteHost.length")
@Type(type=ENCRYPTED_STRING) @Column(columnDefinition="varchar("+(100+ENC_PAD)+")")
@Getter @Setter private String remoteHost;

@ECSearchable
@Enumerated(EnumType.STRING)
@ECIndex @Column(length=20, nullable=false, updatable=false)
@Getter @Setter private AccountMessageType messageType;

@ECSearchable
@Enumerated(EnumType.STRING)
@ECIndex @Column(length=20, nullable=false, updatable=false)
@Getter @Setter private AccountAction action;

@ECSearchable
@Enumerated(EnumType.STRING)
@ECIndex @Column(length=20, nullable=false, updatable=false)
@Getter @Setter private ActionTarget target;


+ 10
- 0
bubble-server/src/main/java/bubble/model/app/AppData.java Näytä tiedosto

@@ -9,6 +9,7 @@ import lombok.experimental.Accessors;
import org.cobbzilla.util.collection.ArrayUtil;
import org.cobbzilla.wizard.model.Identifiable;
import org.cobbzilla.wizard.model.IdentifiableBase;
import org.cobbzilla.wizard.model.entityconfig.EntityFieldType;
import org.cobbzilla.wizard.model.entityconfig.annotations.*;
import org.cobbzilla.wizard.validation.HasValue;
import org.hibernate.annotations.Type;
@@ -46,30 +47,36 @@ public class AppData extends IdentifiableBase implements AppTemplateEntity {
@Override @Transient public String getName() { return getKey(); }
public AppData setName(String n) { return setKey(n); }

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;

@ECSearchable
@ECForeignKey(entity=BubbleApp.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String app;
public boolean hasApp () { return app != null; }

@ECSearchable
@ECForeignKey(entity=AppMatcher.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String matcher;
public boolean hasMatcher() { return matcher != null; }

@ECSearchable
@ECForeignKey(entity=AppSite.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String site;
public boolean hasSite() { return site != null; }

@ECSearchable(filter=true)
@HasValue(message="err.key.required")
@ECIndex @Column(nullable=false, updatable=false, length=5000)
@Getter @Setter private String key;
public boolean hasKey () { return key != null; }

@ECSearchable(filter=true)
@Size(max=100000, message="err.data.length")
@Type(type=ENCRYPTED_STRING) @Column(columnDefinition="varchar("+(100000+ENC_PAD)+")")
@Getter @Setter private String data;
@@ -84,12 +91,15 @@ public class AppData extends IdentifiableBase implements AppTemplateEntity {
return setData(String.valueOf(val+1));
}

@ECSearchable(type=EntityFieldType.expiration_time)
@ECIndex @Getter @Setter private Long expiration;

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean template = false;
public boolean template() { return template != null && template; }

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean enabled = true;
public boolean enabled() { return enabled != null && enabled; }


+ 10
- 0
bubble-server/src/main/java/bubble/model/app/AppMatcher.java Näytä tiedosto

@@ -40,26 +40,32 @@ public class AppMatcher extends IdentifiableBase implements AppTemplateEntity {
public static final String[] VALUE_FIELDS = {"fqdn", "urlRegex", "rule", "template", "enabled"};
public static final String[] CREATE_FIELDS = ArrayUtil.append(VALUE_FIELDS, "name", "site");

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;

@ECSearchable(filter=true)
@ECIndex @Column(nullable=false, updatable=false, length=200)
@Getter @Setter private String name;

@ECSearchable
@ECForeignKey(entity=BubbleApp.class)
@Column(nullable=false, length=UUID_MAXLEN)
@Getter @Setter private String app;

@ECSearchable
@ECForeignKey(entity=AppSite.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String site;

@ECSearchable(filter=true)
@HasValue(message="err.fqdn.required")
@Size(max=1024, message="err.fqdn.length")
@ECIndex @Column(nullable=false, length=1024)
@Getter @Setter private String fqdn;

@ECSearchable(filter=true)
@HasValue(message="err.urlRegex.required")
@Size(max=1024, message="err.urlRegex.length")
@Type(type=ENCRYPTED_STRING) @Column(nullable=false, columnDefinition="varchar("+(1024+ENC_PAD)+") UNIQUE")
@@ -69,18 +75,22 @@ public class AppMatcher extends IdentifiableBase implements AppTemplateEntity {

public boolean matches (String value) { return getPattern().matcher(value).find(); }

@ECSearchable
@ECForeignKey(entity=AppRule.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String rule;

@ECSearchable
@Column(nullable=false)
@Getter @Setter private Boolean blocked = false;
public boolean blocked() { return blocked != null && blocked; }

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean template = false;
public boolean template () { return template == null || template; }

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean enabled = true;
public boolean enabled () { return enabled == null || enabled; }


+ 8
- 0
bubble-server/src/main/java/bubble/model/app/AppRule.java Näytä tiedosto

@@ -46,10 +46,12 @@ public class AppRule extends IdentifiableBaseParentEntity implements AppTemplate
public static final String[] VALUE_FIELDS = {"driver", "configJson", "template", "enabled"};
public static final String[] CREATE_FIELDS = ArrayUtil.append(VALUE_FIELDS, "name");

@ECSearchable(filter=true)
@HasValue(message="err.name.required")
@ECIndex @Column(nullable=false, updatable=false, length=200)
@Getter @Setter private String name;

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;
@@ -58,21 +60,26 @@ public class AppRule extends IdentifiableBaseParentEntity implements AppTemplate
return (account == null && accountUuid == null) || (account != null && account.equals(accountUuid));
}

@ECSearchable
@ECForeignKey(entity=BubbleApp.class)
@Column(nullable=false, length=UUID_MAXLEN)
@Getter @Setter private String app;

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean template = false;
public boolean template () { return template == null || template; }

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean enabled = true;
public boolean enabled () { return enabled == null || enabled; }

@ECSearchable
@Column(nullable=false)
@Getter @Setter private Integer priority = 0;

@ECSearchable
@ECForeignKey(entity=RuleDriver.class)
@HasValue(message="err.driver.required")
@Column(nullable=false, length=UUID_MAXLEN)
@@ -84,6 +91,7 @@ public class AppRule extends IdentifiableBaseParentEntity implements AppTemplate
return d;
}

@ECSearchable(filter=true)
@Size(max=500000, message="err.configJson.length")
@Type(type=ENCRYPTED_STRING) @Column(columnDefinition="varchar("+(500000+ENC_PAD)+")")
@JsonIgnore @Getter @Setter private String configJson;


+ 7
- 0
bubble-server/src/main/java/bubble/model/app/AppSite.java Näytä tiedosto

@@ -42,28 +42,35 @@ public class AppSite extends IdentifiableBase implements AppTemplateEntity {
return this;
}

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;

@ECSearchable(filter=true)
@ECIndex @Column(nullable=false, updatable=false, length=1000)
@Getter @Setter private String name;

@ECSearchable
@ECForeignKey(entity=BubbleApp.class)
@Column(nullable=false, length=UUID_MAXLEN)
@Getter @Setter private String app;

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean template = false;
public boolean template () { return template == null || template; }

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean enabled = true;
public boolean enabled () { return enabled == null || enabled; }

@ECSearchable(filter=true)
@Column(nullable=false, length=10000)
@Getter @Setter private String description;

@ECSearchable(filter=true)
@Column(nullable=false, length=1024)
@Getter @Setter private String url;



+ 7
- 0
bubble-server/src/main/java/bubble/model/app/BubbleApp.java Näytä tiedosto

@@ -41,31 +41,38 @@ public class BubbleApp extends IdentifiableBaseParentEntity implements AccountTe

private static final String[] VALUE_FIELDS = {"url", "description", "template", "enabled"};

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(length=UUID_MAXLEN, nullable=false, updatable=false)
@Getter @Setter private String account;

@ECSearchable(filter=true)
@HasValue(message="err.name.required")
@ECIndex @Column(nullable=false, updatable=false, length=200)
@Getter @Setter private String name;

@ECSearchable(filter=true)
@HasValue(message="err.url.required")
@Size(max=1024, message="err.url.length")
@Type(type=ENCRYPTED_STRING) @Column(columnDefinition="varchar("+(1024+ENC_PAD)+") NOT NULL")
@Getter @Setter private String url;

@ECSearchable(filter=true)
@Size(max=10000, message="err.description.length")
@Type(type=ENCRYPTED_STRING) @Column(columnDefinition="varchar("+(10000+ENC_PAD)+")")
@Getter @Setter private String description;

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean template = false;
public boolean template() { return template != null && template; }

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean enabled = true;
public boolean enabled () { return enabled == null || enabled; }

@ECSearchable
@ECIndex @Getter @Setter private Boolean needsUpdate = false;

public BubbleApp(Account account, BubbleApp app) {


+ 9
- 0
bubble-server/src/main/java/bubble/model/app/RuleDriver.java Näytä tiedosto

@@ -50,28 +50,35 @@ public class RuleDriver extends IdentifiableBase implements AccountTemplate {
return this;
}

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;

@ECSearchable(filter=true)
@HasValue(message="err.name.required")
@ECIndex @Column(length=200, nullable=false, updatable=false)
@Getter @Setter private String name;

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean template = false;
public boolean template() { return template != null && template; }

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean enabled = true;
public boolean enabled () { return enabled == null || enabled; }

@ECSearchable(filter=true)
@Column(length=200)
@Getter @Setter private String author;

@ECSearchable(filter=true)
@Column(length=1024)
@Getter @Setter private String url;

@ECSearchable
@Column(nullable=false, updatable=false, length=1000)
@Getter @Setter private String driverClass;

@@ -84,6 +91,8 @@ public class RuleDriver extends IdentifiableBase implements AccountTemplate {
@Transient @JsonIgnore @Getter(lazy=true) private final AppRuleDriver driver = instantiate(this.driverClass);

@Embedded @Getter @Setter private SemanticVersion version;

@ECSearchable
@ECIndex @Getter @Setter private Boolean needsUpdate = false;

@Transient @Getter @Setter private AppRuleDriverDescriptor descriptor;


+ 12
- 0
bubble-server/src/main/java/bubble/model/bill/AccountPayment.java Näytä tiedosto

@@ -26,35 +26,44 @@ import static org.cobbzilla.wizard.model.crypto.EncryptedTypes.*;
@Entity @NoArgsConstructor @Accessors(chain=true)
public class AccountPayment extends IdentifiableBase implements HasAccountNoName {

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;

@ECSearchable
@ECForeignKey(entity=AccountPaymentMethod.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String paymentMethod;

@ECSearchable
@ECForeignKey(entity=BubblePlan.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String plan;

@ECSearchable
@ECForeignKey(entity=AccountPlan.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String accountPlan;

@ECSearchable
@ECForeignKey(entity=Bill.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String bill;

@ECSearchable
@Enumerated(EnumType.STRING) @Column(nullable=false, updatable=false, length=20)
@Getter @Setter private AccountPaymentType type;

@ECSearchable
@Enumerated(EnumType.STRING) @Column(nullable=false, length=20)
@Getter @Setter private AccountPaymentStatus status;

@ECSearchable
@Type(type=ENCRYPTED_STRING) @Column(updatable=false, columnDefinition="varchar("+(200+ENC_PAD)+")")
@Getter @Setter private String violation;

@ECSearchable
@Type(type=ENCRYPTED_STRING) @Column(updatable=false, columnDefinition="varchar("+(10000+ENC_PAD)+")")
@JsonIgnore @Getter @Setter private String exception;

@@ -68,12 +77,15 @@ public class AccountPayment extends IdentifiableBase implements HasAccountNoName
return this;
}

@ECSearchable
@Type(type=ENCRYPTED_LONG) @Column(updatable=false, columnDefinition="varchar("+(ENC_LONG)+") NOT NULL")
@Getter @Setter private Long amount = 0L;

@ECSearchable
@ECIndex @Column(nullable=false, updatable=false, length=10)
@Getter @Setter private String currency;

@ECSearchable(filter=true)
@Type(type=ENCRYPTED_STRING) @Column(updatable=false, columnDefinition="varchar("+(100000+ENC_PAD)+") NOT NULL")
@Getter @Setter private String info;



+ 6
- 4
bubble-server/src/main/java/bubble/model/bill/AccountPaymentMethod.java Näytä tiedosto

@@ -16,10 +16,7 @@ import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.wizard.filters.Scrubbable;
import org.cobbzilla.wizard.filters.ScrubbableField;
import org.cobbzilla.wizard.model.IdentifiableBase;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECForeignKey;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECIndex;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECIndexes;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECType;
import org.cobbzilla.wizard.model.entityconfig.annotations.*;
import org.cobbzilla.wizard.validation.ValidationResult;
import org.hibernate.annotations.Type;

@@ -53,15 +50,18 @@ public class AccountPaymentMethod extends IdentifiableBase implements HasAccount

@Override public void beforeCreate() { if (!hasUuid()) initUuid(); }

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(length=UUID_MAXLEN, nullable=false, updatable=false)
@Getter @Setter private String account;

@ECSearchable
@ECForeignKey(entity=CloudService.class)
@Column(length=UUID_MAXLEN, nullable=false, updatable=false)
@Getter @Setter private String cloud;
public boolean hasCloud() { return cloud != null; }

@ECSearchable
@Enumerated(EnumType.STRING) @Column(nullable=false, updatable=false, length=20)
@Getter @Setter private PaymentMethodType paymentMethodType;
public boolean hasPaymentMethodType() { return paymentMethodType != null; }
@@ -71,9 +71,11 @@ public class AccountPaymentMethod extends IdentifiableBase implements HasAccount
public boolean hasPaymentInfo () { return paymentInfo != null; }

public static final String DEFAULT_MASKED_PAYMENT_INFO = "XXXX-".repeat(3)+"XXXX";
@ECSearchable
@Type(type=ENCRYPTED_STRING) @Column(updatable=false, columnDefinition="varchar("+(100+ENC_PAD)+") NOT NULL")
@Getter @Setter private String maskedPaymentInfo = DEFAULT_MASKED_PAYMENT_INFO;

@ECSearchable
@Column(nullable=false)
@Getter @Setter private Boolean deleted = false;
public boolean deleted() { return deleted != null && deleted; }


+ 13
- 0
bubble-server/src/main/java/bubble/model/bill/AccountPlan.java Näytä tiedosto

@@ -10,6 +10,7 @@ import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.cobbzilla.wizard.model.IdentifiableBase;
import org.cobbzilla.wizard.model.entityconfig.EntityFieldType;
import org.cobbzilla.wizard.model.entityconfig.annotations.*;

import javax.persistence.Column;
@@ -43,51 +44,63 @@ public class AccountPlan extends IdentifiableBase implements HasAccount {
@Override public void beforeCreate() { if (!hasUuid()) initUuid(); }

// mirrors network name
@ECSearchable(filter=true)
@Size(max=100, message="err.name.length")
@Column(length=100, nullable=false)
@Getter @Setter private String name;

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;

@ECSearchable
@ECForeignKey(entity=BubblePlan.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String plan;

@ECSearchable
@ECForeignKey(entity=AccountPaymentMethod.class)
@Column(updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String paymentMethod;

@ECSearchable
@ECForeignKey(entity=BubbleDomain.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String domain;

@ECSearchable
@ECForeignKey(entity=BubbleNetwork.class, index=false) @ECIndex(unique=true)
@Column(length=UUID_MAXLEN)
@Getter @Setter private String network;

@ECSearchable
@Column(nullable=false)
@Getter @Setter private Boolean enabled = false;
public boolean enabled() { return enabled != null && enabled; }
public boolean disabled() { return !enabled(); }

@ECSearchable(type=EntityFieldType.epoch_time)
@Column(nullable=false)
@ECIndex @Getter @Setter private Long nextBill;

@ECSearchable
@Column(nullable=false, length=20)
@Getter @Setter private String nextBillDate;
public AccountPlan setNextBillDate() { return setNextBillDate(BILL_START_END_FORMAT.print(getNextBill())); }

@ECSearchable
@ECIndex @Getter @Setter private Long deleted;
public boolean deleted() { return deleted != null; }
public boolean notDeleted() { return !deleted(); }

@ECSearchable
@Column(nullable=false)
@ECIndex @Getter @Setter private Boolean closed = false;
public boolean closed() { return closed != null && closed; }
public boolean notClosed() { return !closed(); }

@ECSearchable
@ECIndex(unique=true) @Column(length=UUID_MAXLEN)
@Getter @Setter private String deletedNetwork;
public boolean hasDeletedNetwork() { return deletedNetwork != null; }


+ 12
- 0
bubble-server/src/main/java/bubble/model/bill/Bill.java Näytä tiedosto

@@ -24,48 +24,60 @@ import static org.cobbzilla.wizard.model.crypto.EncryptedTypes.*;
})
public class Bill extends IdentifiableBase implements HasAccountNoName {

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;

@ECSearchable
@ECForeignKey(entity=BubblePlan.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String plan;

@ECSearchable
@ECForeignKey(entity=AccountPlan.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String accountPlan;

@ECSearchable
@ECIndex @Enumerated(EnumType.STRING)
@Column(nullable=false, length=20)
@Getter @Setter private BillStatus status = BillStatus.unpaid;
public boolean paid() { return status == BillStatus.paid; }
public boolean unpaid() { return !paid(); }

@ECSearchable
@ECIndex @Enumerated(EnumType.STRING)
@Column(nullable=false, updatable=false, length=20)
@Getter @Setter private BillItemType type;

@ECSearchable
@Column(nullable=false, updatable=false, length=20)
@ECIndex @Getter @Setter private String periodLabel;

@ECSearchable
@Column(nullable=false, updatable=false, length=20)
@Getter @Setter private String periodStart;

@ECSearchable
@Column(nullable=false, updatable=false, length=20)
@Getter @Setter private String periodEnd;

public int daysInPeriod () { return BillPeriod.daysInPeriod(periodStart, periodEnd); }

@ECSearchable
@Type(type=ENCRYPTED_LONG) @Column(updatable=false, columnDefinition="varchar("+(ENC_LONG)+") NOT NULL")
@Getter @Setter private Long quantity = 0L;

@ECSearchable
@Type(type=ENCRYPTED_LONG) @Column(updatable=false, columnDefinition="varchar("+(ENC_LONG)+") NOT NULL")
@Getter @Setter private Long price = 0L;

@ECSearchable
@ECIndex @Column(nullable=false, updatable=false, length=10)
@Getter @Setter private String currency;

@ECSearchable
@Type(type=ENCRYPTED_LONG) @Column(columnDefinition="varchar("+(ENC_LONG)+")")
@Getter @Setter private Long refundedAmount = 0L;
public boolean hasRefundedAmount () { return refundedAmount != null && refundedAmount > 0L; }


+ 14
- 0
bubble-server/src/main/java/bubble/model/bill/BubblePlan.java Näytä tiedosto

@@ -44,14 +44,17 @@ public class BubblePlan extends IdentifiableBase implements HasAccount {

public BubblePlan (BubblePlan other) { copy(this, other, CREATE_FIELDS); }

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;

@ECSearchable(filter=true)
@HasValue(message="err.name.required")
@ECIndex @Column(nullable=false, updatable=false, length=200)
@Getter @Setter private String name;

@ECSearchable(filter=true)
@HasValue(message="err.chargeName.required")
@Size(message="err.chargeName.length")
@Column(nullable=false, updatable=false, length=12)
@@ -68,37 +71,48 @@ public class BubblePlan extends IdentifiableBase implements HasAccount {
}
}

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean enabled = true;
public boolean enabled () { return enabled == null || enabled; }

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Long price;

@ECSearchable
@ECIndex @Column(nullable=false, length=10)
@Getter @Setter private String currency = "USD";

@ECSearchable
@Enumerated(EnumType.STRING) @Column(nullable=false, updatable=false, length=20)
@Getter @Setter private BillPeriod period = BillPeriod.monthly;

@ECSearchable
@ECIndex @Column(nullable=false, updatable=false, length=20)
@Enumerated(EnumType.STRING) @Getter @Setter private ComputeNodeSizeType computeSizeType;

@ECSearchable
@Column(nullable=false, updatable=false)
@Getter @Setter private Integer nodesIncluded;

@ECSearchable
@Column(nullable=false, updatable=false)
@Getter @Setter private Integer additionalPerNodePrice;

@ECSearchable
@Column(nullable=false, updatable=false)
@Getter @Setter private Integer storageGbIncluded;

@ECSearchable
@Column(nullable=false, updatable=false)
@Getter @Setter private Integer additionalStoragePerGbPrice;

@ECSearchable
@Column(nullable=false, updatable=false)
@Getter @Setter private Integer bandwidthGbIncluded;

@ECSearchable
@Column(nullable=false, updatable=false)
@Getter @Setter private Integer additionalBandwidthPerGbPrice;



+ 7
- 0
bubble-server/src/main/java/bubble/model/cloud/AnsibleRole.java Näytä tiedosto

@@ -43,10 +43,12 @@ public class AnsibleRole extends IdentifiableBase implements AccountTemplate, Ha

public AnsibleRole(AnsibleRole role) { copy(this, role, COPY_FIELDS); }

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;

@ECSearchable(filter=true)
@HasValue(message="err.name.required")
@Pattern(regexp=ROLENAME_PATTERN, message="err.name.invalid")
@ECIndex @Column(nullable=false, updatable=false, length=200)
@@ -74,9 +76,11 @@ public class AnsibleRole extends IdentifiableBase implements AccountTemplate, Ha
.orElse(null);
}

@ECSearchable(filter=true)
@Size(max=10000, message="err.description.length")
@Getter @Setter private String description;

@ECSearchable
@Enumerated(EnumType.STRING)
@ECIndex @Column(nullable=false, length=20)
@Getter @Setter private AnsibleInstallType install = AnsibleInstallType.standard;
@@ -84,13 +88,16 @@ public class AnsibleRole extends IdentifiableBase implements AccountTemplate, Ha
return install.shouldInstall(installType);
}

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Integer priority;

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean template = false;
public boolean template() { return template != null && template; }

@ECSearchable
@ECIndex @Column(nullable=false)
@Getter @Setter private Boolean enabled = true;
public boolean enabled () { return enabled == null || enabled; }


+ 7
- 1
bubble-server/src/main/java/bubble/model/cloud/BubbleBackup.java Näytä tiedosto

@@ -33,18 +33,22 @@ public class BubbleBackup extends IdentifiableBase implements HasAccount {
if (getUuid() == null) initUuid();
}

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;

@ECSearchable
@ECForeignKey(entity=BubbleNetwork.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String network;

@ECSearchable(filter=true)
@Size(max=2000, message="err.path.length")
@Type(type=ENCRYPTED_STRING) @Column(updatable=false, columnDefinition="varchar("+(2000+ENC_PAD)+") NOT NULL")
@Getter @Setter private String path;

@ECSearchable(filter=true)
@Pattern(regexp="[A-Za-z0-9][-A-Za-z0-9\\._]{2,}", message="err.label.invalid")
@Size(max=300, message="err.label.length")
@Type(type=ENCRYPTED_STRING) @Column(updatable=false, columnDefinition="varchar("+(300+ENC_PAD)+")")
@@ -53,12 +57,14 @@ public class BubbleBackup extends IdentifiableBase implements HasAccount {

@Override @JsonIgnore @Transient public String getName() { return hasLabel() ? getLabel() : getPath(); }

@ECSearchable
@Enumerated(EnumType.STRING)
@ECIndex @Column(nullable=false, length=40)
@Getter @Setter private BackupStatus status;
public boolean success () { return status == BackupStatus.backup_completed; }

@Column(length=ERROR_MAXLEN)
@ECSearchable(filter=true)
@Type(type=ENCRYPTED_STRING) @Column(length=ERROR_MAXLEN)
@Getter @Setter private String error;
public boolean hasError () { return !empty(error); }



+ 1
- 0
bubble-server/src/main/java/bubble/model/cloud/BubbleDomain.java Näytä tiedosto

@@ -53,6 +53,7 @@ public class BubbleDomain extends IdentifiableBase implements AccountTemplate {

@Override public Identifiable update(Identifiable other) { copy(this, other, UPDATE_FIELDS); return this; }

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;


+ 1
- 0
bubble-server/src/main/java/bubble/model/cloud/BubbleFootprint.java Näytä tiedosto

@@ -59,6 +59,7 @@ public class BubbleFootprint extends IdentifiableBase implements AccountTemplate

@Override public Identifiable update(Identifiable other) { copy(this, other, UPDATE_FIELDS); return this; }

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;


+ 2
- 1
bubble-server/src/main/java/bubble/model/cloud/BubbleNetwork.java Näytä tiedosto

@@ -33,7 +33,7 @@ import static org.cobbzilla.wizard.model.crypto.EncryptedTypes.ENCRYPTED_STRING;
import static org.cobbzilla.wizard.model.crypto.EncryptedTypes.ENC_PAD;

@ECType(root=true)
@ECTypeURIs(listFields={"name", "domain", "description", "account", "enabled"})
@ECTypeURIs(baseURI=EP_NETWORKS, listFields={"name", "domain", "description", "account", "enabled"})
@ECTypeFields(list={"name", "domain", "description", "account", "enabled"})
@ECTypeChildren(uriPrefix=EP_NETWORKS+"/{BubbleNetwork.name}", value={
@ECTypeChild(type=BubbleNode.class, backref="network")
@@ -57,6 +57,7 @@ public class BubbleNetwork extends IdentifiableBase implements HasNetwork, HasBu

@Transient @JsonIgnore public String getNetwork () { return getUuid(); }

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;


+ 4
- 2
bubble-server/src/main/java/bubble/model/cloud/BubbleNode.java Näytä tiedosto

@@ -38,6 +38,7 @@ import static org.cobbzilla.util.network.NetworkUtil.isLocalIpv4;
import static org.cobbzilla.util.reflect.ReflectionUtil.copy;
import static org.cobbzilla.util.string.ValidationRegexes.IP4_MAXLEN;
import static org.cobbzilla.util.string.ValidationRegexes.IP6_MAXLEN;
import static org.cobbzilla.wizard.model.entityconfig.annotations.ECForeignKeySearchDepth.shallow;

@ECType(root=true)
@ECTypeURIs(baseURI=EP_NODES, listFields={"name", "ip4"})
@@ -86,11 +87,12 @@ public class BubbleNode extends IdentifiableBase implements HasNetwork, HasBubbl

@JsonIgnore @Transient @Override public String getName() { return getFqdn(); }

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;

@ECSearchable
@ECSearchable(fkDepth=shallow)
@ECForeignKey(entity=BubbleDomain.class)
@HasValue(message="err.network.required")
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@@ -99,7 +101,7 @@ public class BubbleNode extends IdentifiableBase implements HasNetwork, HasBubbl
return getDomain() != null && n.getDomain() != null && getDomain().equals(n.getDomain());
}

@ECSearchable
@ECSearchable(fkDepth=shallow)
@ECForeignKey(entity=BubbleNetwork.class)
@HasValue(message="err.network.required")
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)


+ 7
- 1
bubble-server/src/main/java/bubble/model/cloud/BubbleNodeKey.java Näytä tiedosto

@@ -1,7 +1,6 @@
package bubble.model.cloud;

import bubble.model.account.Account;
import bubble.model.account.HasAccount;
import bubble.model.account.HasAccountNoName;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
@@ -12,8 +11,10 @@ import lombok.experimental.Accessors;
import org.cobbzilla.util.security.RsaKeyPair;
import org.cobbzilla.util.security.RsaMessage;
import org.cobbzilla.wizard.model.IdentifiableBase;
import org.cobbzilla.wizard.model.entityconfig.EntityFieldType;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECForeignKey;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECIndex;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECSearchable;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECType;
import org.hibernate.annotations.Type;

@@ -81,14 +82,17 @@ public class BubbleNodeKey extends IdentifiableBase implements HasAccountNoName
return keys.stream().allMatch(k -> k.expiresInLessThan(TOKEN_GENERATION_LIMIT));
}

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;

@ECSearchable
@ECForeignKey(entity=BubbleNode.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String node;

@ECSearchable(filter=true)
@Column(length=10000, updatable=false, nullable=false)
@Getter private String publicKey;
public BubbleNodeKey setPublicKey (String k) {
@@ -114,10 +118,12 @@ public class BubbleNodeKey extends IdentifiableBase implements HasAccountNoName
@Type(type=ENCRYPTED_STRING) @ECIndex(unique=true) @Column(updatable=false, columnDefinition="varchar("+(100+ENC_PAD)+")")
@Getter @Setter private String privateKeyHash;

@ECSearchable(filter=true)
@Size(max=100, message="err.remoteHost.length")
@Type(type=ENCRYPTED_STRING) @Column(updatable=false, columnDefinition="varchar("+(100+ENC_PAD)+") NOT NULL")
@Getter @Setter private String remoteHost;

@ECSearchable(type=EntityFieldType.epoch_time)
@ECIndex @Column(nullable=false, updatable=false)
@Getter @Setter private Long expiration = defaultExpiration();



+ 1
- 0
bubble-server/src/main/java/bubble/model/cloud/CloudService.java Näytä tiedosto

@@ -72,6 +72,7 @@ public class CloudService extends IdentifiableBaseParentEntity implements Accoun

@Override public Identifiable update(Identifiable thing) { copy(this, thing, UPDATE_FIELDS); return this; }

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;


+ 9
- 0
bubble-server/src/main/java/bubble/model/cloud/notify/NotificationBase.java Näytä tiedosto

@@ -13,6 +13,7 @@ import org.cobbzilla.util.daemon.ZillaRuntime;
import org.cobbzilla.wizard.model.IdentifiableBase;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECForeignKey;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECIndex;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECSearchable;

import javax.persistence.*;

@@ -23,31 +24,38 @@ import static org.cobbzilla.util.json.JsonUtil.json;
public class NotificationBase extends IdentifiableBase implements HasAccountNoName {

// synchronous requests may include this
@ECSearchable
@Column(updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String notificationId;
public boolean hasId () { return notificationId != null; }

@ECSearchable
@ECForeignKey(entity=Account.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String account;

@ECSearchable(filter=true)
@ECIndex @Column(nullable=false, updatable=false, length=50)
@Enumerated(EnumType.STRING) @Getter @Setter private NotificationType type;

@Getter @Setter private boolean resolveNodes = false;

@ECSearchable
@ECForeignKey(entity=BubbleNode.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String fromNode;
public boolean hasFromNode () { return fromNode != null; }

@ECSearchable
@ECForeignKey(entity=BubbleNode.class)
@Column(nullable=false, updatable=false, length=UUID_MAXLEN)
@Getter @Setter private String toNode;

@ECSearchable(filter=true)
@Column(nullable=false, updatable=false, length=1024)
@Getter @Setter private String uri;

@ECSearchable(filter=true)
@Column(updatable=false, length=100_000)
@JsonIgnore @Getter @Setter private String payloadJson;
public boolean hasPayload () { return payloadJson != null; }
@@ -66,6 +74,7 @@ public class NotificationBase extends IdentifiableBase implements HasAccountNoNa
@Transient public NotificationReceipt getReceipt () { return receiptJson == null ? null : json(receiptJson, NotificationReceipt.class); }
public <T extends NotificationBase> T setReceipt (NotificationReceipt receipt) { return (T) setReceiptJson(receipt == null ? null : json(receiptJson)); }

@ECSearchable(filter=true)
@Column(length=ERROR_MAXLEN)
@JsonIgnore @Getter @Setter private String error;



+ 2
- 4
bubble-server/src/main/java/bubble/model/cloud/notify/ReceivedNotification.java Näytä tiedosto

@@ -4,10 +4,7 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECIndex;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECType;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECTypeFields;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECTypeURIs;
import org.cobbzilla.wizard.model.entityconfig.annotations.*;

import javax.persistence.Column;
import javax.persistence.Entity;
@@ -25,6 +22,7 @@ public class ReceivedNotification extends NotificationBase {

public ReceivedNotification(SentNotification notification) { copy(this, notification); setUuid(null); }

@ECSearchable(filter=true)
@ECIndex @Column(nullable=false, length=20)
@Enumerated(EnumType.STRING) @Getter @Setter private NotificationProcessingStatus processingStatus = NotificationProcessingStatus.received;



+ 2
- 4
bubble-server/src/main/java/bubble/model/cloud/notify/SentNotification.java Näytä tiedosto

@@ -4,10 +4,7 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECIndex;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECType;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECTypeFields;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECTypeURIs;
import org.cobbzilla.wizard.model.entityconfig.annotations.*;

import javax.persistence.Column;
import javax.persistence.Entity;
@@ -22,6 +19,7 @@ import static bubble.ApiConstants.EP_SENT_NOTIFICATIONS;
@Entity @NoArgsConstructor @Accessors(chain=true)
public class SentNotification extends NotificationBase {

@ECSearchable
@ECIndex @Column(nullable=false, length=20)
@Enumerated(EnumType.STRING) @Getter @Setter private NotificationSendStatus status = NotificationSendStatus.created;



+ 1
- 1
bubble-server/src/main/java/bubble/resources/EntityConfigsResource.java Näytä tiedosto

@@ -35,7 +35,7 @@ public class EntityConfigsResource extends AbstractEntityConfigsResource {
@Autowired private AccountDAO accountDAO;
@Getter(AccessLevel.PROTECTED) @Autowired private BubbleConfiguration configuration;

private AtomicBoolean allowPublic = new AtomicBoolean(false);
@Getter private AtomicBoolean allowPublic = new AtomicBoolean(false);

@POST @Path("/set/{param}")
public Response setConfig (@Context ContainerRequest ctx,


+ 74
- 0
bubble-server/src/main/java/bubble/resources/IdentityResource.java Näytä tiedosto

@@ -0,0 +1,74 @@
package bubble.resources;

import bubble.dao.account.AccountDAO;
import bubble.dao.account.AccountOwnedEntityDAO;
import bubble.model.account.Account;
import bubble.server.BubbleConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.wizard.dao.DAO;
import org.cobbzilla.wizard.model.Identifiable;
import org.glassfish.grizzly.http.server.Request;
import org.glassfish.jersey.server.ContainerRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import java.util.HashMap;
import java.util.Map;

import static bubble.ApiConstants.ID_ENDPOINT;
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON;
import static org.cobbzilla.wizard.resources.ResourceUtil.*;

@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@Path(ID_ENDPOINT)
@Service @Slf4j
public class IdentityResource {

@Autowired private BubbleConfiguration configuration;

@GET
public Response identifyNothing(@Context Request req,
@Context ContainerRequest ctx) { return ok_empty(); }

@GET @Path("/{id}")
public Response identify(@Context Request req,
@Context ContainerRequest ctx,
@PathParam("id") String id) {
final Account caller = userPrincipal(ctx);
final Map<String, Identifiable> entities = new HashMap<>();
for (Class<? extends Identifiable> type : configuration.getEntityClasses()) {
final DAO dao = configuration.getDaoForEntityClass(type);
final Identifiable found;
if (dao instanceof AccountOwnedEntityDAO) {
// find things we own with the given id
found = ((AccountOwnedEntityDAO) dao).findByAccountAndId(caller.getUuid(), id);

} else if (dao instanceof AccountDAO) {
if (caller.admin()) {
// only admin can find any user
found = ((AccountDAO) dao).findById(id);
} else if (id.equals(caller.getUuid()) || id.equals(caller.getName())) {
// other callers can find themselves
found = caller;
} else {
found = null;
}

} else if (caller.admin()) {
// admins can find anything anywhere, regardless of who owns it
found = dao.findByUuid(id);

} else {
// everything else is not found
found = null;
}
if (found != null) entities.put(type.getName(), found);
}
return ok(entities);
}

}

+ 121
- 0
bubble-server/src/main/java/bubble/resources/SearchResource.java Näytä tiedosto

@@ -0,0 +1,121 @@
package bubble.resources;

import bubble.model.account.Account;
import bubble.server.BubbleConfiguration;
import bubble.service.cloud.GeoService;
import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.util.collection.ExpirationMap;
import org.cobbzilla.wizard.dao.AbstractDAO;
import org.cobbzilla.wizard.dao.DAO;
import org.cobbzilla.wizard.dao.SearchResults;
import org.cobbzilla.wizard.model.search.SearchQuery;
import org.cobbzilla.wizard.model.search.SqlViewField;
import org.glassfish.grizzly.http.server.Request;
import org.glassfish.jersey.server.ContainerRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static bubble.ApiConstants.*;
import static java.util.concurrent.TimeUnit.MINUTES;
import static org.cobbzilla.util.daemon.ZillaRuntime.hashOf;
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON;
import static org.cobbzilla.wizard.resources.ResourceUtil.*;

@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@Path(SEARCH_ENDPOINT)
@Service @Slf4j
public class SearchResource {

@Autowired private BubbleConfiguration configuration;
@Autowired private GeoService geoService;

public static final String Q_FILTER = "query";
public static final String Q_META = "meta";
public static final String Q_PAGE = "page";
public static final String Q_SIZE = "size";

private Map<String, DAO> daoCache = new ConcurrentHashMap<>();

@GET @Path("/{type}")
public Response search(@Context Request req,
@Context ContainerRequest ctx,
@PathParam("type") String type,
@QueryParam(Q_META) Boolean meta,
@QueryParam(Q_FILTER) String filter,
@QueryParam(Q_PAGE) Integer page,
@QueryParam(Q_SIZE) Integer size) {
return search(req, ctx, type, meta, filter, page, size, null);
}

private Map<String, Object> _searchCache = new ExpirationMap<>(MINUTES.toMillis(10), MINUTES.toMillis(15));

@POST @Path("/{type}")
public Response search(@Context Request req,
@Context ContainerRequest ctx,
@PathParam("type") String type,
@QueryParam(Q_META) Boolean meta,
@QueryParam(Q_FILTER) String filter,
@QueryParam(Q_PAGE) Integer page,
@QueryParam(Q_SIZE) Integer size,
SearchQuery searchQuery) {

final Account caller = userPrincipal(ctx);
final String cacheKey = hashOf(caller.getUuid(), type, meta, filter, page, size, searchQuery);
return ok(_searchCache.computeIfAbsent(cacheKey, searchKey -> {
final DAO dao = daoCache.computeIfAbsent(type, k -> getDao(type));
if (meta != null) return ((AbstractDAO) dao).getSearchFields();

final SearchQuery q = searchQuery != null ? searchQuery : new SearchQuery();
if (!q.hasLocale()) {
try {
q.setLocale(geoService.getFirstLocale(caller, getRemoteHost(req), normalizeLangHeader(req)));
} catch (Exception e) {
log.warn("search: error setting locale, using default: "+configuration.getDefaultLocale()+": "+e);
q.setLocale(configuration.getDefaultLocale());
}
}
q.setPageNumber(page != null ? page : 1);
q.setPageSize(size != null ? Integer.min(size, MAX_SEARCH_PAGE) : Integer.min(q.getPageSize(), MAX_SEARCH_PAGE));
if (filter != null) q.setFilter(filter);

if (!caller.admin()) {
final Class entityClass = dao.getEntityClass();
if (entityClass.equals(Account.class)) {
// non-admins can only look up themselves
q.setBound("uuid", caller.getUuid());
} else {
final SqlViewField accountField = ((AbstractDAO) dao).findSearchField(entityClass, "account");
if (accountField != null) {
q.setBound("account", caller.getUuid());
} else {
// no results, non-admin cannot search for things that do not have an account
return new SearchResults<>().setError("cannot search "+ entityClass.getName());
}
}
}

final SearchResults results = dao.search(q);
if (results.hasNextPage(q)) {
results.setNextPage(req.getRequestURI()+"?"+Q_PAGE+"="+(q.getPageNumber()+1)+"&"+Q_SIZE+"="+q.getPageSize());
}
return results;
}));
}

public DAO getDao(String type) {
for (Class c : configuration.getEntityClasses()) {
if (c.getSimpleName().equalsIgnoreCase(type)) {
return configuration.getDaoForEntityClass(c);
}
}
throw notFoundEx(type);
}

}

+ 0
- 76
bubble-server/src/main/java/bubble/resources/account/MeResource.java Näytä tiedosto

@@ -2,7 +2,6 @@ package bubble.resources.account;

import bubble.dao.SessionDAO;
import bubble.dao.account.AccountDAO;
import bubble.dao.account.AccountOwnedEntityDAO;
import bubble.dao.account.AccountPolicyDAO;
import bubble.model.account.Account;
import bubble.model.account.AccountPolicy;
@@ -20,7 +19,6 @@ import bubble.resources.notify.SentNotificationsResource;
import bubble.server.BubbleConfiguration;
import bubble.service.account.StandardAccountMessageService;
import bubble.service.account.download.AccountDownloadService;
import bubble.service.cloud.GeoService;
import bubble.service.cloud.StandardNetworkService;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Cleanup;
@@ -31,10 +29,7 @@ import org.cobbzilla.wizard.client.script.ApiRunner;
import org.cobbzilla.wizard.client.script.ApiRunnerListener;
import org.cobbzilla.wizard.client.script.ApiRunnerListenerStreamLogger;
import org.cobbzilla.wizard.client.script.ApiScript;
import org.cobbzilla.wizard.dao.DAO;
import org.cobbzilla.wizard.model.HashedPassword;
import org.cobbzilla.wizard.model.Identifiable;
import org.cobbzilla.wizard.model.search.SearchQuery;
import org.glassfish.grizzly.http.server.Request;
import org.glassfish.jersey.server.ContainerRequest;
import org.springframework.beans.factory.annotation.Autowired;
@@ -44,9 +39,6 @@ import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static bubble.ApiConstants.*;
import static org.cobbzilla.util.daemon.ZillaRuntime.errorString;
@@ -266,72 +258,4 @@ public class MeResource {
return ok(networkService.listLaunchStatuses(caller.getUuid()));
}

@GET @Path(EP_ID)
public Response identifyNothing(@Context Request req,
@Context ContainerRequest ctx) { return ok_empty(); }

@GET @Path(EP_ID+"/{id}")
public Response identify(@Context Request req,
@Context ContainerRequest ctx,
@PathParam("id") String id) {
final Account caller = userPrincipal(ctx);
final Map<String, Identifiable> entities = new HashMap<>();
for (Class<? extends Identifiable> type : configuration.getEntityClasses()) {
final DAO dao = configuration.getDaoForEntityClass(type);
final Identifiable found;
if (dao instanceof AccountOwnedEntityDAO) {
// find things we own with the given id
found = ((AccountOwnedEntityDAO) dao).findByAccountAndId(caller.getUuid(), id);

} else if (dao instanceof AccountDAO) {
if (caller.admin()) {
// only admin can find any user
found = ((AccountDAO) dao).findById(id);
} else if (id.equals(caller.getUuid()) || id.equals(caller.getName())) {
// other callers can find themselves
found = caller;
} else {
found = null;
}

} else if (caller.admin()) {
// admins can find anything anywhere, regardless of who owns it
found = dao.findByUuid(id);

} else {
// everything else is not found
found = null;
}
if (found != null) entities.put(type.getName(), found);
}
return ok(entities);
}

@Autowired private GeoService geoService;

private Map<String, DAO> daoCache = new ConcurrentHashMap<>();

@POST @Path(EP_SEARCH+"/{type}")
public Response search(@Context Request req,
@Context ContainerRequest ctx,
@PathParam("type") String type,
SearchQuery searchQuery) {
final Account caller = userPrincipal(ctx);
final DAO dao = daoCache.computeIfAbsent(type, k -> getDao(type));
if (searchQuery == null) searchQuery = new SearchQuery();
if (!searchQuery.hasLocale()) {
searchQuery.setLocale(geoService.getFirstLocale(caller, getRemoteHost(req), normalizeLangHeader(req)));
}
return ok(dao.search(searchQuery));
}

public DAO getDao(String type) {
for (Class c : configuration.getEntityClasses()) {
if (c.getSimpleName().equalsIgnoreCase(type)) {
return configuration.getDaoForEntityClass(c);
}
}
throw notFoundEx(type);
}

}

+ 8
- 0
bubble-server/src/test/java/bubble/test/dev/DevServerTest.java Näytä tiedosto

@@ -1,7 +1,10 @@
package bubble.test.dev;

import bubble.resources.EntityConfigsResource;
import bubble.server.BubbleConfiguration;
import bubble.test.ActivatedBubbleModelTestBase;
import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.wizard.server.RestServer;
import org.junit.Test;

import static java.util.concurrent.TimeUnit.DAYS;
@@ -20,6 +23,11 @@ public class DevServerTest extends ActivatedBubbleModelTestBase {
@Override protected boolean allowPreExistingDatabase() { return true; }
@Override public boolean doTruncateDb() { return false; }

@Override public void onStart(RestServer<BubbleConfiguration> server) {
getConfiguration().getBean(EntityConfigsResource.class).getAllowPublic().set(true);
super.onStart(server);
}

@Test public void runDevServer () throws Exception {
log.info("runDevServer: Bubble API server started and model initialized. You may now begin testing.");
sleep(DAYS.toMillis(30), "running dev server");


+ 1
- 1
utils/cobbzilla-utils

@@ -1 +1 @@
Subproject commit 708996280e324bb3e5c819743a477ea988312d86
Subproject commit f804680fd96b25582d9a269cfcd82f173c7da4d4

+ 1
- 1
utils/cobbzilla-wizard

@@ -1 +1 @@
Subproject commit 65c0a83a885608d917c1d1a4d85dd8945d35f8d4
Subproject commit 275e0f3fdd4f10f5cdb04416c0d8cbb2092c065e

Ladataan…
Peruuta
Tallenna