From 35c1e6e53bb19f06dffa376409e5a23a819ba1a3 Mon Sep 17 00:00:00 2001
From: yackob03 <jacob.moshenko@gmail.com>
Date: Wed, 2 Oct 2013 02:05:53 -0400
Subject: [PATCH] Allow user to unsubscribe and change their plan.

---
 endpoints/api.py                | 22 ++++++++++++++++++-
 static/js/controllers.js        | 39 ++++++++++++++++++++++++++++++++-
 static/partials/user-admin.html | 12 +++++-----
 3 files changed, 65 insertions(+), 8 deletions(-)

diff --git a/endpoints/api.py b/endpoints/api.py
index 96e0ca01d..a550a58cf 100644
--- a/endpoints/api.py
+++ b/endpoints/api.py
@@ -365,13 +365,13 @@ def subscribe():
 
   request_data = request.get_json()
   plan = request_data['plan']
-  card = request_data['token']
 
   user = current_user.db_user
   private_repos = model.get_private_repo_count(user.username)
 
   if not user.stripe_id:
     # Create the customer and plan simultaneously
+    card = request_data['token']
     cus = stripe.Customer.create(email=user.email, plan=plan, card=card)
     user.stripe_id = cus.id
     user.save()
@@ -384,6 +384,11 @@ def subscribe():
     # Change the plan
     cus = stripe.Customer.retrieve(user.stripe_id)
     cus.plan = plan
+
+    # User may have been a previous customer who is resubscribing
+    if 'token' in request_data:
+      cus.card = request_data['token']
+
     cus.save()
     return jsonify(subscription_view(cus.subscription, private_repos))
 
@@ -399,3 +404,18 @@ def get_subscription():
     return jsonify(subscription_view(cus.subscription, private_repos))
 
   abort(404)
+
+
+
+@app.route('/api/user/plan', methods=['DELETE'])
+@api_login_required
+def cancel_subscription():
+  user = current_user.db_user
+
+  if user.stripe_id:
+    private_repos = model.get_private_repo_count(user.username)
+    cus = stripe.Customer.retrieve(user.stripe_id)
+    cus.cancel_subscription()
+    return make_response('Deleted', 204)
+
+  abort(404)
\ No newline at end of file
diff --git a/static/js/controllers.js b/static/js/controllers.js
index d397ba0ba..988fe4a31 100644
--- a/static/js/controllers.js
+++ b/static/js/controllers.js
@@ -461,6 +461,7 @@ function UserAdminCtrl($scope, Restangular) {
     $scope.subscribedPlan = planDict[sub.plan];
     $scope.planUsagePercent = sub.usedPrivateRepos * 100 / $scope.subscribedPlan.privateRepos;
     $scope.planLoading = false;
+    $scope.planChanging = false;
   }
 
   $scope.planLoading = true;
@@ -470,9 +471,13 @@ function UserAdminCtrl($scope, Restangular) {
     $scope.planLoading = false;
   });
 
+  $scope.planChanging = false;
   $scope.subscribe = function(planId) {
     var submitToken = function(token) {
       $scope.$apply(function() {
+        $scope.planChanging = true;
+        $scope.errorMessage = undefined;
+
         var subscriptionDetails = {
           token: token.id,
           plan: planId,
@@ -483,7 +488,7 @@ function UserAdminCtrl($scope, Restangular) {
         var createSubscriptionRequest = Restangular.one('user/plan');
         createSubscriptionRequest.customPUT(subscriptionDetails).then(subscribedToPlan, function() {
           // Failure
-          $scope.errorMessage = 'Unable to process subscription change.';
+          $scope.errorMessage = 'Unable to subscribe.';
         });
       });
     };
@@ -501,4 +506,36 @@ function UserAdminCtrl($scope, Restangular) {
       token:       submitToken
     });
   };
+
+  $scope.changeSubscription = function(planId) {
+    $scope.planChanging = true;
+    $scope.errorMessage = undefined;
+
+    var subscriptionDetails = {
+      plan: planId,
+    };
+
+    var changeSubscriptionRequest = Restangular.one('user/plan');
+    changeSubscriptionRequest.customPUT(subscriptionDetails).then(subscribedToPlan, function() {
+      // Failure
+      $scope.errorMessage = 'Unable to change subscription.';
+      $scope.planChanging = false;
+    });
+  };
+
+  $scope.cancelSubscription = function() {
+    $scope.planChanging = true;
+    $scope.errorMessage = undefined;
+    var unsubscribeRequest = Restangular.one('user/plan');
+    unsubscribeRequest.customDELETE().then(function() {
+      $scope.subscription = undefined;
+      $scope.subscribedPlan = undefined;
+      $scope.planUsagePercent = 0;
+      $scope.planChanging = false;
+    }, function() {
+      // Failure
+      $scope.errorMessage = 'Unable to unsubscribe.';
+      $scope.planChanging = false;
+    });
+  };
 }
\ No newline at end of file
diff --git a/static/partials/user-admin.html b/static/partials/user-admin.html
index fb70a249e..2173898e1 100644
--- a/static/partials/user-admin.html
+++ b/static/partials/user-admin.html
@@ -1,4 +1,7 @@
 <div class="container">
+  <div class="loading" ng-show="planLoading || planChanging">
+    <div class="spin"></div>
+  </div>
   <div class="row" ng-show="errorMessage">
     <div class="col-md-12">
       <div class="alert alert-danger">{{ errorMessage }}</div>
@@ -17,13 +20,13 @@
         <div class="panel-body">
           {{ plan.privateRepos }} Private Repositories<br>
           <button class="btn btn-primary" ng-hide="subscription" ng-click="subscribe(plan.stripeId)">Subscribe</button>
-          <button class="btn" ng-show="subscription && (subscription.plan != plan.stripeId)" ng-click="subscribe(plan.stripeId)">Change</button>
-          <button class="btn btn-danger" ng-show="subscription.plan == plan.stripeId" ng-click="cancel()">Cancel</button>      
+          <button class="btn" ng-show="subscription && (subscription.plan != plan.stripeId)" ng-click="changeSubscription(plan.stripeId)">Change</button>
+          <button class="btn btn-danger" ng-show="subscription.plan == plan.stripeId" ng-click="cancelSubscription()">Cancel</button>      
         </div>
       </div>
     </div>
   </div>
-  <div class="row" ng-hide="planLoading">
+  <div class="row" ng-show="subscription">
     <div class="col-md-6">
       <div class="panel panel-default">
         <div class="panel-heading">
@@ -39,7 +42,4 @@
       </div>
     </div>
   </div>
-  <div class="loading" ng-show="planLoading">
-    <div class="spin"></div>
-  </div>
 </div>
\ No newline at end of file