From afce400c65f362f7dd6307a5670dc3873d74ab79 Mon Sep 17 00:00:00 2001 From: Julie Lala Date: Sun, 11 Jan 2015 21:42:45 -0500 Subject: stub in subscriptions admin pages --- server/lib/views/staff.js | 34 +++++++++++++++++++++++++++++++++- views/staff/_nav.ejs | 1 + views/staff/subscriptions/index.ejs | 36 ++++++++++++++++++++++++++++++++++++ views/staff/subscriptions/show.ejs | 12 ++++++++++++ 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 views/staff/subscriptions/index.ejs create mode 100644 views/staff/subscriptions/show.ejs diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js index 97ecde6..4351ef0 100644 --- a/server/lib/views/staff.js +++ b/server/lib/views/staff.js @@ -500,6 +500,27 @@ var staff = module.exports = { staff.plans.update ); + + // + // subscriptions + app.get('/staff/subscriptions', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + staff.middleware.ensureSubscriptions, + staff.middleware.ensureSubscriptionsUsers, + + staff.subscriptions.index + ); + app.get('/staff/subscriptions/:id', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + staff.middleware.ensureSubscription, + staff.middleware.ensureSubscriptionUser, + + staff.subscriptions.edit + ); }, paginate: function(req, res){ @@ -669,6 +690,17 @@ var staff = module.exports = { res.redirect("/staff/plans/") }) }, - } + }, + + subscriptions: { + index: function(req, res){ + res.locals.subscriptions = req.subscriptions + res.render('staff/plans/index') + }, + show: function(req, res){ + res.locals.subscription = req.subscription + res.render('staff/plans/show') + }, + }, } diff --git a/views/staff/_nav.ejs b/views/staff/_nav.ejs index db7bedb..e79ff69 100644 --- a/views/staff/_nav.ejs +++ b/views/staff/_nav.ejs @@ -4,4 +4,5 @@ projects media plans + subscriptions \ No newline at end of file diff --git a/views/staff/subscriptions/index.ejs b/views/staff/subscriptions/index.ejs new file mode 100644 index 0000000..d1c0588 --- /dev/null +++ b/views/staff/subscriptions/index.ejs @@ -0,0 +1,36 @@ +[[ include ../_header ]] + +

Users

+ +[[ include ../_nav ]] + +
+ +[[ include ../_pagination ]] + + +[[ subscriptions.forEach(function(subscription){ ]] + + + + + + + +[[ }) ]] +
+
+
+ [[- subscription.user.username ]] + + [[- subscription.user.displayName ]] + + [[- subscription.user.last_seen ]] +
+ + +[[ include ../_pagination ]] + +[[ include ../_footer ]] diff --git a/views/staff/subscriptions/show.ejs b/views/staff/subscriptions/show.ejs new file mode 100644 index 0000000..e2839a6 --- /dev/null +++ b/views/staff/subscriptions/show.ejs @@ -0,0 +1,12 @@ +[[ include ../_header ]] +

User: [[- subscription.user.username ]]

+ +[[ include ../_nav ]] + +
+ +
+info to show..
+- link to recurly profile
+- link to vvalls profile
+- subscription tier + add-ons
-- 
cgit v1.2.3-70-g09d2


From a1c9bdecff30d72eeaef54c66c7211966a97d4e4 Mon Sep 17 00:00:00 2001
From: Julie Lala 
Date: Sun, 11 Jan 2015 21:57:17 -0500
Subject: crud

---
 server/lib/views/staff.js | 69 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 66 insertions(+), 3 deletions(-)

diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js
index 4351ef0..39a8dca 100644
--- a/server/lib/views/staff.js
+++ b/server/lib/views/staff.js
@@ -124,7 +124,35 @@ var staff = module.exports = {
         next()
       })
     },
