@@ -300,6 +300,7 @@ public class ApiConstants { | |||||
public static final String API_TAG_SEARCH = "search"; | public static final String API_TAG_SEARCH = "search"; | ||||
public static final String API_TAG_BACKUP_RESTORE = "backup and restore"; | 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 = "node"; | ||||
public static final String API_TAG_NODE_MANAGER = "node manager"; | |||||
public static String getToken(String json) { | public static String getToken(String json) { | ||||
if (json == null) return null; | if (json == null) return null; | ||||
@@ -2,15 +2,17 @@ | |||||
* Copyright (c) 2020 Bubble, Inc. All rights reserved. | * Copyright (c) 2020 Bubble, Inc. All rights reserved. | ||||
* For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/ | * For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/ | ||||
*/ | */ | ||||
package bubble.server; | |||||
package bubble.model; | |||||
import com.fasterxml.jackson.annotation.JsonIgnore; | import com.fasterxml.jackson.annotation.JsonIgnore; | ||||
import io.swagger.v3.oas.annotations.media.Schema; | |||||
import lombok.Getter; | import lombok.Getter; | ||||
import lombok.Setter; | import lombok.Setter; | ||||
import java.util.HashMap; | import java.util.HashMap; | ||||
import java.util.Map; | import java.util.Map; | ||||
@Schema | |||||
public class AppLinks extends BasicAppLinks { | public class AppLinks extends BasicAppLinks { | ||||
@JsonIgnore @Getter @Setter private Map<String, BasicAppLinks> locale = new HashMap<>(); | @JsonIgnore @Getter @Setter private Map<String, BasicAppLinks> locale = new HashMap<>(); |
@@ -0,0 +1,19 @@ | |||||
/** | |||||
* Copyright (c) 2020 Bubble, Inc. All rights reserved. | |||||
* For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/ | |||||
*/ | |||||
package bubble.model; | |||||
import lombok.Getter; | |||||
import lombok.Setter; | |||||
import org.cobbzilla.wizard.model.entityconfig.annotations.ECField; | |||||
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; | |||||
} |
@@ -35,6 +35,7 @@ import static bubble.ApiConstants.ENTITY_CONFIGS_ENDPOINT; | |||||
import static java.lang.Boolean.TRUE; | import static java.lang.Boolean.TRUE; | ||||
import static org.cobbzilla.util.daemon.ZillaRuntime.die; | import static org.cobbzilla.util.daemon.ZillaRuntime.die; | ||||
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; | import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; | ||||
import static org.cobbzilla.util.http.HttpStatusCodes.SC_OK; | |||||
import static org.cobbzilla.util.io.FileUtil.abs; | import static org.cobbzilla.util.io.FileUtil.abs; | ||||
import static org.cobbzilla.util.string.StringUtil.packagePath; | import static org.cobbzilla.util.string.StringUtil.packagePath; | ||||
import static org.cobbzilla.wizard.resources.ResourceUtil.*; | import static org.cobbzilla.wizard.resources.ResourceUtil.*; | ||||
@@ -57,7 +58,7 @@ public class EntityConfigsResource extends AbstractEntityConfigsResource { | |||||
description="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")}, | parameters={@Parameter(name="param", description="the name of the parameter to set")}, | ||||
responses={ | responses={ | ||||
@ApiResponse(description="the value that was set", | |||||
@ApiResponse(responseCode=SC_OK, description="the value that was set", | |||||
content={@Content(mediaType=APPLICATION_JSON, examples={ | content={@Content(mediaType=APPLICATION_JSON, examples={ | ||||
@ExampleObject(name="should always return true", value="true") | @ExampleObject(name="should always return true", value="true") | ||||
} | } | ||||
@@ -79,7 +80,7 @@ public class EntityConfigsResource extends AbstractEntityConfigsResource { | |||||
@Parameter(name="value", description="the value to set the parameter to") | @Parameter(name="value", description="the value to set the parameter to") | ||||
}, | }, | ||||
responses={ | responses={ | ||||
@ApiResponse(description="the value that was set", | |||||
@ApiResponse(responseCode=SC_OK, description="the value that was set", | |||||
content={@Content(mediaType=APPLICATION_JSON, examples={ | content={@Content(mediaType=APPLICATION_JSON, examples={ | ||||
@ExampleObject(name="if the value was the String 'foo'", value="\"foo\"") | @ExampleObject(name="if the value was the String 'foo'", value="\"foo\"") | ||||
} | } | ||||
@@ -30,6 +30,7 @@ import java.util.Map; | |||||
import static bubble.ApiConstants.ID_ENDPOINT; | import static bubble.ApiConstants.ID_ENDPOINT; | ||||
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; | 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.*; | import static org.cobbzilla.wizard.resources.ResourceUtil.*; | ||||
import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.API_TAG_UTILITY; | import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.API_TAG_UTILITY; | ||||
import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.SEC_API_KEY; | import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.SEC_API_KEY; | ||||
@@ -53,7 +54,7 @@ public class IdentityResource { | |||||
description="Searches all model objects by ID. The id parameter is typically a UUID or name", | 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")}, | parameters={@Parameter(name="id", description="an identifier (typically UUID or name) to search for")}, | ||||
responses={ | responses={ | ||||
@ApiResponse(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", | |||||
@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={ | 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="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="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\"}}"), | ||||
@@ -23,6 +23,7 @@ import javax.ws.rs.core.Response; | |||||
import static bubble.ApiConstants.*; | import static bubble.ApiConstants.*; | ||||
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; | 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.resources.ResourceUtil.ok; | ||||
import static org.cobbzilla.wizard.resources.ResourceUtil.userPrincipal; | import static org.cobbzilla.wizard.resources.ResourceUtil.userPrincipal; | ||||
import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.SEC_API_KEY; | import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.SEC_API_KEY; | ||||
@@ -50,7 +51,7 @@ public class SearchResource { | |||||
@Parameter(name=Q_SORT, description="sort field. prefix with + or - to indicate ascending/descending") | @Parameter(name=Q_SORT, description="sort field. prefix with + or - to indicate ascending/descending") | ||||
}, | }, | ||||
responses={ | responses={ | ||||
@ApiResponse(description="a SearchResults object, or if meta was true then a SqlViewField[] array") | |||||
@ApiResponse(responseCode=SC_OK, description="a SearchResults object, or if meta was true then a SqlViewField[] array") | |||||
} | } | ||||
) | ) | ||||
public Response search(@Context Request req, | public Response search(@Context Request req, | ||||
@@ -80,7 +81,7 @@ public class SearchResource { | |||||
@Parameter(name=Q_SORT, description="sort field. prefix with + or - to indicate ascending/descending") | @Parameter(name=Q_SORT, description="sort field. prefix with + or - to indicate ascending/descending") | ||||
}, | }, | ||||
responses={ | responses={ | ||||
@ApiResponse(description="a SearchResults object, or if meta was true then a SqlViewField[] array") | |||||
@ApiResponse(responseCode=SC_OK, description="a SearchResults object, or if meta was true then a SqlViewField[] array") | |||||
} | } | ||||
) | ) | ||||
public Response search(@Context Request req, | public Response search(@Context Request req, | ||||
@@ -22,6 +22,7 @@ import javax.ws.rs.core.Context; | |||||
import javax.ws.rs.core.Response; | import javax.ws.rs.core.Response; | ||||
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; | 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.*; | import static org.cobbzilla.wizard.resources.ResourceUtil.*; | ||||
import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.SEC_API_KEY; | import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.SEC_API_KEY; | ||||
@@ -46,7 +47,7 @@ public class TagsResource { | |||||
summary="Set a tag", | summary="Set a tag", | ||||
description="Set a tag", | description="Set a tag", | ||||
parameters={@Parameter(name="name", description="name of the tag")}, | parameters={@Parameter(name="name", description="name of the tag")}, | ||||
responses={@ApiResponse(description="a BubbleTags object representing the current list of tags")} | |||||
responses={@ApiResponse(responseCode=SC_OK, description="a BubbleTags object representing the current list of tags")} | |||||
) | ) | ||||
public Response set(@Context ContainerRequest ctx, | public Response set(@Context ContainerRequest ctx, | ||||
@PathParam("name") String name, | @PathParam("name") String name, | ||||
@@ -29,8 +29,7 @@ import java.util.List; | |||||
import static bubble.ApiConstants.API_TAG_ACCOUNT_OBJECTS; | import static bubble.ApiConstants.API_TAG_ACCOUNT_OBJECTS; | ||||
import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; | import static org.cobbzilla.util.http.HttpContentTypes.APPLICATION_JSON; | ||||
import static org.cobbzilla.util.http.HttpStatusCodes.SC_NOT_FOUND; | |||||
import static org.cobbzilla.util.http.HttpStatusCodes.SC_PRECONDITION_FAILED; | |||||
import static org.cobbzilla.util.http.HttpStatusCodes.*; | |||||
import static org.cobbzilla.util.reflect.ReflectionUtil.getFirstTypeParam; | import static org.cobbzilla.util.reflect.ReflectionUtil.getFirstTypeParam; | ||||
import static org.cobbzilla.util.reflect.ReflectionUtil.instantiate; | import static org.cobbzilla.util.reflect.ReflectionUtil.instantiate; | ||||
import static org.cobbzilla.wizard.resources.ResourceUtil.*; | import static org.cobbzilla.wizard.resources.ResourceUtil.*; | ||||
@@ -69,7 +68,7 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned | |||||
tags={API_TAG_ACCOUNT_OBJECTS}, | tags={API_TAG_ACCOUNT_OBJECTS}, | ||||
summary="List objects", | summary="List objects", | ||||
description="List objects", | description="List objects", | ||||
responses={@ApiResponse(description="an array of objects")} | |||||
responses={@ApiResponse(responseCode=SC_OK, description="an array of objects")} | |||||
) | ) | ||||
public Response listEntities(@Context Request req, | public Response listEntities(@Context Request req, | ||||
@Context ContainerRequest ctx) { | @Context ContainerRequest ctx) { | ||||
@@ -141,7 +140,7 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned | |||||
summary="Find by identifier", | summary="Find by identifier", | ||||
description="Find by identifier", | description="Find by identifier", | ||||
responses={ | responses={ | ||||
@ApiResponse(description="the object, if found"), | |||||
@ApiResponse(responseCode=SC_OK, description="the object, if found"), | |||||
@ApiResponse(responseCode=SC_NOT_FOUND, description="if the object does not exist") | @ApiResponse(responseCode=SC_NOT_FOUND, description="if the object does not exist") | ||||
} | } | ||||
) | ) | ||||
@@ -174,7 +173,7 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned | |||||
summary="Create a new object", | summary="Create a new object", | ||||
description="Create a new object. If validation errors occur, status "+SC_PRECONDITION_FAILED+" 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", | description="Create a new object. If validation errors occur, status "+SC_PRECONDITION_FAILED+" 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={ | responses={ | ||||
@ApiResponse(description="the object that was created"), | |||||
@ApiResponse(responseCode=SC_OK, description="the object that was created"), | |||||
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred", | @ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred", | ||||
content={@Content(mediaType=APPLICATION_JSON, examples={ | content={@Content(mediaType=APPLICATION_JSON, examples={ | ||||
@ExampleObject(name="validation errors", value="[{\"messageTemplate\": \"some.symbolic.error\", \"message\": \"some default English message\"}]") | @ExampleObject(name="validation errors", value="[{\"messageTemplate\": \"some.symbolic.error\", \"message\": \"some default English message\"}]") | ||||
@@ -216,7 +215,7 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned | |||||
description="Update an new object. For many types, the object will be created if it does not exist. If validation errors occur, status "+SC_PRECONDITION_FAILED+" 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", | description="Update an new object. For many types, the object will be created if it does not exist. If validation errors occur, status "+SC_PRECONDITION_FAILED+" 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={ | responses={ | ||||
@ApiResponse(description="the object that was updated"), | |||||
@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_NOT_FOUND, description="no object exists with the given id"), | ||||
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred", | @ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred", | ||||
content={@Content(mediaType=APPLICATION_JSON, examples={ | content={@Content(mediaType=APPLICATION_JSON, examples={ | ||||
@@ -253,7 +252,7 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned | |||||
description="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={ | responses={ | ||||
@ApiResponse(description="the object that was deleted"), | |||||
@ApiResponse(responseCode=SC_OK, description="the object that was deleted"), | |||||
@ApiResponse(responseCode=SC_NOT_FOUND, description="no object exists with the given id") | @ApiResponse(responseCode=SC_NOT_FOUND, description="no object exists with the given id") | ||||
} | } | ||||
) | ) | ||||
@@ -19,6 +19,7 @@ import javax.ws.rs.core.Context; | |||||
import javax.ws.rs.core.Response; | import javax.ws.rs.core.Response; | ||||
import static javax.ws.rs.core.MediaType.APPLICATION_JSON; | 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.*; | import static org.cobbzilla.wizard.resources.ResourceUtil.*; | ||||
import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.SEC_API_KEY; | import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.SEC_API_KEY; | ||||
@@ -36,7 +37,7 @@ public class AccountPromotionsResource { | |||||
@Operation(security=@SecurityRequirement(name=SEC_API_KEY), | @Operation(security=@SecurityRequirement(name=SEC_API_KEY), | ||||
summary="List promotions for account", | summary="List promotions for account", | ||||
description="List promotions for account", | description="List promotions for account", | ||||
responses={@ApiResponse(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, | public Response listPromotions(@Context Request req, | ||||
@Context ContainerRequest ctx) { | @Context ContainerRequest ctx) { | ||||
@@ -49,7 +50,7 @@ public class AccountPromotionsResource { | |||||
@Operation(security=@SecurityRequirement(name=SEC_API_KEY), | @Operation(security=@SecurityRequirement(name=SEC_API_KEY), | ||||
summary="Add a promotion to an account. Must be admin.", | summary="Add a promotion to an account. Must be admin.", | ||||
description="Add a promotion to an account. Must be admin.", | description="Add a promotion to an account. Must be admin.", | ||||
responses={@ApiResponse(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, | public Response adminAddPromotion(@Context Request req, | ||||
@Context ContainerRequest ctx, | @Context ContainerRequest ctx, | ||||
@@ -63,7 +64,7 @@ public class AccountPromotionsResource { | |||||
@Operation(security=@SecurityRequirement(name=SEC_API_KEY), | @Operation(security=@SecurityRequirement(name=SEC_API_KEY), | ||||
summary="Remove a promotion from an account. Must be admin.", | summary="Remove a promotion from an account. Must be admin.", | ||||
description="Remove a promotion from an account. Must be admin.", | description="Remove a promotion from an account. Must be admin.", | ||||
responses={@ApiResponse(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, | public Response adminRemovePromotion(@Context Request req, | ||||
@Context ContainerRequest ctx, | @Context ContainerRequest ctx, | ||||
@@ -83,7 +83,7 @@ public class AccountsResource { | |||||
summary="List all accounts", | summary="List all accounts", | ||||
description="List all accounts. Must be admin.", | description="List all accounts. Must be admin.", | ||||
responses={ | responses={ | ||||
@ApiResponse(description="an array of Account objects"), | |||||
@ApiResponse(responseCode=SC_OK, description="an array of Account objects"), | |||||
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if not admin") | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if not admin") | ||||
} | } | ||||
) | ) | ||||
@@ -98,7 +98,7 @@ public class AccountsResource { | |||||
summary="Find account by UUID or email. Non-admins can only find themselves.", | 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.", | description="Find account by UUID or email. Non-admins can only find themselves.", | ||||
responses={ | responses={ | ||||
@ApiResponse(responseCode=SC_OK, description="the Account object that was found", ref="#/components/schemas/Account"), | |||||
@ApiResponse(responseCode=SC_OK, description="the Account object that was found"), | |||||
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if not admin") | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if not admin") | ||||
} | } | ||||
) | ) | ||||
@@ -114,7 +114,7 @@ public class AccountsResource { | |||||
summary="Create a new account", | summary="Create a new account", | ||||
description="Create a new account. Must be admin.", | description="Create a new account. Must be admin.", | ||||
responses={ | responses={ | ||||
@ApiResponse(description="the Account object that was just created", ref="#/components/schemas/Account"), | |||||
@ApiResponse(responseCode=SC_OK, description="the Account object that was just created"), | |||||
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if not admin") | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if not admin") | ||||
} | } | ||||
) | ) | ||||
@@ -178,7 +178,7 @@ public class AccountsResource { | |||||
description="Download all data for user. Must be admin.", | 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={ | responses={ | ||||
@ApiResponse(description="a Map<String, List<String>> of all user data"), | |||||
@ApiResponse(responseCode=SC_OK, description="a Map<String, List<String>> of all user data"), | |||||
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if not admin") | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if not admin") | ||||
} | } | ||||
) | ) | ||||
@@ -201,7 +201,7 @@ public class AccountsResource { | |||||
description="Update an account. Caller must be the same account, or must be admin.", | 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={ | responses={ | ||||
@ApiResponse(responseCode=SC_OK, description="the Account object that was updated", ref="#/components/schemas/Account"), | |||||
@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"), | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is updating any account Account other than themselves"), | ||||
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred") | @ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred") | ||||
} | } | ||||
@@ -235,7 +235,7 @@ public class AccountsResource { | |||||
description="List all launch statuses for an account. Caller must be the same account, or must be admin.", | 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={ | responses={ | ||||
@ApiResponse(description="a List<NodeProgressMeterTick> representing the status of active launch operations"), | |||||
@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") | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves") | ||||
} | } | ||||
) | ) | ||||
@@ -261,7 +261,7 @@ public class AccountsResource { | |||||
description="View the AccountPolicy for an account. Caller must be the same account, or must be admin.", | 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={ | responses={ | ||||
@ApiResponse(description="an AccountPolicy object", ref="#/components/schemas/AccountPolicy"), | |||||
@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") | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves") | ||||
} | } | ||||
) | ) | ||||
@@ -280,7 +280,7 @@ public class AccountsResource { | |||||
description="Update the AccountPolicy for an account. Caller must be the same account, or must be admin.", | 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={ | responses={ | ||||
@ApiResponse(description="an AccountPolicy object", ref="#/components/schemas/AccountPolicy"), | |||||
@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"), | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"), | ||||
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred") | @ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred") | ||||
} | } | ||||
@@ -310,7 +310,7 @@ public class AccountsResource { | |||||
description="Create or update an AccountContact in the AccountPolicy. Caller must be the same account, or must be admin.", | 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={ | responses={ | ||||
@ApiResponse(description="the AccountContact object that was created or updated", ref="#/components/schemas/AccountPolicy"), | |||||
@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"), | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"), | ||||
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred") | @ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred") | ||||
} | } | ||||
@@ -351,7 +351,7 @@ public class AccountsResource { | |||||
description="Send verification message for an AccountContact. Caller must be the same account, or must be admin.", | 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={ | responses={ | ||||
@ApiResponse(description="the AccountContact object that was created or updated", ref="#/components/schemas/AccountContact"), | |||||
@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") | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves") | ||||
} | } | ||||
) | ) | ||||
@@ -382,7 +382,7 @@ public class AccountsResource { | |||||
@Parameter(name="info", description="the contact information, for example an email address or phone number") | @Parameter(name="info", description="the contact information, for example an email address or phone number") | ||||
}, | }, | ||||
responses={ | responses={ | ||||
@ApiResponse(description="the AccountContact object", ref="#/components/schemas/AccountContact"), | |||||
@ApiResponse(responseCode=SC_OK, description="the AccountContact object"), | |||||
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"), | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"), | ||||
@ApiResponse(responseCode=SC_NOT_FOUND, description="no AccountContact exists with the given type and info") | @ApiResponse(responseCode=SC_NOT_FOUND, description="no AccountContact exists with the given type and info") | ||||
} | } | ||||
@@ -409,7 +409,7 @@ public class AccountsResource { | |||||
@Parameter(name="info", description="the contact information, for example an email address or phone number") | @Parameter(name="info", description="the contact information, for example an email address or phone number") | ||||
}, | }, | ||||
responses={ | responses={ | ||||
@ApiResponse(description="the AccountContact object that was deleted", ref="#/components/schemas/AccountContact"), | |||||
@ApiResponse(responseCode=SC_OK, description="the AccountContact object that was deleted"), | |||||
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves") | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves") | ||||
} | } | ||||
) | ) | ||||
@@ -433,7 +433,7 @@ public class AccountsResource { | |||||
description="Delete TOTP authenticator AccountContact from an AccountPolicy. Caller must be the same account, or must be admin.", | 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={ | responses={ | ||||
@ApiResponse(description="the AccountPolicy object that was updated", ref="#/components/schemas/AccountPolicy"), | |||||
@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") | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves") | ||||
} | } | ||||
) | ) | ||||
@@ -463,7 +463,7 @@ public class AccountsResource { | |||||
@Parameter(name="uuid", description="UUID of the AccountContact") | @Parameter(name="uuid", description="UUID of the AccountContact") | ||||
}, | }, | ||||
responses={ | responses={ | ||||
@ApiResponse(description="the AccountPolicy object that was updated", ref="#/components/schemas/AccountPolicy"), | |||||
@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") | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves") | ||||
} | } | ||||
) | ) | ||||
@@ -486,7 +486,7 @@ public class AccountsResource { | |||||
description="Request deletion of an Account. Caller must be the same account, or must be admin.", | 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={ | responses={ | ||||
@ApiResponse(description="the AccountMessage object that was sent", ref="#/components/schemas/AccountMessage"), | |||||
@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") | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves") | ||||
} | } | ||||
) | ) | ||||
@@ -516,7 +516,7 @@ public class AccountsResource { | |||||
description="Change password for an account. Caller must be admin.", | 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={ | responses={ | ||||
@ApiResponse(description="the Account object that was updated", ref="#/components/schemas/Account"), | |||||
@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"), | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"), | ||||
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred") | @ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred") | ||||
} | } | ||||
@@ -595,7 +595,7 @@ public class AccountsResource { | |||||
description="Delete an Account. Caller must be admin.", | 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={ | responses={ | ||||
@ApiResponse(description="the Account object that was deleted", ref="#/components/schemas/Account"), | |||||
@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") | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves") | ||||
} | } | ||||
) | ) | ||||
@@ -634,7 +634,7 @@ public class AccountsResource { | |||||
description="Get status of mitmproxy. Caller must be admin.", | 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={ | responses={ | ||||
@ApiResponse(description="returns true if mitmproxy is enabled, false otherwise", | |||||
@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 enabled", value="true"), | ||||
@ExampleObject(name="mitmproxy is disabled", value="false") | @ExampleObject(name="mitmproxy is disabled", value="false") | ||||
@@ -657,7 +657,7 @@ public class AccountsResource { | |||||
description="Enable mitmproxy. Caller must be admin.", | 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={ | responses={ | ||||
@ApiResponse(description="returns true if mitmproxy is enabled, false otherwise", | |||||
@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 enabled", value="true"), | ||||
@ExampleObject(name="mitmproxy is disabled", value="false") | @ExampleObject(name="mitmproxy is disabled", value="false") | ||||
@@ -680,7 +680,7 @@ public class AccountsResource { | |||||
description="Disable mitmproxy. Caller must be admin.", | 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={ | responses={ | ||||
@ApiResponse(description="returns true if mitmproxy is enabled, false otherwise", | |||||
@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 enabled", value="true"), | ||||
@ExampleObject(name="mitmproxy is disabled", value="false") | @ExampleObject(name="mitmproxy is disabled", value="false") | ||||
@@ -758,7 +758,7 @@ public class AccountsResource { | |||||
summary="List all device types", | summary="List all device types", | ||||
description="List all device types", | description="List all device types", | ||||
parameters={@Parameter(name="id", description="UUID or email of the Account")}, | parameters={@Parameter(name="id", description="UUID or email of the Account")}, | ||||
responses={@ApiResponse(description="returns an array of Strings, each a BubbleDeviceType enum value")} | |||||
responses={@ApiResponse(responseCode=SC_OK, description="returns an array of Strings, each a BubbleDeviceType enum value")} | |||||
) | ) | ||||
public Response getDeviceTypes(@Context ContainerRequest ctx) { | public Response getDeviceTypes(@Context ContainerRequest ctx) { | ||||
return ok(BubbleDeviceType.getSelectableTypes()); | return ok(BubbleDeviceType.getSelectableTypes()); | ||||
@@ -135,7 +135,7 @@ public class AuthResource { | |||||
@Operation(tags={API_TAG_UTILITY}, | @Operation(tags={API_TAG_UTILITY}, | ||||
summary="Read public system configuration", | summary="Read public system configuration", | ||||
description="Read public system configuration", | description="Read public system configuration", | ||||
responses={@ApiResponse(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) { | public Response getPublicSystemConfigs(@Context ContainerRequest ctx) { | ||||
return ok(configuration.getPublicSystemConfigs()); | return ok(configuration.getPublicSystemConfigs()); | ||||
@@ -171,7 +171,7 @@ public class AuthResource { | |||||
summary="Determine if the API has been activated", | summary="Determine if the API has been activated", | ||||
description="Determine if the API has been activated", | description="Determine if the API has been activated", | ||||
responses={ | responses={ | ||||
@ApiResponse(description="returns true if API is activated, false otherwise", | |||||
@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 is activated", value="true"), | ||||
@ExampleObject(name="Bubble has not been activated", value="false") | @ExampleObject(name="Bubble has not been activated", value="false") | ||||
@@ -184,7 +184,7 @@ public class AuthResource { | |||||
@Operation(tags={API_TAG_ACTIVATION}, | @Operation(tags={API_TAG_ACTIVATION}, | ||||
summary="Get activation default configuration", | summary="Get activation default configuration", | ||||
description="Get activation default configuration", | description="Get activation default configuration", | ||||
responses={@ApiResponse(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) { | public Response getActivationConfigs(@Context ContainerRequest ctx) { | ||||
final Account caller = optionalUserPrincipal(ctx); | final Account caller = optionalUserPrincipal(ctx); | ||||
@@ -198,7 +198,7 @@ public class AuthResource { | |||||
summary="Perform one-time activation", | summary="Perform one-time activation", | ||||
description="Perform one-time activation", | description="Perform one-time activation", | ||||
responses={ | responses={ | ||||
@ApiResponse(description="the Account object for the initial admin account, with a new session token"), | |||||
@ApiResponse(responseCode=SC_OK, description="the Account object for the initial admin account, with a new session token"), | |||||
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and activation has already been completed"), | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and activation has already been completed"), | ||||
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred: activation has already been completed, or there were errors processing the ActivationRequest object") | @ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred: activation has already been completed, or there were errors processing the ActivationRequest object") | ||||
} | } | ||||
@@ -326,7 +326,7 @@ public class AuthResource { | |||||
summary="Register a new Account, starts a new API session.", | summary="Register a new Account, starts a new API session.", | ||||
description="Register a new Account, starts a new API session.", | description="Register a new Account, starts a new API session.", | ||||
responses={ | responses={ | ||||
@ApiResponse(responseCode=SC_OK, description="the Account object that was registered", ref="#/components/schemas/Account"), | |||||
@ApiResponse(responseCode=SC_OK, description="the Account object that was registered, `token` property holds session token"), | |||||
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred") | @ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred") | ||||
} | } | ||||
) | ) | ||||
@@ -443,7 +443,7 @@ public class AuthResource { | |||||
description="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={ | responses={ | ||||
@ApiResponse(responseCode=SC_OK, description="the Account object that was logged in", ref="#/components/schemas/Account"), | |||||
@ApiResponse(responseCode=SC_OK, description="the Account object that was logged in"), | |||||
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred") | @ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred") | ||||
} | } | ||||
) | ) | ||||
@@ -524,7 +524,7 @@ public class AuthResource { | |||||
description="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={ | responses={ | ||||
@ApiResponse(responseCode=SC_OK, description="the Account object that was logged in", ref="#/components/schemas/Account"), | |||||
@ApiResponse(responseCode=SC_OK, description="the Account object that was logged in"), | |||||
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred") | @ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred") | ||||
} | } | ||||
) | ) | ||||
@@ -592,7 +592,7 @@ public class AuthResource { | |||||
summary="Called between Bubbles to verify RSA keys", | summary="Called between Bubbles to verify RSA keys", | ||||
description="Called between Bubbles to verify RSA keys", | description="Called between Bubbles to verify RSA keys", | ||||
responses={ | responses={ | ||||
@ApiResponse(responseCode=SC_OK, description="an RsaMessage object representing the encrypted challenge response", ref="#/components/schemas/RsaMessage"), | |||||
@ApiResponse(responseCode=SC_OK, description="an RsaMessage object representing the encrypted challenge response"), | |||||
@ApiResponse(responseCode=SC_NOT_FOUND, description="some error occurred, check response") | @ApiResponse(responseCode=SC_NOT_FOUND, description="some error occurred, check response") | ||||
} | } | ||||
) | ) | ||||
@@ -654,7 +654,7 @@ public class AuthResource { | |||||
summary="Re-key a node. Must be admin. Creates a new NodeKey that, being newest, will be the one the node starts using", | 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", | description="Re-key a node. Must be admin. Creates a new NodeKey that, being newest, will be the one the node starts using", | ||||
responses={ | responses={ | ||||
@ApiResponse(description="the NodeKey that was created", ref="#/components/schemas/BubbleNodeKey"), | |||||
@ApiResponse(responseCode=SC_OK, description="the NodeKey that was created"), | |||||
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"), | @ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"), | ||||
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred") | @ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred") | ||||
} | } | ||||
@@ -727,6 +727,19 @@ public class AuthResource { | |||||
} | } | ||||
@POST @Path(EP_APPROVE+"/{token}") | @POST @Path(EP_APPROVE+"/{token}") | ||||
@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")}, | |||||
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_PRECONDITION_FAILED, description="a validation error occurred, for example the token might be invalid") | |||||
} | |||||
) | |||||
public Response approve(@Context Request req, | public Response approve(@Context Request req, | ||||
@Context ContainerRequest ctx, | @Context ContainerRequest ctx, | ||||
@PathParam("token") String token, | @PathParam("token") String token, | ||||
@@ -764,6 +777,18 @@ public class AuthResource { | |||||
} | } | ||||
@POST @Path(EP_AUTHENTICATOR) | @POST @Path(EP_AUTHENTICATOR) | ||||
@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={ | |||||
@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_PRECONDITION_FAILED, description="a validation error occurred, for example the token might be invalid") | |||||
} | |||||
) | |||||
public Response authenticator(@Context Request req, | public Response authenticator(@Context Request req, | ||||
@Context ContainerRequest ctx, | @Context ContainerRequest ctx, | ||||
AuthenticatorRequest request) { | AuthenticatorRequest request) { | ||||
@@ -816,15 +841,38 @@ public class AuthResource { | |||||
} | } | ||||
@DELETE @Path(EP_AUTHENTICATOR) | @DELETE @Path(EP_AUTHENTICATOR) | ||||
@Operation(security=@SecurityRequirement(name=SEC_API_KEY)) | |||||
@Operation(security=@SecurityRequirement(name=SEC_API_KEY), | |||||
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={ | |||||
@ExampleObject(name="returns an empty JSON object", value="{}") | |||||
})}), | |||||
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="a validation error occurred, for example the token might be invalid") | |||||
} | |||||
) | |||||
public Response flushAuthenticatorTokens(@Context Request req, | public Response flushAuthenticatorTokens(@Context Request req, | ||||
@Context ContainerRequest ctx) { | |||||
@Context ContainerRequest ctx) { | |||||
final Account caller = userPrincipal(ctx); | final Account caller = userPrincipal(ctx); | ||||
authenticatorService.flush(caller.getToken()); | authenticatorService.flush(caller.getToken()); | ||||
return ok_empty(); | return ok_empty(); | ||||
} | } | ||||
@POST @Path(EP_DENY+"/{token}") | @POST @Path(EP_DENY+"/{token}") | ||||
@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")}, | |||||
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_PRECONDITION_FAILED, description="a validation error occurred, for example the token might be invalid") | |||||
} | |||||
) | |||||
public Response deny(@Context Request req, | public Response deny(@Context Request req, | ||||
@Context ContainerRequest ctx, | @Context ContainerRequest ctx, | ||||
@PathParam("token") String token) { | @PathParam("token") String token) { | ||||
@@ -838,6 +886,15 @@ public class AuthResource { | |||||
@GET @Path(EP_CA_CERT) | @GET @Path(EP_CA_CERT) | ||||
@Produces(CONTENT_TYPE_ANY) | @Produces(CONTENT_TYPE_ANY) | ||||
@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")} | |||||
) | |||||
public Response getCaCert(@Context Request req, | public Response getCaCert(@Context Request req, | ||||
@Context ContainerRequest ctx, | @Context ContainerRequest ctx, | ||||
@QueryParam("deviceType") BubbleDeviceType deviceType, | @QueryParam("deviceType") BubbleDeviceType deviceType, | ||||
@@ -867,6 +924,13 @@ public class AuthResource { | |||||
} | } | ||||
@GET @Path(EP_KEY) | @GET @Path(EP_KEY) | ||||
@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") | |||||
} | |||||
) | |||||
public Response getNodeKey(@Context Request req, | public Response getNodeKey(@Context Request req, | ||||
@Context ContainerRequest ctx) { | @Context ContainerRequest ctx) { | ||||
final BubbleNode thisNode = configuration.getThisNode(); | final BubbleNode thisNode = configuration.getThisNode(); | ||||
@@ -886,7 +950,16 @@ public class AuthResource { | |||||
} | } | ||||
@GET @Path(EP_LOGOUT) | @GET @Path(EP_LOGOUT) | ||||
@Operation(security=@SecurityRequirement(name=SEC_API_KEY)) | |||||
@Operation(security=@SecurityRequirement(name=SEC_API_KEY), | |||||
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")}, | |||||
responses={ | |||||
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success"), | |||||
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="If there is no current session to log out of") | |||||
} | |||||
) | |||||
public Response logout(@Context ContainerRequest ctx, | public Response logout(@Context ContainerRequest ctx, | ||||
@QueryParam("all") Boolean all) { | @QueryParam("all") Boolean all) { | ||||
final Account account = optionalUserPrincipal(ctx); | final Account account = optionalUserPrincipal(ctx); | ||||
@@ -900,7 +973,16 @@ public class AuthResource { | |||||
} | } | ||||
@POST @Path(EP_LOGOUT+"/{id}") | @POST @Path(EP_LOGOUT+"/{id}") | ||||
@Operation(security=@SecurityRequirement(name=SEC_API_KEY)) | |||||
@Operation(security=@SecurityRequirement(name=SEC_API_KEY), | |||||
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")}, | |||||
responses={ | |||||
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success"), | |||||
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="If there is no current session to log out of") | |||||
} | |||||
) | |||||
public Response logoutUserEverywhere(@Context ContainerRequest ctx, | public Response logoutUserEverywhere(@Context ContainerRequest ctx, | ||||
@PathParam("id") String id) { | @PathParam("id") String id) { | ||||
final Account caller = optionalUserPrincipal(ctx); | final Account caller = optionalUserPrincipal(ctx); | ||||
@@ -916,11 +998,27 @@ public class AuthResource { | |||||
return ok_empty(); | return ok_empty(); | ||||
} | } | ||||
@GET @Path(EP_TIME) public Response serverTime() { return ok(now()); } | |||||
@GET @Path(EP_TIME) | |||||
@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")})}) | |||||
} | |||||
) | |||||
public Response serverTime() { return ok(now()); } | |||||
@Autowired private GeoService geoService; | @Autowired private GeoService geoService; | ||||
@GET @Path(EP_SUPPORT) | @GET @Path(EP_SUPPORT) | ||||
@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") | |||||
} | |||||
) | |||||
public Response getSupportInfo (@Context Request req, | public Response getSupportInfo (@Context Request req, | ||||
@Context ContainerRequest ctx) { | @Context ContainerRequest ctx) { | ||||
final List<String> locales = geoService.getSupportedLocales(optionalUserPrincipal(ctx), getRemoteHost(req), normalizeLangHeader(req)); | final List<String> locales = geoService.getSupportedLocales(optionalUserPrincipal(ctx), getRemoteHost(req), normalizeLangHeader(req)); | ||||
@@ -928,6 +1026,14 @@ public class AuthResource { | |||||
} | } | ||||
@GET @Path(EP_SUPPORT+"/{locale}") | @GET @Path(EP_SUPPORT+"/{locale}") | ||||
@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") | |||||
} | |||||
) | |||||
public Response getSupportInfo (@Context Request req, | public Response getSupportInfo (@Context Request req, | ||||
@Context ContainerRequest ctx, | @Context ContainerRequest ctx, | ||||
@PathParam("locale") String locale) { | @PathParam("locale") String locale) { | ||||
@@ -935,6 +1041,13 @@ public class AuthResource { | |||||
} | } | ||||
@GET @Path(EP_APP_LINKS) | @GET @Path(EP_APP_LINKS) | ||||
@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") | |||||
} | |||||
) | |||||
public Response getAppLinks (@Context Request req, | public Response getAppLinks (@Context Request req, | ||||
@Context ContainerRequest ctx) { | @Context ContainerRequest ctx) { | ||||
final List<String> locales = geoService.getSupportedLocales(optionalUserPrincipal(ctx), getRemoteHost(req), normalizeLangHeader(req)); | final List<String> locales = geoService.getSupportedLocales(optionalUserPrincipal(ctx), getRemoteHost(req), normalizeLangHeader(req)); | ||||
@@ -942,6 +1055,14 @@ public class AuthResource { | |||||
} | } | ||||
@GET @Path(EP_APP_LINKS+"/{locale}") | @GET @Path(EP_APP_LINKS+"/{locale}") | ||||
@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") | |||||
} | |||||
) | |||||
public Response getAppLinks (@Context Request req, | public Response getAppLinks (@Context Request req, | ||||
@Context ContainerRequest ctx, | @Context ContainerRequest ctx, | ||||
@PathParam("locale") String locale) { | @PathParam("locale") String locale) { | ||||
@@ -950,6 +1071,15 @@ public class AuthResource { | |||||
@GET @Path(EP_PATCH+"/{token}") | @GET @Path(EP_PATCH+"/{token}") | ||||
@Produces(APPLICATION_OCTET_STREAM) | @Produces(APPLICATION_OCTET_STREAM) | ||||
@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")}, | |||||
responses={ | |||||
@ApiResponse(responseCode=SC_OK, description="raw file data", content={@Content(mediaType=APPLICATION_OCTET_STREAM)}), | |||||
@ApiResponse(responseCode=SC_NOT_FOUND, description="token not valid") | |||||
} | |||||
) | |||||
public Response getPatchFile(@Context ContainerRequest ctx, | public Response getPatchFile(@Context ContainerRequest ctx, | ||||
@PathParam("token") String token) { | @PathParam("token") String token) { | ||||
final File patch = nodeManagerService.findPatch(token); | final File patch = nodeManagerService.findPatch(token); | ||||
@@ -961,6 +1091,19 @@ public class AuthResource { | |||||
@GET @Path(EP_UPGRADE+"/{node}/{key}") | @GET @Path(EP_UPGRADE+"/{node}/{key}") | ||||
@Produces(APPLICATION_OCTET_STREAM) | @Produces(APPLICATION_OCTET_STREAM) | ||||
@Operation(tags={API_TAG_NODE}, | |||||
summary="Return bubble jar", | |||||
description="Return bubble jar file for upgrading other nodes to our version.", | |||||
parameters={ | |||||
@Parameter(name="node", description="UUID of the calling node"), | |||||
@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_UNAUTHORIZED, description="calling node is not authorized"), | |||||
@ApiResponse(responseCode=SC_NOT_FOUND, description="token not valid") | |||||
} | |||||
) | |||||
public Response getUpgrade(@Context Request req, | public Response getUpgrade(@Context Request req, | ||||
@Context ContainerRequest ctx, | @Context ContainerRequest ctx, | ||||
@PathParam("node") String nodeUuid, | @PathParam("node") String nodeUuid, | ||||
@@ -1,18 +0,0 @@ | |||||
/** | |||||
* Copyright (c) 2020 Bubble, Inc. All rights reserved. | |||||
* For personal (non-commercial) use, see license: https://getbubblenow.com/bubble-license/ | |||||
*/ | |||||
package bubble.server; | |||||
import lombok.Getter; | |||||
import lombok.Setter; | |||||
public class BasicAppLinks { | |||||
@Getter @Setter private String ios; | |||||
@Getter @Setter private String android; | |||||
@Getter @Setter private String windows; | |||||
@Getter @Setter private String macosx; | |||||
@Getter @Setter private String linux; | |||||
} |
@@ -13,6 +13,7 @@ import bubble.dao.account.AccountDAO; | |||||
import bubble.dao.bill.AccountPlanDAO; | import bubble.dao.bill.AccountPlanDAO; | ||||
import bubble.dao.bill.BubblePlanDAO; | import bubble.dao.bill.BubblePlanDAO; | ||||
import bubble.dao.cloud.CloudServiceDAO; | import bubble.dao.cloud.CloudServiceDAO; | ||||
import bubble.model.AppLinks; | |||||
import bubble.model.bill.AccountPlan; | import bubble.model.bill.AccountPlan; | ||||
import bubble.model.bill.BubblePlan; | import bubble.model.bill.BubblePlan; | ||||
import bubble.model.cloud.BubbleNetwork; | import bubble.model.cloud.BubbleNetwork; | ||||
@@ -17,6 +17,7 @@ openApi: | |||||
licenseUrl: https://getbubblenow.com/bubble-license/ | licenseUrl: https://getbubblenow.com/bubble-license/ | ||||
additionalPackages: | additionalPackages: | ||||
- org.cobbzilla.wizard.model.search | - org.cobbzilla.wizard.model.search | ||||
- org.cobbzilla.wizard.model.support | |||||
defaultLocale: {{#exists BUBBLE_DEFAULT_LOCALE}}{{BUBBLE_DEFAULT_LOCALE}}{{else}}en_US{{/exists}} | defaultLocale: {{#exists BUBBLE_DEFAULT_LOCALE}}{{BUBBLE_DEFAULT_LOCALE}}{{else}}en_US{{/exists}} | ||||
testMode: {{#exists BUBBLE_TEST_MODE}}{{BUBBLE_TEST_MODE}}{{else}}false{{/exists}} | testMode: {{#exists BUBBLE_TEST_MODE}}{{BUBBLE_TEST_MODE}}{{else}}false{{/exists}} | ||||
@@ -1 +1 @@ | |||||
Subproject commit c40f0704e1acb17ca3d1f1a4b590fe11997aa1b6 | |||||
Subproject commit 09d23d287d18bfa2655f56cb80a3dd7c4bcc0816 |