From 1ee21318d4bcbb1296156bca45eef5d76e8b1d66 Mon Sep 17 00:00:00 2001
From: Joseph Schorr <jschorr@gmail.com>
Date: Mon, 28 Oct 2013 17:08:26 -0400
Subject: [PATCH] Have the private option in the new repo form alert the user
 about needing to purchase a plan and let them do so

---
 static/css/quay.css           | 10 +++++
 static/js/app.js              | 49 +++++++++++++++++++--
 static/js/controllers.js      | 80 +++++++++++++++++++++--------------
 static/partials/new-repo.html | 30 ++++++++++++-
 4 files changed, 133 insertions(+), 36 deletions(-)

diff --git a/static/css/quay.css b/static/css/quay.css
index ed0c3b390..47791564c 100644
--- a/static/css/quay.css
+++ b/static/css/quay.css
@@ -130,6 +130,16 @@
   text-decoration: none !important;
 }
 
+.new-repo .required-plan {
+  margin: 10px;
+  margin-top: 20px;
+  margin-left: 50px;
+}
+
+.new-repo .required-plan .alert {
+  color: #444 !important;
+}
+
 .new-repo .new-header {
   font-size: 22px;
 }
diff --git a/static/js/app.js b/static/js/app.js
index 69b3399aa..9d3e615be 100644
--- a/static/js/app.js
+++ b/static/js/app.js
@@ -54,7 +54,7 @@ quayApp = angular.module('quay', ['restangular', 'angularMoment', 'angulartics',
       return keyService;
     }]);
 
