NOTE: The plans page is still broken

- Change the subscribe method to allow for subscribing to the free plan, even when an org
- Change the frontend to no longer have different plan groups
- Change the frontend to display the proper plans (i.e. hide the deprecated plans unless it is the current plan, etc)
This commit is contained in:
Joseph Schorr 2013-12-19 21:51:46 -05:00
parent e3504b91de
commit 3f062ee602
4 changed files with 91 additions and 85 deletions

View file

@ -1540,7 +1540,7 @@ def subscribe(user, plan, token, require_business_plan):
if not plan_found:
abort(404)
if require_business_plan and not plan_found['bus_features']:
if require_business_plan and not plan_found['bus_features'] and not plan_found['price'] == 0:
abort(404)
private_repos = model.get_private_repo_count(user.username)
@ -1679,7 +1679,7 @@ def get_org_subscription(orgname):
return jsonify(subscription_view(cus.subscription, private_repos))
return jsonify({
'plan': 'bus-free',
'plan': 'free',
'usedPrivateRepos': private_repos,
})

View file

@ -32,14 +32,15 @@
<td></td>
</thead>
<tr ng-repeat="plan in plans" ng-class="(subscribedPlan.stripeId === plan.stripeId) ? getActiveSubClass() : ''">
<tr ng-repeat="plan in plans" ng-show="isPlanVisible(plan, subscribedPlan)"
ng-class="(subscribedPlan.stripeId === plan.stripeId) ? getActiveSubClass() : ''">
<td>{{ plan.title }}</td>
<td>{{ plan.privateRepos }}</td>
<td><div class="plan-price">${{ plan.price / 100 }}</div></td>
<td class="controls">
<div ng-switch='plan.stripeId'>
<div ng-switch-when='bus-free'>
<button class="btn button-hidden">Hidden!</button>
<div ng-switch='plan.deprecated'>
<div ng-switch-when='true'>
<b>Existing Plan</b>
</div>
<div ng-switch-default>
<button class="btn" ng-show="subscribedPlan.stripeId !== plan.stripeId"

View file

