Parcourir la source

add support for apps-per-plan

tags/v0.5.0
Jonathan Cobb il y a 4 ans
Parent
révision
34a98cbbba
13 fichiers modifiés avec 239 ajouts et 34 suppressions
  1. +1
    -0
      bubble-server/src/main/java/bubble/ApiConstants.java
  2. +15
    -2
      bubble-server/src/main/java/bubble/dao/bill/BubblePlanAppDAO.java
  3. +2
    -2
      bubble-server/src/main/java/bubble/model/bill/BubblePlan.java
  4. +3
    -1
      bubble-server/src/main/java/bubble/model/bill/BubblePlanApp.java
  5. +20
    -0
      bubble-server/src/main/java/bubble/resources/bill/AccountPlansResource.java
  6. +23
    -0
      bubble-server/src/main/java/bubble/resources/bill/BubblePlanAppsResource.java
  7. +3
    -3
      bubble-server/src/main/java/bubble/resources/bill/BubblePlansResource.java
  8. +1
    -1
      bubble-server/src/main/java/bubble/service/cloud/AnsiblePrepService.java
  9. +2
    -0
      bubble-server/src/test/java/bubble/test/PaymentTest.java
  10. +2
    -2
      bubble-server/src/test/resources/models/manifest-test.json
  11. +26
    -23
      bubble-server/src/test/resources/models/system/bubblePlan.json
  12. +37
    -0
      bubble-server/src/test/resources/models/system/bubblePlan_withApps.json
  13. +104
    -0
      bubble-server/src/test/resources/models/tests/payment/plan_apps.json

+ 1
- 0
bubble-server/src/main/java/bubble/ApiConstants.java Voir le fichier

