瀏覽代碼

WIP. improving openapi docs

tags/v1.4.37
Jonathan Cobb 3 年之前
父節點
當前提交
5ed1e4cd98
共有 23 個文件被更改,包括 297 次插入220 次删除
  1. +1
    -0
      bubble-server/src/main/java/bubble/ApiConstants.java
  2. +5
    -3
      bubble-server/src/main/java/bubble/cloud/email/RenderedEmail.java
  3. +6
    -3
      bubble-server/src/main/java/bubble/cloud/geoCode/GeoCodeResult.java
  4. +6
    -3
      bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocation.java
  5. +2
    -1
      bubble-server/src/main/java/bubble/cloud/geoTime/GeoTimeZone.java
  6. +2
    -2
      bubble-server/src/main/java/bubble/model/AppLinks.java
  7. +7
    -5
      bubble-server/src/main/java/bubble/model/BasicAppLinks.java
  8. +1
    -2
      bubble-server/src/main/java/bubble/model/cloud/BubbleNodeKey.java
  9. +9
    -0
      bubble-server/src/main/java/bubble/resources/BubbleMagicResource.java
  10. +9
    -0
      bubble-server/src/main/java/bubble/resources/DebugResource.java
  11. +16
    -2
      bubble-server/src/main/java/bubble/resources/DetectResource.java
  12. +6
    -14
      bubble-server/src/main/java/bubble/resources/EntityConfigsResource.java
  13. +8
    -11
      bubble-server/src/main/java/bubble/resources/IdentityResource.java
  14. +4
    -8
      bubble-server/src/main/java/bubble/resources/SearchResource.java
  15. +2
    -2
      bubble-server/src/main/java/bubble/resources/TagsResource.java
  16. +10
    -14
      bubble-server/src/main/java/bubble/resources/account/AccountOwnedResource.java
  17. +7
    -3
      bubble-server/src/main/java/bubble/resources/account/AccountPromotionsResource.java
  18. +43
    -43
      bubble-server/src/main/java/bubble/resources/account/AccountsResource.java
  19. +62
    -75
      bubble-server/src/main/java/bubble/resources/account/AuthResource.java
  20. +88
    -27
      bubble-server/src/main/java/bubble/resources/account/MeResource.java
  21. +1
    -0
      bubble-server/src/main/resources/bubble-config.yml
  22. +1
    -1
      utils/cobbzilla-utils
  23. +1
    -1
      utils/cobbzilla-wizard

+ 1
- 0
bubble-server/src/main/java/bubble/ApiConstants.java 查看文件

