summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/index.js2
-rw-r--r--server/lib/middleware.js2
-rw-r--r--server/lib/schemas/Plan.js42
-rw-r--r--server/lib/schemas/Subscription.js25
-rw-r--r--server/lib/views/index.js29
-rw-r--r--server/lib/views/staff.js231
-rw-r--r--server/lib/views/subscription.js41
-rw-r--r--server/repl.js2
8 files changed, 364 insertions, 10 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/middleware.js b/server/lib/middleware.js
index 4848ab0..797d677 100644
--- a/server/lib/middleware.js
+++ b/server/lib/middleware.js
@@ -75,7 +75,7 @@ var middleware = {
}
next()
})
- }
+ }
else {
req.project = null
next()
diff --git a/server/lib/schemas/Plan.js b/server/lib/schemas/Plan.js
new file mode 100644
index 0000000..1208672
--- /dev/null
+++ b/server/lib/schemas/Plan.js
@@ -0,0 +1,42 @@
+/* jshint node: true */
+
+var mongoose = require('mongoose'),
+ _ = require('lodash'),
+ crypto = require('crypto'),
+ config = require('../../../config.json'),
+ util = require('../util');
+
+var PlanSchema = new mongoose.Schema({
+ name: { type: String },
+ slug: { type: String },
+
+ monthly_price: { type: Number },
+ yearly_price: { type: Number },
+
+ basic_layout_monthly_price: { type: Number },
+ basic_layout_yearly_price: { type: Number },
+
+ pro_layout_monthly_price: { type: Number },
+ pro_layout_yearly_price: { type: Number },
+
+ basic_layout_limit: { type: Number },
+ pro_layout_limit: { type: Number },
+
+ stock_project_limit: { type: Number },
+ basic_project_limit: { type: Number },
+ pro_project_limit: { type: Number },
+
+ permissions: {
+ basic_editor: { type: Boolean, default: false },
+ pro_editor: { type: Boolean, default: false },
+ solids: { type: Boolean, default: false },
+ collaborators: { type: Boolean, default: false },
+ no_logo: { type: Boolean, default: false },
+ },
+
+ created_at: { type: Date, default: Date.now },
+ updated_at: { type: Date, default: Date.now },
+})
+
+module.exports = exports = mongoose.model('plan', PlanSchema);
+exports.schema = PlanSchema;
diff --git a/server/lib/schemas/Subscription.js b/server/lib/schemas/Subscription.js
new file mode 100644
index 0000000..8315009
--- /dev/null
+++ b/server/lib/schemas/Subscription.js
@@ -0,0 +1,25 @@
+/* jshint node: true */
+
+var mongoose = require('mongoose'),
+ _ = require('lodash'),
+ crypto = require('crypto'),
+ config = require('../../../config.json'),
+ util = require('../util');
+
+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 },
+ }],
+
+ created_at: { type: Date, default: Date.now },
+ updated_at: { type: Date, default: Date.now },
+})
+
+module.exports = exports = mongoose.model('subscription', SubscriptionSchema);
+exports.schema = SubscriptionSchema;
diff --git a/server/lib/views/index.js b/server/lib/views/index.js
index 8c3e63d..2a8f921 100644
--- a/server/lib/views/index.js
+++ b/server/lib/views/index.js
@@ -4,6 +4,7 @@ var User = require('../schemas/User'),
Project = require('../schemas/Project'),
Documentation = require('../schemas/Documentation'),
Collaborator = require('../schemas/Collaborator'),
+ Plan = require('../schemas/Plan'),
config = require('../../../config'),
marked = require('marked'),
util = require('../util'),
@@ -21,6 +22,7 @@ marked.setOptions({
var views = module.exports = {
staff: require('./staff'),
+ subscription: require('./subscription'),
editor_new: function (req, res) {
if (! req.user) {
@@ -88,13 +90,6 @@ var views = module.exports = {
},
home: function (req, res) {
- // while in development, blank homepage if not logged in
-/*
- if (! req.user) {
- res.send("<html></html>")
- return
- }
-*/
views_middleware.fetchProjects({ featured: true }, null, null, function(err, projects){
res.render('home', {
projects: projects || []
@@ -117,6 +112,13 @@ var views = module.exports = {
res.render('about/' + name)
return
}
+ if (name == "brochure" || name == "plans") {
+ // TODO: fetch plans
+ views_middleware.ensurePlans(req, res, function(){
+ res.render('about/' + name)
+ })
+ return
+ }
if (name == "about" || name == "index") {
res.render('about/' + name)
return
@@ -225,6 +227,19 @@ var views = module.exports = {
}
var views_middleware = {
+ ensurePlans: function(req, res, next){
+ Plan.find(function (err, plans) {
+ res.locals.plans = {}
+ plans.forEach(function(plan){
+ res.locals.plans[ plan.slug ] = plan
+ "monthly_price yearly_price basic_layout_monthly_price basic_layout_yearly_price pro_layout_monthly_price pro_layout_yearly_price".split(" ").forEach(function(key){
+ plan[key] = (plan[key]/100).toFixed(2)+""
+ })
+ })
+ next()
+ })
+ },
+
fetchProjects: function (criteria, limit, offset, next) {
limit = limit || 7
offset = offset || 0
diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js
index 49f492b..74dd7cd 100644
--- a/server/lib/views/staff.js
+++ b/server/lib/views/staff.js
@@ -4,6 +4,8 @@ var User = require('../schemas/User'),
Project = require('../schemas/Project'),
Media = require('../schemas/Media'),
Collaborator = require('../schemas/Collaborator'),
+ Plan = require('../schemas/Plan'),
+ Subscription = require('../schemas/Subscription'),
config = require('../../../config'),
middleware = require('../middleware'),
util = require('../util'),
@@ -16,6 +18,10 @@ var staff = module.exports = {
fields: {
user: "_id username displayName photo created_at updated_at last_seen created_ip last_ip",
project: "_id name slug user_id privacy created_at updated_at",
+ plans: "monthly_price yearly_price basic_layout_monthly_price basic_layout_yearly_price " +
+ "pro_layout_monthly_price pro_layout_yearly_price " +
+ "basic_layout_limit pro_layout_limit stock_project_limit basic_project_limit pro_project_limit",
+ plans_permissions: "basic_editor pro_editor solids collaborators no_logo",
},
defaults: {
@@ -119,6 +125,77 @@ var staff = module.exports = {
})
},
+ 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)
+ res.locals.plans.sort(function(a,b){ return a.monthly_price })
+ next()
+ })
+ },
+ ensurePlan: function (req, res, next) {
+ if (req.params.slug) {
+ Plan.findOne({ slug: req.params.slug }, function(err, plan){
+ if (err || ! plan) {
+ console.error(err)
+ res.redirect("/staff/plans/")
+ }
+ else {
+ req.plan = plan
+ next()
+ }
+ })
+ }
+ else {
+ res.redirect("/staff/plans/")
+ }
+ },
+
+ 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)
@@ -129,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(){
@@ -299,7 +388,21 @@ var staff = module.exports = {
media.user = {}
media.shortUrl = media.url.replace(/^http.:\/\//,"")
return media
- }
+ },
+
+ plan: function(plan){
+ plan = plan.toObject()
+ plan.date = moment( plan.updated_at || plan.created_at ).format("M/DD/YYYY hh:mm a")
+ 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){
@@ -422,7 +525,67 @@ var staff = module.exports = {
staff.media.show
);
+
+ //
+ // plans
+
+ app.get('/staff/plans',
+ middleware.ensureAuthenticated,
+ middleware.ensureIsStaff,
+
+ staff.middleware.ensurePlans,
+
+ staff.plans.index
+ );
+ app.get('/staff/plans/new',
+ middleware.ensureAuthenticated,
+ middleware.ensureIsStaff,
+
+ staff.plans.new
+ );
+ app.post('/staff/plans/new',
+ middleware.ensureAuthenticated,
+ middleware.ensureIsStaff,
+
+ staff.plans.create
+ );
+ app.get('/staff/plans/:slug',
+ middleware.ensureAuthenticated,
+ middleware.ensureIsStaff,
+
+ staff.middleware.ensurePlan,
+ staff.plans.edit
+ );
+ app.post('/staff/plans/:slug',
+ middleware.ensureAuthenticated,
+ middleware.ensureIsStaff,
+
+ staff.middleware.ensurePlan,
+
+ 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.show
+ );
},
paginate: function(req, res){
@@ -540,6 +703,70 @@ var staff = module.exports = {
res.render('staff/media/show_404')
}
},
- }
+ },
+
+ plans: {
+ index: function(req, res){
+ res.locals.fields = staff.fields.plans.split(" ")
+ res.locals.permissions = staff.fields.plans_permissions.split(" ")
+ res.render('staff/plans/index')
+ },
+ new: function(req, res){
+ res.locals.plan = new Plan ()
+ res.render('staff/plans/new')
+ },
+ edit: function(req, res){
+ res.locals.plan = req.plan
+ res.render('staff/plans/edit')
+ },
+ create: function(req, res){
+ var plan = new Plan ()
+ var fields = staff.fields.plans.split(" ")
+ var permissions = staff.fields.plans_permissions.split(" ")
+
+ var data = util.cleanQuery(req.body)
+ data.name = util.sanitize(data.name)
+ data.slug = util.sanitize(data.slug.toLowerCase())
+
+ permissions.forEach(function(field){
+ data[field] = data["permissions_" + field]
+ })
+
+ new Plan (data).save(function(err, doc){
+ if (err || ! doc) { return res.json({ error: err }) }
+ res.redirect("/staff/plans/")
+ })
+ },
+ update: function(req, res){
+ var fields = staff.fields.plans.split(" ")
+ var permissions = staff.fields.plans_permissions.split(" ")
+
+ var data = util.cleanQuery(req.body)
+ data.name = util.sanitize(data.name)
+ data.slug = util.sanitize(data.slug.toLowerCase())
+
+ _.extend(req.plan, data)
+ permissions.forEach(function(field){
+ req.plan.permissions[field] = data["permissions_" + field].length == 2
+ })
+
+ req.plan.save(function(err, doc){
+ if (err || ! doc) { return res.json({ error: err }) }
+ res.redirect("/staff/plans/")
+ })
+ },
+ },
+
+ subscriptions: {
+ index: function(req, res){
+ 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/subscriptions/show')
+ },
+ },
}
diff --git a/server/lib/views/subscription.js b/server/lib/views/subscription.js
new file mode 100644
index 0000000..e29e40d
--- /dev/null
+++ b/server/lib/views/subscription.js
@@ -0,0 +1,41 @@
+/* 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');
+
+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: {
+ },
+
+ 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
+ },
+ },
+
+ // need a route for the webhook,
+ // then calls to get appropriate info from the recurly api
+ webhook: function(req, res){
+ res.status(200).end()
+ },
+}
diff --git a/server/repl.js b/server/repl.js
index ba94d45..353d8c5 100644
--- a/server/repl.js
+++ b/server/repl.js
@@ -9,6 +9,8 @@ mongoose.connect('mongodb://' + DB_HOST + '/vvalls', {}, function(){
"./lib/schemas/Layout",
"./lib/schemas/Media",
"./lib/schemas/Project",
+ "./lib/schemas/Plan",
+ "./lib/schemas/Subscription",
].forEach(function(modName){
// console.log(name, modName)
var namez = modName.split("/"), name = namez[namez.length-1];