@@ -141,6 +141,7 @@ public class ApiConstants {
public static final String EP_MODEL = "/model";
public static final String EP_VPN = "/vpn";
public static final String EP_IPS = "/ips";
public static final String EP_PLAN = "/plan";
public static final String EP_PAYMENT_METHOD = "/paymentMethod";
public static final String EP_PAYMENT_METHODS = PAYMENT_METHODS_ENDPOINT;
public static final String EP_PAYMENT = "/payment";


+ 15
- 2
bubble-server/src/main/java/bubble/dao/bill/BubblePlanAppDAO.java Voir le fichier

@@ -1,7 +1,10 @@
package bubble.dao.bill;

import bubble.dao.account.AccountOwnedEntityDAO;
import bubble.dao.app.BubbleAppDAO;
import bubble.model.app.BubbleApp;
import bubble.model.bill.BubblePlanApp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.List;
@@ -9,8 +12,18 @@ import java.util.List;
@Repository
public class BubblePlanAppDAO extends AccountOwnedEntityDAO<BubblePlanApp> {

public List<BubblePlanApp> findByAccountAndPlan(String account, String bubblePlan) {
return findByFields("account", account, "plan", bubblePlan);
@Autowired private BubbleAppDAO appDAO;

public List<BubblePlanApp> findByPlan(String bubblePlan) {
return findByField("plan", bubblePlan);
}

public BubblePlanApp findByAccountAndPlanAndId(String account, String bubblePlan, String id) {
final BubblePlanApp planApp = findByUniqueFields("plan", bubblePlan, "app", id);
if (planApp != null) return planApp;

final BubbleApp app = appDAO.findByAccountAndId(account, id);
return app == null ? null : findByUniqueFields("plan", bubblePlan, "app", app.getUuid());
}

}

+ 2
- 2
bubble-server/src/main/java/bubble/model/bill/BubblePlan.java Voir le fichier

@@ -9,8 +9,8 @@ import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.cobbzilla.util.collection.HasPriority;
import org.cobbzilla.wizard.model.IdentifiableBase;
import org.cobbzilla.wizard.model.entityconfig.EntityFieldType;
import org.cobbzilla.wizard.model.entityconfig.IdentifiableBaseParentEntity;
import org.cobbzilla.wizard.model.entityconfig.annotations.*;
import org.cobbzilla.wizard.validation.HasValue;
import org.joda.time.format.DateTimeFormat;
@@ -35,7 +35,7 @@ import static org.cobbzilla.util.reflect.ReflectionUtil.copy;
})
@Entity @NoArgsConstructor @Accessors(chain=true)
@ECIndexes({ @ECIndex(unique=true, of={"account", "name"}) })
public class BubblePlan extends IdentifiableBase implements HasAccount, HasPriority {
public class BubblePlan extends IdentifiableBaseParentEntity implements HasAccount, HasPriority {

public static final int MAX_CHARGENAME_LEN = 12;



+ 3
- 1
bubble-server/src/main/java/bubble/model/bill/BubblePlanApp.java Voir le fichier

@@ -20,7 +20,9 @@ import static org.cobbzilla.util.reflect.ReflectionUtil.copy;
@ECType(root=true)
@ECTypeURIs(baseURI=EP_APPS, listFields={"plan", "app"})
@Entity @NoArgsConstructor @Accessors(chain=true)
@ECIndexes({ @ECIndex(unique=true, of={"account", "plan", "app"}) })
@ECIndexes({
@ECIndex(unique=true, of={"plan", "app"})
})
public class BubblePlanApp extends IdentifiableBase implements HasAccountNoName {

public static final String[] CREATE_FIELDS = {"plan", "app"};


+ 20
- 0
bubble-server/src/main/java/bubble/resources/bill/AccountPlansResource.java Voir le fichier

@@ -256,4 +256,24 @@ public class AccountPlansResource extends AccountOwnedResource<AccountPlan, Acco
return paymentMethod == null ? notFound() : ok(paymentMethod);
}

@GET @Path("/{id}"+EP_PLAN)
public Response getBubblePlan(@Context ContainerRequest ctx,
@PathParam("id") String id) {
final AccountPlan accountPlan = find(ctx, id);
if (accountPlan == null) return notFound(id);

final BubblePlan plan = planDAO.findByUuid(accountPlan.getPlan());
return plan == null ? notFound() : ok(plan);
}

@Path("/{id}"+EP_APPS)
public BubblePlanAppsResource getApps(@Context ContainerRequest ctx,
@PathParam("id") String id) {
final AccountPlan accountPlan = find(ctx, id);
if (accountPlan == null) throw notFoundEx(id);
final Account account = accountDAO.findByUuid(getAccountUuid(ctx));
final BubblePlan plan = planDAO.findByUuid(accountPlan.getPlan());
return configuration.subResource(BubblePlanAppsResource.class, account, plan);
}

}

+ 23
- 0
bubble-server/src/main/java/bubble/resources/bill/BubblePlanAppsResource.java Voir le fichier

@@ -8,9 +8,12 @@ import bubble.model.bill.BubblePlan;
import bubble.model.bill.BubblePlanApp;
import bubble.resources.account.AccountOwnedResource;
import lombok.extern.slf4j.Slf4j;
import org.glassfish.grizzly.http.server.Request;
import org.glassfish.jersey.server.ContainerRequest;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

import static org.cobbzilla.wizard.resources.ResourceUtil.notFoundEx;

@Slf4j
@@ -25,6 +28,26 @@ public class BubblePlanAppsResource extends AccountOwnedResource<BubblePlanApp,

@Autowired private BubbleAppDAO appDAO;

@Override protected List<BubblePlanApp> list(ContainerRequest ctx) {
return getDao().findByPlan(plan.getUuid());
}

@Override protected BubblePlanApp find(ContainerRequest ctx, String id) {
return getDao().findByAccountAndPlanAndId(account.getUuid(), plan.getUuid(), id);
}

@Override protected boolean canCreate(Request req, ContainerRequest ctx, Account caller, BubblePlanApp request) {
return caller.admin();
}

@Override protected boolean canUpdate(ContainerRequest ctx, Account caller, BubblePlanApp found, BubblePlanApp request) {
return false;
}

@Override protected boolean canDelete(ContainerRequest ctx, Account caller, BubblePlanApp found) {
return caller.admin();
}

@Override protected BubblePlanApp setReferences(ContainerRequest ctx, Account caller, BubblePlanApp request) {
final BubbleApp app = appDAO.findByAccountAndId(getAccountUuid(ctx), request.getApp());
if (app == null) throw notFoundEx(request.getApp());


+ 3
- 3
bubble-server/src/main/java/bubble/resources/bill/BubblePlansResource.java Voir le fichier

@@ -16,8 +16,7 @@ import static bubble.ApiConstants.EP_APPS;
import static bubble.ApiConstants.PLANS_ENDPOINT;
import static bubble.model.bill.BubblePlan.MAX_CHARGENAME_LEN;
import static org.cobbzilla.util.daemon.ZillaRuntime.empty;
import static org.cobbzilla.wizard.resources.ResourceUtil.invalidEx;
import static org.cobbzilla.wizard.resources.ResourceUtil.notFoundEx;
import static org.cobbzilla.wizard.resources.ResourceUtil.*;

@Path(PLANS_ENDPOINT)
@Service @Slf4j
@@ -36,7 +35,8 @@ public class BubblePlansResource extends AccountOwnedResource<BubblePlan, Bubble
@PathParam("id") String id) {
final BubblePlan plan = find(ctx, id);
if (plan == null) throw notFoundEx(id);
return configuration.subResource(BubblePlanAppsResource.class, account, plan);
final Account caller = userPrincipal(ctx);
return configuration.subResource(BubblePlanAppsResource.class, caller, plan);
}

}

