Merge branch 'master' of ssh://bitbucket.org/yackob03/quay
This commit is contained in:
commit
4d88d9f9f7
6 changed files with 75 additions and 15 deletions
|
@ -118,6 +118,26 @@ def get_logged_in_user():
|
||||||
return jsonify(user_view(user))
|
return jsonify(user_view(user))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/user/private', methods=['GET'])
|
||||||
|
@api_login_required
|
||||||
|
def get_user_private_count():
|
||||||
|
user = current_user.db_user()
|
||||||
|
private_repos = model.get_private_repo_count(user.username)
|
||||||
|
repos_allowed = 0
|
||||||
|
|
||||||
|
if user.stripe_id:
|
||||||
|
cus = stripe.Customer.retrieve(user.stripe_id)
|
||||||
|
if cus.subscription:
|
||||||
|
plan = get_plan(cus.subscription.plan.id)
|
||||||
|
if plan:
|
||||||
|
repos_allowed = plan['privateRepos']
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
'privateCount': private_repos,
|
||||||
|
'reposAllowed': repos_allowed
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/user/convert', methods=['POST'])
|
@app.route('/api/user/convert', methods=['POST'])
|
||||||
@api_login_required
|
@api_login_required
|
||||||
def convert_user_to_organization():
|
def convert_user_to_organization():
|
||||||
|
@ -485,7 +505,11 @@ def get_organization_private_allowed(orgname):
|
||||||
if organization.stripe_id:
|
if organization.stripe_id:
|
||||||
cus = stripe.Customer.retrieve(organization.stripe_id)
|
cus = stripe.Customer.retrieve(organization.stripe_id)
|
||||||
if cus.subscription:
|
if cus.subscription:
|
||||||
repos_allowed = get_plan(cus.subscription.plan.id)
|
repos_allowed = 0
|
||||||
|
plan = get_plan(cus.subscription.plan.id)
|
||||||
|
if plan:
|
||||||
|
repos_allowed = plan['privateRepos']
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'privateAllowed': (private_repos < repos_allowed)
|
'privateAllowed': (private_repos < repos_allowed)
|
||||||
})
|
})
|
||||||
|
|
|
@ -38,14 +38,18 @@
|
||||||
<a href="javascript:void(0)" class="dropdown-toggle user-dropdown" data-toggle="dropdown">
|
<a href="javascript:void(0)" class="dropdown-toggle user-dropdown" data-toggle="dropdown">
|
||||||
<img src="//www.gravatar.com/avatar/{{ user.gravatar }}?s=32&d=identicon" />
|
<img src="//www.gravatar.com/avatar/{{ user.gravatar }}?s=32&d=identicon" />
|
||||||
{{ user.username }}
|
{{ user.username }}
|
||||||
<span class="badge user-notification notification-animated" ng-show="user.askForPassword">1</span>
|
<span class="badge user-notification notification-animated" ng-show="user.askForPassword || overPlan">
|
||||||
|
{{ (user.askForPassword ? 1 : 0) + (overPlan ? 1 : 0) }}
|
||||||
|
</span>
|
||||||
<b class="caret"></b>
|
<b class="caret"></b>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li>
|
<li>
|
||||||
<a href="/user/" target="{{ appLinkTarget() }}">
|
<a href="/user/" target="{{ appLinkTarget() }}">
|
||||||
Account Settings
|
Account Settings
|
||||||
<span class="badge user-notification" ng-show="user.askForPassword">1</span>
|
<span class="badge user-notification" ng-show="user.askForPassword || overPlan">
|
||||||
|
{{ (user.askForPassword ? 1 : 0) + (overPlan ? 1 : 0) }}
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li><a ng-href="/organizations/" target="{{ appLinkTarget() }}">Organizations</a></li>
|
<li><a ng-href="/organizations/" target="{{ appLinkTarget() }}">Organizations</a></li>
|
||||||
|
|
|
@ -1493,10 +1493,26 @@ quayApp.directive('headerBar', function () {
|
||||||
restrict: 'C',
|
restrict: 'C',
|
||||||
scope: {
|
scope: {
|
||||||
},
|
},
|
||||||
controller: function($scope, $element, $location, UserService, Restangular) {
|
controller: function($scope, $element, $location, UserService, PlanService, Restangular) {
|
||||||
$scope.$watch( function () { return UserService.currentUser(); }, function (currentUser) {
|
$scope.overPlan = false;
|
||||||
$scope.user = currentUser;
|
|
||||||
}, true);
|
var checkOverPlan = function() {
|
||||||
|
if ($scope.user.anonymous) {
|
||||||
|
$scope.overPlan = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var checkPrivate = Restangular.one('user/private');
|
||||||
|
checkPrivate.customGET().then(function(resp) {
|
||||||
|
$scope.overPlan = resp.privateCount >= resp.reposAllowed;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Monitor any user changes and place the current user into the scope.
|
||||||
|
UserService.updateUserIn($scope, checkOverPlan);
|
||||||
|
|
||||||
|
// Monitor any plan changes.
|
||||||
|
PlanService.registerListener(this, checkOverPlan);
|
||||||
|
|
||||||
$scope.signout = function() {
|
$scope.signout = function() {
|
||||||
var signoutPost = Restangular.one('signout');
|
var signoutPost = Restangular.one('signout');
|
||||||
|
@ -1511,7 +1527,7 @@ quayApp.directive('headerBar', function () {
|
||||||
return "_self";
|
return "_self";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return directiveDefinitionObject;
|
return directiveDefinitionObject;
|
||||||
|
|
|
@ -810,23 +810,34 @@ function NewRepoCtrl($scope, $location, $http, $timeout, UserService, Restangula
|
||||||
|
|
||||||
var isUserNamespace = (namespace == $scope.user.username);
|
var isUserNamespace = (namespace == $scope.user.username);
|
||||||
|
|
||||||
|
$scope.checkingPlan = true;
|
||||||
$scope.planRequired = null;
|
$scope.planRequired = null;
|
||||||
$scope.isUserNamespace = isUserNamespace;
|
$scope.isUserNamespace = isUserNamespace;
|
||||||
|
|
||||||
if (isUserNamespace) {
|
if (isUserNamespace) {
|
||||||
// Load the user's subscription information in case they want to create a private
|
// Load the user's subscription information in case they want to create a private
|
||||||
// repository.
|
// repository.
|
||||||
PlanService.getSubscription(null, subscribedToPlan, function() {
|
var checkPrivateAllowed = Restangular.one('user/private');
|
||||||
PlanService.getMinimumPlan(1, false, function(minimum) { $scope.planRequired = minimum; });
|
checkPrivateAllowed.get().then(function(resp) {
|
||||||
|
if (resp.privateCount + 1 > resp.reposAllowed) {
|
||||||
|
PlanService.getMinimumPlan(resp.privateCount + 1, false, function(minimum) {
|
||||||
|
$scope.planRequired = minimum;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.checkingPlan = false;
|
||||||
|
}, function() {
|
||||||
|
$scope.planRequired = {};
|
||||||
|
$scope.checkingPlan = false;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$scope.planRequired = null;
|
|
||||||
|
|
||||||
var checkPrivateAllowed = Restangular.one('organization/' + namespace + '/private');
|
var checkPrivateAllowed = Restangular.one('organization/' + namespace + '/private');
|
||||||
checkPrivateAllowed.get().then(function(resp) {
|
checkPrivateAllowed.get().then(function(resp) {
|
||||||
$scope.planRequired = resp.privateAllowed ? null : {};
|
$scope.planRequired = resp.privateAllowed ? null : {};
|
||||||
|
$scope.checkingPlan = false;
|
||||||
}, function() {
|
}, function() {
|
||||||
$scope.planRequired = {};
|
$scope.planRequired = {};
|
||||||
|
$scope.checkingPlan = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Auto-set to private repo.
|
// Auto-set to private repo.
|
||||||
|
|
|
@ -74,12 +74,14 @@
|
||||||
<!-- Payment -->
|
<!-- Payment -->
|
||||||
<div class="required-plan" ng-show="repo.is_public == '0' && planRequired && isUserNamespace">
|
<div class="required-plan" ng-show="repo.is_public == '0' && planRequired && isUserNamespace">
|
||||||
<div class="alert alert-warning">
|
<div class="alert alert-warning">
|
||||||
In order to make this repository private, you’ll need to upgrade your plan from <b>{{ subscribedPlan.title }}</b> to <b>{{ planRequired.title }}</b>. This will cost $<span>{{ planRequired.price / 100 }}</span>/month.
|
In order to make this repository private, you’ll need to upgrade your plan to <b>{{ planRequired.title }}</b>. This will cost $<span>{{ planRequired.price / 100 }}</span>/month.
|
||||||
</div>
|
</div>
|
||||||
<a class="btn btn-primary" ng-click="upgradePlan()" ng-show="!planChanging">Upgrade now</a>
|
<a class="btn btn-primary" ng-click="upgradePlan()" ng-show="!planChanging">Upgrade now</a>
|
||||||
<div class="quay-spinner" ng-show="planChanging"></div>
|
<div class="quay-spinner" ng-show="planChanging"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="quay-spinner" ng-show="repo.is_public == '0' && checkingPlan"></div>
|
||||||
|
|
||||||
<div class="required-plan" ng-show="repo.is_public == '0' && planRequired && !isUserNamespace">
|
<div class="required-plan" ng-show="repo.is_public == '0' && planRequired && !isUserNamespace">
|
||||||
<div class="alert alert-warning">
|
<div class="alert alert-warning">
|
||||||
This organization has reached its private repository limit. Please contact your administrator.
|
This organization has reached its private repository limit. Please contact your administrator.
|
||||||
|
@ -114,7 +116,10 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<button class="btn btn-large btn-success" type="submit" ng-disabled="newRepoForm.$invalid || (repo.is_public == '0' && planRequired)">Create Repository</button>
|
<button class="btn btn-large btn-success" type="submit"
|
||||||
|
ng-disabled="newRepoForm.$invalid || (repo.is_public == '0' && (planRequired || checkingPlan))">
|
||||||
|
Create Repository
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
<input type="password" class="form-control" placeholder="Verify your new password" ng-model="user.repeatPassword"
|
<input type="password" class="form-control" placeholder="Verify your new password" ng-model="user.repeatPassword"
|
||||||
match="user.password" required>
|
match="user.password" required>
|
||||||
<button class="btn btn-danger" ng-disabled="changePasswordForm.$invalid" type="submit"
|
<button class="btn btn-danger" ng-disabled="changePasswordForm.$invalid" type="submit"
|
||||||
analytics-on analytics-event="change-pass">Change Password</button>
|
analytics-on analytics-event="change_pass">Change Password</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Reference in a new issue