@@ -301,6 +301,7 @@ public class ApiConstants {
public static final String API_TAG_BACKUP_RESTORE = "backup and restore";
public static final String API_TAG_NODE = "node";
public static final String API_TAG_NODE_MANAGER = "node manager";
public static final String API_TAG_PAYMENT = "payment";

public static String getToken(String json) {
if (json == null) return null;


+ 5
- 3
bubble-server/src/main/java/bubble/cloud/email/RenderedEmail.java 查看文件

@@ -10,6 +10,8 @@ import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.cobbzilla.mail.SimpleEmailMessage;
import org.cobbzilla.wizard.model.OpenApiSchema;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECField;

import java.util.Map;

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

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

@Getter private final long ctime = now();
@Getter private final String uuid = randomUUID().toString();
@ECField @Getter private final long ctime = now();
@ECField @Getter private final String uuid = randomUUID().toString();
@Getter @Setter private Map<String, Object> ctx;

public RenderedEmail (Map<String, Object> ctx) { this.ctx = ctx; }


+ 6
- 3
bubble-server/src/main/java/bubble/cloud/geoCode/GeoCodeResult.java 查看文件

@@ -10,16 +10,19 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.cobbzilla.wizard.model.OpenApiSchema;
import org.cobbzilla.wizard.model.entityconfig.EntityFieldType;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECField;

import javax.persistence.Transient;

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

@NoArgsConstructor @AllArgsConstructor @Accessors(chain=true)
@NoArgsConstructor @AllArgsConstructor @Accessors(chain=true) @OpenApiSchema
public class GeoCodeResult {

@Getter @Setter private String lat;
@Getter @Setter private String lon;
@ECField(type=EntityFieldType.decimal) @Getter @Setter private String lat;
@ECField(type=EntityFieldType.decimal) @Getter @Setter private String lon;

@JsonIgnore @Transient public double getLatitude () { return big(lat).doubleValue(); }
@JsonIgnore @Transient public double getLongitude () { return big(lon).doubleValue(); }


+ 6
- 3
bubble-server/src/main/java/bubble/cloud/geoLocation/GeoLocation.java 查看文件

@@ -12,12 +12,15 @@ import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.cobbzilla.util.math.Haversine;
import org.cobbzilla.wizard.model.OpenApiSchema;
import org.cobbzilla.wizard.model.entityconfig.EntityFieldType;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECField;

import javax.persistence.Transient;

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

@NoArgsConstructor @Accessors(chain=true) @ToString(of={"lat", "lon"})
@NoArgsConstructor @Accessors(chain=true) @ToString(of={"lat", "lon"}) @OpenApiSchema
public class GeoLocation {

public static final GeoLocation NULL_LOCATION = new GeoLocation().setLat("-1.0").setLon("-1.0");
@@ -27,8 +30,8 @@ public class GeoLocation {

@Getter @Setter private String region;
@Getter @Setter private String city;
@Getter @Setter private String lat;
@Getter @Setter private String lon;
@ECField(type=EntityFieldType.decimal) @Getter @Setter private String lat;
@ECField(type=EntityFieldType.decimal) @Getter @Setter private String lon;

@JsonIgnore @Transient public double getLatitude () { return big(lat).doubleValue(); }
@JsonIgnore @Transient public double getLongitude () { return big(lon).doubleValue(); }


+ 2
- 1
bubble-server/src/main/java/bubble/cloud/geoTime/GeoTimeZone.java 查看文件

@@ -9,8 +9,9 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.cobbzilla.wizard.model.OpenApiSchema;

@NoArgsConstructor @AllArgsConstructor @Accessors(chain=true)
@NoArgsConstructor @AllArgsConstructor @Accessors(chain=true) @OpenApiSchema
public class GeoTimeZone {

public static final GeoTimeZone UTC = new GeoTimeZone("Etc/UTC", "UTC", 0L);


+ 2
- 2
bubble-server/src/main/java/bubble/model/AppLinks.java 查看文件

@@ -5,14 +5,14 @@
package bubble.model;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import org.cobbzilla.wizard.model.OpenApiSchema;

import java.util.HashMap;
import java.util.Map;

@Schema
@OpenApiSchema
public class AppLinks extends BasicAppLinks {

@JsonIgnore @Getter @Setter private Map<String, BasicAppLinks> locale = new HashMap<>();


+ 7
- 5
bubble-server/src/main/java/bubble/model/BasicAppLinks.java 查看文件

@@ -8,12 +8,14 @@ import lombok.Getter;
import lombok.Setter;
import org.cobbzilla.wizard.model.entityconfig.annotations.ECField;

import static org.cobbzilla.wizard.model.entityconfig.EntityFieldType.http_url;

public class BasicAppLinks {

@ECField @Getter @Setter private String ios;
@ECField @Getter @Setter private String android;
@ECField @Getter @Setter private String windows;
@ECField @Getter @Setter private String macosx;
@ECField @Getter @Setter private String linux;
@ECField(type=http_url) @Getter @Setter private String ios;
@ECField(type=http_url) @Getter @Setter private String android;
@ECField(type=http_url) @Getter @Setter private String windows;
@ECField(type=http_url) @Getter @Setter private String macosx;
@ECField(type=http_url) @Getter @Setter private String linux;

}

+ 1
- 2
bubble-server/src/main/java/bubble/model/cloud/BubbleNodeKey.java 查看文件

@@ -7,7 +7,6 @@ package bubble.model.cloud;
import bubble.model.account.Account;
import bubble.model.account.HasAccountNoName;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@@ -37,7 +36,7 @@ import static org.cobbzilla.util.security.ShaUtil.sha256_hex;
import static org.cobbzilla.wizard.model.crypto.EncryptedTypes.ENCRYPTED_STRING;
import static org.cobbzilla.wizard.model.crypto.EncryptedTypes.ENC_PAD;

@Entity @ECType(root=true) @ECTypeCreate(method="DISABLED") @Schema
@Entity @ECType(root=true) @ECTypeCreate(method="DISABLED")
@NoArgsConstructor @Accessors(chain=true) @ToString(of={"publicKeyHash"}, callSuper=true)
public class BubbleNodeKey extends IdentifiableBase implements HasAccountNoName {



+ 9
- 0
bubble-server/src/main/java/bubble/resources/BubbleMagicResource.java 查看文件

@@ -4,6 +4,8 @@
*/
package bubble.resources;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.glassfish.jersey.server.ContainerRequest;
import org.springframework.stereotype.Service;
@@ -17,7 +19,9 @@ import javax.ws.rs.core.Response;

import static bubble.ApiConstants.BUBBLE_MAGIC_ENDPOINT;
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON;
import static org.cobbzilla.util.http.HttpStatusCodes.SC_OK;
import static org.cobbzilla.wizard.resources.ResourceUtil.ok;
import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.API_TAG_UTILITY;

@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@@ -26,6 +30,11 @@ import static org.cobbzilla.wizard.resources.ResourceUtil.ok;
public class BubbleMagicResource {

@GET
@Operation(tags=API_TAG_UTILITY,
summary="Simple health check",
description="Returns a static string, verifies that API can communicate over the network",
responses=@ApiResponse(responseCode=SC_OK, description="fixed response")
)
public Response get(@Context ContainerRequest ctx) {
return ok("you are ok. the magic is ok too.");
}


+ 9
- 0
bubble-server/src/main/java/bubble/resources/DebugResource.java 查看文件

@@ -14,6 +14,8 @@ import bubble.model.account.message.AccountMessageType;
import bubble.model.account.message.ActionTarget;
import bubble.server.BubbleConfiguration;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.glassfish.jersey.server.ContainerRequest;
@@ -37,10 +39,12 @@ import static bubble.cloud.auth.RenderedMessage.filteredInbox;
import static org.cobbzilla.util.daemon.ZillaRuntime.die;
import static org.cobbzilla.util.daemon.ZillaRuntime.empty;
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON;
import static org.cobbzilla.util.http.HttpStatusCodes.SC_OK;
import static org.cobbzilla.util.json.JsonUtil.*;
import static org.cobbzilla.util.reflect.ReflectionUtil.forName;
import static org.cobbzilla.util.reflect.ReflectionUtil.instantiate;
import static org.cobbzilla.wizard.resources.ResourceUtil.*;
import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.API_TAG_UTILITY;

@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@@ -51,6 +55,11 @@ public class DebugResource {
@Autowired private BubbleConfiguration configuration;

@GET @Path("/inbox/{type}/{recipient}")
@Operation(tags=API_TAG_UTILITY,
summary="Read debug mailboxes",
description="Read debug mailboxes. Must be admin. These are only used in testing.",
responses=@ApiResponse(responseCode=SC_OK, description="a JSON array of RenderedMessage")
)
public Response inbox(@Context ContainerRequest ctx,
@PathParam("type") CloudServiceType type,
@PathParam("recipient") String recipient,


+ 16
- 2
bubble-server/src/main/java/bubble/resources/DetectResource.java 查看文件

@@ -4,8 +4,9 @@
*/
package bubble.resources;

import bubble.cloud.CloudServiceType;
import bubble.service.cloud.GeoService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.glassfish.grizzly.http.server.Request;
import org.glassfish.jersey.server.ContainerRequest;
@@ -21,7 +22,10 @@ import javax.ws.rs.core.Response;

import static bubble.ApiConstants.*;
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON;
import static org.cobbzilla.wizard.resources.ResourceUtil.*;
import static org.cobbzilla.util.http.HttpStatusCodes.SC_OK;
import static org.cobbzilla.wizard.resources.ResourceUtil.ok;
import static org.cobbzilla.wizard.resources.ResourceUtil.optionalUserPrincipal;
import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.API_TAG_UTILITY;

@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@@ -32,12 +36,22 @@ public class DetectResource {
@Autowired private GeoService geoService;

@GET @Path(EP_LOCALE)
@Operation(tags=API_TAG_UTILITY,
summary="Detect the caller's locale",
description="Detect the caller's locale",
responses=@ApiResponse(responseCode=SC_OK, description="an array of locale strings in priority order")
)
public Response detectLocales(@Context Request req,
@Context ContainerRequest ctx) {
return ok(geoService.getSupportedLocales(optionalUserPrincipal(ctx), getRemoteHost(req), normalizeLangHeader(req)));
}

@GET @Path(EP_TIMEZONE)
@Operation(tags=API_TAG_UTILITY,
summary="Detect the caller's time zone",
description="Detect the caller's time zone",
responses=@ApiResponse(responseCode=SC_OK, description="the TimeZone ")
)
public Response detectTimezone(@Context Request req,
@Context ContainerRequest ctx) {
return ok(geoService.getTimeZone(optionalUserPrincipal(ctx), getRemoteHost(req)));


+ 6
- 14
bubble-server/src/main/java/bubble/resources/EntityConfigsResource.java 查看文件

@@ -53,17 +53,12 @@ public class EntityConfigsResource extends AbstractEntityConfigsResource {

@POST @Path("/set/{param}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_UTILITY},
tags=API_TAG_UTILITY,
summary="Set a configuration parameter to `true`",
description="Set a configuration parameter to `true`",
parameters={@Parameter(name="param", description="the name of the parameter to set")},
responses={
@ApiResponse(responseCode=SC_OK, description="the value that was set",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="should always return true", value="true")
}
)})
}
parameters=@Parameter(name="param", description="the name of the parameter to set"),
responses=@ApiResponse(responseCode=SC_OK, description="the value that was set",
content=@Content(mediaType=APPLICATION_JSON, examples=@ExampleObject(name="should always return true", value="true")))
)
public Response setConfig (@Context ContainerRequest ctx,
@PathParam("param") String param) {
@@ -72,7 +67,7 @@ public class EntityConfigsResource extends AbstractEntityConfigsResource {

@POST @Path("/set/{param}/{value}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_UTILITY},
tags=API_TAG_UTILITY,
summary="Set a configuration parameter to a value",
description="Set a configuration parameter to a value",
parameters={
@@ -81,10 +76,7 @@ public class EntityConfigsResource extends AbstractEntityConfigsResource {
},
responses={
@ApiResponse(responseCode=SC_OK, description="the value that was set",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="if the value was the String 'foo'", value="\"foo\"")
}
)})
content=@Content(mediaType=APPLICATION_JSON, examples=@ExampleObject(name="if the value was the String 'foo'", value="\"foo\"")))
}
)
public Response setConfig (@Context ContainerRequest ctx,


+ 8
- 11
bubble-server/src/main/java/bubble/resources/IdentityResource.java 查看文件

@@ -49,19 +49,16 @@ public class IdentityResource {

@GET @Path("/{id}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_UTILITY},
tags=API_TAG_UTILITY,
summary="Find what object(s) an ID belongs to. Useful when you have a UUID but don't know what kind of thing it refers to, if any.",
description="Searches all model objects by ID. The id parameter is typically a UUID or name",
parameters={@Parameter(name="id", description="an identifier (typically UUID or name) to search for")},
responses={
@ApiResponse(responseCode=SC_OK, description="a JSON object where the property names are entity types, and a property's corresponding value is the object of that type found with the given ID",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="usually a UUID only matches one object", value="{\"CloudService\": {\"uuid\": \"the-ID-you-searched-for\", \"other-cloud-service-fields\": \"would-be-shown\"}}"),
@ExampleObject(name="a UUID for an Account also matches the AccountPolicy", value="{\"Account\": {\"uuid\": \"the-ID-you-searched-for\", \"other-account-fields\": \"would-be-shown\"}, \"AccountPolicy\": {\"uuid\": \"the-ID-you-searched-for\", \"other-policy-fields\": \"would-be-shown\"}}"),
@ExampleObject(name="empty JSON object when no matches are found", value="{}")
}
)})
}
parameters=@Parameter(name="id", description="an identifier (typically UUID or name) to search for"),
responses=@ApiResponse(responseCode=SC_OK, description="a JSON object where the property names are entity types, and a property's corresponding value is the object of that type found with the given ID",
content=@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="usually a UUID only matches one object", value="{\"CloudService\": {\"uuid\": \"the-ID-you-searched-for\", \"other-cloud-service-fields\": \"would-be-shown\"}}"),
@ExampleObject(name="a UUID for an Account also matches the AccountPolicy", value="{\"Account\": {\"uuid\": \"the-ID-you-searched-for\", \"other-account-fields\": \"would-be-shown\"}, \"AccountPolicy\": {\"uuid\": \"the-ID-you-searched-for\", \"other-policy-fields\": \"would-be-shown\"}}"),
@ExampleObject(name="empty JSON object when no matches are found", value="{}")
}))
)
public Response identify(@Context Request req,
@Context ContainerRequest ctx,


+ 4
- 8
bubble-server/src/main/java/bubble/resources/SearchResource.java 查看文件

@@ -38,7 +38,7 @@ public class SearchResource {

@GET @Path("/{type}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_SEARCH},
tags=API_TAG_SEARCH,
summary="Search model objects",
description="Search model objects",
parameters={
@@ -50,9 +50,7 @@ public class SearchResource {
@Parameter(name=Q_SIZE, description="page size. default is 10, max is 50"),
@Parameter(name=Q_SORT, description="sort field. prefix with + or - to indicate ascending/descending")
},
responses={
@ApiResponse(responseCode=SC_OK, description="a SearchResults object, or if meta was true then a SqlViewField[] array")
}
responses=@ApiResponse(responseCode=SC_OK, description="a SearchResults object, or if meta was true then a SqlViewField[] array")
)
public Response search(@Context Request req,
@Context ContainerRequest ctx,
@@ -68,7 +66,7 @@ public class SearchResource {

@POST @Path("/{type}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_SEARCH},
tags=API_TAG_SEARCH,
summary="Search model objects",
description="Search model objects",
parameters={
@@ -80,9 +78,7 @@ public class SearchResource {
@Parameter(name=Q_SIZE, description="page size. default is 10, max is 50"),
@Parameter(name=Q_SORT, description="sort field. prefix with + or - to indicate ascending/descending")
},
responses={
@ApiResponse(responseCode=SC_OK, description="a SearchResults object, or if meta was true then a SqlViewField[] array")
}
responses=@ApiResponse(responseCode=SC_OK, description="a SearchResults object, or if meta was true then a SqlViewField[] array")
)
public Response search(@Context Request req,
@Context ContainerRequest ctx,


+ 2
- 2
bubble-server/src/main/java/bubble/resources/TagsResource.java 查看文件

@@ -46,8 +46,8 @@ public class TagsResource {
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
summary="Set a tag",
description="Set a tag",
parameters={@Parameter(name="name", description="name of the tag")},
responses={@ApiResponse(responseCode=SC_OK, description="a BubbleTags object representing the current list of tags")}
parameters=@Parameter(name="name", description="name of the tag"),
responses=@ApiResponse(responseCode=SC_OK, description="a BubbleTags object representing the current list of tags")
)
public Response set(@Context ContainerRequest ctx,
@PathParam("name") String name,


+ 10
- 14
bubble-server/src/main/java/bubble/resources/account/AccountOwnedResource.java 查看文件

@@ -65,10 +65,10 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned

@GET
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT_OBJECTS},
tags=API_TAG_ACCOUNT_OBJECTS,
summary="List objects",
description="List objects",
responses={@ApiResponse(responseCode=SC_OK, description="an array of objects")}
responses=@ApiResponse(responseCode=SC_OK, description="an array of objects")
)
public Response listEntities(@Context Request req,
@Context ContainerRequest ctx) {
@@ -136,7 +136,7 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned

@GET @Path("/{id}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT_OBJECTS},
tags=API_TAG_ACCOUNT_OBJECTS,
summary="Find by identifier",
description="Find by identifier",
responses={
@@ -169,15 +169,13 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned

@PUT
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT_OBJECTS},
tags=API_TAG_ACCOUNT_OBJECTS,
summary="Create a new object",
description="Create a new object. If validation errors occur, status "+SC_INVALID+" is returned and the response will contain an array of errors. Within each error, the `messageTemplate` field refers to messages that can be localized using the /messages resource",
responses={
@ApiResponse(responseCode=SC_OK, description="the object that was created"),
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="validation errors", value="[{\"messageTemplate\": \"some.symbolic.error\", \"message\": \"some default English message\"}]")
})})
content=@Content(mediaType=APPLICATION_JSON, examples=@ExampleObject(name="validation errors", value="[{\"messageTemplate\": \"some.symbolic.error\", \"message\": \"some default English message\"}]")))
}
)
public Response create(@Context Request req,
@@ -210,17 +208,15 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned

@POST @Path("/{id}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT_OBJECTS},
tags=API_TAG_ACCOUNT_OBJECTS,
summary="Update an existing object",
description="Update an new object. For many types, the object will be created if it does not exist. If validation errors occur, status "+SC_INVALID+" is returned and the response will contain an array of errors. Within each error, the `messageTemplate` field refers to messages that can be localized using the /messages resource",
parameters={@Parameter(name="id", description="the UUID (or name, if allowed) of the object to update")},
parameters=@Parameter(name="id", description="the UUID (or name, if allowed) of the object to update"),
responses={
@ApiResponse(responseCode=SC_OK, description="the object that was updated"),
@ApiResponse(responseCode=SC_NOT_FOUND, description="no object exists with the given id"),
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="validation errors", value="[{\"messageTemplate\": \"some.symbolic.error\", \"message\": \"some default English message\"}]")
})})
content=@Content(mediaType=APPLICATION_JSON, examples=@ExampleObject(name="validation errors", value="[{\"messageTemplate\": \"some.symbolic.error\", \"message\": \"some default English message\"}]")))
}
)
public Response update(@Context Request req,
@@ -247,10 +243,10 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned

@DELETE @Path("/{id}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT_OBJECTS},
tags=API_TAG_ACCOUNT_OBJECTS,
summary="Delete an existing object",
description="Delete an existing object",
parameters={@Parameter(name="id", description="the UUID (or name, if allowed) of the object to delete")},
parameters=@Parameter(name="id", description="the UUID (or name, if allowed) of the object to delete"),
responses={
@ApiResponse(responseCode=SC_OK, description="the object that was deleted"),
@ApiResponse(responseCode=SC_NOT_FOUND, description="no object exists with the given id")


+ 7
- 3
bubble-server/src/main/java/bubble/resources/account/AccountPromotionsResource.java 查看文件

@@ -18,6 +18,7 @@ import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;

import static bubble.ApiConstants.API_TAG_PAYMENT;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.cobbzilla.util.http.HttpStatusCodes.SC_OK;
import static org.cobbzilla.wizard.resources.ResourceUtil.*;
@@ -35,9 +36,10 @@ public class AccountPromotionsResource {

@GET
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags=API_TAG_PAYMENT,
summary="List promotions for account",
description="List promotions for account",
responses={@ApiResponse(responseCode=SC_OK, description="an array of Promotion objects owned by the Account")}
responses=@ApiResponse(responseCode=SC_OK, description="an array of Promotion objects owned by the Account")
)
public Response listPromotions(@Context Request req,
@Context ContainerRequest ctx) {
@@ -48,9 +50,10 @@ public class AccountPromotionsResource {

@PUT
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags=API_TAG_PAYMENT,
summary="Add a promotion to an account. Must be admin.",
description="Add a promotion to an account. Must be admin.",
responses={@ApiResponse(responseCode=SC_OK, description="an array of Promotion objects owned by the Account")}
responses=@ApiResponse(responseCode=SC_OK, description="an array of Promotion objects owned by the Account")
)
public Response adminAddPromotion(@Context Request req,
@Context ContainerRequest ctx,
@@ -62,9 +65,10 @@ public class AccountPromotionsResource {

@DELETE @Path("/{id}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags=API_TAG_PAYMENT,
summary="Remove a promotion from an account. Must be admin.",
description="Remove a promotion from an account. Must be admin.",
responses={@ApiResponse(responseCode=SC_OK, description="an array of Promotion objects owned by the Account")}
responses=@ApiResponse(responseCode=SC_OK, description="an array of Promotion objects owned by the Account")
)
public Response adminRemovePromotion(@Context Request req,
@Context ContainerRequest ctx,


+ 43
- 43
bubble-server/src/main/java/bubble/resources/account/AccountsResource.java 查看文件

@@ -79,7 +79,7 @@ public class AccountsResource {

@GET
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="List all accounts",
description="List all accounts. Must be admin.",
responses={
@@ -94,7 +94,7 @@ public class AccountsResource {

@GET @Path("/{id}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Find account by UUID or email. Non-admins can only find themselves.",
description="Find account by UUID or email. Non-admins can only find themselves.",
responses={
@@ -110,7 +110,7 @@ public class AccountsResource {

@PUT
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Create a new account",
description="Create a new account. Must be admin.",
responses={
@@ -173,10 +173,10 @@ public class AccountsResource {

@POST @Path("/{id}"+EP_DOWNLOAD)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Download all data for an account",
description="Download all data for user. Must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
parameters=@Parameter(name="id", description="UUID or email of the Account"),
responses={
@ApiResponse(responseCode=SC_OK, description="a Map<String, List<String>> of all user data"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if not admin")
@@ -196,10 +196,10 @@ public class AccountsResource {

@POST @Path("/{id}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Update an account",
description="Update an account. Caller must be the same account, or must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
parameters=@Parameter(name="id", description="UUID or email of the Account"),
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object that was updated"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is updating any account Account other than themselves"),
@@ -230,10 +230,10 @@ public class AccountsResource {

@GET @Path("/{id}"+EP_STATUS)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="List all launch statuses for an account",
description="List all launch statuses for an account. Caller must be the same account, or must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
parameters=@Parameter(name="id", description="UUID or email of the Account"),
responses={
@ApiResponse(responseCode=SC_OK, description="a List<NodeProgressMeterTick> representing the status of active launch operations"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves")
@@ -256,10 +256,10 @@ public class AccountsResource {

@GET @Path("/{id}"+EP_POLICY)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="View the AccountPolicy for an account",
description="View the AccountPolicy for an account. Caller must be the same account, or must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
parameters=@Parameter(name="id", description="UUID or email of the Account"),
responses={
@ApiResponse(responseCode=SC_OK, description="an AccountPolicy object"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves")
@@ -275,10 +275,10 @@ public class AccountsResource {

@POST @Path("/{id}"+EP_POLICY)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Update the AccountPolicy for an account",
description="Update the AccountPolicy for an account. Caller must be the same account, or must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
parameters=@Parameter(name="id", description="UUID or email of the Account"),
responses={
@ApiResponse(responseCode=SC_OK, description="an AccountPolicy object"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"),
@@ -305,10 +305,10 @@ public class AccountsResource {

@POST @Path("/{id}"+EP_POLICY+EP_CONTACTS)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Create or update an AccountContact in the AccountPolicy",
description="Create or update an AccountContact in the AccountPolicy. Caller must be the same account, or must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
parameters=@Parameter(name="id", description="UUID or email of the Account"),
responses={
@ApiResponse(responseCode=SC_OK, description="the AccountContact object that was created or updated"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"),
@@ -346,10 +346,10 @@ public class AccountsResource {

@POST @Path("/{id}"+EP_POLICY+EP_CONTACTS+"/verify")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Send verification message for an AccountContact",
description="Send verification message for an AccountContact. Caller must be the same account, or must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
parameters=@Parameter(name="id", description="UUID or email of the Account"),
responses={
@ApiResponse(responseCode=SC_OK, description="the AccountContact object that was created or updated"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves")
@@ -373,7 +373,7 @@ public class AccountsResource {

@GET @Path("/{id}"+EP_POLICY+EP_CONTACTS+"/{type}/{info}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Find an AccountContact within an AccountPolicy",
description="Find an AccountContact within an AccountPolicy. Caller must be the same account, or must be admin.",
parameters={
@@ -400,7 +400,7 @@ public class AccountsResource {

@DELETE @Path("/{id}"+EP_POLICY+EP_CONTACTS+"/{type}/{info}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Delete an AccountContact within an AccountPolicy",
description="Delete an AccountContact within an AccountPolicy. Caller must be the same account, or must be admin.",
parameters={
@@ -428,10 +428,10 @@ public class AccountsResource {

@DELETE @Path("/{id}"+EP_POLICY+EP_CONTACTS+EP_AUTHENTICATOR)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Delete TOTP authenticator AccountContact from an AccountPolicy",
description="Delete TOTP authenticator AccountContact from an AccountPolicy. Caller must be the same account, or must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
parameters=@Parameter(name="id", description="UUID or email of the Account"),
responses={
@ApiResponse(responseCode=SC_OK, description="the AccountPolicy object that was updated"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves")
@@ -455,7 +455,7 @@ public class AccountsResource {

@DELETE @Path("/{id}"+EP_POLICY+EP_CONTACTS+"/{uuid}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Delete AccountContact from an AccountPolicy by UUID",
description="Delete AccountContact from an AccountPolicy by UUID. Caller must be the same account, or must be admin.",
parameters={
@@ -481,10 +481,10 @@ public class AccountsResource {

@DELETE @Path("/{id}"+EP_REQUEST)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Request deletion of an Account",
description="Request deletion of an Account. Caller must be the same account, or must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
parameters=@Parameter(name="id", description="UUID or email of the Account"),
responses={
@ApiResponse(responseCode=SC_OK, description="the AccountMessage object that was sent"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves")
@@ -511,10 +511,10 @@ public class AccountsResource {

@POST @Path("/{id}"+EP_CHANGE_PASSWORD)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Change password for an account",
description="Change password for an account. Caller must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
parameters=@Parameter(name="id", description="UUID or email of the Account"),
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object that was updated"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"),
@@ -590,10 +590,10 @@ public class AccountsResource {

@DELETE @Path("/{id}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Delete an Account",
description="Delete an Account. Caller must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
parameters=@Parameter(name="id", description="UUID or email of the Account"),
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object that was deleted"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves")
@@ -629,16 +629,16 @@ public class AccountsResource {

@GET @Path("/{id}"+EP_MITM)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_UTILITY},
tags=API_TAG_UTILITY,
summary="Get status of mitmproxy",
description="Get status of mitmproxy. Caller must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
parameters=@Parameter(name="id", description="UUID or email of the Account"),
responses={
@ApiResponse(responseCode=SC_OK, description="returns true if mitmproxy is enabled, false otherwise",
content={@Content(mediaType=APPLICATION_JSON, examples={
content=@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="mitmproxy is enabled", value="true"),
@ExampleObject(name="mitmproxy is disabled", value="false")
})}),
})),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin"),
@ApiResponse(responseCode=SC_INVALID, description="if mitmproxy not installed")
}
@@ -652,16 +652,16 @@ public class AccountsResource {

@POST @Path("/{id}"+EP_MITM+EP_ENABLE)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_UTILITY},
tags=API_TAG_UTILITY,
summary="Enable mitmproxy",
description="Enable mitmproxy. Caller must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
parameters=@Parameter(name="id", description="UUID or email of the Account"),
responses={
@ApiResponse(responseCode=SC_OK, description="returns true if mitmproxy is enabled, false otherwise",
content={@Content(mediaType=APPLICATION_JSON, examples={
content=@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="mitmproxy is enabled", value="true"),
@ExampleObject(name="mitmproxy is disabled", value="false")
})}),
})),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin"),
@ApiResponse(responseCode=SC_INVALID, description="if mitmproxy is not installed or an error occurred enabling it")
}
@@ -675,16 +675,16 @@ public class AccountsResource {

@POST @Path("/{id}"+EP_MITM+EP_DISABLE)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_UTILITY},
tags=API_TAG_UTILITY,
summary="Disable mitmproxy",
description="Disable mitmproxy. Caller must be admin.",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
parameters=@Parameter(name="id", description="UUID or email of the Account"),
responses={
@ApiResponse(responseCode=SC_OK, description="returns true if mitmproxy is enabled, false otherwise",
content={@Content(mediaType=APPLICATION_JSON, examples={
content=@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="mitmproxy is enabled", value="true"),
@ExampleObject(name="mitmproxy is disabled", value="false")
})}),
})),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin"),
@ApiResponse(responseCode=SC_INVALID, description="if mitmproxy is not installed or an error occurred disabling it")
}
@@ -754,11 +754,11 @@ public class AccountsResource {

@GET @Path("/{id}"+EP_DEVICE_TYPES)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_UTILITY},
tags=API_TAG_UTILITY,
summary="List all device types",
description="List all device types",
parameters={@Parameter(name="id", description="UUID or email of the Account")},
responses={@ApiResponse(responseCode=SC_OK, description="returns an array of Strings, each a BubbleDeviceType enum value")}
parameters=@Parameter(name="id", description="UUID or email of the Account"),
responses=@ApiResponse(responseCode=SC_OK, description="returns an array of Strings, each a BubbleDeviceType enum value")
)
public Response getDeviceTypes(@Context ContainerRequest ctx) {
return ok(BubbleDeviceType.getSelectableTypes());


+ 62
- 75
bubble-server/src/main/java/bubble/resources/account/AuthResource.java 查看文件

@@ -40,7 +40,6 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import lombok.Cleanup;
@@ -133,17 +132,17 @@ public class AuthResource {
}

@GET @Path(EP_CONFIGS)
@Operation(tags={API_TAG_UTILITY},
@Operation(tags=API_TAG_UTILITY,
summary="Read public system configuration",
description="Read public system configuration",
responses={@ApiResponse(responseCode=SC_OK, description="a Map<String, Object> of public system configuration settings")}
responses=@ApiResponse(responseCode=SC_OK, description="a Map<String, Object> of public system configuration settings")
)
public Response getPublicSystemConfigs(@Context ContainerRequest ctx) {
return ok(configuration.getPublicSystemConfigs());
}

@GET @Path(EP_READY)
@Operation(tags={API_TAG_UTILITY},
@Operation(tags=API_TAG_UTILITY,
summary="Determine if the API is running and ready for login",
description="Determine if the API is running and ready for login",
responses={
@@ -168,24 +167,24 @@ public class AuthResource {
}

@GET @Path(EP_ACTIVATE)
@Operation(tags={API_TAG_ACTIVATION},
@Operation(tags=API_TAG_ACTIVATION,
summary="Determine if the API has been activated",
description="Determine if the API has been activated",
responses={
@ApiResponse(responseCode=SC_OK, description="returns true if API is activated, false otherwise",
content={@Content(mediaType=APPLICATION_JSON, examples={
content=@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="Bubble is activated", value="true"),
@ExampleObject(name="Bubble has not been activated", value="false")
})})
}))
}
)
public Response isActivated(@Context ContainerRequest ctx) { return ok(accountDAO.activated()); }

@GET @Path(EP_ACTIVATE+EP_CONFIGS)
@Operation(tags={API_TAG_ACTIVATION},
@Operation(tags=API_TAG_ACTIVATION,
summary="Get activation default configuration",
description="Get activation default configuration",
responses={@ApiResponse(responseCode=SC_OK, description="returns an array of CloudService[] representing the default CloudServices and their settings")}
responses=@ApiResponse(responseCode=SC_OK, description="returns an array of CloudService[] representing the default CloudServices and their settings")
)
public Response getActivationConfigs(@Context ContainerRequest ctx) {
final Account caller = optionalUserPrincipal(ctx);
@@ -195,7 +194,7 @@ public class AuthResource {

@Transactional
@PUT @Path(EP_ACTIVATE)
@Operation(tags={API_TAG_ACTIVATION},
@Operation(tags=API_TAG_ACTIVATION,
summary="Perform one-time activation",
description="Perform one-time activation",
responses={
@@ -261,10 +260,10 @@ public class AuthResource {
}

@POST @Path(EP_RESTORE+"/{restoreKey}")
@Operation(tags={API_TAG_BACKUP_RESTORE},
@Operation(tags=API_TAG_BACKUP_RESTORE,
summary="Restore a Bubble from a backup stored by sage.",
description="Restore a Bubble from a backup stored by sage.",
parameters={@Parameter(name="restoreKey", description="the restore key")},
parameters=@Parameter(name="restoreKey", description="the restore key"),
responses={
@ApiResponse(responseCode=SC_OK, description="the NotificationReceipt from a successful request to retrieve the backup"),
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred")
@@ -294,10 +293,10 @@ public class AuthResource {

@POST @Path(EP_RESTORE + EP_APPLY + "/{restoreKey}")
@Consumes(MULTIPART_FORM_DATA)
@Operation(tags={API_TAG_BACKUP_RESTORE},
@Operation(tags=API_TAG_BACKUP_RESTORE,
summary="Restore a Bubble from a backup uploaded by user.",
description="Restore a Bubble from a backup uploaded by user.",
parameters={@Parameter(name="restoreKey", description="the restore key")},
parameters=@Parameter(name="restoreKey", description="the restore key"),
responses={
@ApiResponse(responseCode=SC_OK, description="upon success a 200 HTTP status with an empty response is returned"),
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred")
@@ -323,11 +322,11 @@ public class AuthResource {
}

@POST @Path(EP_REGISTER)
@Operation(tags={API_TAG_AUTH},
@Operation(tags=API_TAG_AUTH,
summary="Register a new Account, starts a new API session.",
description="Register a new Account, starts a new API session.",
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object that was registered, `token` property holds session token", content=@Content(mediaType=APPLICATION_JSON, schema=@Schema(ref="#/components/schema/Account"))),
@ApiResponse(responseCode=SC_OK, description="the Account object that was registered, `token` property holds session token"),
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred")
}
)
@@ -439,10 +438,10 @@ public class AuthResource {
}

@POST @Path(EP_LOGIN)
@Operation(tags={API_TAG_AUTH},
@Operation(tags=API_TAG_AUTH,
summary="Login an Account, starts a new API session.",
description="Login an Account, starts a new API session.",
parameters={@Parameter(name="k", description="for a new Bubble that was launched with the lock enabled, the unlock key is required for the first login")},
parameters=@Parameter(name="k", description="for a new Bubble that was launched with the lock enabled, the unlock key is required for the first login"),
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object that was logged in"),
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred")
@@ -520,10 +519,10 @@ public class AuthResource {
}

@POST @Path(EP_APP_LOGIN+"/{session}")
@Operation(tags={API_TAG_AUTH},
@Operation(tags=API_TAG_AUTH,
summary="Login an Account using an existing session token, starts a new API session. If an existing session exists, it is invalidated",
description="Login an Account using an existing session token, starts a new API session. If an existing session exists, it is invalidated",
parameters={@Parameter(name="session", description="the session token to use for logging in")},
parameters=@Parameter(name="session", description="the session token to use for logging in"),
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object that was logged in"),
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred")
@@ -589,7 +588,7 @@ public class AuthResource {
public TrustedAuthResource getTrustedAuthResource() { return configuration.subResource(TrustedAuthResource.class); }

@POST @Path(EP_VERIFY_KEY)
@Operation(tags={API_TAG_NODE},
@Operation(tags=API_TAG_NODE,
summary="Called between Bubbles to verify RSA keys",
description="Called between Bubbles to verify RSA keys",
responses={
@@ -651,7 +650,7 @@ public class AuthResource {

@POST @Path(EP_REKEY)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_NODE},
tags=API_TAG_NODE,
summary="Re-key a node. Must be admin. Creates a new NodeKey that, being newest, will be the one the node starts using",
description="Re-key a node. Must be admin. Creates a new NodeKey that, being newest, will be the one the node starts using",
responses={
@@ -697,7 +696,7 @@ public class AuthResource {
}

@POST @Path(EP_FORGOT_PASSWORD)
@Operation(tags={API_TAG_AUTH},
@Operation(tags=API_TAG_AUTH,
summary="Send a reset password message",
description="Send a reset password message",
responses={
@@ -728,16 +727,16 @@ public class AuthResource {
}

@POST @Path(EP_APPROVE+"/{token}")
@Operation(tags={API_TAG_AUTH},
@Operation(tags=API_TAG_AUTH,
summary="Approve a request",
description="Approve a request. The token comes from an email or SMS message sent to the user.",
parameters={@Parameter(name="token", description="the confirmation token")},
parameters=@Parameter(name="token", description="the confirmation token"),
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success",
content={@Content(mediaType=APPLICATION_JSON, examples={
content=@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="if no login requested, returns an empty response", value=""),
@ExampleObject(name="if login requested, returns an Account object with either a valid session token ('token' property) or additional auth factors required (check 'multifactorAuth' property)")
})}),
})),
@ApiResponse(responseCode=SC_INVALID, description="a validation error occurred, for example the token might be invalid")
}
)
@@ -778,15 +777,15 @@ public class AuthResource {
}

@POST @Path(EP_AUTHENTICATOR)
@Operation(tags={API_TAG_AUTH},
@Operation(tags=API_TAG_AUTH,
summary="Approve a TOTP request",
description="Approve a TOTP request. The token comes the end user's authenticator app.",
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success",
content={@Content(mediaType=APPLICATION_JSON, examples={
content=@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="if no login requested, returns an empty response", value=""),
@ExampleObject(name="if login requested, returns an Account object with either a valid session token ('token' property) or additional auth factors required (check 'multifactorAuth' property)")
})}),
})),
@ApiResponse(responseCode=SC_INVALID, description="a validation error occurred, for example the token might be invalid")
}
)
@@ -843,14 +842,14 @@ public class AuthResource {

@DELETE @Path(EP_AUTHENTICATOR)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_AUTH},
tags=API_TAG_AUTH,
summary="Flush authenticator tokens",
description="Flush authenticator tokens. The next operation that requires TOTP auth will require the user to re-authenticate.",
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success",
content={@Content(mediaType=APPLICATION_JSON, examples={
content=@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="returns an empty JSON object", value="{}")
})}),
})),
@ApiResponse(responseCode=SC_INVALID, description="a validation error occurred, for example the token might be invalid")
}
)
@@ -862,15 +861,15 @@ public class AuthResource {
}

@POST @Path(EP_DENY+"/{token}")
@Operation(tags={API_TAG_AUTH},
@Operation(tags=API_TAG_AUTH,
summary="Deny a request",
description="Deny a request. The token comes from an email or SMS message sent to the user.",
parameters={@Parameter(name="token", description="the confirmation token")},
parameters=@Parameter(name="token", description="the confirmation token"),
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success",
content={@Content(mediaType=APPLICATION_JSON, examples={
content=@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="returns the denial AccountMessage")
})}),
})),
@ApiResponse(responseCode=SC_INVALID, description="a validation error occurred, for example the token might be invalid")
}
)
@@ -887,14 +886,14 @@ public class AuthResource {

@GET @Path(EP_CA_CERT)
@Produces(CONTENT_TYPE_ANY)
@Operation(tags={API_TAG_UTILITY},
@Operation(tags=API_TAG_UTILITY,
summary="Get the CA Certificate for this Bubble",
description="Get the CA Certificate for this Bubble. Response body is the certificate itself, in a format determined by deviceType or type",
parameters={
@Parameter(name="deviceType", description="the device type"),
@Parameter(name="type", description="the certificate type")
},
responses={@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success, response body is certificate")}
responses=@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success, response body is certificate")
)
public Response getCaCert(@Context Request req,
@Context ContainerRequest ctx,
@@ -925,12 +924,10 @@ public class AuthResource {
}

@GET @Path(EP_KEY)
@Operation(tags={API_TAG_UTILITY},
@Operation(tags=API_TAG_UTILITY,
summary="Get the Node Key for this Bubble",
description="Get the Node Key for this Bubble",
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success")
}
responses=@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success")
)
public Response getNodeKey(@Context Request req,
@Context ContainerRequest ctx) {
@@ -952,10 +949,10 @@ public class AuthResource {

@GET @Path(EP_LOGOUT)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_AUTH},
tags=API_TAG_AUTH,
summary="Logout",
description="Logout of the current session, or logout of all sessions everywhere if the `all` parameter is true.",
parameters={@Parameter(name="all", description="logout of all sessions everywhere")},
parameters=@Parameter(name="all", description="logout of all sessions everywhere"),
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success"),
@ApiResponse(responseCode=SC_INVALID, description="If there is no current session to log out of")
@@ -975,10 +972,10 @@ public class AuthResource {

@POST @Path(EP_LOGOUT+"/{id}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_AUTH},
tags=API_TAG_AUTH,
summary="Logout a user everywhere",
description="Logout of the current session, or logout of all sessions everywhere if the `all` parameter is true.",
parameters={@Parameter(name="id", description="UUID or email of user to logout")},
parameters=@Parameter(name="id", description="UUID or email of user to logout"),
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success"),
@ApiResponse(responseCode=SC_INVALID, description="If there is no current session to log out of")
@@ -1000,25 +997,21 @@ public class AuthResource {
}

@GET @Path(EP_TIME)
@Operation(tags={API_TAG_UTILITY},
@Operation(tags=API_TAG_UTILITY,
summary="Get current system time",
description="Get current system time. Returns current time as epoch time in milliseconds",
responses={
@ApiResponse(responseCode=SC_OK, description="Returns current time as epoch time in milliseconds",
content={@Content(mediaType=APPLICATION_JSON, examples={@ExampleObject(name="time in milliseconds", value="1606858589683")})})
}
responses=@ApiResponse(responseCode=SC_OK, description="Returns current time as epoch time in milliseconds",
content=@Content(mediaType=APPLICATION_JSON, examples=@ExampleObject(name="time in milliseconds", value="1606858589683")))
)
public Response serverTime() { return ok(now()); }

@Autowired private GeoService geoService;

@GET @Path(EP_SUPPORT)
@Operation(tags={API_TAG_UTILITY},
@Operation(tags=API_TAG_UTILITY,
summary="Get support information",
description="Get support information for the user's current locale, if available. Use the default locale otherwise.",
responses={
@ApiResponse(responseCode=SC_OK, description="SupportInfo object")
}
responses=@ApiResponse(responseCode=SC_OK, description="SupportInfo object")
)
public Response getSupportInfo (@Context Request req,
@Context ContainerRequest ctx) {
@@ -1027,13 +1020,11 @@ public class AuthResource {
}

@GET @Path(EP_SUPPORT+"/{locale}")
@Operation(tags={API_TAG_UTILITY},
@Operation(tags=API_TAG_UTILITY,
summary="Get support information",
description="Get support information for the given locale, if available. Use the default locale otherwise.",
parameters={@Parameter(name="locale", description="locale to find support for")},
responses={
@ApiResponse(responseCode=SC_OK, description="SupportInfo object")
}
parameters=@Parameter(name="locale", description="locale to find support for"),
responses=@ApiResponse(responseCode=SC_OK, description="SupportInfo object")
)
public Response getSupportInfo (@Context Request req,
@Context ContainerRequest ctx,
@@ -1042,12 +1033,10 @@ public class AuthResource {
}

@GET @Path(EP_APP_LINKS)
@Operation(tags={API_TAG_UTILITY},
@Operation(tags=API_TAG_UTILITY,
summary="Get links to native applications",
description="Get links to native applications for the current user's locale, if available. Use the default locale otherwise.",
responses={
@ApiResponse(responseCode=SC_OK, description="AppLinks object")
}
responses=@ApiResponse(responseCode=SC_OK, description="AppLinks object")
)
public Response getAppLinks (@Context Request req,
@Context ContainerRequest ctx) {
@@ -1056,13 +1045,11 @@ public class AuthResource {
}

@GET @Path(EP_APP_LINKS+"/{locale}")
@Operation(tags={API_TAG_UTILITY},
@Operation(tags=API_TAG_UTILITY,
summary="Get links to native applications",
description="Get links to native applications for the given locale, if available. Use the default locale otherwise.",
parameters={@Parameter(name="locale", description="locale to find app links for")},
responses={
@ApiResponse(responseCode=SC_OK, description="AppLinks object")
}
parameters=@Parameter(name="locale", description="locale to find app links for"),
responses=@ApiResponse(responseCode=SC_OK, description="AppLinks object")
)
public Response getAppLinks (@Context Request req,
@Context ContainerRequest ctx,
@@ -1072,12 +1059,12 @@ public class AuthResource {

@GET @Path(EP_PATCH+"/{token}")
@Produces(APPLICATION_OCTET_STREAM)
@Operation(tags={API_TAG_NODE_MANAGER},
@Operation(tags=API_TAG_NODE_MANAGER,
summary="Find a node-manager patch file",
description="Find a node-manager patch file. The file must previously have been registered, yielding a token",
parameters={@Parameter(name="token", description="token of the patch file to retrieve")},
parameters=@Parameter(name="token", description="token of the patch file to retrieve"),
responses={
@ApiResponse(responseCode=SC_OK, description="raw file data", content={@Content(mediaType=APPLICATION_OCTET_STREAM)}),
@ApiResponse(responseCode=SC_OK, description="raw file data", content=@Content(mediaType=APPLICATION_OCTET_STREAM)),
@ApiResponse(responseCode=SC_NOT_FOUND, description="token not valid")
}
)
@@ -1092,7 +1079,7 @@ public class AuthResource {

@GET @Path(EP_UPGRADE+"/{node}/{key}")
@Produces(APPLICATION_OCTET_STREAM)
@Operation(tags={API_TAG_NODE},
@Operation(tags=API_TAG_NODE,
summary="Return bubble jar",
description="Return bubble jar file for upgrading other nodes to our version.",
parameters={
@@ -1100,7 +1087,7 @@ public class AuthResource {
@Parameter(name="key", description="UUID of the calling node's BubbleNodeKey")
},
responses={
@ApiResponse(responseCode=SC_OK, description="raw jar file data", content={@Content(mediaType=APPLICATION_OCTET_STREAM)}),
@ApiResponse(responseCode=SC_OK, description="raw jar file data", content=@Content(mediaType=APPLICATION_OCTET_STREAM)),
@ApiResponse(responseCode=SC_UNAUTHORIZED, description="calling node is not authorized"),
@ApiResponse(responseCode=SC_NOT_FOUND, description="token not valid")
}


+ 88
- 27
bubble-server/src/main/java/bubble/resources/account/MeResource.java 查看文件

@@ -35,6 +35,7 @@ import bubble.service.cloud.NodeLaunchMonitor;
import bubble.service.upgrade.BubbleJarUpgradeService;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
@@ -78,8 +79,7 @@ import static bubble.resources.account.AuthResource.forgotPasswordMessage;
import static java.util.concurrent.TimeUnit.MINUTES;
import static org.cobbzilla.util.daemon.ZillaRuntime.*;
import static org.cobbzilla.util.http.HttpContentTypes.*;
import static org.cobbzilla.util.http.HttpStatusCodes.SC_OK;
import static org.cobbzilla.util.http.HttpStatusCodes.SC_INVALID;
import static org.cobbzilla.util.http.HttpStatusCodes.*;
import static org.cobbzilla.util.json.JsonUtil.json;
import static org.cobbzilla.wizard.resources.ResourceUtil.*;
import static org.cobbzilla.wizard.server.RestServerBase.reportError;
@@ -102,12 +102,10 @@ public class MeResource {

@GET
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Get account record for current session",
description="Get account record for current session",
responses={
@ApiResponse(responseCode=SC_OK, description="Account object")
}
responses=@ApiResponse(responseCode=SC_OK, description="Account object")
)
public Response me(@Context ContainerRequest ctx) {
try {
@@ -127,12 +125,10 @@ public class MeResource {

@GET @Path(EP_LOCALE)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Get the account locale",
description="Get the account locale",
responses={
@ApiResponse(responseCode=SC_OK, description="Locale string", content=@Content(mediaType=APPLICATION_JSON, examples={@ExampleObject(name="default locale", value="en_US")}))
}
responses=@ApiResponse(responseCode=SC_OK, description="Locale string", content=@Content(mediaType=APPLICATION_JSON, examples=@ExampleObject(name="default locale", value="en_US")))
)
public Response getLocale(@Context ContainerRequest ctx) {
final Account account = userPrincipal(ctx);
@@ -141,12 +137,10 @@ public class MeResource {

@POST @Path(EP_LOCALE+"/{locale}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Set the account locale",
description="Set the account locale",
responses={
@ApiResponse(responseCode=SC_OK, description="updated Account object")
}
responses=@ApiResponse(responseCode=SC_OK, description="updated Account object")
)
public Response setLocale(@Context ContainerRequest ctx,
@PathParam("locale") String locale) {
@@ -177,18 +171,16 @@ public class MeResource {
}

@GET @Path(EP_ERROR_API)
@Operation(tags={API_TAG_UTILITY},
@Operation(tags=API_TAG_UTILITY,
summary="Get error API information",
description="Get error API information",
responses={
@ApiResponse(responseCode=SC_OK, description="a Map of API information")
}
responses=@ApiResponse(responseCode=SC_OK, description="a Map of API information")
)
public Response errorApi(@Context Request req) { return ok(getErrorApi()); }

@POST @Path(EP_CHANGE_PASSWORD)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
tags=API_TAG_ACCOUNT,
summary="Request account password change",
description="Request account password change. A message will be sent to the user with a token to approve the change and set a new password. If the password can be changed directly, this returns the updated Account object. If approvals are required for a password change, an Account object will be returned and the `multifactorAuth` property will indicate what auth methods are required to approve the change.",
responses={
@@ -248,7 +240,20 @@ public class MeResource {
@Autowired private StandardAccountMessageService messageService;

@POST @Path(EP_APPROVE+"/{token}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY))
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags=API_TAG_AUTH,
summary="Approve a request",
description="Approve a request. The token comes from an email or SMS message sent to the user.",
parameters=@Parameter(name="token", description="the confirmation token"),
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success",
content=@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="if no login requested, returns an empty response", value=""),
@ExampleObject(name="if login requested, returns an Account object with either a valid session token ('token' property) or additional auth factors required (check 'multifactorAuth' property)")
})),
@ApiResponse(responseCode=SC_INVALID, description="a validation error occurred, for example the token might be invalid")
}
)
public Response approve(@Context Request req,
@Context ContainerRequest ctx,
@PathParam("token") String token) {
@@ -265,7 +270,20 @@ public class MeResource {
}

@POST @Path(EP_DENY+"/{token}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY))
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags=API_TAG_AUTH,
summary="Deny a request",
description="Deny a request. The token comes from an email or SMS message sent to the user.",
parameters=@Parameter(name="token", description="the confirmation token"),
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success",
content=@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="returns the denial AccountMessage")
})),
@ApiResponse(responseCode=SC_INVALID, description="a validation error occurred, for example the token might be invalid"),
@ApiResponse(responseCode=SC_NOT_FOUND, description="the token might be invalid")
}
)
public Response deny(@Context Request req,
@Context ContainerRequest ctx,
@PathParam("token") String token) {
@@ -276,7 +294,15 @@ public class MeResource {
}

@POST @Path(EP_DOWNLOAD)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY))
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags=API_TAG_ACCOUNT,
summary="Request account data download",
description="Request account data download. This begins the process of collecting the account data.",
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success"),
@ApiResponse(responseCode=SC_INVALID, description="a validation error occurred, for example the account has no verified contacts")
}
)
public Response requestDownloadAccountData(@Context Request req,
@Context ContainerRequest ctx) {
final Account caller = userPrincipal(ctx);
@@ -290,7 +316,16 @@ public class MeResource {
}

@POST @Path(EP_DOWNLOAD+"/{uuid}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY))
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags=API_TAG_ACCOUNT,
summary="Download account data",
description="Download account data.",
parameters=@Parameter(name="uuid", description="the uuid of the download to retrieve"),
responses={
@ApiResponse(responseCode=SC_OK, description="Account data as JSON"),
@ApiResponse(responseCode=SC_NOT_FOUND, description="uuid was invalid")
}
)
public Response downloadAccountData(@Context Request req,
@Context ContainerRequest ctx,
@PathParam("uuid") String uuid) {
@@ -301,7 +336,12 @@ public class MeResource {
}

@POST @Path(EP_SCRIPT) @Produces(TEXT_PLAIN)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY))
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags=API_TAG_UTILITY,
summary="Run an API script",
description="Run an API script",
responses=@ApiResponse(responseCode=SC_OK, description="Script output")
)
public Response runScript(@Context ContainerRequest ctx,
JsonNode script) {
final Account caller = userPrincipal(ctx);
@@ -309,6 +349,8 @@ public class MeResource {
final StringWriter writer = new StringWriter();
final ApiRunnerListener listener = new ApiRunnerListenerStreamLogger("runScript", writer);
@Cleanup final ApiClientBase api = configuration.newApiClient();
api.setToken(caller.getToken());

final ApiRunner runner = new ApiRunner(api, listener);
try {
if (script.isArray()) {
@@ -446,7 +488,12 @@ public class MeResource {
@Autowired private NodeLaunchMonitor launchMonitor;

@GET @Path(EP_STATUS)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY))
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags=API_TAG_ACCOUNT,
summary="List all launch statuses for an account",
description="List all launch statuses for an account. Caller must be the same account, or must be admin.",
responses=@ApiResponse(responseCode=SC_OK, description="a List<NodeProgressMeterTick> representing the status of active launch operations")
)
public Response listLaunchStatuses(@Context Request req,
@Context ContainerRequest ctx) {
final Account caller = userPrincipal(ctx);
@@ -471,7 +518,16 @@ public class MeResource {

@POST @Path(EP_MODEL)
@Consumes(MULTIPART_FORM_DATA)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY))
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags=API_TAG_UTILITY,
summary="Load model objects",
description="Load model objects",
parameters={
@Parameter(name="file", description="model JSON"),
@Parameter(name="name", description="name of model")
},
responses=@ApiResponse(responseCode=SC_OK, description="the model that was loaded")
)
public Response uploadModel(@Context Request req,
@Context ContainerRequest ctx,
@FormDataParam("file") InputStream in,
@@ -497,7 +553,12 @@ public class MeResource {
private static final long UPGRADE_CHECK_INTERVAL = MINUTES.toMillis(5);

@GET @Path(EP_UPGRADE)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY))
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags=API_TAG_UTILITY,
summary="Check for upgrade",
description="Check for upgrade. Must be admin. The check runs in the background, this returns an empty JSON object",
responses=@ApiResponse(responseCode=SC_OK, description="the upgrade check has been started", content=@Content(mediaType=APPLICATION_JSON, examples=@ExampleObject(name="empty JSON object", value="{}")))
)
public Response checkForUpgrade(@Context Request req,
@Context ContainerRequest ctx) {
final Account caller = userPrincipal(ctx);


+ 1
- 0
bubble-server/src/main/resources/bubble-config.yml 查看文件

@@ -18,6 +18,7 @@ openApi:
additionalPackages:
- org.cobbzilla.wizard.model.search
- org.cobbzilla.wizard.model.support
- bubble.cloud

defaultLocale: {{#exists BUBBLE_DEFAULT_LOCALE}}{{BUBBLE_DEFAULT_LOCALE}}{{else}}en_US{{/exists}}
testMode: {{#exists BUBBLE_TEST_MODE}}{{BUBBLE_TEST_MODE}}{{else}}false{{/exists}}


+ 1
- 1
utils/cobbzilla-utils

@@ -1 +1 @@
Subproject commit 51119dc923d483f8b97fb0de3b36e3ff893e2ee9
Subproject commit 2c3bfe646107b1b0ff9a3c4b001f051e4bd81fa0

+ 1
- 1
utils/cobbzilla-wizard

@@ -1 +1 @@
Subproject commit 126e4b4da345a14006998703147f4744c535a0df
Subproject commit f12add50c534143a443b09bf275211ee603563b4

Loading…
取消
儲存