diff options
| author | Jules Laplace <jules@okfoc.us> | 2016-10-28 18:07:56 -0400 |
|---|---|---|
| committer | Jules Laplace <jules@okfoc.us> | 2016-10-28 18:07:56 -0400 |
| commit | a9c9d6adf470d0966e6c6bef0803e298fd2d4117 (patch) | |
| tree | 6ccec2a448992a5f43226532051a6df09afbc203 /server/lib/api | |
| parent | 343b0b3dc5bb7dbe762182a486e63a4aff6ef8fc (diff) | |
| parent | 9e7bacd46c1e5d0e1c24433690d421ab3f3a11f2 (diff) | |
merge
Diffstat (limited to 'server/lib/api')
| -rw-r--r-- | server/lib/api/blueprint.js | 142 | ||||
| -rw-r--r-- | server/lib/api/index.js | 2 | ||||
| -rw-r--r-- | server/lib/api/layouts.js | 44 | ||||
| -rw-r--r-- | server/lib/api/profile.js | 1 | ||||
| -rw-r--r-- | server/lib/api/projects.js | 18 | ||||
| -rw-r--r-- | server/lib/api/rooms.js | 139 | ||||
| -rw-r--r-- | server/lib/api/subscription.js | 206 |
7 files changed, 499 insertions, 53 deletions
diff --git a/server/lib/api/blueprint.js b/server/lib/api/blueprint.js new file mode 100644 index 0000000..e780b92 --- /dev/null +++ b/server/lib/api/blueprint.js @@ -0,0 +1,142 @@ +/* jshint node: true */ + +var _ = require('lodash'), + crypto = require('crypto'), + util = require('../util'), + upload = require('../upload'), + config = require('../../../config.json'), + Blueprint = require('../schemas/Blueprint'); + +var blueprint = { + + user: function(req, res){ + var offset = Number(req.query.offset) || 0 + var limit = Math.min( Number(req.query.limit), 50 ) || 20 + var query = { user_id: req.user._id } + if (req.query.tag) { + query.tag = req.query.tag + } + Blueprint.find(query) + .sort({'created_at': -1}) + .skip(offset) + .limit(limit) + .exec(function(err, media){ + res.json(media || []) + }) + }, + + show: function(req, res){ + Blueprint.findOne({ slug: req.params.slug }, function(err, doc){ + if (doc) { + res.json(doc) + return + } + else { + Project.count({}, function(err, count){ + var name = "Project #" + (count || 0) + res.json({ _id: "new", name: name, isNew: true }) + }) + } + }) + }, + + create: function(req, res){ + var data = util.cleanQuery(req.body) + data.user_id = req.user._id + data.created_at = new Date () + + if (data.tag) { + data.tag = util.sanitize(data.tag) + } + + new Blueprint(data).save(function(err, rec){ + if (err || ! rec) { return res.json({ error: err }) } + return res.json(rec) + }) + }, + + upload: function(req, res){ + var data = util.cleanQuery(req.body) + data.user_id = req.user._id + data.created_at = new Date () + data.type = "image" + + upload.put("media", req.files.image, { + username: req.user.username, + unacceptable: function(err){ + res.json({ error: { errors: { media: { message: "Problem saving image: " + err } } } }) + }, + success: function(url){ + data.url = url + done() + } + }) + + function done () { + new Blueprint(data).save(function(err, rec) { + if (err || ! rec) { return res.json({ error: err }) } + res.json(rec) + }) + } + }, + + scale: function(req, res){ + var _id = req.body._id + var data = util.cleanQuery(req.body) + if (! _id) { return res.json({ error: 404 }) } + Blueprint.findOne({ _id: _id }, function(err, doc){ + if (! doc) { return res.json({ error: 404 }) } + if (String(doc.user_id) !== String(req.user._id)) { return res.json({ error: 404 }) } + doc.scale = data.scale + doc.units = data.units + doc.line = data.line + doc.save(function(err, rec){ + if (err || ! rec) { return res.json({ error: err }) } + res.json(rec) + }) + }) + }, + + update: function(req, res){ + var _id = req.body._id + var data = util.cleanQuery(req.body) + if (! _id) { return res.json({ error: 404 }) } + Blueprint.findOne({ _id: _id }, function(err, doc){ + if (! doc) { return res.json({ error: 404 }) } + if (String(doc.user_id) !== String(req.user._id)) { return res.json({ error: 404 }) } + + doc.name = util.sanitize(data.name) + doc.slug = util.slugify(data.name) + doc.units = util.sanitize(data.units) + doc.viewHeight = util.sanitizeNumber(data.viewHeight) + doc.wallHeight = util.sanitizeNumber(data.wallHeight) + doc.shapes = JSON.parse(data.shapes) + doc.startPosition = JSON.parse(data.startPosition) + + doc.save(function(err, rec){ + if (err || ! rec) { return res.json({ error: err }) } + res.json(rec) + }) + }) + }, + + destroy: function(req, res){ + var _id = util.sanitize(req.body._id) + if (! _id || ! _id.length) { + res.json({ error: 404 }) + return + } + Blueprint.findOne({ _id: _id }, function(err, doc){ + if (! doc) { return res.json({ error: 404 }) } + if (String(doc.user_id) !== String(req.user._id)) { + return res.json({ error: "access denied" }) + } + Blueprint.remove({ _id: _id }, function(err){ + res.json({ status: "OK" }) + }) + }) + } + +} + +module.exports = blueprint diff --git a/server/lib/api/index.js b/server/lib/api/index.js index 11e13fc..8254232 100644 --- a/server/lib/api/index.js +++ b/server/lib/api/index.js @@ -1,6 +1,7 @@ /* jshint node: true */ var api = { + blueprint: require('./blueprint'), docs: require('./docs'), layouts: require('./layouts'), media: require('./media'), @@ -8,6 +9,7 @@ var api = { projects: require('./projects'), rooms: require('./rooms'), collaborator: require('./collaborator'), + subscription: require('./subscription'), } module.exports = api diff --git a/server/lib/api/layouts.js b/server/lib/api/layouts.js index 641e9e2..2c68f71 100644 --- a/server/lib/api/layouts.js +++ b/server/lib/api/layouts.js @@ -3,13 +3,26 @@ var _ = require('lodash'), util = require('../util'), upload = require('../upload'), + middleware = require('../middleware'), config = require('../../../config.json'), + Blueprint = require('../schemas/Blueprint'), Layout = require('../schemas/Layout'); var layouts = { index: function(req, res){ - Layout.find({}, function(err, docs){ - res.json(docs) + Layout.find({ is_stock: true }, function(err, stock_layouts){ + Layout.find({ user_id: req.user._id, is_stock: false }, function(err, user_layouts){ + Blueprint.find({ user_id: req.user._id }, function(err, blueprints){ + res.json({ + layouts: stock_layouts, + user_layouts: user_layouts, + blueprints: blueprints, + user: res.locals.user, + layoutCount: res.locals.layoutCount, + projectCount: res.locals.projectCount, + }) + }) + }) }) }, @@ -37,15 +50,24 @@ var layouts = { data.rooms = JSON.parse(data.rooms) data.startPosition = JSON.parse(data.startPosition) - upload.put("layouts", req.files.thumbnail, { - unacceptable: function(err){ - res.json({ error: { errors: { thumbnail: { message: "Problem saving thumbnail: " + err } } } }) - }, - success: function(url){ - data.photo = url - done() - } - }) + Layout.findOne({ slug: data.slug }, function(err, doc){ + if (! err || doc) { + data.slug = data.slug + "-" + Date.now() + } + do_upload() + }) + + function do_upload () { + upload.put("layouts", req.files.thumbnail, { + unacceptable: function(err){ + res.json({ error: { errors: { thumbnail: { message: "Problem saving thumbnail: " + err } } } }) + }, + success: function(url){ + data.photo = url + done() + } + }) + } function done() { new Layout(data).save(function(err, doc){ 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/api/projects.js b/server/lib/api/projects.js index 1bf046f..50d3b49 100644 --- a/server/lib/api/projects.js +++ b/server/lib/api/projects.js @@ -37,9 +37,15 @@ var projects = { data.slug = util.slugify(data.name) + "-" + (+new Date) data.description = util.sanitize(data.description) data.viewHeight = Number(data.viewHeight || 0) - data.rooms = JSON.parse(data.rooms) + if (data.shapes) { + data.shapes = JSON.parse(data.shapes) + } + else { + data.rooms = JSON.parse(data.rooms) + } data.walls = JSON.parse(data.walls) data.media = JSON.parse(data.media) + data.sculpture = JSON.parse(data.sculpture) data.colors = JSON.parse(data.colors) data.startPosition = JSON.parse(data.startPosition) data.lastPosition = JSON.parse(data.lastPosition) @@ -100,11 +106,17 @@ var projects = { data.updated_at = new Date () _.extend(doc, data) - - doc.rooms = JSON.parse(data.rooms) + + if (data.shapes) { + doc.shapes = JSON.parse(data.shapes) + } + else { + doc.rooms = JSON.parse(data.rooms) + } doc.walls = JSON.parse(data.walls) doc.colors = JSON.parse(data.colors) doc.media = JSON.parse(data.media) + doc.sculpture = JSON.parse(data.sculpture) doc.startPosition = JSON.parse(data.startPosition) doc.lastPosition = JSON.parse(data.lastPosition) diff --git a/server/lib/api/rooms.js b/server/lib/api/rooms.js index c044309..2a1d2fe 100644 --- a/server/lib/api/rooms.js +++ b/server/lib/api/rooms.js @@ -6,6 +6,8 @@ var Clipper = require("../../../public/assets/javascripts/rectangles/engine/room var Builder = require("../../../public/assets/javascripts/rectangles/engine/rooms/builder.js") var Grouper = require("../../../public/assets/javascripts/rectangles/engine/rooms/grouper.js") var Walls = require("../../../public/assets/javascripts/rectangles/engine/rooms/_walls.js") +var shapes = require("../../../public/assets/javascripts/rectangles/engine/shapes/shapelist.js") +var RegionList = require("../../../public/assets/javascripts/rectangles/engine/shapes/regionlist.js") /* jshint node: true */ @@ -21,47 +23,106 @@ var rooms = module.exports = { if (! doc) { res.json({ status: 404 }); return } doc = doc.toObject() - doc.rooms.forEach(function(data){ - var rect = new Rect(data.rect.x[0], data.rect.y[0], data.rect.x[1], data.rect.y[1]) - var room = new Room({ - id: data.id, - rect: rect, - height: data.height - }) - Rooms.add(room) - }) - Rooms.clipper.solve_rects() - Rooms.builder.build() - - var walls = [], mx_walls = [], mx_floor = [], mx_ceiling = [] - var collections = Rooms.grouper.collect() - Rooms.grouper.cull(collections) - Rooms.grouper.group(walls, collections, FRONT) - Rooms.grouper.group(walls, collections, BACK) - Rooms.grouper.group(walls, collections, LEFT) - Rooms.grouper.group(walls, collections, RIGHT) - walls.forEach(function(wall){ - wall.mx.forEach(function(mx){ - var data = mx.report() - data.id = wall.id - mx_walls.push(data) - }) - }) - - doc.mx_walls = mx_walls - doc.mx_floor = mx_floor - doc.mx_ceiling = mx_ceiling - - Rooms.forEach(function(room){ - room.mx_floor.forEach(function(mx){ - mx_floor.push( mx.report() ) - }) - room.mx_ceiling.forEach(function(mx){ - mx_ceiling.push( mx.report() ) - }) - }) + if (doc.shapes.length) { + parseMxShapes(doc) + } + else { + parseMxRooms(doc) + } res.json(doc) }) } } + +function parseMxShapes (doc) { + var viewHeight = doc.viewHeight + var wallHeight = doc.wallHeight + + shapes.deserialize( doc.shapes ) + + var walls = [], mx_walls = [], mx_floor = [], mx_ceiling = [] + var regions = RegionList.build() + + regions.forEach(function(region){ + var room = new Room({ + rect: region, + regions: [region], + height: wallHeight, + }) + + room.sides = region.sides + region.id = Rooms.uid("room_") + Rooms.list[ region.id ] = room + Rooms.builder.build_walls(region) + mx_floor.push( Rooms.builder.make_floor(room, region) ) + mx_ceiling.push( Rooms.builder.make_ceiling(room, region) ) + }) + + var collections = Rooms.grouper.collect() + Rooms.grouper.cull(collections) + Rooms.grouper.group(walls, collections, FRONT) + Rooms.grouper.group(walls, collections, BACK) + Rooms.grouper.group(walls, collections, LEFT) + Rooms.grouper.group(walls, collections, RIGHT) + walls.forEach(function(wall){ + wall.mx.forEach(function(mx){ + var data = mx.report() + data.id = wall.id + mx_walls.push(data) + }) + }) + + doc.mx_walls = mx_walls + doc.mx_floor = mx_floor + doc.mx_ceiling = mx_ceiling + + Rooms.forEach(function(room){ + mx_floor.push( room.mx_floor ) + room.mx_ceiling.forEach(function(mx){ + mx_ceiling.push( mx.report() ) + }) + }) +} + +function parseMxRooms (doc) { + doc.rooms.forEach(function(data){ + var rect = new Rect(data.rect.x[0], data.rect.y[0], data.rect.x[1], data.rect.y[1]) + var room = new Room({ + id: data.id, + rect: rect, + height: data.height + }) + Rooms.add(room) + }) + Rooms.clipper.solve_rects() + Rooms.builder.build() + + var walls = [], mx_walls = [], mx_floor = [], mx_ceiling = [] + var collections = Rooms.grouper.collect() + Rooms.grouper.cull(collections) + Rooms.grouper.group(walls, collections, FRONT) + Rooms.grouper.group(walls, collections, BACK) + Rooms.grouper.group(walls, collections, LEFT) + Rooms.grouper.group(walls, collections, RIGHT) + walls.forEach(function(wall){ + wall.mx.forEach(function(mx){ + var data = mx.report() + data.id = wall.id + mx_walls.push(data) + }) + }) + + doc.mx_walls = mx_walls + doc.mx_floor = mx_floor + doc.mx_ceiling = mx_ceiling + + Rooms.forEach(function(room){ + room.mx_floor.forEach(function(mx){ + mx_floor.push( mx.report() ) + }) + room.mx_ceiling.forEach(function(mx){ + mx_ceiling.push( mx.report() ) + }) + }) +}
\ No newline at end of file diff --git a/server/lib/api/subscription.js b/server/lib/api/subscription.js new file mode 100644 index 0000000..c2fff4c --- /dev/null +++ b/server/lib/api/subscription.js @@ -0,0 +1,206 @@ +/* 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'), + Plan = require('../schemas/Plan'); + Subscription = require('../schemas/Subscription'), + Recurly = require('node-recurly'), + recurly = new Recurly(require('../webhook/recurly-config')); + +var plan_levels = { + free: 0, + basic: 1, + pro: 2, + custom: 3, +} + +var subscription = module.exports = { + middleware: { + ensureSubscription: function(req, res, next){ + Subscription.findOne({ user_id: req.user._id }, function(err, data){ + if (err) { return next() } + req.subscription = data + next() + }) + }, + ensurePlans: function(req, res, next){ + Plan.find({}).sort({ 'level': 1 }).exec(function (err, plans) { + res.locals.plans = (plans || []) + next() + }) + }, + }, + + // synchronise an account with recurly.. + // useful when testing locally (where webhooks cannot be received) + // parses the XML from the subscription API into something usable + sync: function(req, res){ + var subscriber = req.subscription || new Subscription () + var user = req.user + recurly.subscriptions.listByAccount(req.user._id, function(recurlyRes){ + var data = recurlyRes.data + if (recurlyRes.description !== 200) { + res.json({ error: "no account" }) + return + } + var subscriptions = data.subscriptions.subscription.length ? data.subscriptions.subscription : [data.subscriptions.subscription] + var is_active = subscriptions.some(function(subscription_data){ + if (subscription_data.state == "active") { + set_active(subscription_data) + return true + } + return false + }) + if (! is_active) { + set_cancelled() + } + }) + function set_cancelled(){ + user.plan_type = "free" + user.plan_level = plan_levels["free"] + + return subscriber.remove(function(){ + user.save(function(){ + res.json({ error: "account cancelled" }) + }) + }) + } + function set_active(data){ + var plan = data.plan.plan_code.split("-") + var plan_type = plan[0] + var plan_period = plan[1] + + user.plan_type = plan_type + user.plan_level = plan_levels[plan_type] + + subscriber.uuid = data.uuid + subscriber.user_id = user._id + subscriber.plan_type = plan_type + subscriber.plan_period = plan_period + subscriber.plan_level = plan_levels[plan_type] + + var add_ons = data.subscription_add_ons.subscription_add_on + if (add_ons) { + if (add_ons.add_on_code) { + add_ons = [ add_ons ] + } + // TODO: handle multiple add-ons.. presumably this will work + add_ons.forEach(function(add_on){ + var add_on_type = add_on.add_on_code.split("-")[1] + if (add_on_type == "basic") { + subscriber.basic_layouts = parseInt( add_on.quantity._ ) + } + if (add_on_type == "pro") { + subscriber.pro_layouts = parseInt( add_on.quantity._ ) + } + }) + } + else { + subscriber.basic_layouts = 0 + subscriber.pro_layouts = 0 + } + subscriber.save(function(){ + user.save(function(){ + res.json({ + subscription: subscriber, + plans: res.locals.plans + }) + }) + }) + } + }, + + show: function(req, res){ + if (req.subscription) { + res.json({ + subscription: req.subscription, + plans: res.locals.plans + }) + } + else { + res.json({ + error: "no subscription", + plans: res.locals.plans, + }) + } + }, + + update: function(req, res){ + if (! req.subscription ) { + return res.json({ error: "no subscription" }) + } + if (! (req.body.plan_type in plan_levels)) { + return res.json({ error: "bad input" }) + } + var subscriber = req.subscription + var user = req.user + + var plan_type = req.body.plan_type + var basic_layouts = Math.max(0, parseInt(req.body.basic_layouts || 0, 10)) + var pro_layouts = Math.max(0, parseInt(req.body.pro_layouts || 0, 10)) + if (plan_type != "pro") { pro_layouts = 0 } + + if (plan_type == subscription.plan_type + && basic_layouts == subscriber.basic_layouts + && pro_layouts == subscriber.pro_layouts) { + return res.json(subscriber) + } + + var data = { subscription_add_ons: [] } + data.plan_code = plan_type + "-monthly" + + if (plan_levels[plan_type] > 0 && basic_layouts > 0) { + data.subscription_add_ons.push({ add_on_code: "extra-basic-layout", quantity: basic_layouts }) + } + + if (plan_type == "pro" && pro_layouts > 0) { + data.subscription_add_ons.push({ add_on_code: "extra-pro-layout", quantity: pro_layouts }) + } + + // data.plan_code + // data.subscription_add_ons = [] + // add_on.add_on_code + // add_on.quantity + console.log(data) + recurly.subscriptions.update(subscriber.uuid, data, function(err, data){ + console.log("got response from RECURLY ...") + if (err) { + console.log("error updating recurly subscription", err) + return res.json({ error: err }) + } + subscriber.plan_type = plan_type + subscriber.basic_layouts = basic_layouts + subscriber.pro_layouts = pro_layouts + subscriber.save(function(){ + user.plan_level = plan_levels[plan_type] + user.plan_type = plan_type + user.save(function(){ + return res.json(subscriber) + }) + }) + }) + }, + + destroy: function(req, res){ + if (! req.subscription ) { + return res.json({ error: "no subscription" }) + } + var subscriber = req.subscription + + recurly.subscriptions.terminate(subscriber.uuid, "partial", function(err, data){ + subscriber.remove(function(){ + req.user.plan_code = 0 + req.user.plan_type = "free" + req.user.save(function(){ + res.json({ status: "OK" }) + }) + }) + }) + }, + +};
\ No newline at end of file |