+ 1
- 1
bubble-server/src/main/java/bubble/service/cloud/AnsiblePrepService.java Voir le fichier

@@ -90,7 +90,7 @@ public class AnsiblePrepService {
if (configuration.paymentsEnabled()) {
final AccountPlan accountPlan = accountPlanDAO.findByAccountAndNetwork(account.getUuid(), network.getUuid());
if (accountPlan == null) return die("prepAnsible: no AccountPlan found for network: "+network.getUuid());
planApps = planAppDAO.findByAccountAndPlan(account.getUuid(), accountPlan.getPlan());
planApps = planAppDAO.findByPlan(accountPlan.getPlan());
} else {
planApps = null;
}


+ 2
- 0
bubble-server/src/test/java/bubble/test/PaymentTest.java Voir le fichier

@@ -14,4 +14,6 @@ public class PaymentTest extends PaymentTestBase {
modelTest("payment/pay_credit_refund_and_restart");
}

@Test public void testAppsForPlan () throws Exception { modelTest("payment/plan_apps"); }

}

+ 2
- 2
bubble-server/src/test/resources/models/manifest-test.json Voir le fichier

@@ -2,11 +2,11 @@
"system/cloudService",
"system/cloudService_test",
"system/bubbleDomain",
"system/bubblePlan",
"system/bubbleFootprint",
"system/ruleDriver",
"system/account_testDevice",
"manifest-app-analytics",
"manifest-app-user-block-hn",
"manifest-app-user-block-localhost"
"manifest-app-user-block-localhost",
"system/bubblePlan_withApps"
]

+ 26
- 23
bubble-server/src/test/resources/models/system/bubblePlan.json Voir le fichier

@@ -1,23 +1,26 @@
[{
"name": "bubble",
"chargeName": "BubbleVPNP",
"computeSizeType": "small",
"nodesIncluded": 1,
"additionalPerNodePrice": 1200,
"price": 1200,
"storageGbIncluded": 15,
"additionalStoragePerGbPrice": 2,
"bandwidthGbIncluded": 500,
"additionalBandwidthPerGbPrice": 2
}, {
"name": "bubble_plus",
"chargeName": "BubblePlus",
"computeSizeType": "medium",
"nodesIncluded": 1,
"additionalPerNodePrice": 1900,
"price": 1900,
"storageGbIncluded": 40,
"additionalStoragePerGbPrice": 2,
"bandwidthGbIncluded": 1000,
"additionalBandwidthPerGbPrice": 2
}]
[
{
"name": "bubble",
"chargeName": "BubbleVPNP",
"computeSizeType": "small",
"nodesIncluded": 1,
"additionalPerNodePrice": 1200,
"price": 1200,
"storageGbIncluded": 15,
"additionalStoragePerGbPrice": 2,
"bandwidthGbIncluded": 500,
"additionalBandwidthPerGbPrice": 2
},
{
"name": "bubble_plus",
"chargeName": "BubblePlus",
"computeSizeType": "medium",
"nodesIncluded": 1,
"additionalPerNodePrice": 1900,
"price": 1900,
"storageGbIncluded": 40,
"additionalStoragePerGbPrice": 2,
"bandwidthGbIncluded": 1000,
"additionalBandwidthPerGbPrice": 2
}
]