@ -261,6 +261,10 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
var planService = {};
var listeners = [];
planService.getFreePlan = function() {
return 'free';
};
planService.registerListener = function(obj, callback) {
listeners.push({'obj': obj, 'callback': callback});
};
@ -278,6 +282,27 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
CookieService.putSession('quay.notedplan', planId);
};
planService.isOrgCompatible = function(plan) {
return plan['stripeId'] == planService.getFreePlan() || plan['bus_features'];
};
planService.getMatchingBusinessPlan = function(callback) {
planService.getPlans(function() {
planService.getSubscription(null, function(sub) {
var plan = planDict[sub.plan];
if (!plan) {
planService.getMinimumPlan(0, true, callback);
return;
}
var count = Math.max(sub.usedPrivateRepos, plan.privateRepos);
planService.getMinimumPlan(count, true, callback);
}, function() {
planService.getMinimumPlan(0, true, callback);
});
});
};
planService.handleNotedPlan = function() {
var planId = planService.getAndResetNotedPlan();
if (!planId) { return; }
@ -288,13 +313,11 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
}
planService.getPlan(planId, function(plan) {
planService.isBusinessPlan(planId, function(bus) {
if (bus) {
document.location = '/organizations/new/?plan=' + planId;
} else {
document.location = '/user?plan=' + planId;
}
});
if (planService.isOrgCompatible(plan)) {
document.location = '/organizations/new/?plan=' + planId;
} else {
document.location = '/user?plan=' + planId;
}
});
});
};
@ -333,69 +356,51 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
var getPlans = Restangular.one('plans');
getPlans.get().then(function(data) {
var i = 0;
for(i = 0; i < data.user.length; i++) {
planDict[data.user[i].stripeId] = data.user[i];
for(i = 0; i < data.plans.length; i++) {
planDict[data.plans[i].stripeId] = data.plans[i];
}
for(i = 0; i < data.business.length; i++) {
planDict[data.business[i].stripeId] = data.business[i];
}
plans = data;
plans = data.plans;
callback(plans);
}, function() { callback([]); });
};
planService.getMatchingBusinessPlan = function(callback) {
planService.getPlans(function() {
planService.getSubscription(null, function(sub) {
var plan = planDict[sub.plan];
if (!plan) {
planService.getMinimumPlan(0, true, callback);
return;
}
var count = Math.max(sub.usedPrivateRepos, plan.privateRepos);
planService.getMinimumPlan(count, true, callback);
}, function() {
planService.getMinimumPlan(0, true, callback);
});
});
};
planService.isBusinessPlan = function(planId, callback) {
planService.getPlans = function(callback, opt_includePersonal) {
planService.verifyLoaded(function() {
planSource = plans.business;
for (var i = 0; i < planSource.length; i++) {
var plan = planSource[i];
if (plan.stripeId == planId) {
callback(true);
return;
}
var filtered = [];
for (var i = 0; i < plans.length; ++i) {
var plan = plans[i];
if (plan['deprecated']) { continue; }
if (!opt_includePersonal && !planService.isOrgCompatible(plan)) { continue; }
filtered.push(plan);
}
callback(false);
callback(filtered);
});
};
planService.getPlans = function(callback) {
planService.verifyLoaded(callback);
};
planService.getPlan = function(planId, callback) {
planService.getPlanIncludingDeprecated(planId, function(plan) {
if (!plan['deprecated']) {
callback(plan);
}
});
};
planService.getPlanIncludingDeprecated = function(planId, callback) {
planService.verifyLoaded(function() {
if (planDict[planId]) {
if (planDict[planId]) {
callback(planDict[planId]);
}
});
};
planService.getMinimumPlan = function(privateCount, isBusiness, callback) {
planService.verifyLoaded(function() {
var planSource = plans.user;
if (isBusiness) {
planSource = plans.business;
}
planService.verifyLoaded(function() {
for (var i = 0; i < plans.length; i++) {
var plan = plans[i];
if (isBusiness && !planService.isOrgCompatible(plan)) {
continue;
}
for (var i = 0; i < planSource.length; i++) {
var plan = planSource[i];
if (plan.privateRepos >= privateCount) {
callback(plan);
return;
@ -453,6 +458,8 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
}
planService.getPlan(planId, function(plan) {
if (orgname && !planService.isOrgCompatible(plan)) { return; }
planService.getCardInfo(orgname, function(cardInfo) {
if (plan.price > 0 && !cardInfo.last4) {
planService.showSubscribeDialog($scope, orgname, planId, callbacks);
@ -1843,6 +1850,18 @@ quayApp.directive('planManager', function () {
controller: function($scope, $element, PlanService, Restangular) {
var hasSubscription = false;
$scope.isPlanVisible = function(plan, subscribedPlan) {
if (plan['deprecated']) {
return plan == subscribedPlan;
}
if ($scope.organization && !PlanService.isOrgCompatible(plan)) {
return false;
}
return true;
};
$scope.getActiveSubClass = function() {
return 'active';
};
@ -1865,17 +1884,17 @@ quayApp.directive('planManager', function () {
};
$scope.cancelSubscription = function() {
$scope.changeSubscription(getFreePlan());
$scope.changeSubscription(PlanService.getFreePlan());
};
var subscribedToPlan = function(sub) {
$scope.subscription = sub;
if (sub.plan != getFreePlan()) {
if (sub.plan != PlanService.getFreePlan()) {
hasSubscription = true;
}
PlanService.getPlan(sub.plan, function(subscribedPlan) {
PlanService.getPlanIncludingDeprecated(sub.plan, function(subscribedPlan) {
$scope.subscribedPlan = subscribedPlan;
$scope.planUsagePercent = sub.usedPrivateRepos * 100 / $scope.subscribedPlan.privateRepos;
@ -1905,22 +1924,13 @@ quayApp.directive('planManager', function () {
});
};
var getFreePlan = function() {
for (var i = 0; i < $scope.plans.length; ++i) {
if ($scope.plans[i].price == 0) {
return $scope.plans[i].stripeId;
}
}
return 'free';
};
var update = function() {
$scope.planLoading = true;
if (!$scope.plans) { return; }
PlanService.getSubscription($scope.organization, subscribedToPlan, function() {
// User/Organization has no subscription.
subscribedToPlan({ 'plan': getFreePlan() });
subscribedToPlan({ 'plan': PlanService.getFreePlan() });
});
};
@ -1929,13 +1939,13 @@ quayApp.directive('planManager', function () {
if (!$scope.user && !$scope.organization) { return; }
$scope.loadingPlans = true;
PlanService.getPlans(function(plans) {
$scope.plans = plans[$scope.organization ? 'business' : 'user'];
PlanService.verifyLoaded(function(plans) {
$scope.plans = plans;
update();
if ($scope.readyForPlan) {
var planRequested = $scope.readyForPlan();
if (planRequested && planRequested != getFreePlan()) {
if (planRequested && planRequested != PlanService.getFreePlan()) {
$scope.changeSubscription(planRequested);
}
}

View file

@ -22,7 +22,7 @@ function PlansCtrl($scope, $location, UserService, PlanService) {
// Load the list of plans.
PlanService.getPlans(function(plans) {
$scope.plans = plans;
});
}, /* include the personal plan */ true);
// Monitor any user changes and place the current user into the scope.
UserService.updateUserIn($scope);
@ -621,7 +621,7 @@ function UserAdminCtrl($scope, $timeout, $location, Restangular, PlanService, Us
});
PlanService.getPlans(function(plans) {
$scope.orgPlans = plans.business;
$scope.orgPlans = plans;
});
$scope.convertStep = 1;
@ -1074,17 +1074,12 @@ function OrgAdminCtrl($rootScope, $scope, Restangular, $routeParams, UserService
// Load the list of plans.
PlanService.getPlans(function(plans) {
$scope.plans = plans.business;
$scope.plans = plans;
$scope.plan_map = {};
var addPlans = function(plans) {
for (var i = 0; i < plans.length; ++i) {
$scope.plan_map[plans[i].stripeId] = plans[i];
}
};
addPlans(plans.user);
addPlans(plans.business);
for (var i = 0; i < plans.length; ++i) {
$scope.plan_map[plans[i].stripeId] = plans[i];
}
});
$scope.orgname = orgname;
@ -1230,7 +1225,7 @@ function NewOrgCtrl($scope, $routeParams, $timeout, $location, UserService, Plan
// Load the list of plans.
PlanService.getPlans(function(plans) {
$scope.plans = plans.business;
$scope.plans = plans;
$scope.currentPlan = null;
if (requested) {
PlanService.getPlan(requested, function(plan) {