-    $provide.factory('PlanService', [function() {
+    $provide.factory('PlanService', ['Restangular', 'KeyService', function(Restangular, KeyService) {
       var plans = [
         {
           title: 'Open Source',
@@ -96,11 +96,54 @@ quayApp = angular.module('quay', ['restangular', 'angularMoment', 'angulartics',
 
       planService.planList = function() {
         return plans;
-      }
+      };
 
       planService.getPlan = function(planId) {
         return planDict[planId];
-      }
+      };
+
+      planService.getMinimumPlan = function(privateCount) {
+        for (var i = 0; i < plans.length; i++) {
+          var plan = plans[i];
+          if (plan.privateRepos >= privateCount) {
+            return plan;
+          }
+        }
+
+        return null;
+      };
+
+      planService.showSubscribeDialog = function($scope, planId, started, success, failed) {
+        var submitToken = function(token) {
+          $scope.$apply(function() {
+            started();
+          });
+
+          mixpanel.track('plan_subscribe');
+
+          var subscriptionDetails = {
+            token: token.id,
+            plan: planId,
+          };
+
+          var createSubscriptionRequest = Restangular.one('user/plan');
+          $scope.$apply(function() {
+            createSubscriptionRequest.customPUT(subscriptionDetails).then(success, failed);
+          });
+        };
+
+        var planDetails = planService.getPlan(planId)
+        StripeCheckout.open({
+          key:         KeyService.stripePublishableKey,
+          address:     false, // TODO change to true
+          amount:      planDetails.price,
+          currency:    'usd',
+          name:        'Quay ' + planDetails.title + ' Subscription',
+          description: 'Up to ' + planDetails.privateRepos + ' private repositories',
+          panelLabel:  'Subscribe',
+          token:       submitToken
+        });
+      };
 
       return planService;
     }]);
diff --git a/static/js/controllers.js b/static/js/controllers.js
index 334311918..df1ea6e22 100644
--- a/static/js/controllers.js
+++ b/static/js/controllers.js
@@ -701,6 +701,8 @@ function UserAdminCtrl($scope, $timeout, Restangular, PlanService, UserService,
 
     if (sub.usedPrivateRepos > $scope.subscribedPlan.privateRepos) {
       $scope.errorMessage = 'You are using more private repositories than your plan allows, please upgrate your subscription to avoid disruptions in your service.';
+    } else {
+      $scope.errorMessage = null;
     }
 
     $scope.planLoading = false;
@@ -709,7 +711,7 @@ function UserAdminCtrl($scope, $timeout, Restangular, PlanService, UserService,
     mixpanel.people.set({
       'plan': sub.plan
     });
-  }
+  };
 
   $scope.planLoading = true;
   var getSubscription = Restangular.one('user/plan');
@@ -720,36 +722,16 @@ function UserAdminCtrl($scope, $timeout, Restangular, PlanService, UserService,
 
   $scope.planChanging = false;
   $scope.subscribe = function(planId) {
-    var submitToken = function(token) {
-      $scope.$apply(function() {
-        mixpanel.track('plan_subscribe');
-
-        $scope.planChanging = true;
-        $scope.errorMessage = undefined;
-
-        var subscriptionDetails = {
-          token: token.id,
-          plan: planId,
-        };
-
-        var createSubscriptionRequest = Restangular.one('user/plan');
-        createSubscriptionRequest.customPUT(subscriptionDetails).then(subscribedToPlan, function() {
-          // Failure
-          $scope.errorMessage = 'Unable to subscribe.';
-        });
-      });
-    };
-
-    var planDetails = PlanService.getPlan(planId)
-    StripeCheckout.open({
-      key:         KeyService.stripePublishableKey,
-      address:     false, // TODO change to true
-      amount:      planDetails.price,
-      currency:    'usd',
-      name:        'Quay ' + planDetails.title + ' Subscription',
-      description: 'Up to ' + planDetails.privateRepos + ' private repositories',
-      panelLabel:  'Subscribe',
-      token:       submitToken
+    PlanService.showSubscribeDialog($scope, planId, function() {
+      // Subscribing.
+      $scope.planChanging = true;
+    }, function(plan) {
+      // Subscribed.
+      subscribedToPlan(plan);
+    }, function() {
+      // Failure.
+      $scope.errorMessage = 'Unable to subscribe.';
+      $scope.planChanging = false;
     });
   };
 
@@ -920,7 +902,7 @@ function V1Ctrl($scope, $location, UserService) {
   };
 }
 
-function NewRepoCtrl($scope, $location, $http, UserService, Restangular) {
+function NewRepoCtrl($scope, $location, $http, UserService, Restangular, PlanService) {
   $scope.repo = {
     'is_public': 1,
     'description': '',
@@ -999,6 +981,16 @@ function NewRepoCtrl($scope, $location, $http, UserService, Restangular) {
     });
   };
 
+  var subscribedToPlan = function(sub) {
+    $scope.planChanging = false;
+    $scope.subscription = sub;
+    $scope.subscribedPlan = PlanService.getPlan(sub.plan);
+    $scope.planRequired = null;
+    if ($scope.subscription.usedPrivateRepos >= $scope.subscribedPlan.privateRepos) {
+      $scope.planRequired = PlanService.getMinimumPlan($scope.subscription.usedPrivateRepos);
+    }
+  };
+
   $scope.$watch( function () { return UserService.currentUser(); }, function (currentUser) {
     $scope.user = currentUser;
 
@@ -1061,4 +1053,28 @@ function NewRepoCtrl($scope, $location, $http, UserService, Restangular) {
       $scope.creating = false;
     });
   };
+
+  $scope.upgradePlan = function() {
+    PlanService.showSubscribeDialog($scope, $scope.planRequired.stripeId, function() {
+      // Subscribing.
+      $scope.planChanging = true;
+    }, function(plan) {
+      // Subscribed.
+      subscribedToPlan(plan);
+    }, function() {
+      // Failure.
+      $('#couldnotsubscribeModal').modal();
+      $scope.planChanging = false;
+    });
+  };
+
+  $scope.plans = PlanService.planList();
+
+  // Load the user's subscription information in case they want to create a private
+  // repository.
+  var getSubscription = Restangular.one('user/plan');
+  getSubscription.get().then(subscribedToPlan, function() {
+    // User has no subscription
+    $scope.planRequired = PlanService.getMinimumPlan(1);
+  });
 }
\ No newline at end of file
diff --git a/static/partials/new-repo.html b/static/partials/new-repo.html
index cde232546..dd02d2faa 100644
--- a/static/partials/new-repo.html
+++ b/static/partials/new-repo.html
@@ -62,6 +62,15 @@
             <span class="description-text">You choose who can see, pull and push from/to this repository.</span>
           </div>
         </div>
+
+        <!-- Payment -->
+        <div class="required-plan" ng-show="repo.is_public == '0' && planRequired">
+          <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.
+          </div>
+          <a class="btn btn-primary" ng-click="upgradePlan()" ng-show="!planChanging">Upgrade now</a>
+          <i class="fa fa-spinner fa-spin fa-3x" ng-show="planChanging"></i>
+        </div>
       </div>
     </div>
   </div>
@@ -91,7 +100,7 @@
   <div class="row">
     <div class="col-md-1"></div>
     <div class="col-md-8">
-      <button class="btn btn-large btn-success" type="submit" ng-click="createNewRepo" ng-disabled="newRepoForm.$invalid">Create Repository</button>
+      <button class="btn btn-large btn-success" type="submit" ng-disabled="newRepoForm.$invalid || (repo.is_public == '0' && planRequired)">Create Repository</button>
     </div>
   </div>
 
@@ -179,3 +188,22 @@
     </div><!-- /.modal-content -->
   </div><!-- /.modal-dialog -->
 </div><!-- /.modal -->
+
+
+<!-- Modal message dialog -->
+<div class="modal fade" id="couldnotsubscribeModal">
+  <div class="modal-dialog">
+    <div class="modal-content">
+      <div class="modal-header">
+        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+        <h4 class="modal-title">Cannot upgrade plan</h4>
+      </div>
+      <div class="modal-body">
+        Your current plan could not be upgraded. Please try again.
+      </div>
+      <div class="modal-footer">
+        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+      </div>
+    </div><!-- /.modal-content -->
+  </div><!-- /.modal-dialog -->
+</div><!-- /.modal -->