+ 37
- 0
bubble-server/src/test/resources/models/system/bubblePlan_withApps.json Voir le fichier

@@ -0,0 +1,37 @@
[
{
"name": "bubble",
"chargeName": "BubbleVPNP",
"computeSizeType": "small",
"nodesIncluded": 1,
"additionalPerNodePrice": 1200,
"price": 1200,
"storageGbIncluded": 15,
"additionalStoragePerGbPrice": 2,
"bandwidthGbIncluded": 500,
"additionalBandwidthPerGbPrice": 2,
"children": {
"BubblePlanApp": [
{"app": "UserBlocker"}
]
}
},
{
"name": "bubble_plus",
"chargeName": "BubblePlus",
"computeSizeType": "medium",
"nodesIncluded": 1,
"additionalPerNodePrice": 1900,
"price": 1900,
"storageGbIncluded": 40,
"additionalStoragePerGbPrice": 2,
"bandwidthGbIncluded": 1000,
"additionalBandwidthPerGbPrice": 2,
"children": {
"BubblePlanApp": [
{"app": "TrafficAnalytics"},
{"app": "UserBlocker"}
]
}
}
]

+ 104
- 0
bubble-server/src/test/resources/models/tests/payment/plan_apps.json Voir le fichier

@@ -0,0 +1,104 @@
[
{
"comment": "create a user account",
"request": {
"uri": "users",
"method": "put",
"entity": {
"name": "test_user_free",
"password": "password",
"contact": {"type": "email", "info": "test-user@example.com"}
}
}
},

{
"before": "sleep 22s", // wait for account objects to be created
"comment": "login as new user",
"request": {
"session": "new",
"uri": "auth/login",
"entity": {
"name": "test_user_free",
"password": "password"
}
},
"response": {
"store": "testAccount",
"sessionName": "userSession",
"session": "token"
}
},

{
"comment": "get plans",
"request": { "uri": "plans" },
"response": {
"store": "plans",
"check": [{"condition": "json.length >= 1"}]
}
},

{
"comment": "add basic plan, using 'free' payment method",
"request": {
"uri": "me/plans",
"method": "put",
"entity": {
"name": "test-net-{{rand 5}}",
"domain": "{{defaultDomain}}",
"locale": "en_US",
"timezone": "EST",
"plan": "{{plans.[0].name}}",
"footprint": "US",
"paymentMethodObject": {
"paymentMethodType": "free",
"paymentInfo": "free"
}
}
},
"response": {
"store": "accountPlan"
}
},

{
"comment": "get plan apps, should be 1",
"request": { "uri": "me/plans/{{accountPlan.uuid}}/apps" },
"response": {
"check": [{"condition": "json.length == 1"}]
}
},

{
"comment": "add plus plan, using 'free' payment method",
"request": {
"uri": "me/plans",
"method": "put",
"entity": {
"name": "test-net-{{rand 5}}",
"domain": "{{defaultDomain}}",
"locale": "en_US",
"timezone": "EST",
"plan": "{{plans.[1].name}}",
"footprint": "US",
"paymentMethodObject": {
"paymentMethodType": "free",
"paymentInfo": "free"
}
}
},
"response": {
"store": "accountPlan2"
}
},

{
"comment": "get plan apps, should be 2",
"request": { "uri": "me/plans/{{accountPlan2.uuid}}/apps" },
"response": {
"check": [{"condition": "json.length == 2"}]
}
}

]

Chargement…
Annuler
Enregistrer