-    
+
+    ensureSubscriptions: function(req, res, next){
+      var paginationInfo = res.locals.pagination = {}
+      var criteria = req.criteria || {}
+      var limit = paginationInfo.limit = Math.min( Number(req.query.limit) || 50, 200 )
+      var offset = paginationInfo.offset = Number(req.query.offset) || 0
+      var sort
+      paginationInfo.sort = req.query.sort
+      paginationInfo.sortOptions = ["date", "name"]
+      switch (req.query.sort) {
+        case 'created':
+          sort = {'created_at': -1}
+          break
+        default:
+        case 'date':
+          sort = {'updated_at': -1}
+          break
+      }
+      Subscription.find(criteria)
+          .select(staff.fields.project)
+          .sort(sort)
+          .skip(offset)
+          .limit(limit)
+          .exec(function (err, subscriptions) {
+        res.locals.subscriptions = subscriptions.map(staff.helpers.subscription)
+        next()
+      })
+    },
+
     ensurePlans: function(req, res, next){
       Plan.find(function (err, plans) {
         res.locals.plans = (plans || []).map(staff.helpers.plan)
@@ -150,6 +178,24 @@ var staff = module.exports = {
       }
     },
 
+    ensureSubscription: function (req, res, next) {
+      if (req.params.id) {
+        Subscription.findOne({ _id: req.params.id }, function(err, subscription){
+          if (err || ! subscription) {
+            console.error(err)
+            res.redirect("/staff/subscriptions/")
+          }
+          else {
+            req.subscription = subscription
+            next()
+          }
+        })
+      }
+      else {
+        res.redirect("/staff/subscriptions/")
+      }
+    },
+
     ensureRecentProjects: function(req, res, next){
       var dreq = { params: { sort: 'created_at', limit: 20, offset: 0 } }
       staff.middleware.ensureProjects(dreq, res, next)
@@ -160,11 +206,23 @@ var staff = module.exports = {
       staff.middleware.ensureObjectsUsers(res.locals.projects, next)
     },
 
+    ensureSubscriptionsUsers: function(req, res, next){
+      if (! res.locals.subscriptions || ! res.locals.subscriptions.length) { return next() }
+      staff.middleware.ensureObjectsUsers(res.locals.subscriptions, next)
+    },
+
     ensureMediaUsers: function(req, res, next){
       if (! res.locals.media || ! res.locals.media.length) { return next() }
       staff.middleware.ensureObjectsUsers(res.locals.media, next)
     },
 
+    ensureSubscriptionUser: function(req, res, next){
+      if (! res.locals.subscription) { return next() }
+      staff.middleware.ensureObjectsUsers([ res.locals.subscription ], function(){
+        next()
+      })
+    },
+
     ensureMediaUser: function(req, res, next){
       if (! res.locals.media) { return next() }
       staff.middleware.ensureObjectsUsers([ res.locals.media ], function(){
@@ -338,6 +396,13 @@ var staff = module.exports = {
       plan.user = {}
       return plan
 	  },
+
+	  subscription: function(subscription){
+      subscription = subscription.toObject()
+      subscription.date = moment( subscription.updated_at || subscription.created_at ).format("M/DD/YYYY hh:mm a")
+      subscription.user = {}
+      return subscription
+	  },
 	},
 
 	route: function(app){
@@ -694,11 +759,9 @@ var staff = module.exports = {
   
   subscriptions: {
     index: function(req, res){
-      res.locals.subscriptions = req.subscriptions
       res.render('staff/plans/index')
     },
     show: function(req, res){
-      res.locals.subscription = req.subscription
       res.render('staff/plans/show')
     },
   },
-- 
cgit v1.2.3-70-g09d2


From ffdee0615c775466053daff3ce4afd1d11c83e33 Mon Sep 17 00:00:00 2001
From: Julie Lala 
Date: Sun, 11 Jan 2015 22:37:07 -0500
Subject: pagination

---
 server/lib/views/staff.js | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js
index 39a8dca..64cfe77 100644
--- a/server/lib/views/staff.js
+++ b/server/lib/views/staff.js
@@ -759,10 +759,13 @@ var staff = module.exports = {
   
   subscriptions: {
     index: function(req, res){
-      res.render('staff/plans/index')
+      res.locals.pagination.count = res.locals.subscriptions.length
+      res.locals.pagination.max = res.locals.subscriptionCount
+      staff.paginate(req, res)
+      res.render('staff/subscriptions/index')
     },
     show: function(req, res){
-      res.render('staff/plans/show')
+      res.render('staff/subscriptions/show')
     },
   },
 
-- 
cgit v1.2.3-70-g09d2


From 77c4c8d066611ad651af8df7290fb3e54d074081 Mon Sep 17 00:00:00 2001
From: Julie Lala 
Date: Sun, 11 Jan 2015 23:37:49 -0500
Subject: fix

---
 server/lib/views/staff.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js
index 64cfe77..d4abf1f 100644
--- a/server/lib/views/staff.js
+++ b/server/lib/views/staff.js
@@ -584,7 +584,7 @@ var staff = module.exports = {
       staff.middleware.ensureSubscription,
       staff.middleware.ensureSubscriptionUser,
 
-      staff.subscriptions.edit
+      staff.subscriptions.show
     );
   },
   
@@ -765,7 +765,7 @@ var staff = module.exports = {
       res.render('staff/subscriptions/index')
     },
     show: function(req, res){
-      res.render('staff/subscriptions/show')
+      res.render('staff/subscriptions /show')
     },
   },
 
-- 
cgit v1.2.3-70-g09d2


From dcfbf734436fad76f5ca2e1cecadf4051118d56f Mon Sep 17 00:00:00 2001
From: Julie Lala 
Date: Mon, 12 Jan 2015 12:24:57 -0500
Subject: stubbing webhook

---
 server/index.js                  |  2 ++
 server/lib/views/staff.js        |  2 +-
 server/lib/views/subscription.js | 21 ++++++---------------
 3 files changed, 9 insertions(+), 16 deletions(-)

diff --git a/server/index.js b/server/index.js
index 9a9323c..a14eaab 100644
--- a/server/index.js
+++ b/server/index.js
@@ -70,6 +70,8 @@ site.setup = function(){
 	app.all('*', middleware.ensureLocals);
 	app.all('*', middleware.ensureIP);
 
+  app.get('/subscribe/webhook', views.subscription.webhook);
+
 	server = http.createServer(app)
 	server.listen(app.get('port'), function () {
 		console.log('Express server listening on port ' + app.get('port'));
diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js
index d4abf1f..74dd7cd 100644
--- a/server/lib/views/staff.js
+++ b/server/lib/views/staff.js
@@ -765,7 +765,7 @@ var staff = module.exports = {
       res.render('staff/subscriptions/index')
     },
     show: function(req, res){
-      res.render('staff/subscriptions /show')
+      res.render('staff/subscriptions/show')
     },
   },
 
diff --git a/server/lib/views/subscription.js b/server/lib/views/subscription.js
index ba54bb4..e29e40d 100644
--- a/server/lib/views/subscription.js
+++ b/server/lib/views/subscription.js
@@ -32,19 +32,10 @@ var subscription = module.exports = {
       return project
 	  },
 	},
-
-	route: function(app){
-    app.get('/staff',
-      middleware.ensureAuthenticated,
-      middleware.ensureIsStaff,
-      
-      staff.middleware.ensureRecentUsers,
-      staff.middleware.ensureUsersCount,
-      staff.middleware.ensureProjectsCount,
-      staff.middleware.ensureMediaCount,
-
-      staff.index
-    );
-  },
-
+	
+  // need a route for the webhook,
+  // then calls to get appropriate info from the recurly api
+	webhook: function(req, res){
+    res.status(200).end()
+	},
 }
-- 
cgit v1.2.3-70-g09d2


From 5229023137d5d929db5ef7dcc8fd27d59676a99f Mon Sep 17 00:00:00 2001
From: Jules Laplace 
Date: Mon, 12 Jan 2015 14:14:29 -0500
Subject: bump year

---
 Gruntfile.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Gruntfile.js b/Gruntfile.js
index 21bbfb0..f62cc82 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -140,7 +140,7 @@ module.exports = function(grunt) {
 		},
 		uglify: {
 			options: {
-				banner: '/* vvalls by okfocus 2014 */\n'
+				banner: '/* vvalls by okfocus 2015 */\n'
 			},
 			js: {
 				src: 'public/assets/javascripts/app.concat.js',
-- 
cgit v1.2.3-70-g09d2


From 034f8343f2d194c2b1e3dbb20cfb8658e2795ce0 Mon Sep 17 00:00:00 2001
From: Jules Laplace 
Date: Mon, 12 Jan 2015 18:38:42 -0500
Subject: parsing some xml for webhooks

---
 package.json                     | 37 +++++++++---------
 server/index.js                  |  1 +
 server/lib/views/subscription.js | 81 +++++++++++++++++++++++++++++++++++-----
 3 files changed, 92 insertions(+), 27 deletions(-)

diff --git a/package.json b/package.json
index adefb82..34e0c4c 100644
--- a/package.json
+++ b/package.json
@@ -6,32 +6,33 @@
     "url": "git://github.com/okfocus/vvalls.git"
   },
   "dependencies": {
-    "express": "~3.4.8",
-    "monk": "~0.7.1",
-    "socket.io": "~0.9.16",
+    "body-parser": "1.3.0",
     "connect-mongo": "~0.4.1",
-    "passport": "~0.2.0",
-    "passport-local": "~1.0.0",
-    "passport-twitter": "~1.0.2",
-    "passport-facebook": "~1.0.3",
-    "passport.socketio": "~3.0.1",
-    "node-restful": "~0.1.14",
     "ejs": "^0.8.8",
-    "useful-string": "0.0.1",
+    "emailjs": "~0.3.6",
+    "express": "~3.4.8",
     "express-subdomain-handler": "~0.1.0",
     "express-subdomains": "0.0.5",
+    "html-entities": "~1.0.10",
+    "intro.js": "^0.9.0",
+    "knox": "~0.8.10",
     "lodash": "~2.4.1",
+    "marked": "~0.3.2",
+    "moment": "~2.6.0",
     "mongoose": "~3.8.8",
-    "mongoose-unique-validator": "~0.3.0",
     "mongoose-lifecycle": "~1.0.0",
-    "knox": "~0.8.10",
-    "moment": "~2.6.0",
-    "html-entities": "~1.0.10",
+    "mongoose-unique-validator": "~0.3.0",
+    "monk": "~0.7.1",
     "multer": "~0.1.0",
-    "body-parser": "1.3.0",
-    "marked": "~0.3.2",
-    "emailjs": "~0.3.6",
-    "intro.js": "^0.9.0"
+    "node-restful": "~0.1.14",
+    "passport": "~0.2.0",
+    "passport-facebook": "~1.0.3",
+    "passport-local": "~1.0.0",
+    "passport-twitter": "~1.0.2",
+    "passport.socketio": "~3.0.1",
+    "socket.io": "~0.9.16",
+    "useful-string": "0.0.1",
+    "xml2js": "^0.4.4"
   },
   "devDependencies": {
     "grunt": "~0.4.1",
diff --git a/server/index.js b/server/index.js
index a14eaab..0f4941a 100644
--- a/server/index.js
+++ b/server/index.js
@@ -70,6 +70,7 @@ site.setup = function(){
 	app.all('*', middleware.ensureLocals);
 	app.all('*', middleware.ensureIP);
 
+	// where should this live?
   app.get('/subscribe/webhook', views.subscription.webhook);
 
 	server = http.createServer(app)
diff --git a/server/lib/views/subscription.js b/server/lib/views/subscription.js
index e29e40d..251e217 100644
--- a/server/lib/views/subscription.js
+++ b/server/lib/views/subscription.js
@@ -6,7 +6,15 @@ var User = require('../schemas/User'),
 	middleware = require('../middleware'),
 	util = require('../util'),
 	_ = require('lodash'),
-	moment = require('moment');
+	moment = require('moment'),
+	xml2js = require('xml2js');
+
+var parser = new xml2js.Parser();
+// fs.readFile('./foo.xml', function(err, data) {
+// 	parser.parseString(data, function (err, result) {
+// 		console.log(inspect(result, { colors: true, depth: Infinity }));
+// 	});
+// });
 
 var subscription = module.exports = {
 	
@@ -24,18 +32,73 @@ var subscription = module.exports = {
 	middleware: {
   },
 
-	helpers: {
-	  project: function(project){
-      project = project.toObject()
-      project.date = moment( project.updated_at || project.created_at ).format("M/DD/YYYY hh:mm a")
-      project.user = {}
-      return project
-	  },
-	},
+	fields: [
+		"new_account_notification",
+		"canceled_account_notification",
+		"billing_info_updated_notification",
+		"reactivated_account_notification",
+		"new_invoice_notification",
+		"closed_invoice_notification",
+		"past_due_invoice_notification",
+		"new_subscription_notification",
+		"updated_subscription_notification",
+		"canceled_subscription_notification",
+		"expired_subscription_notification",
+		"renewed_subscription_notification",
+		"successful_payment_notification",
+		"failed_payment_notification",
+		"successful_refund_notification",
+		"void_payment_notification",
+	],  
+
+  callbacks: {
+		// accounts
+		new_account_notification: function(data){
+		},
+		canceled_account_notification: function(data){
+		},
+		billing_info_updated_notification: function(data){
+		},
+		reactivated_account_notification: function(data){
+		},
+		
+		// invoices
+		new_invoice_notification: function(data){
+		},
+		closed_invoice_notification: function(data){
+		},
+		past_due_invoice_notification: function(data){
+		},
+		
+		// subscriptions
+		new_subscription_notification: function(data){
+		},
+		updated_subscription_notification: function(data){
+		},
+		canceled_subscription_notification: function(data){
+		},
+		expired_subscription_notification: function(data){
+		},
+		renewed_subscription_notification: function(data){
+		},
+		
+		// payments
+		successful_payment_notification: function(data){
+		},
+		failed_payment_notification: function(data){
+		},
+		successful_refund_notification: function(data){
+		},
+		void_payment_notification: function(data){
+		},
+  },
 	
   // need a route for the webhook,
   // then calls to get appropriate info from the recurly api
 	webhook: function(req, res){
     res.status(200).end()
+		parser.parseString(data, function (err, result) {
+			console.log(inspect(result, { colors: true, depth: Infinity }));
+		});
 	},
 }
-- 
cgit v1.2.3-70-g09d2


From ffa627b1032f9244df8c685c86fd24f3e7c2881a Mon Sep 17 00:00:00 2001
From: Julie Lala 
Date: Mon, 12 Jan 2015 23:35:57 -0500
Subject: etc

---
 server/lib/views/subscription.js | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/server/lib/views/subscription.js b/server/lib/views/subscription.js
index 251e217..b9c79cb 100644
--- a/server/lib/views/subscription.js
+++ b/server/lib/views/subscription.js
@@ -18,39 +18,35 @@ var parser = new xml2js.Parser();
 
 var subscription = module.exports = {
 	
-	fields: {
-	  user: "_id username displayName photo created_at updated_at last_seen created_ip last_ip",
-	},
-	
-	defaults: {
-	  user: {
-	    _id: "", username: "", displayName: "",
-      created_at: "", updated_at: "", created_ip: "", last_ip: "",
-	  },
-	},
-
-	middleware: {
-  },
-
 	fields: [
+	  // accounts
 		"new_account_notification",
 		"canceled_account_notification",
 		"billing_info_updated_notification",
 		"reactivated_account_notification",
+
+		// invoices
 		"new_invoice_notification",
 		"closed_invoice_notification",
 		"past_due_invoice_notification",
+		
+		// subscriptions
 		"new_subscription_notification",
 		"updated_subscription_notification",
 		"canceled_subscription_notification",
 		"expired_subscription_notification",
 		"renewed_subscription_notification",
+		
+		// payments
 		"successful_payment_notification",
 		"failed_payment_notification",
 		"successful_refund_notification",
 		"void_payment_notification",
 	],  
 
+	middleware: {
+  },
+
   callbacks: {
 		// accounts
 		new_account_notification: function(data){
@@ -99,6 +95,11 @@ var subscription = module.exports = {
     res.status(200).end()
 		parser.parseString(data, function (err, result) {
 			console.log(inspect(result, { colors: true, depth: Infinity }));
+			for (var i in data) {
+			  if (subscription.callbacks[i]) {
+			    subscription.callbacks[i](data)
+			  }
+			}
 		});
 	},
 }
-- 
cgit v1.2.3-70-g09d2


From 904a18b763889c9f85d874388fdff9daaefb89cd Mon Sep 17 00:00:00 2001
From: Jules Laplace 
Date: Wed, 14 Jan 2015 15:44:34 -0500
Subject: roll back devicePixelRatio fix on desktop

---
 public/assets/javascripts/app.js   |  4 +++-
 public/assets/javascripts/mx/mx.js | 14 +++++++-------
 public/assets/stylesheets/app.css  |  4 ++++
 3 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/public/assets/javascripts/app.js b/public/assets/javascripts/app.js
index 41edafe..a146325 100644
--- a/public/assets/javascripts/app.js
+++ b/public/assets/javascripts/app.js
@@ -3,7 +3,7 @@ if (is_mobile) {
 	$("html").addClass("mobile")
 }
 else {
- $("html").addClass("desktop")
+  $("html").addClass("desktop")
 }
 
 
@@ -23,6 +23,8 @@ app.launch = function () {
   
 	var movements
 
+	app.devicePixelRatio = is_mobile ? devicePixelRatio : 1
+
 	scene = new MX.Scene().addTo('#scene')
 	scene.width = window.innerWidth
 	scene.height = window.innerHeight
diff --git a/public/assets/javascripts/mx/mx.js b/public/assets/javascripts/mx/mx.js
index d59a551..ab9a9a0 100644
--- a/public/assets/javascripts/mx/mx.js
+++ b/public/assets/javascripts/mx/mx.js
@@ -162,24 +162,24 @@ var MX = MX || (function (undefined) {
         Object.defineProperty(this, 'width', {
             get: function () {
                 return width
-                    || parseInt(self.el.style.width*devicePixelRatio, 10)
+                    || parseInt(self.el.style.width, 10) * app.devicePixelRatio
                     || 0
             },
             set: function (val) {
                 width = val
-                this.el.style.width = (width/devicePixelRatio) + 'px'
+                this.el.style.width = (width/app.devicePixelRatio) + 'px'
             }
         })
 
         Object.defineProperty(this, 'height', {
             get: function () {
                 return height
-                    || parseInt(self.el.style.height*devicePixelRatio, 10)
+                    || parseInt(self.el.style.height, 10) * app.devicePixelRatio
                     || 0
             },
             set: function (val) {
                 height = val
-                this.el.style.height = (height/devicePixelRatio) + 'px'
+                this.el.style.height = (height/app.devicePixelRatio) + 'px'
             }
         })
     }
@@ -302,9 +302,9 @@ var MX = MX || (function (undefined) {
                         + (-this.y).toFixed(floatPrecision) + 'px,'
                         + (-this.z).toFixed(floatPrecision) + 'px) '
                     + 'scale3d('
-                        + (devicePixelRatio * this.scaleX).toFixed(floatPrecision) + ','
-                        + (devicePixelRatio * this.scaleY).toFixed(floatPrecision) + ','
-                        + (devicePixelRatio * this.scaleZ).toFixed(floatPrecision) + ') '
+                        + (app.devicePixelRatio * this.scaleX).toFixed(floatPrecision) + ','
+                        + (app.devicePixelRatio * this.scaleY).toFixed(floatPrecision) + ','
+                        + (app.devicePixelRatio * this.scaleZ).toFixed(floatPrecision) + ') '
 
                 if (rotationTranslation) {
                     transformString += rotationTranslation.before
diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css
index a149166..0ce2c5e 100755
--- a/public/assets/stylesheets/app.css
+++ b/public/assets/stylesheets/app.css
@@ -929,6 +929,9 @@ border-left: 1px solid black;
 .no-templates {
 	display: none;
 }
+.no-templates a {
+	border-bottom: 1px solid;
+}
 
 .templates span {
 	display: block;
@@ -2373,6 +2376,7 @@ button {
   font-weight: 500;
   width: 100%;
 	font-size:14px;
+	font-family:'Lato', sans-serif;
 }
 
 #builder-units {
-- 
cgit v1.2.3-70-g09d2


From 717e87b7422db8e1eda655fbf04e45fe5f877c9b Mon Sep 17 00:00:00 2001
From: Jules Laplace 
Date: Tue, 20 Jan 2015 00:10:23 -0500
Subject: combining webhook stuff

---
 package.json                       |   1 +
 server/index.js                    |   3 --
 server/lib/api/profile.js          |   1 +
 server/lib/schemas/Subscription.js |   1 +
 server/lib/schemas/User.js         |   4 +-
 server/lib/views/index.js          |   1 -
 server/lib/views/subscription.js   | 105 -------------------------------------
 server/lib/webhook/config.js       |   6 +++
 server/lib/webhook/index.js        |  88 +++++++++++++++++++++++++++++++
 9 files changed, 100 insertions(+), 110 deletions(-)
 delete mode 100644 server/lib/views/subscription.js
 create mode 100644 server/lib/webhook/config.js
 create mode 100644 server/lib/webhook/index.js

diff --git a/package.json b/package.json
index 34e0c4c..8afb96e 100644
--- a/package.json
+++ b/package.json
@@ -24,6 +24,7 @@
     "mongoose-unique-validator": "~0.3.0",
     "monk": "~0.7.1",
     "multer": "~0.1.0",
+    "node-recurly": "^2.1.0",
     "node-restful": "~0.1.14",
     "passport": "~0.2.0",
     "passport-facebook": "~1.0.3",
diff --git a/server/index.js b/server/index.js
index 0f4941a..9a9323c 100644
--- a/server/index.js
+++ b/server/index.js
@@ -70,9 +70,6 @@ site.setup = function(){
 	app.all('*', middleware.ensureLocals);
 	app.all('*', middleware.ensureIP);
 
-	// where should this live?
-  app.get('/subscribe/webhook', views.subscription.webhook);
-
 	server = http.createServer(app)
 	server.listen(app.get('port'), function () {
 		console.log('Express server listening on port ' + app.get('port'));
diff --git a/server/lib/api/profile.js b/server/lib/api/profile.js
index 996505f..d72a2c3 100644
--- a/server/lib/api/profile.js
+++ b/server/lib/api/profile.js
@@ -32,6 +32,7 @@ var profile = {
 		delete data.old_password
 		delete data.new_password
 		delete data.isStaff
+		delete data.plan_level
 		data.updated_at = new Date ()
 		
 		if (req.files.avatar) {
diff --git a/server/lib/schemas/Subscription.js b/server/lib/schemas/Subscription.js
index 8315009..7f2579b 100644
--- a/server/lib/schemas/Subscription.js
+++ b/server/lib/schemas/Subscription.js
@@ -15,6 +15,7 @@ var SubscriptionSchema = new mongoose.Schema({
 	plans: [{
     tier: { type: String },
     monthly: { type: Boolean },
+    projects: [{ type: mongoose.Schema.ObjectId }],
 	}],
 	
 	created_at: { type: Date, default: Date.now },
diff --git a/server/lib/schemas/User.js b/server/lib/schemas/User.js
index 180a140..ae1d912 100644
--- a/server/lib/schemas/User.js
+++ b/server/lib/schemas/User.js
@@ -54,7 +54,9 @@ var UserSchema = new mongoose.Schema({
 		type: String,
 		default: "",
 	},
-
+	
+	plan_level: { type: Number, default: 0 },
+	
 	location: { type: String, default: "" },
 	photo: { type: String, default: "" },
 	bio: { type: String, default: "" },
diff --git a/server/lib/views/index.js b/server/lib/views/index.js
index 2a8f921..0ce0357 100644
--- a/server/lib/views/index.js
+++ b/server/lib/views/index.js
@@ -22,7 +22,6 @@ marked.setOptions({
 var views = module.exports = {
 
 	staff: require('./staff'),
-	subscription: require('./subscription'),
 
 	editor_new: function (req, res) {
 		if (! req.user) {
diff --git a/server/lib/views/subscription.js b/server/lib/views/subscription.js
deleted file mode 100644
index b9c79cb..0000000
--- a/server/lib/views/subscription.js
+++ /dev/null
@@ -1,105 +0,0 @@
-/* jshint node: true */
-
-var User = require('../schemas/User'),
-	Subscription = require('../schemas/Subscription'),
-	config = require('../../../config'),
-	middleware = require('../middleware'),
-	util = require('../util'),
-	_ = require('lodash'),
-	moment = require('moment'),
-	xml2js = require('xml2js');
-
-var parser = new xml2js.Parser();
-// fs.readFile('./foo.xml', function(err, data) {
-// 	parser.parseString(data, function (err, result) {
-// 		console.log(inspect(result, { colors: true, depth: Infinity }));
-// 	});
-// });
-
-var subscription = module.exports = {
-	
-	fields: [
-	  // accounts
-		"new_account_notification",
-		"canceled_account_notification",
-		"billing_info_updated_notification",
-		"reactivated_account_notification",
-
-		// invoices
-		"new_invoice_notification",
-		"closed_invoice_notification",
-		"past_due_invoice_notification",
-		
-		// subscriptions
-		"new_subscription_notification",
-		"updated_subscription_notification",
-		"canceled_subscription_notification",
-		"expired_subscription_notification",
-		"renewed_subscription_notification",
-		
-		// payments
-		"successful_payment_notification",
-		"failed_payment_notification",
-		"successful_refund_notification",
-		"void_payment_notification",
-	],  
-
-	middleware: {
-  },
-
-  callbacks: {
-		// accounts
-		new_account_notification: function(data){
-		},
-		canceled_account_notification: function(data){
-		},
-		billing_info_updated_notification: function(data){
-		},
-		reactivated_account_notification: function(data){
-		},
-		
-		// invoices
-		new_invoice_notification: function(data){
-		},
-		closed_invoice_notification: function(data){
-		},
-		past_due_invoice_notification: function(data){
-		},
-		
-		// subscriptions
-		new_subscription_notification: function(data){
-		},
-		updated_subscription_notification: function(data){
-		},
-		canceled_subscription_notification: function(data){
-		},
-		expired_subscription_notification: function(data){
-		},
-		renewed_subscription_notification: function(data){
-		},
-		
-		// payments
-		successful_payment_notification: function(data){
-		},
-		failed_payment_notification: function(data){
-		},
-		successful_refund_notification: function(data){
-		},
-		void_payment_notification: function(data){
-		},
-  },
-	
-  // need a route for the webhook,
-  // then calls to get appropriate info from the recurly api
-	webhook: function(req, res){
-    res.status(200).end()
-		parser.parseString(data, function (err, result) {
-			console.log(inspect(result, { colors: true, depth: Infinity }));
-			for (var i in data) {
-			  if (subscription.callbacks[i]) {
-			    subscription.callbacks[i](data)
-			  }
-			}
-		});
-	},
-}
diff --git a/server/lib/webhook/config.js b/server/lib/webhook/config.js
new file mode 100644
index 0000000..ecafeb3
--- /dev/null
+++ b/server/lib/webhook/config.js
@@ -0,0 +1,6 @@
+module.exports = {
+	API_KEY: require('process').env['VVALLS_RECURLY_SECRET'],
+	SUBDOMAIN: 'vvalls',
+	ENVIRONMENT: 'sandbox',
+	DEBUG: true,
+};
diff --git a/server/lib/webhook/index.js b/server/lib/webhook/index.js
new file mode 100644
index 0000000..c4b4b76
--- /dev/null
+++ b/server/lib/webhook/index.js
@@ -0,0 +1,88 @@
+// // where should this live?
+// app.get('/subscribe/webhook', views.subscription.webhook);
+
+/* jshint node: true */
+
+var User = require('../schemas/User'),
+	Subscription = require('../schemas/Subscription'),
+	config = require('../../../config'),
+	middleware = require('../middleware'),
+	util = require('../util'),
+	_ = require('lodash'),
+	moment = require('moment'),
+	xml2js = require('xml2js'),
+	Recurly = require('node-recurly'),
+	recurly = new Recurly(require('./config'));
+
+var parser = new xml2js.Parser();
+// fs.readFile('./foo.xml', function(err, data) {
+// 	parser.parseString(data, function (err, result) {
+// 		console.log(inspect(result, { colors: true, depth: Infinity }));
+// 	});
+// });
+
+/*
+app.use(express.basicAuth(function(user, pass, callback) {
+ var result = (user === 'testUser' && pass === 'testPass');
+ callback(null, result);
+}));
+*/
+
+var subscription = module.exports = {
+	
+  callbacks: {
+		// accounts
+		new_account_notification: function(data){
+		},
+		canceled_account_notification: function(data){
+		},
+		billing_info_updated_notification: function(data){
+		},
+		reactivated_account_notification: function(data){
+		},
+		
+		// invoices
+		new_invoice_notification: function(data){
+		},
+		closed_invoice_notification: function(data){
+		},
+		past_due_invoice_notification: function(data){
+		},
+		
+		// subscriptions
+		new_subscription_notification: function(data){
+		},
+		updated_subscription_notification: function(data){
+		},
+		canceled_subscription_notification: function(data){
+		},
+		expired_subscription_notification: function(data){
+		},
+		renewed_subscription_notification: function(data){
+		},
+		
+		// payments
+		successful_payment_notification: function(data){
+		},
+		failed_payment_notification: function(data){
+		},
+		successful_refund_notification: function(data){
+		},
+		void_payment_notification: function(data){
+		},
+  },
+	
+  // need a route for the webhook,
+  // then calls to get appropriate info from the recurly api
+	webhook: function(req, res){
+    res.status(200).end()
+		parser.parseString(data, function (err, result) {
+			console.log(inspect(result, { colors: true, depth: Infinity }));
+			for (var i in data) {
+			  if (subscription.callbacks[i]) {
+			    subscription.callbacks[i](data[i])
+			  }
+			}
+		});
+	},
+}
-- 
cgit v1.2.3-70-g09d2


From 3eee6a15ee44a75f6deedd073f60b88d342d56ef Mon Sep 17 00:00:00 2001
From: Jules Laplace 
Date: Thu, 22 Jan 2015 16:54:08 -0500
Subject: recurly links on brochure

---
 server/lib/schemas/Plan.js  |  2 ++
 server/lib/schemas/User.js  |  1 +
 server/lib/webhook/index.js |  1 +
 views/about/brochure.ejs    | 19 +++++++++++++++----
 4 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/server/lib/schemas/Plan.js b/server/lib/schemas/Plan.js
index 1208672..8a19b99 100644
--- a/server/lib/schemas/Plan.js
+++ b/server/lib/schemas/Plan.js
@@ -10,6 +10,8 @@ var PlanSchema = new mongoose.Schema({
   name: { type: String },
   slug: { type: String },
 
+  level: { type: Number },
+
   monthly_price: { type: Number },
   yearly_price: { type: Number },
 
diff --git a/server/lib/schemas/User.js b/server/lib/schemas/User.js
index ae1d912..867939e 100644
--- a/server/lib/schemas/User.js
+++ b/server/lib/schemas/User.js
@@ -56,6 +56,7 @@ var UserSchema = new mongoose.Schema({
 	},
 	
 	plan_level: { type: Number, default: 0 },
+	subscription_id: { type: mongoose.Schema.ObjectId },
 	
 	location: { type: String, default: "" },
 	photo: { type: String, default: "" },
diff --git a/server/lib/webhook/index.js b/server/lib/webhook/index.js
index c4b4b76..ebbd01a 100644
--- a/server/lib/webhook/index.js
+++ b/server/lib/webhook/index.js
@@ -33,6 +33,7 @@ var subscription = module.exports = {
   callbacks: {
 		// accounts
 		new_account_notification: function(data){
+			// 
 		},
 		canceled_account_notification: function(data){
 		},
diff --git a/views/about/brochure.ejs b/views/about/brochure.ejs
index e75f8c6..cffa51f 100644
--- a/views/about/brochure.ejs
+++ b/views/about/brochure.ejs
@@ -33,8 +33,14 @@
         
  • Each new floor plan can have up to [[- plans.basic.basic_project_limit ]] exhibitions
  • VValls logo appears when embedding an exhibition on a web page
  • - - + [[ if (! logged_in) { ]] + + [[ } else if (! profile.plan_level || profile.plan_level < plan.level) { ]] + + [[ } else if (profile.plan_level == plan.level) { ]] + Current Level + [[ } else { ]] + [[ } ]] @@ -49,8 +55,13 @@
  • Includes planning for 3D objects in the room
  • No VValls logo on embed
  • - - + [[ if (! logged_in) { ]] + + [[ } else if (! profile.plan_level || profile.plan_level < plan.level) { ]] + + [[ } else if (profile.plan_level == plan.level) { ]] + Current Level + [[ } ]] -- cgit v1.2.3-70-g09d2 From e0debd761bc24cd42f4140d2b6cc32a4271fe975 Mon Sep 17 00:00:00 2001 From: Julie Lala Date: Fri, 23 Jan 2015 02:35:46 -0500 Subject: getting webhooks in order.. didnt need as many as i thought --- Procfile | 3 +- config.json.example | 1 + server/index.js | 2 +- server/lib/schemas/User.js | 2 + server/lib/webhook/config.js | 2 +- server/lib/webhook/index.js | 119 +++++++++++++----------------------------- server/lib/webhook/webhook.js | 118 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 161 insertions(+), 86 deletions(-) create mode 100644 server/lib/webhook/webhook.js diff --git a/Procfile b/Procfile index 983db91..bab08fb 100644 --- a/Procfile +++ b/Procfile @@ -1 +1,2 @@ -web: node server \ No newline at end of file +web: node server +webhook: node server/lib/webhook \ No newline at end of file diff --git a/config.json.example b/config.json.example index 6028021..b8c310c 100644 --- a/config.json.example +++ b/config.json.example @@ -3,6 +3,7 @@ "hostName": "lvh.me", "port": 3000, "socketPort": 1337, + "webhookPort": 5000, "databaseHost": "lvh.me", "pageSize": 10, "env": { "development": 1 } diff --git a/server/index.js b/server/index.js index 9a9323c..02fea3c 100644 --- a/server/index.js +++ b/server/index.js @@ -72,7 +72,7 @@ site.setup = function(){ server = http.createServer(app) server.listen(app.get('port'), function () { - console.log('Express server listening on port ' + app.get('port')); + console.log('Vvalls server listening on port ' + app.get('port')); }); // var io = websocket.listen(server) diff --git a/server/lib/schemas/User.js b/server/lib/schemas/User.js index 867939e..77de2d4 100644 --- a/server/lib/schemas/User.js +++ b/server/lib/schemas/User.js @@ -56,6 +56,8 @@ var UserSchema = new mongoose.Schema({ }, plan_level: { type: Number, default: 0 }, + plan_type: { type: String, default: "free" }, + last_charged: { type: Date, default: null }, subscription_id: { type: mongoose.Schema.ObjectId }, location: { type: String, default: "" }, diff --git a/server/lib/webhook/config.js b/server/lib/webhook/config.js index ecafeb3..3d7e1c5 100644 --- a/server/lib/webhook/config.js +++ b/server/lib/webhook/config.js @@ -1,5 +1,5 @@ module.exports = { - API_KEY: require('process').env['VVALLS_RECURLY_SECRET'], + API_KEY: process.env['VVALLS_RECURLY_SECRET'], SUBDOMAIN: 'vvalls', ENVIRONMENT: 'sandbox', DEBUG: true, diff --git a/server/lib/webhook/index.js b/server/lib/webhook/index.js index ebbd01a..7dd68e6 100644 --- a/server/lib/webhook/index.js +++ b/server/lib/webhook/index.js @@ -1,89 +1,42 @@ -// // where should this live? -// app.get('/subscribe/webhook', views.subscription.webhook); +var config = require('../../../config.json'), + http = require('http'), + express = require('express'), + bodyParser = require('body-parser'), + mongoose = require('mongoose'); -/* jshint node: true */ +var http = require('http'), + express = require('express'), + bodyParser = require('body-parser'), + multer = require('multer'), + MongoStore = require('connect-mongo')(express), + passport = require('passport'), + path = require('path'), + mongoose = require('mongoose'); -var User = require('../schemas/User'), - Subscription = require('../schemas/Subscription'), - config = require('../../../config'), - middleware = require('../middleware'), - util = require('../util'), - _ = require('lodash'), - moment = require('moment'), - xml2js = require('xml2js'), - Recurly = require('node-recurly'), - recurly = new Recurly(require('./config')); +var app = express() +var server +var DATABASE_URI = process.env.MONGOLAB_URI || ('mongodb://' + config.databaseHost + '/vvalls') -var parser = new xml2js.Parser(); -// fs.readFile('./foo.xml', function(err, data) { -// parser.parseString(data, function (err, result) { -// console.log(inspect(result, { colors: true, depth: Infinity })); -// }); -// }); +var site = {} -/* -app.use(express.basicAuth(function(user, pass, callback) { - var result = (user === 'testUser' && pass === 'testPass'); - callback(null, result); -})); -*/ +site.init = function(){ + mongoose.connect(DATABASE_URI, {}, site.ready); +} + +site.ready = function(){ + app.set('port', config.webhookPort); + app.use(bodyParser()); + app.use(express.query()); + app.set('env', config.env.production ? "production" : "development") + app.get('env') === 'development' && app.use(express.errorHandler()); -var subscription = module.exports = { - - callbacks: { - // accounts - new_account_notification: function(data){ - // - }, - canceled_account_notification: function(data){ - }, - billing_info_updated_notification: function(data){ - }, - reactivated_account_notification: function(data){ - }, - - // invoices - new_invoice_notification: function(data){ - }, - closed_invoice_notification: function(data){ - }, - past_due_invoice_notification: function(data){ - }, - - // subscriptions - new_subscription_notification: function(data){ - }, - updated_subscription_notification: function(data){ - }, - canceled_subscription_notification: function(data){ - }, - expired_subscription_notification: function(data){ - }, - renewed_subscription_notification: function(data){ - }, - - // payments - successful_payment_notification: function(data){ - }, - failed_payment_notification: function(data){ - }, - successful_refund_notification: function(data){ - }, - void_payment_notification: function(data){ - }, - }, - - // need a route for the webhook, - // then calls to get appropriate info from the recurly api - webhook: function(req, res){ - res.status(200).end() - parser.parseString(data, function (err, result) { - console.log(inspect(result, { colors: true, depth: Infinity })); - for (var i in data) { - if (subscription.callbacks[i]) { - subscription.callbacks[i](data[i]) - } - } - }); - }, + server = http.createServer(app) + server.listen(app.get('port'), function () { + console.log('Webhook server listening on port ' + app.get('port')); + }); + + app.get('/', function(req,res){ res.send('HI THERE') }) + app.get('/subscribe/webhook', require('./webhook').webhook); } + +site.init() diff --git a/server/lib/webhook/webhook.js b/server/lib/webhook/webhook.js new file mode 100644 index 0000000..067af30 --- /dev/null +++ b/server/lib/webhook/webhook.js @@ -0,0 +1,118 @@ +// // where should this live? +// app.get('/subscribe/webhook', views.subscription.webhook); + +/* +app.use(express.basicAuth(function(user, pass, callback) { + var result = (user === 'testUser' && pass === 'testPass'); + callback(null, result); +})); +*/ + + +/* jshint node: true */ + +var User = require('../schemas/User'), + Subscription = require('../schemas/Subscription'), + config = require('../../../config'), + middleware = require('../middleware'), + util = require('../util'), + _ = require('lodash'), + moment = require('moment'), + xml2js = require('xml2js'), + Recurly = require('node-recurly'), + recurly = new Recurly(require('./config')); + +var parser = new xml2js.Parser(); + +var subscription = module.exports = { + plan_level: { + free: 0, + basic: 1, + pro: 2, + }, + + callbacks: { + // accounts + new_account_notification: function(data){ + // fires on successful signup + // use the account_code to find the user, + }, + canceled_account_notification: function(data){ + }, + billing_info_updated_notification: function(data){ + }, + reactivated_account_notification: function(data){ + }, + + // invoices + new_invoice_notification: function(data){ + }, + closed_invoice_notification: function(data){ + }, + past_due_invoice_notification: function(data){ + }, + + // subscriptions + new_subscription_notification: function(data){ + var account = data.account + User.findOne({ _id: account.account_code }, function(err, user){ + if (err) return; + var subscription = data.subscription + + var plan = subscription.plan.plan_code.split("_") + var plan_type = plan[0] + var plan_period = plan[1] + + user.plan_type = plan_type + user.plan_level = subscription.plan_level[plan_type] + + // subscription.uuid + // subscription.subscription_add_ons[] + // subscription.subscription_add_ons[0].quantity + user.save(function(){ + }) + + }) + }, + updated_subscription_notification: function(data){ + }, + canceled_subscription_notification: function(data){ + }, + expired_subscription_notification: function(data){ + }, + renewed_subscription_notification: function(data){ + }, + + // payments + successful_payment_notification: function(data){ + var account = data.account + User.findOne({ _id: account.account_code }, function(err, user){ + if (err) return; + user.last_charged = new Date(data.transaction.date) + user.save(function(){ + }) + }) + }, + failed_payment_notification: function(data){ + }, + successful_refund_notification: function(data){ + }, + void_payment_notification: function(data){ + }, + + }, + + // need a route for the webhook, + // then calls to get appropriate info from the recurly api + webhook: function(req, res){ + res.status(200).end() + parser.parseString(data, function (err, result) { + console.log(inspect(result, { colors: true, depth: Infinity })); + for (var i in data) { + if (subscription.callbacks[i]) { + subscription.callbacks[i](data[i]) + } + } + }); + }, +} -- cgit v1.2.3-70-g09d2 From 74fb7a313b4d9ad3517e97133febff9cada96fe0 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 23 Jan 2015 14:46:44 -0500 Subject: handle subscribe and payment events with webhook --- server/lib/schemas/Subscription.js | 17 +++--- server/lib/schemas/User.js | 1 - server/lib/webhook/index.js | 4 +- server/lib/webhook/webhook.js | 108 ++++++++++++++++++++++--------------- 4 files changed, 76 insertions(+), 54 deletions(-) diff --git a/server/lib/schemas/Subscription.js b/server/lib/schemas/Subscription.js index 7f2579b..99e4ebf 100644 --- a/server/lib/schemas/Subscription.js +++ b/server/lib/schemas/Subscription.js @@ -8,14 +8,15 @@ var mongoose = require('mongoose'), var SubscriptionSchema = new mongoose.Schema({ user_id: { type: mongoose.Schema.ObjectId, index: true }, - - monthly_total: { type: Number }, - yearly_total: { type: Number }, - - plans: [{ - tier: { type: String }, - monthly: { type: Boolean }, - projects: [{ type: mongoose.Schema.ObjectId }], + + plan_level: { type: Number, default: 0 }, + plan_type: { type: String, default: "free" }, + last_charged: { type: Date, default: null }, + + subscription_uuid: { type: String }, + subscription_add_ons: [{ + name: { type: String }, + quantity: { type: Number }, }], created_at: { type: Date, default: Date.now }, diff --git a/server/lib/schemas/User.js b/server/lib/schemas/User.js index 77de2d4..06ad33d 100644 --- a/server/lib/schemas/User.js +++ b/server/lib/schemas/User.js @@ -58,7 +58,6 @@ var UserSchema = new mongoose.Schema({ plan_level: { type: Number, default: 0 }, plan_type: { type: String, default: "free" }, last_charged: { type: Date, default: null }, - subscription_id: { type: mongoose.Schema.ObjectId }, location: { type: String, default: "" }, photo: { type: String, default: "" }, diff --git a/server/lib/webhook/index.js b/server/lib/webhook/index.js index 7dd68e6..11419c2 100644 --- a/server/lib/webhook/index.js +++ b/server/lib/webhook/index.js @@ -13,6 +13,8 @@ var http = require('http'), path = require('path'), mongoose = require('mongoose'); +var webhook = require('./webhook'); + var app = express() var server var DATABASE_URI = process.env.MONGOLAB_URI || ('mongodb://' + config.databaseHost + '/vvalls') @@ -36,7 +38,7 @@ site.ready = function(){ }); app.get('/', function(req,res){ res.send('HI THERE') }) - app.get('/subscribe/webhook', require('./webhook').webhook); + webhook.route(app) } site.init() diff --git a/server/lib/webhook/webhook.js b/server/lib/webhook/webhook.js index 067af30..2e5e627 100644 --- a/server/lib/webhook/webhook.js +++ b/server/lib/webhook/webhook.js @@ -24,7 +24,7 @@ var User = require('../schemas/User'), var parser = new xml2js.Parser(); -var subscription = module.exports = { +var subscribe = module.exports = { plan_level: { free: 0, basic: 1, @@ -32,87 +32,107 @@ var subscription = module.exports = { }, callbacks: { +/* // accounts - new_account_notification: function(data){ + new_account_notification: function(data, user){ // fires on successful signup - // use the account_code to find the user, }, - canceled_account_notification: function(data){ + canceled_account_notification: function(data, user){ }, - billing_info_updated_notification: function(data){ + billing_info_updated_notification: function(data, user){ }, - reactivated_account_notification: function(data){ + reactivated_account_notification: function(data, user){ }, // invoices - new_invoice_notification: function(data){ + new_invoice_notification: function(data, user){ }, - closed_invoice_notification: function(data){ + closed_invoice_notification: function(data, user){ }, - past_due_invoice_notification: function(data){ + past_due_invoice_notification: function(data, user){ }, - +*/ + // subscriptions - new_subscription_notification: function(data){ + new_subscription_notification: function(data, user){ var account = data.account - User.findOne({ _id: account.account_code }, function(err, user){ - if (err) return; - var subscription = data.subscription - - var plan = subscription.plan.plan_code.split("_") + Subscription.findOne({ "uuid": data.subscription.uuid }, function(err, subscription){ + if (err || subscription) return; + + var plan = data.subscription.plan.plan_code.split("-") var plan_type = plan[0] var plan_period = plan[1] user.plan_type = plan_type - user.plan_level = subscription.plan_level[plan_type] - - // subscription.uuid - // subscription.subscription_add_ons[] - // subscription.subscription_add_ons[0].quantity - user.save(function(){ - }) + user.plan_period = plan_period + user.plan_level = subscribe.plan_level[plan_type] + var subscriber = new Subscription () + subscriber.user_id = user._id + subscriber.uuid = data.subscription.uuid + subscriber.add_ons = subscription.add_ons.map(function(add_on){ + return { + name: add_on.plan, + quantity: add_on.quantity, + } + }) + subscriber.save(function(err, data){ + if (err) return; + user.save(function(err){ + // saved! + }) + }) }) }, - updated_subscription_notification: function(data){ + +/* + updated_subscription_notification: function(data, user){ }, - canceled_subscription_notification: function(data){ + canceled_subscription_notification: function(data, user){ }, - expired_subscription_notification: function(data){ + expired_subscription_notification: function(data, user){ }, - renewed_subscription_notification: function(data){ + renewed_subscription_notification: function(data, user){ }, - +*/ // payments - successful_payment_notification: function(data){ + successful_payment_notification: function(data, user){ var account = data.account - User.findOne({ _id: account.account_code }, function(err, user){ - if (err) return; - user.last_charged = new Date(data.transaction.date) - user.save(function(){ - }) - }) + user.last_charged = new Date(data.transaction.date) + user.save(function(){ + }) }, - failed_payment_notification: function(data){ +/* + failed_payment_notification: function(data, user){ }, - successful_refund_notification: function(data){ + successful_refund_notification: function(data, user){ }, - void_payment_notification: function(data){ + void_payment_notification: function(data, user){ }, - +*/ }, - // need a route for the webhook, + execute: function(action, data){ + User.findOne({ _id: data.account.account_code }, function(err, user){ + if (err) { return } + subscribe.callbacks[action](data, user) + }) + }, + // then calls to get appropriate info from the recurly api - webhook: function(req, res){ + handle: function(req, res){ res.status(200).end() parser.parseString(data, function (err, result) { console.log(inspect(result, { colors: true, depth: Infinity })); - for (var i in data) { - if (subscription.callbacks[i]) { - subscription.callbacks[i](data[i]) + for (var action in result) { + if (subscribe.callbacks[action]) { + subscribe.execute(action, result[action]); } } }); }, + + route: function(app){ + app.post('/subscribe/webhook', subscribe.handle); + }, } -- cgit v1.2.3-70-g09d2 From 5efb0ed941ed80136e63014c4f615574b2b613d7 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 23 Jan 2015 17:58:41 -0500 Subject: edit subscription partial stub --- server/lib/api/index.js | 1 + server/lib/api/subscription.js | 22 ++++++++++ server/lib/schemas/Subscription.js | 3 +- server/lib/webhook/config.js | 6 --- server/lib/webhook/recurly-config.js | 6 +++ server/lib/webhook/webhook.js | 8 ++-- views/about/brochure.ejs | 12 +++--- views/partials/edit-subscription.ejs | 33 +++++++++++++++ views/profile.ejs | 82 ++++++++++++++++++++---------------- 9 files changed, 119 insertions(+), 54 deletions(-) create mode 100644 server/lib/api/subscription.js delete mode 100644 server/lib/webhook/config.js create mode 100644 server/lib/webhook/recurly-config.js create mode 100644 views/partials/edit-subscription.ejs diff --git a/server/lib/api/index.js b/server/lib/api/index.js index 11e13fc..9478d9b 100644 --- a/server/lib/api/index.js +++ b/server/lib/api/index.js @@ -8,6 +8,7 @@ var api = { projects: require('./projects'), rooms: require('./rooms'), collaborator: require('./collaborator'), + subscription: require('./subscription'), } module.exports = api diff --git a/server/lib/api/subscription.js b/server/lib/api/subscription.js new file mode 100644 index 0000000..6fe8c61 --- /dev/null +++ b/server/lib/api/subscription.js @@ -0,0 +1,22 @@ +/* jshint node: true */ + +var _ = require('lodash'), + util = require('../util'), + upload = require('../upload'), + config = require('../../../config.json'), + User = require('../schemas/User'), + Project = require('../schemas/Project'), + Layout = require('../schemas/Layout'), + Subscription = require('../schemas/Subscription'); + +var subscription = module.exports = { + +/* + index: function(req, res){ + Project.find({ user_id: req.user._id }, function(err, docs){ + res.json(docs) + }) + }, +*/ + +}; \ No newline at end of file diff --git a/server/lib/schemas/Subscription.js b/server/lib/schemas/Subscription.js index 99e4ebf..2f49ea1 100644 --- a/server/lib/schemas/Subscription.js +++ b/server/lib/schemas/Subscription.js @@ -9,9 +9,8 @@ var mongoose = require('mongoose'), var SubscriptionSchema = new mongoose.Schema({ user_id: { type: mongoose.Schema.ObjectId, index: true }, - plan_level: { type: Number, default: 0 }, plan_type: { type: String, default: "free" }, - last_charged: { type: Date, default: null }, + plan_period: { type: String, default: "monthly" }, subscription_uuid: { type: String }, subscription_add_ons: [{ diff --git a/server/lib/webhook/config.js b/server/lib/webhook/config.js deleted file mode 100644 index 3d7e1c5..0000000 --- a/server/lib/webhook/config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - API_KEY: process.env['VVALLS_RECURLY_SECRET'], - SUBDOMAIN: 'vvalls', - ENVIRONMENT: 'sandbox', - DEBUG: true, -}; diff --git a/server/lib/webhook/recurly-config.js b/server/lib/webhook/recurly-config.js new file mode 100644 index 0000000..3d7e1c5 --- /dev/null +++ b/server/lib/webhook/recurly-config.js @@ -0,0 +1,6 @@ +module.exports = { + API_KEY: process.env['VVALLS_RECURLY_SECRET'], + SUBDOMAIN: 'vvalls', + ENVIRONMENT: 'sandbox', + DEBUG: true, +}; diff --git a/server/lib/webhook/webhook.js b/server/lib/webhook/webhook.js index 2e5e627..e9a7925 100644 --- a/server/lib/webhook/webhook.js +++ b/server/lib/webhook/webhook.js @@ -20,7 +20,7 @@ var User = require('../schemas/User'), moment = require('moment'), xml2js = require('xml2js'), Recurly = require('node-recurly'), - recurly = new Recurly(require('./config')); + recurly = new Recurly(require('./recurly-config')); var parser = new xml2js.Parser(); @@ -64,12 +64,14 @@ var subscribe = module.exports = { var plan_period = plan[1] user.plan_type = plan_type - user.plan_period = plan_period user.plan_level = subscribe.plan_level[plan_type] var subscriber = new Subscription () - subscriber.user_id = user._id subscriber.uuid = data.subscription.uuid + subscriber.user_id = user._id + subscriber.plan_type = plan_type + subscriber.plan_period = plan_period + subscriber.plan_level = subscribe.plan_level[plan_type] subscriber.add_ons = subscription.add_ons.map(function(add_on){ return { name: add_on.plan, diff --git a/views/about/brochure.ejs b/views/about/brochure.ejs index cffa51f..1c808f8 100644 --- a/views/about/brochure.ejs +++ b/views/about/brochure.ejs @@ -35,9 +35,9 @@
  • [[ if (! logged_in) { ]] - [[ } else if (! profile.plan_level || profile.plan_level < plan.level) { ]] - - [[ } else if (profile.plan_level == plan.level) { ]] + [[ } else if (! user.plan_level || user.plan_level < plan.level) { ]] + + [[ } else if (user.plan_level == plan.level) { ]] Current Level [[ } else { ]] [[ } ]] @@ -57,9 +57,9 @@
  • [[ if (! logged_in) { ]] - [[ } else if (! profile.plan_level || profile.plan_level < plan.level) { ]] - - [[ } else if (profile.plan_level == plan.level) { ]] + [[ } else if (! user.plan_level || user.plan_level < plan.level) { ]] + + [[ } else if (user.plan_level == plan.level) { ]] Current Level [[ } ]] diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs new file mode 100644 index 0000000..0aa5281 --- /dev/null +++ b/views/partials/edit-subscription.ejs @@ -0,0 +1,33 @@ +
    + X +
    +
    + +
      +
    • +

      Edit Subscription

      +
    • +
    • + [[ if (! user.plan_level) { ]] + You are currently using the free plan. For access to all of Vvalls features, + consider upgrading to a paid plan. +

      + View the Plans + [[ } else { ]] + Your current plan level is XXX + You have been a member since XXX + $cost/month OR $cost/year + + You are using N basic layouts + Buy more + + You are using N pro layouts + Buy more / Upgrade your account + + Cancel your subscription + [[ } ]] +

    • +
    +
    +
    +
    diff --git a/views/profile.ejs b/views/profile.ejs index 88af6b0..e149847 100644 --- a/views/profile.ejs +++ b/views/profile.ejs @@ -9,48 +9,53 @@ [[- include partials/header ]]
    - [[ if (profile.photo && profile.photo.length) { ]] -
    -
    - [[ } else { ]] -
    - - - [[ if (isOwnProfile) { ]] -
    click to add profile pic
    - - [[ } ]] -
    -
    + [[ if (profile.photo && profile.photo.length) { ]] +
    +
    + [[ } else { ]] +
    + + + [[ if (isOwnProfile) { ]] +
    click to add profile pic
    + [[ } ]] -
    -
    -

    [[- profile.displayName ]]

    - [[ if (profile.location) { ]] - - [[- profile.location ]] - - [[ } ]] - [[ if (profile.website && profile.website.length) { ]] - - [[- profile.website ]] - - [[ } ]] - [[ if (profile.twitterName && profile.twitterName.length) { ]] - - @[[- profile.twitterName ]] - - [[ } ]] -
    -
    - +
    +
    + [[ } ]] +
    +
    +

    [[- profile.displayName ]]

    + [[ if (profile.location) { ]] + + [[- profile.location ]] + + [[ } ]] + [[ if (profile.website && profile.website.length) { ]] + + [[- profile.website ]] + + [[ } ]] + [[ if (profile.twitterName && profile.twitterName.length) { ]] + + @[[- profile.twitterName ]] + + [[ } ]] + [[ if (profile.plan_level == 1) { ]] + PREMIUM + [[ } else if (profile.plan_level == 2) { ]] + PRO + [[ } ]] +
    +
    [[ if (projects.length) { ]] +

    [[- profile.username ]] has [[- projectCount ]] project[[- projectCount != 1 ? "s" : "" ]]

    - [[ include projects/list-projects ]] + [[ } else { ]] - +

    Welcome to VVALLS

    @@ -69,8 +74,11 @@

    This person has no projects.

    [[ } ]]
    + [[ } ]] -
    + + + [[ include partials/edit-subscription ]] [[ include partials/edit-profile ]] [[ include projects/layouts-modal ]] [[ include projects/edit-project ]] -- cgit v1.2.3-70-g09d2 From 29e0f23c5ade5072851aaa74314166b0c7281272 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 23 Jan 2015 19:28:53 -0500 Subject: stub subscription modal js --- .../javascripts/ui/site/EditSubscriptionModal.js | 21 ++++++++++ views/partials/edit-subscription.ejs | 45 +++++++++++++++------- 2 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 public/assets/javascripts/ui/site/EditSubscriptionModal.js diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js new file mode 100644 index 0000000..1b3b859 --- /dev/null +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -0,0 +1,21 @@ + +var EditSubscriptionModal = ModalFormView.extend({ + el: ".mediaDrawer.editSubscription", + action: "/api/subscription", + method: "put", + + fixedClose: true, + + events: { + "click [data-role='changePasswordToggle']": 'togglePasswordFields' + }, + + load: function(){ + this.reset() + $.get("/api/subscription", function(data){ + + this.show() + }.bind(this)) + }, + +}) diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index 0aa5281..1f8db62 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -7,24 +7,43 @@
  • Edit Subscription

  • -
  • - [[ if (! user.plan_level) { ]] +
    You are currently using the free plan. For access to all of Vvalls features, consider upgrading to a paid plan.

    View the Plans - [[ } else { ]] - Your current plan level is XXX - You have been a member since XXX - $cost/month OR $cost/year +

    +
    + Your current plan level is + + + + + + + + + + + + + + + + + + + + + + + + +
    Basic plan@ $/
    Additional basic layouts@ $/Buy more
    Additional PRO layouts$/Buy more
    Total$/
    + + - You are using N basic layouts - Buy more - - You are using N pro layouts - Buy more / Upgrade your account - - Cancel your subscription + [[ } ]]
  • -- cgit v1.2.3-70-g09d2 From b60055ee8c77eb9bb035f72147ce6c710ab4347c Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Wed, 14 Jan 2015 15:44:34 -0500 Subject: roll back devicePixelRatio fix on desktop --- public/assets/javascripts/app.js | 4 +++- public/assets/javascripts/mx/mx.js | 14 +++++++------- public/assets/stylesheets/app.css | 4 ++++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/public/assets/javascripts/app.js b/public/assets/javascripts/app.js index 41edafe..a146325 100644 --- a/public/assets/javascripts/app.js +++ b/public/assets/javascripts/app.js @@ -3,7 +3,7 @@ if (is_mobile) { $("html").addClass("mobile") } else { - $("html").addClass("desktop") + $("html").addClass("desktop") } @@ -23,6 +23,8 @@ app.launch = function () { var movements + app.devicePixelRatio = is_mobile ? devicePixelRatio : 1 + scene = new MX.Scene().addTo('#scene') scene.width = window.innerWidth scene.height = window.innerHeight diff --git a/public/assets/javascripts/mx/mx.js b/public/assets/javascripts/mx/mx.js index d59a551..ab9a9a0 100644 --- a/public/assets/javascripts/mx/mx.js +++ b/public/assets/javascripts/mx/mx.js @@ -162,24 +162,24 @@ var MX = MX || (function (undefined) { Object.defineProperty(this, 'width', { get: function () { return width - || parseInt(self.el.style.width*devicePixelRatio, 10) + || parseInt(self.el.style.width, 10) * app.devicePixelRatio || 0 }, set: function (val) { width = val - this.el.style.width = (width/devicePixelRatio) + 'px' + this.el.style.width = (width/app.devicePixelRatio) + 'px' } }) Object.defineProperty(this, 'height', { get: function () { return height - || parseInt(self.el.style.height*devicePixelRatio, 10) + || parseInt(self.el.style.height, 10) * app.devicePixelRatio || 0 }, set: function (val) { height = val - this.el.style.height = (height/devicePixelRatio) + 'px' + this.el.style.height = (height/app.devicePixelRatio) + 'px' } }) } @@ -302,9 +302,9 @@ var MX = MX || (function (undefined) { + (-this.y).toFixed(floatPrecision) + 'px,' + (-this.z).toFixed(floatPrecision) + 'px) ' + 'scale3d(' - + (devicePixelRatio * this.scaleX).toFixed(floatPrecision) + ',' - + (devicePixelRatio * this.scaleY).toFixed(floatPrecision) + ',' - + (devicePixelRatio * this.scaleZ).toFixed(floatPrecision) + ') ' + + (app.devicePixelRatio * this.scaleX).toFixed(floatPrecision) + ',' + + (app.devicePixelRatio * this.scaleY).toFixed(floatPrecision) + ',' + + (app.devicePixelRatio * this.scaleZ).toFixed(floatPrecision) + ') ' if (rotationTranslation) { transformString += rotationTranslation.before diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index aecd6be..62a5682 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -913,6 +913,9 @@ border-left: 1px solid black; .no-templates { display: none; } +.no-templates a { + border-bottom: 1px solid; +} .templates span { display: block; @@ -2357,6 +2360,7 @@ button { font-weight: 500; width: 100%; font-size:14px; + font-family:'Lato', sans-serif; } #builder-units { -- cgit v1.2.3-70-g09d2 From 0a8849bc0abea10fa0d53207159c09f433c25555 Mon Sep 17 00:00:00 2001 From: Julie Lala Date: Mon, 26 Jan 2015 20:37:06 -0500 Subject: methodz --- server/lib/api/subscription.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/server/lib/api/subscription.js b/server/lib/api/subscription.js index 6fe8c61..bd19127 100644 --- a/server/lib/api/subscription.js +++ b/server/lib/api/subscription.js @@ -18,5 +18,17 @@ var subscription = module.exports = { }) }, */ + show: function(req,res){ + // fetch from recurly + }, + + update: function(req,res){ + // update plan_type on recurly + // update add_ons on recurly + }, + + destroy: function(req,res){ + // destroy on recurly + }, }; \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 3059c3203d2cec4e2e745be8c21c6d3fbddb0c14 Mon Sep 17 00:00:00 2001 From: Julie Lala Date: Wed, 28 Jan 2015 01:39:28 -0500 Subject: rigging EditSubscriptionModal --- Gruntfile.js | 1 + config.json.example | 1 - public/assets/javascripts/ui/_router.js | 10 ++++++++++ server/index.js | 1 + server/lib/api/subscription.js | 19 ++++++++++++++++--- server/lib/webhook/webhook.js | 14 ++++++++++++++ views/about/brochure.ejs | 3 +++ views/partials/edit-subscription.ejs | 1 - views/partials/scripts.ejs | 1 + 9 files changed, 46 insertions(+), 5 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index f62cc82..ed236c5 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -99,6 +99,7 @@ module.exports = function(grunt) { "public/assets/javascripts/ui/site/LayoutsModal.js", "public/assets/javascripts/ui/site/EditProjectModal.js", "public/assets/javascripts/ui/site/EditProfileModal.js", + "public/assets/javascripts/ui/site/EditSubscriptionModal.js", "public/assets/javascripts/ui/site/DocumentModal.js", "public/assets/javascripts/ui/site/HomeView.js", diff --git a/config.json.example b/config.json.example index b8c310c..dc79edd 100644 --- a/config.json.example +++ b/config.json.example @@ -5,6 +5,5 @@ "socketPort": 1337, "webhookPort": 5000, "databaseHost": "lvh.me", - "pageSize": 10, "env": { "development": 1 } } diff --git a/public/assets/javascripts/ui/_router.js b/public/assets/javascripts/ui/_router.js index 3532428..9e7ce75 100644 --- a/public/assets/javascripts/ui/_router.js +++ b/public/assets/javascripts/ui/_router.js @@ -9,6 +9,7 @@ var SiteRouter = Router.extend({ "click [data-role='new-project-modal']": 'newProject', "click [data-role='edit-project-modal']": 'editProject', "click [data-role='edit-profile-modal']": 'editProfile', + "click [data-role='edit-subscription-modal']": 'editSubscription', "click [data-role='new-document-modal']": 'newDocument', "click [data-role='edit-document-modal']": 'editDocument', "click [data-role='destroy-document-modal']": 'destroyDocument', @@ -29,6 +30,7 @@ var SiteRouter = Router.extend({ "/profile": 'profile', "/profile/edit": 'editProfile', + "/profile/billing": 'editSubscription', "/profile/:name": 'profile', "/about/:name/edit": 'editDocument', "/about/new": 'newDocument', @@ -56,6 +58,7 @@ var SiteRouter = Router.extend({ "/profile": 'profile', "/profile/edit": 'editProfile', + "/profile/billing": 'editSubscription', "/profile/:name": 'profile', "/project/:name": 'projectViewer', @@ -69,6 +72,7 @@ var SiteRouter = Router.extend({ this.newProjectModal = new NewProjectModal() this.editProjectModal = new EditProjectModal() this.editProfileModal = new EditProfileModal() + this.editSubscriptionModal = new EditSubscriptionModal() this.passwordForgotModal = new PasswordForgot() this.documentModal = new DocumentModal() this.profileView = new ProfileView() @@ -195,6 +199,12 @@ var SiteRouter = Router.extend({ this.editProfileModal.load() }, + editSubscription: function(e){ + e && e.preventDefault() + window.history.pushState(null, document.title, "/profile/billing") + + this.editSubscriptionModal.load() + }, newDocument: function(e){ diff --git a/server/index.js b/server/index.js index 02fea3c..475054d 100644 --- a/server/index.js +++ b/server/index.js @@ -102,6 +102,7 @@ site.route = function () { app.get('/profile', views.profile) app.get('/profile/edit', views.profile) + app.get('/profile/billing', views.profile) app.get('/profile/:username', views.profile) app.get('/about', views.docs); diff --git a/server/lib/api/subscription.js b/server/lib/api/subscription.js index bd19127..83644cf 100644 --- a/server/lib/api/subscription.js +++ b/server/lib/api/subscription.js @@ -18,16 +18,29 @@ var subscription = module.exports = { }) }, */ - show: function(req,res){ + middleware: { + fetchAccount: function(req, res, next){ + recurly.subscriptions.listByAccount(req.user._id, function(data){ + }) + }, + }, + + // synchronise an account with recurly.. + // useful when testing locally (if webhooks do not fire) + sync: function(req, res){ + // fetch req.user._id + }, + + show: function(req, res){ // fetch from recurly }, - update: function(req,res){ + update: function(req, res){ // update plan_type on recurly // update add_ons on recurly }, - destroy: function(req,res){ + destroy: function(req, res){ // destroy on recurly }, diff --git a/server/lib/webhook/webhook.js b/server/lib/webhook/webhook.js index e9a7925..4f23d0b 100644 --- a/server/lib/webhook/webhook.js +++ b/server/lib/webhook/webhook.js @@ -134,7 +134,21 @@ var subscribe = module.exports = { }); }, + list: function(req, res){ + recurly.subscriptions.listByAccount(req.params.id, function(data){ + if (data.data != 404) { + res.json(data) + return + } + else { + res.json(data) + return + } + }) + }, + route: function(app){ app.post('/subscribe/webhook', subscribe.handle); + app.get('/subscribe/list/:id', subscribe.list); }, } diff --git a/views/about/brochure.ejs b/views/about/brochure.ejs index 1c808f8..49b03db 100644 --- a/views/about/brochure.ejs +++ b/views/about/brochure.ejs @@ -123,6 +123,9 @@ text-align: center; margin-bottom: 10px; } +.about_plan ul { + margin-bottom: 60px; +} .planbox li { list-style-type: none; margin-bottom: 5px; diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index 1f8db62..adc3f71 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -44,7 +44,6 @@ - [[ } ]] diff --git a/views/partials/scripts.ejs b/views/partials/scripts.ejs index fc94992..04bd945 100644 --- a/views/partials/scripts.ejs +++ b/views/partials/scripts.ejs @@ -95,6 +95,7 @@ + -- cgit v1.2.3-70-g09d2