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:
parent
e3504b91de
commit
3f062ee602
4 changed files with 91 additions and 85 deletions
|
@ -1540,7 +1540,7 @@ def subscribe(user, plan, token, require_business_plan):
|
||||||
if not plan_found:
|
if not plan_found:
|
||||||
abort(404)
|
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)
|
abort(404)
|
||||||
|
|
||||||
private_repos = model.get_private_repo_count(user.username)
|
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(subscription_view(cus.subscription, private_repos))
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'plan': 'bus-free',
|
'plan': 'free',
|
||||||
'usedPrivateRepos': private_repos,
|
'usedPrivateRepos': private_repos,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -32,14 +32,15 @@
|
||||||
<td></td>
|
<td></td>
|
||||||
</thead>
|
</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.title }}</td>
|
||||||
<td>{{ plan.privateRepos }}</td>
|
<td>{{ plan.privateRepos }}</td>
|
||||||
<td><div class="plan-price">${{ plan.price / 100 }}</div></td>
|
<td><div class="plan-price">${{ plan.price / 100 }}</div></td>
|
||||||
<td class="controls">
|
<td class="controls">
|
||||||
<div ng-switch='plan.stripeId'>
|
<div ng-switch='plan.deprecated'>
|
||||||
<div ng-switch-when='bus-free'>
|
<div ng-switch-when='true'>
|
||||||
<button class="btn button-hidden">Hidden!</button>
|
<b>Existing Plan</b>
|
||||||
</div>
|
</div>
|
||||||
<div ng-switch-default>
|
<div ng-switch-default>
|
||||||
<button class="btn" ng-show="subscribedPlan.stripeId !== plan.stripeId"
|
<button class="btn" ng-show="subscribedPlan.stripeId !== plan.stripeId"
|
||||||
|
|
144
static/js/app.js
144
static/js/app.js
|
@ -261,6 +261,10 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
||||||
var planService = {};
|
var planService = {};
|
||||||
var listeners = [];
|
var listeners = [];
|
||||||
|
|
||||||
|
planService.getFreePlan = function() {
|
||||||
|
return 'free';
|
||||||
|
};
|
||||||
|
|
||||||
planService.registerListener = function(obj, callback) {
|
planService.registerListener = function(obj, callback) {
|
||||||
listeners.push({'obj': obj, 'callback': callback});
|
listeners.push({'obj': obj, 'callback': callback});
|
||||||
};
|
};
|
||||||
|
@ -278,6 +282,27 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
||||||
CookieService.putSession('quay.notedplan', planId);
|
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() {
|
planService.handleNotedPlan = function() {
|
||||||
var planId = planService.getAndResetNotedPlan();
|
var planId = planService.getAndResetNotedPlan();
|
||||||
if (!planId) { return; }
|
if (!planId) { return; }
|
||||||
|
@ -288,13 +313,11 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
||||||
}
|
}
|
||||||
|
|
||||||
planService.getPlan(planId, function(plan) {
|
planService.getPlan(planId, function(plan) {
|
||||||
planService.isBusinessPlan(planId, function(bus) {
|
if (planService.isOrgCompatible(plan)) {
|
||||||
if (bus) {
|
document.location = '/organizations/new/?plan=' + planId;
|
||||||
document.location = '/organizations/new/?plan=' + planId;
|
} else {
|
||||||
} else {
|
document.location = '/user?plan=' + planId;
|
||||||
document.location = '/user?plan=' + planId;
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -333,69 +356,51 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
||||||
var getPlans = Restangular.one('plans');
|
var getPlans = Restangular.one('plans');
|
||||||
getPlans.get().then(function(data) {
|
getPlans.get().then(function(data) {
|
||||||
var i = 0;
|
var i = 0;
|
||||||
for(i = 0; i < data.user.length; i++) {
|
for(i = 0; i < data.plans.length; i++) {
|
||||||
planDict[data.user[i].stripeId] = data.user[i];
|
planDict[data.plans[i].stripeId] = data.plans[i];
|
||||||
}
|
}
|
||||||
for(i = 0; i < data.business.length; i++) {
|
plans = data.plans;
|
||||||
planDict[data.business[i].stripeId] = data.business[i];
|
|
||||||
}
|
|
||||||
plans = data;
|
|
||||||
callback(plans);
|
callback(plans);
|
||||||
}, function() { callback([]); });
|
}, function() { callback([]); });
|
||||||
};
|
};
|
||||||
|
|
||||||
planService.getMatchingBusinessPlan = function(callback) {
|
planService.getPlans = function(callback, opt_includePersonal) {
|
||||||
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.verifyLoaded(function() {
|
planService.verifyLoaded(function() {
|
||||||
planSource = plans.business;
|
var filtered = [];
|
||||||
for (var i = 0; i < planSource.length; i++) {
|
for (var i = 0; i < plans.length; ++i) {
|
||||||
var plan = planSource[i];
|
var plan = plans[i];
|
||||||
if (plan.stripeId == planId) {
|
if (plan['deprecated']) { continue; }
|
||||||
callback(true);
|
if (!opt_includePersonal && !planService.isOrgCompatible(plan)) { continue; }
|
||||||
return;
|
filtered.push(plan);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
callback(false);
|
callback(filtered);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
planService.getPlans = function(callback) {
|
|
||||||
planService.verifyLoaded(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
planService.getPlan = function(planId, callback) {
|
planService.getPlan = function(planId, callback) {
|
||||||
|
planService.getPlanIncludingDeprecated(planId, function(plan) {
|
||||||
|
if (!plan['deprecated']) {
|
||||||
|
callback(plan);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
planService.getPlanIncludingDeprecated = function(planId, callback) {
|
||||||
planService.verifyLoaded(function() {
|
planService.verifyLoaded(function() {
|
||||||
if (planDict[planId]) {
|
if (planDict[planId]) {
|
||||||
callback(planDict[planId]);
|
callback(planDict[planId]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
planService.getMinimumPlan = function(privateCount, isBusiness, callback) {
|
planService.getMinimumPlan = function(privateCount, isBusiness, callback) {
|
||||||
planService.verifyLoaded(function() {
|
planService.verifyLoaded(function() {
|
||||||
var planSource = plans.user;
|
for (var i = 0; i < plans.length; i++) {
|
||||||
if (isBusiness) {
|
var plan = plans[i];
|
||||||
planSource = plans.business;
|
if (isBusiness && !planService.isOrgCompatible(plan)) {
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = 0; i < planSource.length; i++) {
|
|
||||||
var plan = planSource[i];
|
|
||||||
if (plan.privateRepos >= privateCount) {
|
if (plan.privateRepos >= privateCount) {
|
||||||
callback(plan);
|
callback(plan);
|
||||||
return;
|
return;
|
||||||
|
@ -453,6 +458,8 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
||||||
}
|
}
|
||||||
|
|
||||||
planService.getPlan(planId, function(plan) {
|
planService.getPlan(planId, function(plan) {
|
||||||
|
if (orgname && !planService.isOrgCompatible(plan)) { return; }
|
||||||
|
|
||||||
planService.getCardInfo(orgname, function(cardInfo) {
|
planService.getCardInfo(orgname, function(cardInfo) {
|
||||||
if (plan.price > 0 && !cardInfo.last4) {
|
if (plan.price > 0 && !cardInfo.last4) {
|
||||||
planService.showSubscribeDialog($scope, orgname, planId, callbacks);
|
planService.showSubscribeDialog($scope, orgname, planId, callbacks);
|
||||||
|
@ -1843,6 +1850,18 @@ quayApp.directive('planManager', function () {
|
||||||
controller: function($scope, $element, PlanService, Restangular) {
|
controller: function($scope, $element, PlanService, Restangular) {
|
||||||
var hasSubscription = false;
|
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() {
|
$scope.getActiveSubClass = function() {
|
||||||
return 'active';
|
return 'active';
|
||||||
};
|
};
|
||||||
|
@ -1865,17 +1884,17 @@ quayApp.directive('planManager', function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.cancelSubscription = function() {
|
$scope.cancelSubscription = function() {
|
||||||
$scope.changeSubscription(getFreePlan());
|
$scope.changeSubscription(PlanService.getFreePlan());
|
||||||
};
|
};
|
||||||
|
|
||||||
var subscribedToPlan = function(sub) {
|
var subscribedToPlan = function(sub) {
|
||||||
$scope.subscription = sub;
|
$scope.subscription = sub;
|
||||||
|
|
||||||
if (sub.plan != getFreePlan()) {
|
if (sub.plan != PlanService.getFreePlan()) {
|
||||||
hasSubscription = true;
|
hasSubscription = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlanService.getPlan(sub.plan, function(subscribedPlan) {
|
PlanService.getPlanIncludingDeprecated(sub.plan, function(subscribedPlan) {
|
||||||
$scope.subscribedPlan = subscribedPlan;
|
$scope.subscribedPlan = subscribedPlan;
|
||||||
$scope.planUsagePercent = sub.usedPrivateRepos * 100 / $scope.subscribedPlan.privateRepos;
|
$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() {
|
var update = function() {
|
||||||
$scope.planLoading = true;
|
$scope.planLoading = true;
|
||||||
if (!$scope.plans) { return; }
|
if (!$scope.plans) { return; }
|
||||||
|
|
||||||
PlanService.getSubscription($scope.organization, subscribedToPlan, function() {
|
PlanService.getSubscription($scope.organization, subscribedToPlan, function() {
|
||||||
// User/Organization has no subscription.
|
// 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; }
|
if (!$scope.user && !$scope.organization) { return; }
|
||||||
|
|
||||||
$scope.loadingPlans = true;
|
$scope.loadingPlans = true;
|
||||||
PlanService.getPlans(function(plans) {
|
PlanService.verifyLoaded(function(plans) {
|
||||||
$scope.plans = plans[$scope.organization ? 'business' : 'user'];
|
$scope.plans = plans;
|
||||||
update();
|
update();
|
||||||
|
|
||||||
if ($scope.readyForPlan) {
|
if ($scope.readyForPlan) {
|
||||||
var planRequested = $scope.readyForPlan();
|
var planRequested = $scope.readyForPlan();
|
||||||
if (planRequested && planRequested != getFreePlan()) {
|
if (planRequested && planRequested != PlanService.getFreePlan()) {
|
||||||
$scope.changeSubscription(planRequested);
|
$scope.changeSubscription(planRequested);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ function PlansCtrl($scope, $location, UserService, PlanService) {
|
||||||
// Load the list of plans.
|
// Load the list of plans.
|
||||||
PlanService.getPlans(function(plans) {
|
PlanService.getPlans(function(plans) {
|
||||||
$scope.plans = plans;
|
$scope.plans = plans;
|
||||||
});
|
}, /* include the personal plan */ true);
|
||||||
|
|
||||||
// Monitor any user changes and place the current user into the scope.
|
// Monitor any user changes and place the current user into the scope.
|
||||||
UserService.updateUserIn($scope);
|
UserService.updateUserIn($scope);
|
||||||
|
@ -621,7 +621,7 @@ function UserAdminCtrl($scope, $timeout, $location, Restangular, PlanService, Us
|
||||||
});
|
});
|
||||||
|
|
||||||
PlanService.getPlans(function(plans) {
|
PlanService.getPlans(function(plans) {
|
||||||
$scope.orgPlans = plans.business;
|
$scope.orgPlans = plans;
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.convertStep = 1;
|
$scope.convertStep = 1;
|
||||||
|
@ -1074,17 +1074,12 @@ function OrgAdminCtrl($rootScope, $scope, Restangular, $routeParams, UserService
|
||||||
|
|
||||||
// Load the list of plans.
|
// Load the list of plans.
|
||||||
PlanService.getPlans(function(plans) {
|
PlanService.getPlans(function(plans) {
|
||||||
$scope.plans = plans.business;
|
$scope.plans = plans;
|
||||||
$scope.plan_map = {};
|
$scope.plan_map = {};
|
||||||
|
|
||||||
var addPlans = function(plans) {
|
for (var i = 0; i < plans.length; ++i) {
|
||||||
for (var i = 0; i < plans.length; ++i) {
|
$scope.plan_map[plans[i].stripeId] = plans[i];
|
||||||
$scope.plan_map[plans[i].stripeId] = plans[i];
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
addPlans(plans.user);
|
|
||||||
addPlans(plans.business);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.orgname = orgname;
|
$scope.orgname = orgname;
|
||||||
|
@ -1230,7 +1225,7 @@ function NewOrgCtrl($scope, $routeParams, $timeout, $location, UserService, Plan
|
||||||
|
|
||||||
// Load the list of plans.
|
// Load the list of plans.
|
||||||
PlanService.getPlans(function(plans) {
|
PlanService.getPlans(function(plans) {
|
||||||
$scope.plans = plans.business;
|
$scope.plans = plans;
|
||||||
$scope.currentPlan = null;
|
$scope.currentPlan = null;
|
||||||
if (requested) {
|
if (requested) {
|
||||||
PlanService.getPlan(requested, function(plan) {
|
PlanService.getPlan(requested, function(plan) {
|
||||||
|
|
Reference in a new issue