From 2d4ed7d888727e1b973c2581b694d900e30c2ebd Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Wed, 7 Jan 2015 13:53:27 -0500 Subject: plan/subscription schemas --- server/lib/views/index.js | 8 +------ server/lib/views/subscription.js | 51 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 server/lib/views/subscription.js (limited to 'server/lib/views') diff --git a/server/lib/views/index.js b/server/lib/views/index.js index 8c3e63d..3326499 100644 --- a/server/lib/views/index.js +++ b/server/lib/views/index.js @@ -21,6 +21,7 @@ marked.setOptions({ var views = module.exports = { staff: require('./staff'), + subscription: require('./subscription'), editor_new: function (req, res) { if (! req.user) { @@ -88,13 +89,6 @@ var views = module.exports = { }, home: function (req, res) { - // while in development, blank homepage if not logged in -/* - if (! req.user) { - res.send("") - return - } -*/ views_middleware.fetchProjects({ featured: true }, null, null, function(err, projects){ res.render('home', { projects: projects || [] diff --git a/server/lib/views/subscription.js b/server/lib/views/subscription.js new file mode 100644 index 0000000..77db1a0 --- /dev/null +++ b/server/lib/views/subscription.js @@ -0,0 +1,51 @@ +/* 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", + project: "_id name slug user_id privacy created_at updated_at", + }, + + 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 + }, + }, + + route: function(app){ + app.get('/staff', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + staff.middleware.ensureRecentUsers, + staff.middleware.ensureUsersCount, + staff.middleware.ensureProjectsCount, + staff.middleware.ensureMediaCount, + + staff.index + ); + }, + +} -- cgit v1.2.3-70-g09d2 From 9c6f8f8568d20d75eb22955dbf2752ea777e59f8 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Wed, 7 Jan 2015 14:34:41 -0500 Subject: stub in brochure page --- public/assets/stylesheets/app.css | 14 +++++++ server/lib/schemas/Plan.js | 6 +++ server/lib/schemas/Subscription.js | 2 +- server/lib/views/index.js | 5 +++ server/lib/views/subscription.js | 1 - views/about/_blank.ejs | 2 +- views/about/about.ejs | 16 +------- views/about/brochure.ejs | 79 ++++++++++++++++++++++++++++++++++++++ views/about/howto.ejs | 2 +- views/builder.ejs | 2 +- views/docs.ejs | 2 +- views/editor.ejs | 2 +- views/home.ejs | 2 +- views/modal.ejs | 2 +- views/profile.ejs | 2 +- views/reader.ejs | 2 +- views/staff/_header.ejs | 2 +- 17 files changed, 116 insertions(+), 27 deletions(-) create mode 100644 views/about/brochure.ejs (limited to 'server/lib/views') diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index aecd6be..0463e26 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -673,7 +673,21 @@ iframe.embed { font-weight: 300; } +.aboutintro { + text-align: center; + line-height: 43px; + font-size: 24px; + padding: 5% 0; + font-weight: 300; +} +.aboutintro .inner { + max-width: 800px; + margin: 0 auto; + text-align: center; +} + /* PROFILE PAGE */ + .profilePic { background-size: cover; background-position: center; diff --git a/server/lib/schemas/Plan.js b/server/lib/schemas/Plan.js index 3e74997..1057bb2 100644 --- a/server/lib/schemas/Plan.js +++ b/server/lib/schemas/Plan.js @@ -13,6 +13,12 @@ var PlanSchema = new mongoose.Schema({ 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 }, diff --git a/server/lib/schemas/Subscription.js b/server/lib/schemas/Subscription.js index 8d0b10e..8315009 100644 --- a/server/lib/schemas/Subscription.js +++ b/server/lib/schemas/Subscription.js @@ -15,7 +15,7 @@ var SubscriptionSchema = new mongoose.Schema({ plans: [{ tier: { type: String }, monthly: { type: Boolean }, - }] + }], created_at: { type: Date, default: Date.now }, updated_at: { type: Date, default: Date.now }, diff --git a/server/lib/views/index.js b/server/lib/views/index.js index 3326499..5f9088b 100644 --- a/server/lib/views/index.js +++ b/server/lib/views/index.js @@ -111,6 +111,11 @@ var views = module.exports = { res.render('about/' + name) return } + if (name == "brochure") { + // TODO: fetch plans + res.render('about/' + name) + return + } if (name == "about" || name == "index") { res.render('about/' + name) return diff --git a/server/lib/views/subscription.js b/server/lib/views/subscription.js index 77db1a0..ba54bb4 100644 --- a/server/lib/views/subscription.js +++ b/server/lib/views/subscription.js @@ -12,7 +12,6 @@ var subscription = 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", }, defaults: { diff --git a/views/about/_blank.ejs b/views/about/_blank.ejs index 0e9ea7e..3c23fa7 100644 --- a/views/about/_blank.ejs +++ b/views/about/_blank.ejs @@ -1,7 +1,7 @@ - vvalls + VValls [[ include ../partials/meta ]] diff --git a/views/about/about.ejs b/views/about/about.ejs index dd536be..2aec982 100644 --- a/views/about/about.ejs +++ b/views/about/about.ejs @@ -1,7 +1,7 @@ - vvalls + About VValls [[ include ../partials/meta ]] @@ -50,17 +50,3 @@ [[ include ../partials/scripts ]] - \ No newline at end of file diff --git a/views/about/brochure.ejs b/views/about/brochure.ejs new file mode 100644 index 0000000..00083cf --- /dev/null +++ b/views/about/brochure.ejs @@ -0,0 +1,79 @@ + + + + VValls Subscriptions + [[ include ../partials/meta ]] + + +
+ [[ include ../partials/header ]] + +

Subscriptions

+ +
+
+ Want to get more out of VValls? Consider becoming a subscription user. +
+
+ +
+

[[- plans.free.name ]]

+
    +
  • One exhibition with pre-designed template floor plan +
+
+ +
+

[[- plans.premium.name ]]

+
    +
  • $[[- plans.premium.monthly_price ]]/mo or $[[- plans.premium.yearly_price ]]/year +
  • [[- plans.premium.stock_layout_project_limit ]] exhibitions included with pre-designed template floor plans +
  • Each new basic floor plan costs $[[- plans.premium.basic_layout_monthly_price ]]/mo + or $[[- plans.premium.basic_layout_yearly_price ]]/year, minimum 3 months +
  • Each new basic floor plan can have up to [[- plans.premium.basic_layout_project_limit ]] exhibitions +
  • VValls logo appears when embedding an exhibition on a web page +
+
+ +
+

[[- plans.pro.name ]]

+
    +
  • $[[- plans.pro.monthly_price ]]/mo or $[[- plans.pro.yearly_price ]]/year +
  • Comes with [[- plans.premium.pro_layout_limit ]] pro floor plan and [[- plans.premium.pro_layout_project_limit ]] exhibitions +
  • Each new pro floor plan costs $[[- plans.pro.pro_layout_monthly_price ]]/mo + or $[[- plans.pro.pro_layout_yearly_price ]]/year, minimum 3 months +
  • Each new pro floor plan can have up to [[- plans.pro.pro_layout_project_limit ]] exhibitions +
  • Includes planning for 3D objects in the room +
  • No VValls logo on embed +
+
+ +
+ Buying any extra floor plan unlocks collaboration. Invite an artist or curator to work on the exhibition with you. +
+ +
+ Basic Floor plan: Rectangle-based design of any dimension. +
+ +
+ Pro Floor plan: Trace an arbitrary floorplan. +
+ + +
+

Custom

+ We offer many types of customizations and white-label options for business and educational uses. + Contact us for more information +
+ + + [[ include ../partials/confirm-modal ]] + [[ include ../projects/layouts-modal ]] + [[ include ../partials/sign-in ]] + [[ include ../partials/footer ]] + +
+ +[[ include ../partials/scripts ]] + diff --git a/views/about/howto.ejs b/views/about/howto.ejs index 5278a40..914c3b3 100644 --- a/views/about/howto.ejs +++ b/views/about/howto.ejs @@ -1,7 +1,7 @@ - vvalls + How to Use VValls [[ include ../partials/meta ]] diff --git a/views/builder.ejs b/views/builder.ejs index afb8c66..0ba4238 100644 --- a/views/builder.ejs +++ b/views/builder.ejs @@ -1,7 +1,7 @@ - vvalls + VValls [[ include partials/meta ]] diff --git a/views/docs.ejs b/views/docs.ejs index b3ead82..a1f081f 100644 --- a/views/docs.ejs +++ b/views/docs.ejs @@ -1,7 +1,7 @@ - vvalls + VValls [[ include partials/meta ]] diff --git a/views/editor.ejs b/views/editor.ejs index 656615c..74e4d6d 100755 --- a/views/editor.ejs +++ b/views/editor.ejs @@ -1,7 +1,7 @@ - vvalls + VValls [[ include partials/meta ]] diff --git a/views/home.ejs b/views/home.ejs index 36fc2fc..ffb0976 100755 --- a/views/home.ejs +++ b/views/home.ejs @@ -1,7 +1,7 @@ - vvalls + VValls [[ include partials/meta ]] diff --git a/views/modal.ejs b/views/modal.ejs index 7ca869c..732953d 100644 --- a/views/modal.ejs +++ b/views/modal.ejs @@ -1,7 +1,7 @@ - vvalls + VValls [[ include partials/meta ]] diff --git a/views/profile.ejs b/views/profile.ejs index a62652c..88af6b0 100644 --- a/views/profile.ejs +++ b/views/profile.ejs @@ -1,7 +1,7 @@ - vvalls + VValls | [[- profile.displayName ]] [[ include partials/meta ]] diff --git a/views/reader.ejs b/views/reader.ejs index 6c9856a..7035356 100644 --- a/views/reader.ejs +++ b/views/reader.ejs @@ -1,7 +1,7 @@ - vvalls + VValls [[ include partials/meta ]] diff --git a/views/staff/_header.ejs b/views/staff/_header.ejs index 3bbf4f1..a73c12e 100644 --- a/views/staff/_header.ejs +++ b/views/staff/_header.ejs @@ -1,7 +1,7 @@ - vvalls | staff + VValls | staff [[ include ../partials/meta ]] -- cgit v1.2.3-70-g09d2 From 5dd9742da846e8db863a951f1502d0edf5a3f90b Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Wed, 7 Jan 2015 18:02:13 -0500 Subject: forms for editing plans --- server/lib/schemas/Plan.js | 6 +-- server/lib/views/staff.js | 22 ++++++++ views/about/brochure.ejs | 4 +- views/staff/_nav.ejs | 6 +++ views/staff/media/index.ejs | 7 +-- views/staff/media/show.ejs | 7 +-- views/staff/media/show_404.ejs | 9 +--- views/staff/plans/_form.ejs | 109 ++++++++++++++++++++++++++++++++++++++ views/staff/plans/edit.ejs | 13 +++++ views/staff/plans/index.ejs | 54 +++++++++++++++++++ views/staff/plans/new.ejs | 15 ++++++ views/staff/projects/index.ejs | 7 +-- views/staff/projects/show.ejs | 9 +--- views/staff/projects/show_404.ejs | 7 +-- views/staff/users/index.ejs | 7 +-- views/staff/users/media.ejs | 13 ++--- views/staff/users/show.ejs | 7 +-- views/staff/users/show_404.ejs | 16 +++--- 18 files changed, 244 insertions(+), 74 deletions(-) create mode 100644 views/staff/_nav.ejs create mode 100644 views/staff/plans/_form.ejs create mode 100644 views/staff/plans/edit.ejs create mode 100644 views/staff/plans/index.ejs create mode 100644 views/staff/plans/new.ejs (limited to 'server/lib/views') diff --git a/server/lib/schemas/Plan.js b/server/lib/schemas/Plan.js index 1057bb2..1208672 100644 --- a/server/lib/schemas/Plan.js +++ b/server/lib/schemas/Plan.js @@ -22,9 +22,9 @@ var PlanSchema = new mongoose.Schema({ basic_layout_limit: { type: Number }, pro_layout_limit: { type: Number }, - stock_layout_project_limit: { type: Number }, - basic_layout_project_limit: { type: Number }, - pro_layout_project_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 }, diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js index 49f492b..c3739e9 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'), @@ -540,6 +542,26 @@ var staff = module.exports = { res.render('staff/media/show_404') } }, + }, + + plans: { + index: function(req, res){ + res.locals.fields = ( + "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" + ).split(" ") + + res.locals.permissions = "basic_editor pro_editor solids collaborators no_logo".split(" ") + + res.render('staff/plans/index') + }, + new: function(req, res){ + res.render('staff/plans/new') + }, + edit: function(req, res){ + res.render('staff/plans/edit') + }, } } diff --git a/views/about/brochure.ejs b/views/about/brochure.ejs index 00083cf..d816dc4 100644 --- a/views/about/brochure.ejs +++ b/views/about/brochure.ejs @@ -35,7 +35,7 @@ -
+

[[- plans.pro.name ]]

  • $[[- plans.pro.monthly_price ]]/mo or $[[- plans.pro.yearly_price ]]/year @@ -57,7 +57,7 @@
- Pro Floor plan: Trace an arbitrary floorplan. + Pro Floor plan: Trace an arbitrary floor plan.
diff --git a/views/staff/_nav.ejs b/views/staff/_nav.ejs new file mode 100644 index 0000000..2115e9f --- /dev/null +++ b/views/staff/_nav.ejs @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/views/staff/media/index.ejs b/views/staff/media/index.ejs index 516af2d..3805c8e 100644 --- a/views/staff/media/index.ejs +++ b/views/staff/media/index.ejs @@ -2,12 +2,7 @@

Media

- +[[ include ../_nav ]]
diff --git a/views/staff/media/show.ejs b/views/staff/media/show.ejs index 76dcd32..9d05cb9 100644 --- a/views/staff/media/show.ejs +++ b/views/staff/media/show.ejs @@ -2,12 +2,7 @@

Media: [[- media.type ]]

- +[[ include ../_nav ]]
diff --git a/views/staff/media/show_404.ejs b/views/staff/media/show_404.ejs index f07cef2..c6bac6f 100644 --- a/views/staff/media/show_404.ejs +++ b/views/staff/media/show_404.ejs @@ -2,13 +2,8 @@

Media not found

- - +[[ include ../_nav ]] +
[[ include ../_footer ]] diff --git a/views/staff/plans/_form.ejs b/views/staff/plans/_form.ejs new file mode 100644 index 0000000..b97716f --- /dev/null +++ b/views/staff/plans/_form.ejs @@ -0,0 +1,109 @@ + +
+ + +
+ +
+ + +
+ + + +
+ + +
+ +
+ + +
+ + + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + + +
+ + +
+ +
+ + +
+ + + +
+ + +
+ +
+ + +
+ +
+ + +
+ + + +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ + + + diff --git a/views/staff/plans/edit.ejs b/views/staff/plans/edit.ejs new file mode 100644 index 0000000..503c97d --- /dev/null +++ b/views/staff/plans/edit.ejs @@ -0,0 +1,13 @@ +[[ include ../_header ]] + +

Edit Plan

+ +[[ include ../_nav ]] + +
+ +
+[[- include form ]] +
+ +[[ include ../_footer ]] diff --git a/views/staff/plans/index.ejs b/views/staff/plans/index.ejs new file mode 100644 index 0000000..aa6c35a --- /dev/null +++ b/views/staff/plans/index.ejs @@ -0,0 +1,54 @@ +[[ include ../_header ]] + +

Plans

+ +[[ include ../_nav ]] + +
+ + + + + [[ plans.forEach(function(plan){ ]] + + [[ }) ]] + + + + + [[ plans.forEach(function(plan){ ]] + + [[ }) ]] + + + [[ fields.forEach(function(field){ ]] + + + [[ plans.forEach(function(plan){ ]] + + [[ }) ]] + + [[ }) ]] + + [[ permissions.forEach(function(permission){ ]] + + + [[ plans.forEach(function(plan){ ]] + + [[ }) ]] + + [[ }) ]] + +
+ [[- plan.name ]] +
+ edit +
[[- field.replace(/_/," ") ]] + [[- plan[field] ]] +
[[- permission.replace(/_/," ") ]] + [[- plan.permissions[permission] ? "x" : " " ]] +
+ +
+ +[[ include ../_footer ]] diff --git a/views/staff/plans/new.ejs b/views/staff/plans/new.ejs new file mode 100644 index 0000000..d56a1c3 --- /dev/null +++ b/views/staff/plans/new.ejs @@ -0,0 +1,15 @@ +[[ include ../_header ]] + +

New Plan

+ +[[ include ../_nav ]] + +
+ +
+[[- include form ]] +
+ +[[ include ../_footer ]] + + diff --git a/views/staff/projects/index.ejs b/views/staff/projects/index.ejs index 482ea25..e4ba469 100644 --- a/views/staff/projects/index.ejs +++ b/views/staff/projects/index.ejs @@ -2,12 +2,7 @@

Projects

- +[[ include ../_nav ]]
diff --git a/views/staff/projects/show.ejs b/views/staff/projects/show.ejs index 1034b31..b090a41 100644 --- a/views/staff/projects/show.ejs +++ b/views/staff/projects/show.ejs @@ -2,13 +2,8 @@

[[- project.name ]]

- - +[[ include ../_nav ]] +
diff --git a/views/staff/projects/show_404.ejs b/views/staff/projects/show_404.ejs index 70320c0..f5e1658 100644 --- a/views/staff/projects/show_404.ejs +++ b/views/staff/projects/show_404.ejs @@ -2,12 +2,7 @@

Project not found

- +[[ include ../_nav ]]
diff --git a/views/staff/users/index.ejs b/views/staff/users/index.ejs index f14d666..1795dde 100644 --- a/views/staff/users/index.ejs +++ b/views/staff/users/index.ejs @@ -2,12 +2,7 @@

Users

- +[[ include ../_nav ]]
diff --git a/views/staff/users/media.ejs b/views/staff/users/media.ejs index c1097dd..8927c00 100644 --- a/views/staff/users/media.ejs +++ b/views/staff/users/media.ejs @@ -1,15 +1,10 @@ [[ include ../_header ]] -

User Media: [[- profile.username ]]

+

User Media: [[- profile.username ]]

- - -
+[[ include ../_nav ]] + +
[[ include ../_pagination ]] [[ include ../_gallery ]] diff --git a/views/staff/users/show.ejs b/views/staff/users/show.ejs index 8e9b447..4ce1d9a 100644 --- a/views/staff/users/show.ejs +++ b/views/staff/users/show.ejs @@ -1,12 +1,7 @@ [[ include ../_header ]]

User: [[- profile.username ]]

- +[[ include ../_nav ]]
diff --git a/views/staff/users/show_404.ejs b/views/staff/users/show_404.ejs index bcd0271..11663fa 100644 --- a/views/staff/users/show_404.ejs +++ b/views/staff/users/show_404.ejs @@ -1,13 +1,9 @@ [[ include ../_header ]] -

User not found

- - - -
+ +

User not found

+ +[[ include ../_nav ]] + +
[[ include ../_footer ]] -- cgit v1.2.3-70-g09d2 From 190a145cf1433fde570df1ac9784d4c5cea77d3d Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Wed, 7 Jan 2015 18:28:46 -0500 Subject: everything but saving --- server/lib/middleware.js | 2 +- server/lib/views/staff.js | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) (limited to 'server/lib/views') 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/views/staff.js b/server/lib/views/staff.js index c3739e9..ce676ed 100644 --- a/server/lib/views/staff.js +++ b/server/lib/views/staff.js @@ -120,6 +120,31 @@ var staff = module.exports = { next() }) }, + + ensurePlans: function(req, res, next){ + Plan.exec(function (err, plans) { + res.locals.plans = plans.map(staff.helpers.plan) + 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) + req.plan = null + } + else { + req.plan = plan + } + next() + }) + } + else { + req.plan = null + next() + } + }, ensureRecentProjects: function(req, res, next){ var dreq = { params: { sort: 'created_at', limit: 20, offset: 0 } } @@ -424,7 +449,43 @@ 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.plans.update + ); }, paginate: function(req, res){ @@ -557,11 +618,18 @@ var staff = module.exports = { res.render('staff/plans/index') }, new: function(req, res){ + res.locals.plan = new Plan () res.render('staff/plans/new') }, edit: function(req, res){ res.render('staff/plans/edit') }, + create: function(req, res){ + res.redirect("/staff/plans/") + }, + update: function(req, res){ + res.redirect("/staff/plans/") + }, } } -- cgit v1.2.3-70-g09d2 From 664099f91ae3ed2d667d331b19c2e41dec60124c Mon Sep 17 00:00:00 2001 From: Julie Lala Date: Fri, 9 Jan 2015 06:43:31 -0500 Subject: fix up plans form --- public/assets/stylesheets/app.css | 6 +- public/assets/stylesheets/staff.css | 16 ++++ server/lib/views/staff.js | 70 ++++++++++++---- server/repl.js | 2 + views/staff/_nav.ejs | 1 + views/staff/index.ejs | 6 +- views/staff/plans/_form.ejs | 160 ++++++++++++++++++++++-------------- views/staff/plans/edit.ejs | 2 +- views/staff/plans/index.ejs | 11 ++- views/staff/plans/new.ejs | 4 +- 10 files changed, 186 insertions(+), 92 deletions(-) (limited to 'server/lib/views') diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index 0463e26..9e86ac3 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -2478,7 +2478,7 @@ form li { form label { float:left; } -form input[type="text"],form input[type="password"] { +form input[type="text"],form input[type="password"],form input[type="number"] { border: 1px solid; font-size: 20px; padding: 5px; @@ -3048,8 +3048,8 @@ a[data-role="forgot-password"] { form li { font-size: 16px; } - form input[type="text"], form input[type="password"] { - font-size: 15px; + form input[type="text"],form input[type="password"],form input[type="number"] { + font-size: 15px; } .page h1 { font-size: 26px; diff --git a/public/assets/stylesheets/staff.css b/public/assets/stylesheets/staff.css index de31571..e5cafa2 100644 --- a/public/assets/stylesheets/staff.css +++ b/public/assets/stylesheets/staff.css @@ -71,6 +71,22 @@ hr { color: #00f; border-bottom: 1px solid; } +.staff form { + max-width: none; + width: 600px; + padding: 20px; +} +.staff form label { + float: none; +} +.staff form p { + width: 350px; + margin: 5px 0; + color: #444; +} +.staff form div li { + width: 180px; +} #iframe-embed, #iframe-embed tr, #iframe-embed td { width: 79vw; } diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js index ce676ed..6639137 100644 --- a/server/lib/views/staff.js +++ b/server/lib/views/staff.js @@ -18,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: { @@ -122,8 +126,8 @@ var staff = module.exports = { }, ensurePlans: function(req, res, next){ - Plan.exec(function (err, plans) { - res.locals.plans = plans.map(staff.helpers.plan) + Plan.find(function (err, plans) { + res.locals.plans = (plans || []).map(staff.helpers.plan) next() }) }, @@ -132,17 +136,16 @@ var staff = module.exports = { Plan.findOne({ slug: req.params.slug }, function(err, plan){ if (err || ! plan) { console.error(err) - req.plan = null + res.redirect("/staff/plans/") } else { req.plan = plan + next() } - next() }) } else { - req.plan = null - next() + res.redirect("/staff/plans/") } }, @@ -326,7 +329,14 @@ 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 + }, }, route: function(app){ @@ -452,7 +462,8 @@ var staff = module.exports = { // // plans - app.get('/staff/plans/', + + app.get('/staff/plans', middleware.ensureAuthenticated, middleware.ensureIsStaff, @@ -484,6 +495,8 @@ var staff = module.exports = { middleware.ensureAuthenticated, middleware.ensureIsStaff, + staff.middleware.ensurePlan, + staff.plans.update ); }, @@ -607,14 +620,8 @@ var staff = module.exports = { plans: { index: function(req, res){ - res.locals.fields = ( - "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" - ).split(" ") - - res.locals.permissions = "basic_editor pro_editor solids collaborators no_logo".split(" ") - + res.locals.fields = staff.fields.plans.split(" ") + res.locals.permissions = staff.fields.plans_permissions.split(" ") res.render('staff/plans/index') }, new: function(req, res){ @@ -625,10 +632,37 @@ var staff = module.exports = { res.render('staff/plans/edit') }, create: function(req, res){ - res.redirect("/staff/plans/") + 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){ - res.redirect("/staff/plans/") + 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[field] = data["permissions_" + field] + }) + + req.plan.save(function(err, doc){ + if (err || ! doc) { return res.json({ error: err }) } + res.redirect("/staff/plans/") + }) }, } 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]; diff --git a/views/staff/_nav.ejs b/views/staff/_nav.ejs index 2115e9f..db7bedb 100644 --- a/views/staff/_nav.ejs +++ b/views/staff/_nav.ejs @@ -3,4 +3,5 @@ users projects media + plans \ No newline at end of file diff --git a/views/staff/index.ejs b/views/staff/index.ejs index 5ca7269..1b73641 100644 --- a/views/staff/index.ejs +++ b/views/staff/index.ejs @@ -2,11 +2,7 @@

Staff Area

- + [[ include _nav ]]
diff --git a/views/staff/plans/_form.ejs b/views/staff/plans/_form.ejs index b97716f..fc86516 100644 --- a/views/staff/plans/_form.ejs +++ b/views/staff/plans/_form.ejs @@ -1,109 +1,149 @@ + -
+
    + +
  • +

    New Plan

    +
  • + +
  • - -
+
+ -
+
  • - -
  • +
    + -
    +
  • +

    Plan Pricing

    +
  • + +
  • - -
  • +
    + -
    +
  • - -
  • +
    + + +

    + Note: Pricing should be in cents, i.e. a price of $10.00 should be entered as 1000. +

    -
    - - -
    +
  • +

    Additional Template Pricing

    +
  • -
    - - -
    +
  • + +
    +
  • -
    - - -
    +
  • + +
    +
  • -
    - - -
    +
  • + +
    +
  • + +
  • + +
    +
  • -
    - - -
    +
  • +

    Per-Plan Template Limits

    +
  • -
    - - -
    +
  • + +
    +
  • + +
  • + +
    +
  • -
    +
  • +

    Per-Plan Project Limits

    +
  • + +
  • - -
  • +
    + -
    +
  • - -
  • +
    + -
    +
  • - -
  • +
    + +
  • +

    Permissions

    +
  • +
    - +
  • -
  • + + -
    - +
  • -
  • + + -
    - +
  • -
  • + + -
    - +
  • -
  • + + -
    - +
  • -
  • + + + +

    + These permissions should harmonize with the restrictions on layouts set above. +

    + - +
  • + +
  • + diff --git a/views/staff/plans/edit.ejs b/views/staff/plans/edit.ejs index 503c97d..9848873 100644 --- a/views/staff/plans/edit.ejs +++ b/views/staff/plans/edit.ejs @@ -7,7 +7,7 @@
    -[[- include form ]] +[[- include _form ]] [[ include ../_footer ]] diff --git a/views/staff/plans/index.ejs b/views/staff/plans/index.ejs index aa6c35a..121a2fc 100644 --- a/views/staff/plans/index.ejs +++ b/views/staff/plans/index.ejs @@ -6,6 +6,7 @@
    +[[ if (plans.length) { ]]
    @@ -30,7 +31,11 @@ [[ plans.forEach(function(plan){ ]] [[ }) ]] @@ -46,8 +51,10 @@ [[ }) ]] [[ }) ]] -
    [[- field.replace(/_/," ") ]] - [[- plan[field] ]] + [[ if (field.indexOf("_price") != -1) { ]] + [[- plan[field] == 0 ? "" : "$" + (plan[field]/100).toFixed(2) ]] + [[ } else { ]] + [[- plan[field] ]] + [[ } ]]
    +
    +[[ } ]] + New Plan
    diff --git a/views/staff/plans/new.ejs b/views/staff/plans/new.ejs index d56a1c3..297d3d6 100644 --- a/views/staff/plans/new.ejs +++ b/views/staff/plans/new.ejs @@ -7,9 +7,7 @@
    -[[- include form ]] +[[- include _form ]]
    [[ include ../_footer ]] - - -- cgit v1.2.3-70-g09d2 From b386c3b88034e4e372f147ffd368c2de1d23a865 Mon Sep 17 00:00:00 2001 From: Julie Lala Date: Fri, 9 Jan 2015 07:28:43 -0500 Subject: saving plans --- public/assets/stylesheets/staff.css | 2 +- server/lib/views/staff.js | 6 +++++- views/staff/plans/_form.ejs | 10 +++++----- views/staff/plans/index.ejs | 34 +++++++++++++++++++--------------- 4 files changed, 30 insertions(+), 22 deletions(-) (limited to 'server/lib/views') diff --git a/public/assets/stylesheets/staff.css b/public/assets/stylesheets/staff.css index e5cafa2..fffadbf 100644 --- a/public/assets/stylesheets/staff.css +++ b/public/assets/stylesheets/staff.css @@ -67,7 +67,7 @@ hr { .staff .body a { border-bottom: 1px dotted; } -.staff .editLinks a { +.staff .editLinks a, .staff a.bluelink { color: #00f; border-bottom: 1px solid; } diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js index 6639137..2fdc2c3 100644 --- a/server/lib/views/staff.js +++ b/server/lib/views/staff.js @@ -629,6 +629,7 @@ var staff = module.exports = { res.render('staff/plans/new') }, edit: function(req, res){ + res.locals.plan = req.plan res.render('staff/plans/edit') }, create: function(req, res){ @@ -650,13 +651,16 @@ var staff = module.exports = { }) }, 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[field] = data["permissions_" + field] + req.plan.permissions[field] = data["permissions_" + field].length == 2 }) req.plan.save(function(err, doc){ diff --git a/views/staff/plans/_form.ejs b/views/staff/plans/_form.ejs index fc86516..ae5ca5a 100644 --- a/views/staff/plans/_form.ejs +++ b/views/staff/plans/_form.ejs @@ -107,31 +107,31 @@
  • - +
  • - +
  • - +
  • - +
  • - +
  • diff --git a/views/staff/plans/index.ejs b/views/staff/plans/index.ejs index 121a2fc..16fcf14 100644 --- a/views/staff/plans/index.ejs +++ b/views/staff/plans/index.ejs @@ -6,31 +6,33 @@
    -[[ if (plans.length) { ]] - - [[ plans.forEach(function(plan){ ]] + [[ plans.forEach(function(plan){ ]] + [[ }) ]] - - - [[ plans.forEach(function(plan){ ]] + + [[ plans.forEach(function(plan){ ]] + [[ }) ]] [[ fields.forEach(function(field){ ]] - + [[ plans.forEach(function(plan){ ]] - [[ }) ]] + + + + [[ permissions.forEach(function(permission){ ]] - + [[ plans.forEach(function(plan){ ]] - [[ }) ]] [[ }) ]]
    - [[- plan.name ]] + + [[- plan.name ]]
    [[- field.replace(/_/," ") ]][[- field.replace(/_/g," ") ]] + [[ if (field.indexOf("_price") != -1) { ]] [[- plan[field] == 0 ? "" : "$" + (plan[field]/100).toFixed(2) ]] [[ } else { ]] @@ -41,20 +43,22 @@
    [[- permission.replace(/_/," ") ]][[- permission.replace(/_/g," ") ]] - [[- plan.permissions[permission] ? "x" : " " ]] + + [[- plan.permissions[permission] ? "x" : " " ]]

    -[[ } ]] - New Plan
    -- cgit v1.2.3-70-g09d2 From 372b8eb7f2a34902c72f5a831404070b5bd761c1 Mon Sep 17 00:00:00 2001 From: Julie Lala Date: Fri, 9 Jan 2015 07:53:23 -0500 Subject: edit brochure --- server/lib/views/index.js | 20 ++++++++++++++++++-- views/about/brochure.ejs | 12 ++++++------ 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'server/lib/views') diff --git a/server/lib/views/index.js b/server/lib/views/index.js index 5f9088b..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'), @@ -111,9 +112,11 @@ var views = module.exports = { res.render('about/' + name) return } - if (name == "brochure") { + if (name == "brochure" || name == "plans") { // TODO: fetch plans - res.render('about/' + name) + views_middleware.ensurePlans(req, res, function(){ + res.render('about/' + name) + }) return } if (name == "about" || name == "index") { @@ -224,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/views/about/brochure.ejs b/views/about/brochure.ejs index d816dc4..4ce558a 100644 --- a/views/about/brochure.ejs +++ b/views/about/brochure.ejs @@ -19,7 +19,7 @@

    [[- plans.free.name ]]

      -
    • One exhibition with pre-designed template floor plan +
    • [[- plans.free.stock_project_limit ]] exhibition with pre-designed template floor plan
    @@ -27,10 +27,10 @@

    [[- plans.premium.name ]]

    • $[[- plans.premium.monthly_price ]]/mo or $[[- plans.premium.yearly_price ]]/year -
    • [[- plans.premium.stock_layout_project_limit ]] exhibitions included with pre-designed template floor plans +
    • [[- plans.premium.stock_project_limit ]] exhibitions included with pre-designed template floor plans
    • Each new basic floor plan costs $[[- plans.premium.basic_layout_monthly_price ]]/mo or $[[- plans.premium.basic_layout_yearly_price ]]/year, minimum 3 months -
    • Each new basic floor plan can have up to [[- plans.premium.basic_layout_project_limit ]] exhibitions +
    • Each new basic floor plan can have up to [[- plans.premium.basic_project_limit ]] exhibitions
    • VValls logo appears when embedding an exhibition on a web page
    @@ -39,10 +39,10 @@

    [[- plans.pro.name ]]

    • $[[- plans.pro.monthly_price ]]/mo or $[[- plans.pro.yearly_price ]]/year -
    • Comes with [[- plans.premium.pro_layout_limit ]] pro floor plan and [[- plans.premium.pro_layout_project_limit ]] exhibitions +
    • Comes with [[- plans.premium.pro_layout_limit ]] pro floor plan and [[- plans.premium.pro_project_limit ]] exhibitions
    • Each new pro floor plan costs $[[- plans.pro.pro_layout_monthly_price ]]/mo or $[[- plans.pro.pro_layout_yearly_price ]]/year, minimum 3 months -
    • Each new pro floor plan can have up to [[- plans.pro.pro_layout_project_limit ]] exhibitions +
    • Each new pro floor plan can have up to [[- plans.pro.pro_project_limit ]] exhibitions
    • Includes planning for 3D objects in the room
    • No VValls logo on embed
    @@ -57,7 +57,7 @@
    - Pro Floor plan: Trace an arbitrary floor plan. + Pro Floor plan: Trace an arbitrary floor plan from image.
    -- cgit v1.2.3-70-g09d2 From 63d8dd85a47c20d3c9bad963d7845d4d5b1c2e2e Mon Sep 17 00:00:00 2001 From: Julie Lala Date: Fri, 9 Jan 2015 08:23:35 -0500 Subject: very light styling on brochure page --- server/lib/views/staff.js | 1 + views/about/brochure.ejs | 122 +++++++++++++++++++++++++++++----------------- 2 files changed, 77 insertions(+), 46 deletions(-) (limited to 'server/lib/views') diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js index 2fdc2c3..97ecde6 100644 --- a/server/lib/views/staff.js +++ b/server/lib/views/staff.js @@ -128,6 +128,7 @@ var staff = module.exports = { 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() }) }, diff --git a/views/about/brochure.ejs b/views/about/brochure.ejs index 4ce558a..75e7b60 100644 --- a/views/about/brochure.ejs +++ b/views/about/brochure.ejs @@ -13,58 +13,54 @@
    Want to get more out of VValls? Consider becoming a subscription user. +

    -
    -
    -

    [[- plans.free.name ]]

    -
      -
    • [[- plans.free.stock_project_limit ]] exhibition with pre-designed template floor plan -
    -
    +
    +

    [[- plans.free.name ]]

    +
      +
    • [[- plans.free.stock_project_limit ]] exhibition with pre-designed template floor plan +
    +
    -
    -

    [[- plans.premium.name ]]

    -
      -
    • $[[- plans.premium.monthly_price ]]/mo or $[[- plans.premium.yearly_price ]]/year -
    • [[- plans.premium.stock_project_limit ]] exhibitions included with pre-designed template floor plans -
    • Each new basic floor plan costs $[[- plans.premium.basic_layout_monthly_price ]]/mo - or $[[- plans.premium.basic_layout_yearly_price ]]/year, minimum 3 months -
    • Each new basic floor plan can have up to [[- plans.premium.basic_project_limit ]] exhibitions -
    • VValls logo appears when embedding an exhibition on a web page -
    -
    +
    +

    [[- plans.basic.name ]]

    +
      +
    • $[[- plans.basic.monthly_price ]]/mo or $[[- plans.basic.yearly_price ]]/year +
    • [[- plans.basic.stock_project_limit ]] exhibitions included with pre-designed template floor plans +
    • Each new basic floor plan costs $[[- plans.basic.basic_layout_monthly_price ]]/mo + or $[[- plans.basic.basic_layout_yearly_price ]]/year, minimum 3 months +
    • Each new basic floor plan can have up to [[- plans.basic.basic_project_limit ]] exhibitions +
    • VValls logo appears when embedding an exhibition on a web page +
    +
    -
    -

    [[- plans.pro.name ]]

    -
      -
    • $[[- plans.pro.monthly_price ]]/mo or $[[- plans.pro.yearly_price ]]/year -
    • Comes with [[- plans.premium.pro_layout_limit ]] pro floor plan and [[- plans.premium.pro_project_limit ]] exhibitions -
    • Each new pro floor plan costs $[[- plans.pro.pro_layout_monthly_price ]]/mo - or $[[- plans.pro.pro_layout_yearly_price ]]/year, minimum 3 months -
    • Each new pro floor plan can have up to [[- plans.pro.pro_project_limit ]] exhibitions -
    • Includes planning for 3D objects in the room -
    • No VValls logo on embed -
    -
    +
    +

    [[- plans.pro.name ]]

    +
      +
    • $[[- plans.pro.monthly_price ]]/mo or $[[- plans.pro.yearly_price ]]/year +
    • Comes with [[- plans.pro.pro_layout_limit ]] pro floor plan and [[- plans.pro.pro_project_limit ]] exhibitions +
    • Each new pro floor plan costs $[[- plans.pro.pro_layout_monthly_price ]]/mo + or $[[- plans.pro.pro_layout_yearly_price ]]/year, minimum 3 months +
    • Each new pro floor plan can have up to [[- plans.pro.pro_project_limit ]] exhibitions +
    • Includes planning for 3D objects in the room +
    • No VValls logo on embed +
    +
    -
    - Buying any extra floor plan unlocks collaboration. Invite an artist or curator to work on the exhibition with you. -
    - -
    - Basic Floor plan: Rectangle-based design of any dimension. -
    - -
    - Pro Floor plan: Trace an arbitrary floor plan from image. -
    - +
    +
      +
    • Buying any extra floor plan unlocks collaboration. Invite an artist or curator to work on the exhibition with you. +
    • Basic Floor plan: Rectangle-based design of any dimension. +
    • Pro Floor plan: Trace an arbitrary floor plan from image. +
    +
    -
    -

    Custom

    - We offer many types of customizations and white-label options for business and educational uses. - Contact us for more information +
    +

    Custom

    +
  • We offer customized white-label options for business and educational uses. +
  • Contact us for more information. +
  • @@ -77,3 +73,37 @@ [[ include ../partials/scripts ]] + \ No newline at end of file -- cgit v1.2.3-70-g09d2 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 (limited to 'server/lib/views') 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(-)
    
    (limited to 'server/lib/views')
    
    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(-)
    
    (limited to 'server/lib/views')
    
    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(-)
    
    (limited to 'server/lib/views')
    
    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(-)
    
    (limited to 'server/lib/views')
    
    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 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(-)
    
    (limited to 'server/lib/views')
    
    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(-)
    
    (limited to 'server/lib/views')
    
    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 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
    
    (limited to 'server/lib/views')
    
    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 5adac681bdb43b8b709795fa501689fb9ae8a4e1 Mon Sep 17 00:00:00 2001
    From: Jules Laplace 
    Date: Wed, 28 Jan 2015 19:18:27 -0500
    Subject: many methods
    
    ---
     package.json                        |   1 +
     server/lib/api/subscription.js      | 124 ++++++++++++++++++++++++++++++++----
     server/lib/middleware.js            |   2 +-
     server/lib/schemas/Subscription.js  |   6 +-
     server/lib/views/staff.js           |   2 +-
     server/lib/webhook/webhook.js       |   2 +-
     views/about/brochure.ejs            |  15 +++--
     views/partials/header.ejs           |   1 +
     views/staff/_users.ejs              |   1 +
     views/staff/plans/_form.ejs         |   5 ++
     views/staff/subscriptions/index.ejs |   2 +-
     views/staff/users/show.ejs          |   1 +
     12 files changed, 135 insertions(+), 27 deletions(-)
    
    (limited to 'server/lib/views')
    
    diff --git a/package.json b/package.json
    index 8afb96e..e89fcd9 100644
    --- a/package.json
    +++ b/package.json
    @@ -15,6 +15,7 @@
         "express-subdomains": "0.0.5",
         "html-entities": "~1.0.10",
         "intro.js": "^0.9.0",
    +    "js2xml": "^1.0.0",
         "knox": "~0.8.10",
         "lodash": "~2.4.1",
         "marked": "~0.3.2",
    diff --git a/server/lib/api/subscription.js b/server/lib/api/subscription.js
    index 83644cf..40aa715 100644
    --- a/server/lib/api/subscription.js
    +++ b/server/lib/api/subscription.js
    @@ -9,7 +9,22 @@ var _ = require('lodash'),
     	Layout = require('../schemas/Layout'),
     	Subscription = require('../schemas/Subscription');
     
    +var plan_levels = {
    +  free: 0,
    +  basic: 1,
    +  pro: 2,
    +}
    +
     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()
    +      })
    +    },
    +  }
     
     /*
     	index: function(req, res){
    @@ -18,30 +33,115 @@ var subscription = module.exports = {
     		})
     	},
     */
    -  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)
    +  // useful when testing locally (where webhooks cannot be received)
       sync: function(req, res){
    -    // fetch req.user._id
    +    var subscriber = req.subscription || new Subscription ()
    +    var user = req.user
    +    recurly.subscriptions.listByAccount(req.user._id, function(data){
    +      if (data.description !== 200) {
    +        res.json({ error: "no account" })
    +        return
    +      }
    +      if (! data.subscriptions.subscription) {
    +        res.json({ error: "account error" })
    +        return
    +      }
    +
    +      var plan = data.subscriptions.subscription.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.subscriptions.subscription.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.subscriptions.subscription.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.render(subscriber)
    +        })
    +      })
    +    })
       },
     
       show: function(req, res){
    -    // fetch from recurly
    +    res.json(req.subscription || { error: "no subscription" })
       },
       
       update: function(req, res){
    -    // update plan_type on recurly
    -    // update add_ons on recurly
    +    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
    +    
    +    // change..
    +    // data.plan_code
    +    // data.subscription_add_ons = []
    +    //   add_on.add_on_code
    +    //   add_on.quantity
    +    var basic_layouts = max(0, parseInt(req.body.basic_layouts))
    +    var pro_layouts = max(0, parseInt(req.body.pro_layouts))
    +
    +    var data = {}
    +    data.plan_code = req.body.plan_type + "_monthly"
    +    data.subscription_add_ons = []
    +    
    +    if (plan_levels[req.body.plan_type]) {
    +      data.subscription_add_ons.push({ add_on_code: "extra-basic-layout", quantity: basic_layouts })
    +    }
    +    
    +    if (req.body.plan_type == "pro") {
    +      data.subscription_add_ons.push({ add_on_code: "extra-pro-layout", quantity: pro_layouts })
    +    }
    +    
    +    
    +    recurly.subscriptions.update(subscriber.uuid, data, function(){
    +      return res.json(subscriber)
    +    })
       },
       
       destroy: function(req, res){
    -    // destroy on recurly
    +    if (! req.subscription ) {
    +      return res.json({ error: "no subscription" })
    +    }
    +    var subscriber = req.subscription
    +
    +    recurly.subscriptions.cancel(subscriber.uuid, function(){
    +      subscriber.remove(function(){
    +        req.user.plan_code = 0
    +        req.user.plan_type = "free"
    +      })
    +    })
       },
     
     };
    \ No newline at end of file
    diff --git a/server/lib/middleware.js b/server/lib/middleware.js
    index 797d677..7dfe821 100644
    --- a/server/lib/middleware.js
    +++ b/server/lib/middleware.js
    @@ -59,7 +59,7 @@ var middleware = {
     		res.locals.opt = {}
     		next()
     	},
    -	
    +  
     	ensureProject: function (req, res, next) {
     		if (req.params.slug) {
     			Project.findOne({ slug: req.params.slug }, function(err, project){
    diff --git a/server/lib/schemas/Subscription.js b/server/lib/schemas/Subscription.js
    index b766555..24c5096 100644
    --- a/server/lib/schemas/Subscription.js
    +++ b/server/lib/schemas/Subscription.js
    @@ -13,10 +13,8 @@ var SubscriptionSchema = new mongoose.Schema({
     	plan_period: { type: String, default: "monthly" },
     
     	subscription_uuid: { type: String },
    -	subscription_add_ons: [{
    -		name: { type: String },
    -		quantity: { type: Number },
    -	}],
    +	basic_layouts: { type: Number, default: 0 },
    +	pro_layouts: { type: Number, default: 0 },
     	
     	history: [{
     	  action: { type: String },
    diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js
    index 74dd7cd..67193fe 100644
    --- a/server/lib/views/staff.js
    +++ b/server/lib/views/staff.js
    @@ -154,7 +154,7 @@ var staff = module.exports = {
         },
     
         ensurePlans: function(req, res, next){
    -      Plan.find(function (err, plans) {
    +      Plan.find({}).sort({ 'level': -1 }).exec(function (err, plans) {
             res.locals.plans = (plans || []).map(staff.helpers.plan)
             res.locals.plans.sort(function(a,b){ return a.monthly_price })
             next()
    diff --git a/server/lib/webhook/webhook.js b/server/lib/webhook/webhook.js
    index 4f23d0b..a871a3a 100644
    --- a/server/lib/webhook/webhook.js
    +++ b/server/lib/webhook/webhook.js
    @@ -149,6 +149,6 @@ var subscribe = module.exports = {
     	
     	route: function(app){
     		app.post('/subscribe/webhook', subscribe.handle);
    -		app.get('/subscribe/list/:id', subscribe.list);
    +		app.get('/subscribe/list/:id', subscribe.middleware.ensureSubscription, subscribe.list);
     	},
     }
    diff --git a/views/about/brochure.ejs b/views/about/brochure.ejs
    index 49b03db..1dad763 100644
    --- a/views/about/brochure.ejs
    +++ b/views/about/brochure.ejs
    @@ -34,12 +34,11 @@
             
  • VValls logo appears when embedding an exhibition on a web page
  • [[ if (! logged_in) { ]] - - [[ } else if (! user.plan_level || user.plan_level < plan.level) { ]] - + + [[ } else if (! user.plan_level) { ]] + [[ } else if (user.plan_level == plan.level) { ]] Current Level - [[ } else { ]] [[ } ]] @@ -56,11 +55,13 @@
  • No VValls logo on embed
  • [[ if (! logged_in) { ]] - - [[ } else if (! user.plan_level || user.plan_level < plan.level) { ]] - + + [[ } else if (! user.plan_level) { ]] + [[ } else if (user.plan_level == plan.level) { ]] Current Level + [[ } else if (user.plan_level < plan.level) { ]] + [[ } ]] diff --git a/views/partials/header.ejs b/views/partials/header.ejs index ce5bab9..2acf2bc 100644 --- a/views/partials/header.ejs +++ b/views/partials/header.ejs @@ -64,6 +64,7 @@ [[ if (profile && String(user._id) == String(profile._id)) { ]] Settings + Subscription [[ } else if (! profile) { ]] Profile [[ } ]] diff --git a/views/staff/_users.ejs b/views/staff/_users.ejs index d46058f..053e289 100644 --- a/views/staff/_users.ejs +++ b/views/staff/_users.ejs @@ -12,6 +12,7 @@ [view profile] + [recurly] [[- user.last_seen ]] diff --git a/views/staff/plans/_form.ejs b/views/staff/plans/_form.ejs index ae5ca5a..b55c5cd 100644 --- a/views/staff/plans/_form.ejs +++ b/views/staff/plans/_form.ejs @@ -16,6 +16,11 @@
  • +
  • + +
    +
  • +
  • diff --git a/views/staff/subscriptions/index.ejs b/views/staff/subscriptions/index.ejs index d1c0588..3efffb5 100644 --- a/views/staff/subscriptions/index.ejs +++ b/views/staff/subscriptions/index.ejs @@ -1,6 +1,6 @@ [[ include ../_header ]] -

    Users

    +

    Subscriptions

    [[ include ../_nav ]] diff --git a/views/staff/users/show.ejs b/views/staff/users/show.ejs index 4ce1d9a..d6a21d5 100644 --- a/views/staff/users/show.ejs +++ b/views/staff/users/show.ejs @@ -19,6 +19,7 @@ [view profile] [view media] + [view on recurly] -- cgit v1.2.3-70-g09d2 From d86d15c60c06843f8f22cdcf5b809c3a48e6a628 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 30 Jan 2015 17:05:15 -0500 Subject: plans partial, min on number fields --- .../javascripts/ui/site/EditSubscriptionModal.js | 32 +++--- public/assets/stylesheets/app.css | 60 ++++++++++- server/index.js | 2 + server/lib/api/subscription.js | 10 +- server/lib/views/index.js | 9 ++ views/about/brochure.ejs | 113 +-------------------- views/partials/edit-subscription.ejs | 17 ++-- views/staff/plans/_form.ejs | 24 ++--- 8 files changed, 114 insertions(+), 153 deletions(-) (limited to 'server/lib/views') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index 8952e42..d5eb9ac 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -47,22 +47,28 @@ var EditSubscriptionModal = ModalFormView.extend({ basic: 1, pro: 2, }, + + sync: function(){ + $.put(this.syncAction, this.didLoad.bind(this)) + }, loaded: false, load: function(){ this.reset() if (this.loaded) { return this.show() } - $.get(this.action, function(data){ - this.loaded = true - if (data.subscriber) { - this.subscriber = data.subscription - this.plans = data.plans - } - else if (data.error) { - // ...no subscription found - } - return this.show() - }.bind(this)) + $.get(this.action, this.didLoad.bind(this)) + }, + didLoad: function(data){ + this.loaded = true + this.plans = data.plans + if (data.subscription) { + this.subscriber = data.subscription + } + else if (data.error) { + // ...no subscription found + this.subscriber = null + } + return this.show() }, show: function(){ @@ -122,20 +128,18 @@ var EditSubscriptionModal = ModalFormView.extend({ type: "put", data: { _csrf: this.$csrf.val() }, success: function(data){ - window.location.href = "/profile" } }) }, destroy: function(){ - var msg = "Are you sure you want to cancel your subscription " + sanitize(this.$name.val()) + "?" + var msg = "Are you sure you want to cancel your subscription?" ConfirmModal.confirm(msg, function(){ $.ajax({ url: this.destroyAction, type: "delete", data: { _csrf: this.$csrf.val() }, success: function(data){ - window.location.href = "/profile" } }) }.bind(this)) diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index 0ce2c5e..5d7199c 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -156,7 +156,7 @@ a{ display: none; border-right:0px!important; } -.editProfile, .profileLink { +.profileLink { border-right:0px!important; } .editing #help-button { @@ -849,6 +849,7 @@ iframe.embed { } + .projectList.about.gopro { padding:6% 0; } @@ -900,6 +901,57 @@ iframe.embed { background:black; color:white; } + +/* PLANS BROCHURE */ +/* nb these styles should be fixed for narrower screens/mobile layout */ +.about_plan { + width: 28vw; + margin: 2vw; + float: left; + min-height: 28vw; + position: relative; +} +.about_plan button { + position: absolute; + bottom: 5%; + left: 5%; + width: 90%; +} +.about_custom { + clear: both; + width: 76vw; + margin: 2vw 10vw; +} +.planbox { + padding: 2vw; + border: 1px solid #ddd; + background: white; + border-radius: 25px; + font-size: 15px; + line-height: 23px; + text-align: center; +} +.planbox h3 { + text-align: center; + margin-bottom: 10px; +} +.about_plan ul { + margin-bottom: 60px; +} +.planbox li { + list-style-type: none; + margin-bottom: 5px; +} +.planbox.miscbox { + border: 0; + background: #f8f8f8; +} +.about_custom a { + border-bottom: 1px solid; +} + +/* LAYOUTS MODAL */ + .templates { overflow: auto; max-height: 100%; @@ -918,8 +970,8 @@ iframe.embed { } .templates::-webkit-scrollbar-thumb { -background-color: white; -border-left: 1px solid black; + background-color: white; + border-left: 1px solid black; } .templates::-webkit-scrollbar-track { @@ -990,6 +1042,8 @@ border-left: 1px solid black; float:right; } +/* MX SCENE STUFF */ + .mx-scene { position:fixed; top:0; diff --git a/server/index.js b/server/index.js index 2f6cb2d..fa7044b 100644 --- a/server/index.js +++ b/server/index.js @@ -156,6 +156,8 @@ site.route = function () { app.put('/api/subscription', middleware.ensureAuthenticated, api.subscription.middleware.ensureSubscription, api.subscription.update) app.delete('/api/subscription', middleware.ensureAuthenticated, api.subscription.middleware.ensureSubscription, api.subscription.destroy) + app.get('/partials/plans', views.partials.plans) + app.get('/test/*', middleware.ensureAuthenticated, middleware.ensureIsStaff, views.modal) views.staff.route(app) diff --git a/server/lib/api/subscription.js b/server/lib/api/subscription.js index 9478d78..b7b3434 100644 --- a/server/lib/api/subscription.js +++ b/server/lib/api/subscription.js @@ -84,7 +84,10 @@ var subscription = module.exports = { subscriber.save(function(){ user.save(function(){ - res.render(subscriber) + res.render({ + subscription: req.subscription, + plans: res.locals.plans + }) }) }) }) @@ -98,7 +101,10 @@ var subscription = module.exports = { }) } else { - res.json({ error: "no subscription" }) + res.json({ + error: "no subscription", + plans: res.locals.plans, + }) } }, diff --git a/server/lib/views/index.js b/server/lib/views/index.js index 0ce0357..89167f7 100644 --- a/server/lib/views/index.js +++ b/server/lib/views/index.js @@ -104,6 +104,15 @@ var views = module.exports = { }) }, + partials: { + plans: function (req, res){ + views_middleware.ensurePlans(req, res, function(){ + console.log("<<<<
    -
    -

    [[- plans.free.name ]]

    -
      -
    • [[- plans.free.stock_project_limit ]] exhibition with pre-designed template floor plan -
    -
    - -
    -

    [[- plans.basic.name ]]

    -
      -
    • $[[- plans.basic.monthly_price ]]/mo or $[[- plans.basic.yearly_price ]]/year -
    • Comes with [[- plans.basic.basic_layout_limit ]] basic floor plan and [[- plans.basic.basic_project_limit ]] exhibitions -
    • Each new basic floor plan costs $[[- plans.basic.basic_layout_monthly_price ]]/mo - or $[[- plans.basic.basic_layout_yearly_price ]]/year, minimum 3 months -
    • 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 (! user.plan_level) { ]] - - [[ } else if (user.plan_level == plan.level) { ]] - Current Level - [[ } ]] -
    -
    - -
    -

    [[- plans.pro.name ]]

    -
      -
    • $[[- plans.pro.monthly_price ]]/mo or $[[- plans.pro.yearly_price ]]/year -
    • Comes with [[- plans.pro.pro_layout_limit ]] pro floor plan and [[- plans.pro.pro_project_limit ]] exhibitions -
    • Each new pro floor plan costs $[[- plans.pro.pro_layout_monthly_price ]]/mo - or $[[- plans.pro.pro_layout_yearly_price ]]/year, minimum 3 months -
    • Each new pro floor plan can have up to [[- plans.pro.pro_project_limit ]] exhibitions -
    • Includes planning for 3D objects in the room -
    • No VValls logo on embed -
    • - [[ if (! logged_in) { ]] - - [[ } else if (! user.plan_level) { ]] - - [[ } else if (user.plan_level == plan.level) { ]] - Current Level - [[ } else if (user.plan_level < plan.level) { ]] - - [[ } ]] -
    -
    - -
    -
      -
    • Buying any extra floor plan unlocks collaboration. Invite an artist or curator to work on the exhibition with you. -
    • Basic Floor plan: Rectangle-based design of any dimension. -
    • Pro Floor plan: Trace an arbitrary floor plan from image. -
    -
    - -
    -

    Want Something Custom?

    -
  • We offer customized white-label options for business and educational uses. -
  • Contact us for more information. - + [[ include _plans ]] - [[ include ../partials/confirm-modal ]] [[ include ../projects/layouts-modal ]] [[ include ../partials/sign-in ]] @@ -91,51 +28,3 @@ [[ include ../partials/scripts ]] - \ No newline at end of file diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index bb7cc27..2f6e4c1 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -7,15 +7,14 @@
  • Edit Subscription

  • -
    - You are currently using the free plan. For access to all of Vvalls features, +
  • + You are currently using the free version of Vvalls. For access to all of Vvalls features, consider upgrading to a paid plan. -

    - View the Plans -

  • - + +
    +

    [[- plans.basic.name ]]

    +
      +
    • $[[- plans.basic.monthly_price ]]/mo or $[[- plans.basic.yearly_price ]]/year +
    • Comes with [[- plans.basic.basic_layout_limit ]] basic floor plan and [[- plans.basic.basic_project_limit ]] exhibitions +
    • Each new basic floor plan costs $[[- plans.basic.basic_layout_monthly_price ]]/mo + or $[[- plans.basic.basic_layout_yearly_price ]]/year, minimum 3 months +
    • 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 (! user.plan_level) { ]] + + [[ } else if (user.plan_level == plan.level) { ]] + Current Level + [[ } ]] +
    +
    + +
    +

    [[- plans.pro.name ]]

    +
      +
    • $[[- plans.pro.monthly_price ]]/mo or $[[- plans.pro.yearly_price ]]/year +
    • Comes with [[- plans.pro.pro_layout_limit ]] pro floor plan and [[- plans.pro.pro_project_limit ]] exhibitions +
    • Each new pro floor plan costs $[[- plans.pro.pro_layout_monthly_price ]]/mo + or $[[- plans.pro.pro_layout_yearly_price ]]/year, minimum 3 months +
    • Each new pro floor plan can have up to [[- plans.pro.pro_project_limit ]] exhibitions +
    • Includes planning for 3D objects in the room +
    • No VValls logo on embed +
    • + [[ if (! logged_in) { ]] + + [[ } else if (! user.plan_level) { ]] + + [[ } else if (user.plan_level == plan.level) { ]] + Current Level + [[ } else if (user.plan_level < plan.level) { ]] + + [[ } ]] +
    +
    + +
    +
      +
    • Buying any extra floor plan unlocks collaboration.
      Invite an artist or curator to work on the exhibition with you. +
    • Basic Floor plan: Rectangle-based design of any dimension. +
    • Pro Floor plan: Trace an arbitrary floor plan from image. +
    +
    + +
    +

    Want Something Custom?

    +
  • We offer customized white-label options for business and educational uses. +
  • Contact us for more information. +
  • diff --git a/views/partials/edit-subscription.ejs b/views/partials/edit-subscription.ejs index 2f6e4c1..cc296f6 100644 --- a/views/partials/edit-subscription.ejs +++ b/views/partials/edit-subscription.ejs @@ -1,19 +1,19 @@
    X
    -
    +
    • Edit Subscription

    • -
    • +
    • You are currently using the free version of Vvalls. For access to all of Vvalls features, consider upgrading to a paid plan.

      - +
    • -
    • Your current plan level is diff --git a/views/staff/_users.ejs b/views/staff/_users.ejs index 053e289..46811b6 100644 --- a/views/staff/_users.ejs +++ b/views/staff/_users.ejs @@ -12,7 +12,8 @@ + [[ }) ]]
      [[- user.last_seen ]] -- cgit v1.2.3-70-g09d2 From b9ad0704417aaa8cf4da7a1ec2109959622bd454 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Mon, 2 Feb 2015 11:31:31 -0500 Subject: setting up staging env --- server/lib/views/staff.js | 3 ++- views/staff/plans/_form.ejs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'server/lib/views') diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js index 67193fe..c3ecc97 100644 --- a/server/lib/views/staff.js +++ b/server/lib/views/staff.js @@ -728,8 +728,9 @@ var staff = module.exports = { data.name = util.sanitize(data.name) data.slug = util.sanitize(data.slug.toLowerCase()) + data.permissions = {} permissions.forEach(function(field){ - data[field] = data["permissions_" + field] + data.permissions[field] = data["permissions_" + field].length == 2 }) new Plan (data).save(function(err, doc){ diff --git a/views/staff/plans/_form.ejs b/views/staff/plans/_form.ejs index 0240e56..61be7e8 100644 --- a/views/staff/plans/_form.ejs +++ b/views/staff/plans/_form.ejs @@ -100,7 +100,7 @@
    • - +
    • -- cgit v1.2.3-70-g09d2 From 03842d65cc018f9a718b2408d19e978f3d08e042 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Mon, 2 Feb 2015 13:23:51 -0500 Subject: sanity --- server/lib/views/index.js | 2 +- server/lib/webhook/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'server/lib/views') diff --git a/server/lib/views/index.js b/server/lib/views/index.js index 9f244c8..be46cc6 100644 --- a/server/lib/views/index.js +++ b/server/lib/views/index.js @@ -107,7 +107,7 @@ var views = module.exports = { partials: { plans: function (req, res){ views_middleware.ensurePlans(req, res, function(){ - res.render('about/_plans') + res.render('about/_plans', { logged_in: res.locals.logged_in || false }) }) }, }, diff --git a/server/lib/webhook/index.js b/server/lib/webhook/index.js index 11419c2..798e4be 100644 --- a/server/lib/webhook/index.js +++ b/server/lib/webhook/index.js @@ -37,7 +37,7 @@ site.ready = function(){ console.log('Webhook server listening on port ' + app.get('port')); }); - app.get('/', function(req,res){ res.send('HI THERE') }) + app.get('/', function(req,res){ res.send('hello@vvalls.com') }) webhook.route(app) } -- cgit v1.2.3-70-g09d2 From ca838d172cbd7fca1f2cba3bb1f095821710920a Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Mon, 2 Feb 2015 17:53:16 -0500 Subject: userlist sort --- public/assets/stylesheets/staff.css | 14 ++++++++++++++ server/lib/views/staff.js | 4 +++- views/staff/_users.ejs | 13 +++++++++++++ views/staff/users/show.ejs | 31 ++++++++++++++++++++++++++++--- 4 files changed, 58 insertions(+), 4 deletions(-) (limited to 'server/lib/views') diff --git a/public/assets/stylesheets/staff.css b/public/assets/stylesheets/staff.css index fffadbf..d93e46e 100644 --- a/public/assets/stylesheets/staff.css +++ b/public/assets/stylesheets/staff.css @@ -30,6 +30,15 @@ nav { nav a { margin-left: 10px; } +nav.subnav { + background: white; + padding: 10px; + font-weight: 200; + font-size: 12px; +} +.alphabet a { + margin-left: 5px; +} hr { border: 1px solid #bbb; margin: 10px auto 10px; @@ -62,8 +71,13 @@ hr { user-select: none; } .staff { + background: white; font-size: 15px; } +.staff hr { + border: 1px solid black; + border-top: 0; +} .staff .body a { border-bottom: 1px dotted; } diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js index c3ecc97..b772859 100644 --- a/server/lib/views/staff.js +++ b/server/lib/views/staff.js @@ -368,8 +368,10 @@ var staff = module.exports = { helpers: { user: function(user){ + var last_seen = moment( user.last_seen || user.updated_at || user.created_at ) user = user.toObject() - user.last_seen = moment( user.last_seen || user.updated_at || user.created_at ).fromNow() + user.last_seen = last_seen.format("YYYY/MM/DD HH:MM") + " " + last_seen.fromNow() + user.last_charged = user.last_charged && moment( user.last_charged ).format("YYYY/MM/DD HH:MM") user.created_ip = util.num2ip( user.created_ip ) user.last_ip = util.num2ip( user.last_ip ) return user diff --git a/views/staff/_users.ejs b/views/staff/_users.ejs index 46811b6..1af47aa 100644 --- a/views/staff/_users.ejs +++ b/views/staff/_users.ejs @@ -1,9 +1,22 @@ + + [[ users.forEach(function(user){ ]] + diff --git a/views/staff/users/show.ejs b/views/staff/users/show.ejs index d6a21d5..e441109 100644 --- a/views/staff/users/show.ejs +++ b/views/staff/users/show.ejs @@ -17,13 +17,38 @@ [[- profile.displayName ]]
      + [[- user.plan_type ]] + [[- user.last_charged ]] + [[- user.username ]]
      + + [[ if (profile.subscription) { ]] +

      Subscription

      + + + + + + + + + +
      + plan + + [[- profile.plan_type ]] +
      + last charged + + [[- profile.last_charged ]] +
      + [[ } ]] +

      Profile

      -- cgit v1.2.3-70-g09d2 From 1169b347c1f339b64f30466004a3f9a06ef7e117 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Mon, 2 Feb 2015 18:16:09 -0500 Subject: find users by initial --- public/assets/stylesheets/staff.css | 8 ++++++++ server/lib/views/staff.js | 12 ++++++++++++ views/staff/_users.ejs | 10 ++++++++-- 3 files changed, 28 insertions(+), 2 deletions(-) (limited to 'server/lib/views') diff --git a/public/assets/stylesheets/staff.css b/public/assets/stylesheets/staff.css index d93e46e..ebc240a 100644 --- a/public/assets/stylesheets/staff.css +++ b/public/assets/stylesheets/staff.css @@ -39,6 +39,14 @@ nav.subnav { .alphabet a { margin-left: 5px; } +.body .error { + color: #f00; + border: 1px solid #f00; + margin: 20px 5px 200px 5px; + padding: 10px; + width: 400px; + display: inline-block; +} hr { border: 1px solid #bbb; margin: 10px auto 10px; diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js index b772859..07050f1 100644 --- a/server/lib/views/staff.js +++ b/server/lib/views/staff.js @@ -38,6 +38,7 @@ var staff = module.exports = { 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 initial = util.sanitize(req.query.initial) var sort paginationInfo.sort = req.query.sort paginationInfo.sortOptions = ["date", "last_seen", "username"] @@ -54,6 +55,9 @@ var staff = module.exports = { paginationInfo.sort = "username" break } + if (initial) { + criteria.username = new RegExp('^' + initial, "i") + } User.find(criteria) .select(staff.fields.user) .sort(sort) @@ -61,6 +65,14 @@ var staff = module.exports = { .limit(limit) .exec(function (err, users) { res.locals.users = users.map(staff.helpers.user) + if (! res.locals.users.length) { + if (initial) { + res.locals.opt.error = "No users found starting with " + initial.toUpperCase() + "" + } + else { + res.locals.opt.error = "No users found" + } + } next() }) }, diff --git a/views/staff/_users.ejs b/views/staff/_users.ejs index 1af47aa..9caf893 100644 --- a/views/staff/_users.ejs +++ b/views/staff/_users.ejs @@ -1,12 +1,18 @@ +[[ if (! users.length || opt.error) { ]] +
      + [[- opt.error ]] +
      +[[ } ]] +
      [[ users.forEach(function(user){ ]] -- cgit v1.2.3-70-g09d2 From 8ae88bc8540c0b2265748cb0df452c0370630289 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Mon, 20 Jul 2015 14:53:38 -0400 Subject: show plans on homepage --- server/lib/views/index.js | 16 ++++++++++------ views/about/_plans.ejs | 6 +++--- views/home.ejs | 15 ++++++--------- 3 files changed, 19 insertions(+), 18 deletions(-) (limited to 'server/lib/views') diff --git a/server/lib/views/index.js b/server/lib/views/index.js index be46cc6..5241ddb 100644 --- a/server/lib/views/index.js +++ b/server/lib/views/index.js @@ -89,17 +89,21 @@ var views = module.exports = { }, home: function (req, res) { - views_middleware.fetchProjects({ featured: true }, null, null, function(err, projects){ - res.render('home', { - projects: projects || [] + views_middleware.ensurePlans(req, res, function(err){ + views_middleware.fetchProjects({ featured: true }, null, null, function(err, projects){ + res.render('home', { + projects: projects || [], + }) }) }) }, demoHome: function (req, res) { - views_middleware.fetchProjects({ featured: true }, null, null, function(err, projects){ - res.render('home', { - projects: projects || [] + views_middleware.ensurePlans(req, res, function(err){ + views_middleware.fetchProjects({ featured: true }, null, null, function(err, projects){ + res.render('home', { + projects: projects || [], + }) }) }) }, diff --git a/views/about/_plans.ejs b/views/about/_plans.ejs index af2a050..ba42e28 100644 --- a/views/about/_plans.ejs +++ b/views/about/_plans.ejs @@ -1,4 +1,3 @@ -
      +

      Want Something Custom?

    • We offer customized white-label options for business and educational uses. diff --git a/views/home.ejs b/views/home.ejs index b83e3e9..2bf5662 100755 --- a/views/home.ejs +++ b/views/home.ejs @@ -62,15 +62,12 @@ [[ include projects/list-projects ]] -
      - - -

      Ready To Go Pro?

      - Use VValls as part of your product, service, or marketing campaign. - We offer many types of customizations, including automation of layouts, more elaborate floor plans, enhanced video, interactivity, and other features. - Contact -
      -
      +

      Sign Up

      + +
      + [[ include about/_plans ]] +
      + [[ include partials/confirm-modal ]] [[ include projects/layouts-modal ]] [[ include partials/sign-in ]] -- cgit v1.2.3-70-g09d2 From f84ea4bf323f99479298f0576006267bf4182632 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Thu, 6 Aug 2015 17:50:55 -0400 Subject: pass thru plans --- public/assets/stylesheets/staff.css | 2 +- server/index.js | 2 ++ server/lib/middleware.js | 14 ++++++++++++-- server/lib/views/staff.js | 9 ++++++++- 4 files changed, 23 insertions(+), 4 deletions(-) (limited to 'server/lib/views') diff --git a/public/assets/stylesheets/staff.css b/public/assets/stylesheets/staff.css index ebc240a..7ae4a1e 100644 --- a/public/assets/stylesheets/staff.css +++ b/public/assets/stylesheets/staff.css @@ -45,7 +45,7 @@ nav.subnav { margin: 20px 5px 200px 5px; padding: 10px; width: 400px; - display: inline-block; + display: block; } hr { border: 1px solid #bbb; diff --git a/server/index.js b/server/index.js index 4926a94..30cf69a 100644 --- a/server/index.js +++ b/server/index.js @@ -82,6 +82,8 @@ site.setup = function(){ // var io = websocket.listen(server) // auth.initSockets(io, SessionStore) + + middleware.updatePlans() } site.route = function () { diff --git a/server/lib/middleware.js b/server/lib/middleware.js index 7dfe821..35c520c 100644 --- a/server/lib/middleware.js +++ b/server/lib/middleware.js @@ -6,11 +6,14 @@ var passport = require('passport'), config = require('../../config.json'), User = require('./schemas/User'), Collaborator = require('./schemas/Collaborator'), - Project = require('./schemas/Project'); + Project = require('./schemas/Project'), + Plan = require('./schemas/Plan'); var middleware = { + plans: [], + enableCORS: function (req, res, next) { res.header('Access-Control-Allow-Credentials', true); // TODO Check https vs. http @@ -46,7 +49,7 @@ var middleware = { }, ensureLocals: function (req, res, next) { - res.locals.token = req.csrfToken(); + res.locals.token = req.csrfToken() res.locals.logged_in = req.isAuthenticated() res.locals.user = req.user || { _id: undefined } res.locals.config = config @@ -56,6 +59,7 @@ var middleware = { res.locals.ogUrl = "http://vvalls.com/" res.locals.ogDescription = "3D gallery space, fully customizable" res.locals.ogAuthor = "VValls" + res.locals.plans = plans res.locals.opt = {} next() }, @@ -106,6 +110,12 @@ var middleware = { }) } }, + + updatePlans: function(){ + Plan.find({}).sort({ 'level': -1 }).exec(function (err, plans) { + middleware.plans = plans.map(function(plan){ return plan.toObject() }) + }) + }, } diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js index 07050f1..19b361d 100644 --- a/server/lib/views/staff.js +++ b/server/lib/views/staff.js @@ -56,7 +56,12 @@ var staff = module.exports = { break } if (initial) { - criteria.username = new RegExp('^' + initial, "i") + if (initial == "?") { + criteria.username = new RegExp('^[$a-zA-Z]', "i") + } + else { + criteria.username = new RegExp('^' + initial, "i") + } } User.find(criteria) .select(staff.fields.user) @@ -749,6 +754,7 @@ var staff = module.exports = { new Plan (data).save(function(err, doc){ if (err || ! doc) { return res.json({ error: err }) } + middleware.updatePlans() res.redirect("/staff/plans/") }) }, @@ -767,6 +773,7 @@ var staff = module.exports = { req.plan.save(function(err, doc){ if (err || ! doc) { return res.json({ error: err }) } + middleware.updatePlans() res.redirect("/staff/plans/") }) }, -- cgit v1.2.3-70-g09d2 From 33e5644226649d277c6b84dc37fccdd5b7c6e86c Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 7 Aug 2015 12:23:35 -0400 Subject: more accurate counts --- public/assets/javascripts/ui/site/LayoutsModal.js | 10 ++-- server/lib/api/layouts.js | 4 +- server/lib/middleware.js | 60 +++++++++++++++++++++-- server/lib/schemas/Plan.js | 2 +- server/lib/schemas/Project.js | 1 + server/lib/views/staff.js | 45 ++++++++++++++++- views/staff/_nav.ejs | 1 + views/staff/plans/_form.ejs | 6 +-- views/staff/projects/index.ejs | 2 +- 9 files changed, 113 insertions(+), 18 deletions(-) (limited to 'server/lib/views') diff --git a/public/assets/javascripts/ui/site/LayoutsModal.js b/public/assets/javascripts/ui/site/LayoutsModal.js index 639d55c..f69b38f 100644 --- a/public/assets/javascripts/ui/site/LayoutsModal.js +++ b/public/assets/javascripts/ui/site/LayoutsModal.js @@ -16,13 +16,15 @@ var LayoutsIndex = View.extend({ populate: function(data){ /* - if (data.layoutCount > data.plan.basic_layout_limit) { + if (data.layoutCounts.basic > data.plan.basic_layout_limit) { } - if (data.projectCount > data.plan.stock_project_limit) { + if (data.layoutCounts.pro > data.plan.pro_layout_limit) { } - if (data.projectCount > data.plan.basic_project_limit) { + if (data.projectCounts.stock > data.plan.stock_project_limit) { } - if (data.projectCount > data.plan.pro_project_limit) { + if (data.projectCounts.basic > data.plan.basic_project_limit) { + } + if (data.projectCounts.pro > data.plan.pro_project_limit) { } */ if (! data.layouts.length) { diff --git a/server/lib/api/layouts.js b/server/lib/api/layouts.js index 7e7976c..1c87fae 100644 --- a/server/lib/api/layouts.js +++ b/server/lib/api/layouts.js @@ -16,8 +16,8 @@ var layouts = { layouts: docs, plan: middleware.plans[ res.locals.user.plan_level || 0 ], user: res.locals.user, - layoutCount: res.locals.layoutCount, - projectCount: res.locals.projectCount, + layoutCounts: res.locals.layoutCounts, + projectCounts: res.locals.projectCounts, }) }) }, diff --git a/server/lib/middleware.js b/server/lib/middleware.js index 9d09a10..fe4dc49 100644 --- a/server/lib/middleware.js +++ b/server/lib/middleware.js @@ -60,20 +60,48 @@ var middleware = { res.locals.ogUrl = "http://vvalls.com/" res.locals.ogDescription = "3D gallery space, fully customizable" res.locals.ogAuthor = "VValls" - res.locals.plans = plans + res.locals.plans = middleware.plans res.locals.opt = {} next() }, ensureUserProjectsCount: function(req, res, next){ - Project.count({ user_id: req.user.id }, function(err, count){ - res.locals.projectCount = count || 0 + var counts = { stock: 0, basic: 0, pro: 0 } + res.locals.projectCounts = counts + Project.count({ user_id: req.user.id, layout_type: 0 }, function(err, count){ + res.locals.projectCounts.stock = count || 0 + if (req.user.plan_level > 0) { return middleware.ensureBasicProjectsCount(req, res, next) } + else next() + }) + }, + ensureBasicProjectsCount: function(req, res, next){ + Project.count({ user_id: req.user.id, layout_type: 1 }, function(err, count){ + res.locals.projectCounts.basic = count || 0 + if (req.user.plan_level > 1) { return middleware.ensureProProjectsCount(req, res, next) } + else next() + }) + }, + ensureProProjectsCount: function(req, res, next){ + Project.count({ user_id: req.user.id, layout_type: 2 }, function(err, count){ + res.locals.projectCounts.pro = count || 0 next() }) }, + ensureUserLayoutsCount: function(req, res, next){ - Layout.count({ user_id: req.user.id }, function(err, count){ - res.locals.layoutCount = count || 0 + var counts = { basic: 0, pro: 0 } + res.locals.layoutCounts = counts + if (req.user.plan_level == 0) { return next() } + + Layout.count({ user_id: req.user.id, layout_type: 1 }, function(err, count){ + res.locals.layoutCounts.basic = count || 0 + if (req.user.plan_level > 1) { return middleware.ensureProLayoutsCount(req, res, next) } + else next() + }) + }, + ensureProLayoutsCount: function(req, res, next){ + Project.count({ user_id: req.user.id, layout_type: 2 }, function(err, count){ + res.locals.layoutCounts.pro = count || 0 next() }) }, @@ -100,6 +128,28 @@ var middleware = { } }, + ensureLayout: function (req, res, next) { + if (req.params.slug) { + Layout.findOne({ slug: req.params.slug }, function(err, layout){ + if (err) { + console.error(err) + req.layout = null + } + else if (! project) { + req.layout = null + } + else { + req.layout = layout + } + next() + }) + } + else { + req.layout = null + next() + } + }, + ensureIsCollaborator: function(req, res, next) { req.isCollaborator = false req.isOwner = false diff --git a/server/lib/schemas/Plan.js b/server/lib/schemas/Plan.js index 8a19b99..388ce69 100644 --- a/server/lib/schemas/Plan.js +++ b/server/lib/schemas/Plan.js @@ -31,7 +31,7 @@ var PlanSchema = new mongoose.Schema({ permissions: { basic_editor: { type: Boolean, default: false }, pro_editor: { type: Boolean, default: false }, - solids: { type: Boolean, default: false }, + sculpture: { type: Boolean, default: false }, collaborators: { type: Boolean, default: false }, no_logo: { type: Boolean, default: false }, }, diff --git a/server/lib/schemas/Project.js b/server/lib/schemas/Project.js index e9501fc..855d95a 100644 --- a/server/lib/schemas/Project.js +++ b/server/lib/schemas/Project.js @@ -39,6 +39,7 @@ var ProjectSchema = new mongoose.Schema({ created_at: { type: Date }, updated_at: { type: Date }, featured: { type: Boolean, default: false }, + layout_type: { type: Number, default: 0 }, }); module.exports = exports = mongoose.model('project', ProjectSchema); diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js index 19b361d..6c97bbd 100644 --- a/server/lib/views/staff.js +++ b/server/lib/views/staff.js @@ -21,7 +21,7 @@ var staff = module.exports = { 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", + plans_permissions: "basic_editor pro_editor sculpture collaborators no_logo", }, defaults: { @@ -401,6 +401,13 @@ var staff = module.exports = { return project }, + layout: function(layout){ + layout = layout.toObject() + layout.date = moment( layout.updated_at || layout.created_at ).format("M/DD/YYYY hh:mm a") + layout.user = {} + return layout + }, + media: function(media){ media = media.toObject() media.date = moment( media.updated_at || media.created_at ).format("M/DD/YYYY hh:mm a") @@ -520,7 +527,41 @@ var staff = module.exports = { staff.projects.feature ); - + + // + // layouts + + app.get('/staff/layouts', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + staff.middleware.ensureLayoutsCount, + + staff.middleware.ensureLayouts, + staff.middleware.ensureLayoutsUsers, + + staff.layouts.index + ); + app.get('/staff/layouts/:slug', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + middleware.ensureLayout, + staff.middleware.ensureLayout, + staff.middleware.ensureLayoutUser, + + staff.layouts.show + ); + app.put('/staff/layouts/:slug/feature', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + middleware.ensureLayout, + staff.middleware.ensureLayout, + + staff.layouts.make_stock + ); + // // media diff --git a/views/staff/_nav.ejs b/views/staff/_nav.ejs index a607638..3bb3b08 100644 --- a/views/staff/_nav.ejs +++ b/views/staff/_nav.ejs @@ -2,6 +2,7 @@ home users projects + layouts media plans diff --git a/views/staff/plans/_form.ejs b/views/staff/plans/_form.ejs index 61be7e8..85375fa 100644 --- a/views/staff/plans/_form.ejs +++ b/views/staff/plans/_form.ejs @@ -124,9 +124,9 @@
    • - - - + + +
    • diff --git a/views/staff/projects/index.ejs b/views/staff/projects/index.ejs index e4ba469..1d309ce 100644 --- a/views/staff/projects/index.ejs +++ b/views/staff/projects/index.ejs @@ -7,7 +7,7 @@
      [[ include ../_pagination ]] -[[ include ../_projects ]] +[[ include ../_layouts ]] [[ include ../_pagination ]] [[ include ../_footer ]] -- cgit v1.2.3-70-g09d2 From a8005cd5db8d24342a6b7d53ccedc9808050eef7 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 7 Aug 2015 14:58:34 -0400 Subject: layouts staff stuff --- server/lib/schemas/Layout.js | 2 ++ server/lib/views/staff.js | 75 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 3 deletions(-) (limited to 'server/lib/views') diff --git a/server/lib/schemas/Layout.js b/server/lib/schemas/Layout.js index e3f2616..cff1d78 100644 --- a/server/lib/schemas/Layout.js +++ b/server/lib/schemas/Layout.js @@ -26,6 +26,8 @@ var LayoutSchema = new mongoose.Schema({ rooms: [mongoose.Schema.Types.Mixed], startPosition: mongoose.Schema.Types.Mixed, viewHeight: { type: Number }, + is_stock: { type: Boolean, default: false }, + is_pro: { type: Boolean, default: false }, user_id: { type: mongoose.Schema.ObjectId, index: true }, created_at: { type: Date }, updated_at: { type: Date }, diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js index 6c97bbd..0fdbbb7 100644 --- a/server/lib/views/staff.js +++ b/server/lib/views/staff.js @@ -17,7 +17,8 @@ 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", + project: "_id name slug user_id privacy layout_type created_at updated_at", + layout: "_id name slug user_id layout_type 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", @@ -116,6 +117,35 @@ var staff = module.exports = { }) }, + ensureLayouts: 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) { + default: + case 'date': + sort = {'updated_at': -1} + break + case 'name': + paginationInfo.sort = "name" + sort = {'slug': 1} + break + } + Layout.find(criteria) + .select(staff.fields.layout) + .sort(sort) + .skip(offset) + .limit(limit) + .exec(function (err, layouts) { + res.locals.layouts = layouts.map(staff.helpers.layout) + next() + }) + }, + ensureMedia: function(req, res, next){ var paginationInfo = res.locals.pagination = {} var criteria = req.criteria || {} @@ -223,6 +253,11 @@ var staff = module.exports = { staff.middleware.ensureObjectsUsers(res.locals.projects, next) }, + ensureLayoutsUsers: function(req, res, next){ + if (! res.locals.layouts || ! res.locals.layouts.length) { return next() } + staff.middleware.ensureObjectsUsers(res.locals.layouts, next) + }, + ensureSubscriptionsUsers: function(req, res, next){ if (! res.locals.subscriptions || ! res.locals.subscriptions.length) { return next() } staff.middleware.ensureObjectsUsers(res.locals.subscriptions, next) @@ -321,6 +356,13 @@ var staff = module.exports = { }) }, + ensureLayoutsCount: function(req, res, next){ + Layout.count({}, function(err, count){ + res.locals.layoutCount = count || 0 + next() + }) + }, + ensureMediaCount: function(req, res, next){ Media.count({}, function(err, count){ res.locals.mediaCount = count || 0 @@ -552,7 +594,7 @@ var staff = module.exports = { staff.layouts.show ); - app.put('/staff/layouts/:slug/feature', + app.put('/staff/layouts/:slug/stock', middleware.ensureAuthenticated, middleware.ensureIsStaff, @@ -561,7 +603,7 @@ var staff = module.exports = { staff.layouts.make_stock ); - + // // media @@ -744,7 +786,34 @@ var staff = module.exports = { }) }, }, + + // /staff/layouts/ + // /staff/layouts/:name + layouts: { + index: function(req, res){ + res.locals.pagination.count = res.locals.layouts.length + res.locals.pagination.max = res.locals.layoutCount + staff.paginate(req, res) + res.render('staff/layouts/index') + }, + show: function(req, res){ + if (res.locals.layout) { + res.render('staff/layouts/show', { + }) + } + else { + res.render('staff/layouts/show_404') + } + }, + feature: function(req, res){ + res.locals.layout.is_stock = req.body.state == "true" + res.locals.layout.save(function(err, layout){ + res.json({ state: layout.featured }) + }) + }, + }, + media: { index: function(req, res){ res.locals.pagination.count = res.locals.media.length -- cgit v1.2.3-70-g09d2 From 6f0e2933af03a3fb89b5ce2df0579fd8ef6c175b Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 7 Aug 2015 18:07:59 -0400 Subject: fix --- server/lib/views/staff.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'server/lib/views') diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js index 0fdbbb7..a3d5bea 100644 --- a/server/lib/views/staff.js +++ b/server/lib/views/staff.js @@ -423,6 +423,19 @@ var staff = module.exports = { next() }) }, + + ensureLayout: function(req, res, next){ + res.locals.layout = req.layout + next() + }, + ensureLayoutUser: function(req, res, next){ + if (! res.locals.layout) { return next() } + User.findOne({ _id: res.locals.layout.user_id }, staff.fields.user, function(err, user){ + res.locals.layoutUser = staff.helpers.user(user) || staff.defaults.user + next() + }) + }, + }, helpers: { @@ -805,7 +818,7 @@ var staff = module.exports = { res.render('staff/layouts/show_404') } }, - feature: function(req, res){ + make_stock: function(req, res){ res.locals.layout.is_stock = req.body.state == "true" res.locals.layout.save(function(err, layout){ res.json({ state: layout.featured }) -- cgit v1.2.3-70-g09d2 From 71c3a4a02c7c46533aec836ef30a0d0ffa96399b Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Mon, 10 Aug 2015 18:20:22 -0400 Subject: layout stuff --- .../javascripts/mx/extensions/mx.movements.js | 6 +- .../assets/javascripts/mx/primitives/mx.image.js | 3 +- .../rectangles/engine/map/tools/ortho.js | 26 +- .../rectangles/engine/map/tools/polyline.js | 24 +- .../rectangles/engine/shapes/shapelist.js | 1 + public/assets/javascripts/ui/lib/Toolbar.js | 22 ++ public/assets/javascripts/ui/site/StaffView.js | 26 +- public/assets/test/ortho3.html | 38 +-- public/assets/test/ortho4.html | 261 +++++++++++++++++++++ server/lib/middleware.js | 2 +- server/lib/schemas/Media.js | 1 + server/lib/views/staff.js | 3 +- views/staff/_layouts.ejs | 2 +- views/staff/layouts/show.ejs | 4 +- 14 files changed, 352 insertions(+), 67 deletions(-) create mode 100644 public/assets/javascripts/ui/lib/Toolbar.js create mode 100644 public/assets/test/ortho4.html (limited to 'server/lib/views') diff --git a/public/assets/javascripts/mx/extensions/mx.movements.js b/public/assets/javascripts/mx/extensions/mx.movements.js index fa59908..9ed8790 100644 --- a/public/assets/javascripts/mx/extensions/mx.movements.js +++ b/public/assets/javascripts/mx/extensions/mx.movements.js @@ -162,13 +162,13 @@ MX.Movements = function (cam) { case 8: // backspace e.preventDefault() - if (app.controller.sculptureEditor.sculpture) { + if (app.controller.sculptureEditor && app.controller.sculptureEditor.sculpture) { app.controller.sculptureEditor.sculpture.remove() } - else if (app.controller.mediaEditor.scenery) { + else if (app.controller.mediaEditor && app.controller.mediaEditor.scenery) { app.controller.mediaEditor.scenery.remove() } - else if (app.controller.textEditor.scenery) { + else if (app.controller.textEditor && app.controller.textEditor.scenery) { app.controller.textEditor.scenery.remove() } } diff --git a/public/assets/javascripts/mx/primitives/mx.image.js b/public/assets/javascripts/mx/primitives/mx.image.js index 64de4b2..f9de141 100644 --- a/public/assets/javascripts/mx/primitives/mx.image.js +++ b/public/assets/javascripts/mx/primitives/mx.image.js @@ -17,7 +17,7 @@ MX.Image = MX.Object3D.extend({ this.el.style.backgroundRepeat = 'no-repeat' - this.load(ops) + ops.src && this.load(ops) }, load: function(ops){ @@ -64,7 +64,6 @@ MX.Image = MX.Object3D.extend({ if (recenter) { ctx.restore() } - }, }) diff --git a/public/assets/javascripts/rectangles/engine/map/tools/ortho.js b/public/assets/javascripts/rectangles/engine/map/tools/ortho.js index be3d707..ef41096 100644 --- a/public/assets/javascripts/rectangles/engine/map/tools/ortho.js +++ b/public/assets/javascripts/rectangles/engine/map/tools/ortho.js @@ -12,11 +12,11 @@ var OrthoPolylineTool = MapTool.extend(function (base) { if (map.ui.placing) { // close polyline or cancel map.ui.placing = false - if (line.points.length > 2) { - line.build() + if (shapes.workline.points.length > 2) { + shapes.workline.build() } else { - line.reset() + shapes.workline.reset() } return } @@ -29,24 +29,24 @@ var OrthoPolylineTool = MapTool.extend(function (base) { // compare to initial point var p = last_point.clone() if (map.ui.placing) { - if (line.lastPoint().eq(p)) { + if (shapes.workline.lastPoint().eq(p)) { return } - else if (line.canCloseWith(p)) { - line.close() - line.build() + else if (shapes.workline.canCloseWith(p)) { + shapes.workline.close() + shapes.workline.build() map.ui.placing = false } else { - line.add(p) + shapes.workline.add(p) prev_point = p horizontal = ! horizontal } } else { map.ui.placing = true - line = new Polyline () - line.add(p) + shapes.workline = new Polyline () + shapes.workline.add(p) first_point = prev_point = p horizontal = false } @@ -55,7 +55,7 @@ var OrthoPolylineTool = MapTool.extend(function (base) { last_point.a = cursor.x.a last_point.b = cursor.y.a if (map.ui.placing) { - if (line.points.length == 1) { + if (shapes.workline.points.length == 1) { var x = abs(prev_point.a - last_point.a) var y = abs(prev_point.b - last_point.b) if (x > y) { @@ -86,7 +86,7 @@ var OrthoPolylineTool = MapTool.extend(function (base) { } } - if (line.canCloseWith(last_point)) { + if (shapes.workline.canCloseWith(last_point)) { document.body.style.cursor = "pointer" last_point.assign(first_point) cursor.x.a = cursor.x.b = last_point.a @@ -107,7 +107,7 @@ var OrthoPolylineTool = MapTool.extend(function (base) { } } exports.cancel = function(){ - if (map.ui.placing) { line.reset() } + if (map.ui.placing) { shapes.workline.reset() } first_point = null map.ui.placing = false } diff --git a/public/assets/javascripts/rectangles/engine/map/tools/polyline.js b/public/assets/javascripts/rectangles/engine/map/tools/polyline.js index 559aea8..1ab86f6 100644 --- a/public/assets/javascripts/rectangles/engine/map/tools/polyline.js +++ b/public/assets/javascripts/rectangles/engine/map/tools/polyline.js @@ -9,11 +9,11 @@ var PolylineTool = MapTool.extend(function (base) { if (map.ui.placing) { // close polyline or cancel map.ui.placing = false - if (line.points.length > 2) { - line.build() + if (shapes.workline.points.length > 2) { + shapes.workline.build() } else { - line.reset() + shapes.workline.reset() } return } @@ -24,27 +24,27 @@ var PolylineTool = MapTool.extend(function (base) { // compare to initial point var p = last_point.clone() if (map.ui.placing) { - if (line.canCloseWith(p)) { - line.close() - line.build() + if (shapes.workline.canCloseWith(p)) { + shapes.workline.close() + shapes.workline.build() map.ui.placing = false } else { - line.add(p) + shapes.workline.add(p) } } else { map.ui.placing = true - line = new Polyline () - line.add(p) + shapes.workline = new Polyline () + shapes.workline.add(p) } } exports.move = function(e, cursor){ last_point.a = cursor.x.a last_point.b = cursor.y.a - if (map.ui.placing && line.canCloseWith(last_point)) { + if (map.ui.placing && shapes.workline.canCloseWith(last_point)) { document.body.style.cursor = "pointer" - last_point.assign(line.points[0]) + last_point.assign(shapes.workline.points[0]) cursor.x.a = cursor.x.b = last_point.a cursor.y.a = cursor.y.b = last_point.b return @@ -62,7 +62,7 @@ var PolylineTool = MapTool.extend(function (base) { } } exports.cancel = function(){ - if (map.ui.placing) { line.reset() } + if (map.ui.placing) { shapes.workline.reset() } map.ui.placing = false } return exports diff --git a/public/assets/javascripts/rectangles/engine/shapes/shapelist.js b/public/assets/javascripts/rectangles/engine/shapes/shapelist.js index 00e1a4e..932ce36 100644 --- a/public/assets/javascripts/rectangles/engine/shapes/shapelist.js +++ b/public/assets/javascripts/rectangles/engine/shapes/shapelist.js @@ -2,6 +2,7 @@ var ShapeList = Fiber.extend(function(base){ var exports = {} exports.init = function(){ this.shapes = [] + this.workline = null } exports.add = function(shape){ this.shapes.push(shape) diff --git a/public/assets/javascripts/ui/lib/Toolbar.js b/public/assets/javascripts/ui/lib/Toolbar.js new file mode 100644 index 0000000..a9ce51c --- /dev/null +++ b/public/assets/javascripts/ui/lib/Toolbar.js @@ -0,0 +1,22 @@ +var Toolbar = Fiber.extend(function(base){ + var exports = {} + exports.init = function(rapper){ + this.rapper = (typeof rapper == "string") ? $(rapper)[0] : rapper + this.tools = {} + this.els = {} + } + exports.add = function(role, fn){ + var self = this + this.tools[role] = fn + this.els[role] = $("[data-role=" + role + "]", self.rapper) + this.els[role].click(function(){ + $(".active", self.rapper).removeClass('active') + $(this).addClass('active') + fn() + }) + } + exports.pick = function(role){ + this.els[role].trigger("click") + } + return exports +}) \ No newline at end of file diff --git a/public/assets/javascripts/ui/site/StaffView.js b/public/assets/javascripts/ui/site/StaffView.js index 0398f71..59649e3 100644 --- a/public/assets/javascripts/ui/site/StaffView.js +++ b/public/assets/javascripts/ui/site/StaffView.js @@ -4,11 +4,13 @@ var StaffView = View.extend({ events: { "click #toggle-staff": "toggleStaff", "click #toggle-featured": "toggleFeatured", + "click #toggle-stock": "toggleStock", }, initialize: function() { this.$toggleStaff = $("#toggle-staff") this.$toggleFeatured = $("#toggle-featured") + this.$toggleStock = $("#toggle-stock") this.$mediaEmbed = $("#media-embed") if (this.$toggleStaff.length && this.$toggleStaff.data().isstaff) { this.$toggleStaff.html("Is Staff") @@ -16,6 +18,9 @@ var StaffView = View.extend({ if (this.$toggleFeatured.length && this.$toggleFeatured.data().featured) { this.$toggleFeatured.html("Featured Project") } + if (this.$toggleStock.length && this.$toggleStock.data().stock) { + this.$toggleStock.html("Layout is Stock") + } if (this.$mediaEmbed.length) { var media = this.$mediaEmbed.data() this.$mediaEmbed.html( Parser.tag( media ) ) @@ -67,6 +72,25 @@ var StaffView = View.extend({ $("#isFeaturedProject").html(data.state ? "yes" : "no") }.bind(this) }) - }, + }, + + toggleStock: function(){ + console.log("stock") + var state = ! this.$toggleStock.data().stock + $.ajax({ + type: "put", + dataType: "json", + url: window.location.href + "/stock", + data: { + state: state, + _csrf: $("#_csrf").val(), + }, + success: function(data){ + this.$toggleStock.data("stock", data.state) + this.$toggleStock.html(data.state ? "Stock Layout" : "Make this layout Stock") + $("#isStockLayout").html(data.state ? "yes" : "no") + }.bind(this) + }) + }, }) diff --git a/public/assets/test/ortho3.html b/public/assets/test/ortho3.html index ef5732c..f41a0ba 100644 --- a/public/assets/test/ortho3.html +++ b/public/assets/test/ortho3.html @@ -80,6 +80,7 @@ body { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/server/lib/middleware.js b/server/lib/middleware.js index 94c4acd..04cb330 100644 --- a/server/lib/middleware.js +++ b/server/lib/middleware.js @@ -114,7 +114,7 @@ var middleware = { console.error(err) req.layout = null } - else if (! project) { + else if (! layout) { req.layout = null } else { diff --git a/server/lib/schemas/Media.js b/server/lib/schemas/Media.js index 8247467..f37fb12 100644 --- a/server/lib/schemas/Media.js +++ b/server/lib/schemas/Media.js @@ -42,6 +42,7 @@ var MediaSchema = new mongoose.Schema({ mute: { type: Boolean, default: false }, keyframe: { type: Number, default: 0.0 }, tag: { type: String, default: "" }, + scale: { type: Number, default: 1.0 }, widthDimension: { type: Number }, heightDimension: { type: Number }, diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js index a3d5bea..43330e2 100644 --- a/server/lib/views/staff.js +++ b/server/lib/views/staff.js @@ -6,6 +6,7 @@ var User = require('../schemas/User'), Collaborator = require('../schemas/Collaborator'), Plan = require('../schemas/Plan'), Subscription = require('../schemas/Subscription'), + Layout = require('../schemas/Layout'), config = require('../../../config'), middleware = require('../middleware'), util = require('../util'), @@ -821,7 +822,7 @@ var staff = module.exports = { make_stock: function(req, res){ res.locals.layout.is_stock = req.body.state == "true" res.locals.layout.save(function(err, layout){ - res.json({ state: layout.featured }) + res.json({ state: layout.is_stock }) }) }, }, diff --git a/views/staff/_layouts.ejs b/views/staff/_layouts.ejs index 3f3e6b2..d97883b 100644 --- a/views/staff/_layouts.ejs +++ b/views/staff/_layouts.ejs @@ -1,5 +1,5 @@
    • -[[ layouts.forEach(function(project){ ]] +[[ layouts.forEach(function(layout){ ]]
      [[- layout.name ]] diff --git a/views/staff/layouts/show.ejs b/views/staff/layouts/show.ejs index 0a2014b..b66449f 100644 --- a/views/staff/layouts/show.ejs +++ b/views/staff/layouts/show.ejs @@ -45,14 +45,14 @@ featured? - [[- layout.plan_type == 0 ? "yes" : "no" ]] + [[- layout.is_stock ? "yes" : "no" ]]


      - +

      -- cgit v1.2.3-70-g09d2 From d9050d0faacb0434a94e4bce2acc8f99e189db4f Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Wed, 12 Aug 2015 12:30:44 -0400 Subject: refactor staff area --- server/lib/views/staff.js | 918 ----------------------------------- server/lib/views/staff/defaults.js | 6 + server/lib/views/staff/fields.js | 9 + server/lib/views/staff/helpers.js | 52 ++ server/lib/views/staff/index.js | 452 +++++++++++++++++ server/lib/views/staff/middleware.js | 421 ++++++++++++++++ views/staff/projects/index.ejs | 2 +- 7 files changed, 941 insertions(+), 919 deletions(-) delete mode 100644 server/lib/views/staff.js create mode 100644 server/lib/views/staff/defaults.js create mode 100644 server/lib/views/staff/fields.js create mode 100644 server/lib/views/staff/helpers.js create mode 100644 server/lib/views/staff/index.js create mode 100644 server/lib/views/staff/middleware.js (limited to 'server/lib/views') diff --git a/server/lib/views/staff.js b/server/lib/views/staff.js deleted file mode 100644 index 43330e2..0000000 --- a/server/lib/views/staff.js +++ /dev/null @@ -1,918 +0,0 @@ -/* jshint node: true */ - -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'), - Layout = require('../schemas/Layout'), - config = require('../../../config'), - middleware = require('../middleware'), - util = require('../util'), - _ = require('lodash'), - moment = require('moment'); - - -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 layout_type created_at updated_at", - layout: "_id name slug user_id layout_type 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 sculpture collaborators no_logo", - }, - - defaults: { - user: { - _id: "", username: "", displayName: "", - created_at: "", updated_at: "", created_ip: "", last_ip: "", - }, - }, - - middleware: { - - ensureUsers: 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 initial = util.sanitize(req.query.initial) - var sort - paginationInfo.sort = req.query.sort - paginationInfo.sortOptions = ["date", "last_seen", "username"] - switch (req.query.sort) { - case 'date': - sort = {'created_at': -1} - break - case 'last_seen': - sort = {'last_seen': -1} - break - case 'username': - default: - sort = {'username': 1} - paginationInfo.sort = "username" - break - } - if (initial) { - if (initial == "?") { - criteria.username = new RegExp('^[$a-zA-Z]', "i") - } - else { - criteria.username = new RegExp('^' + initial, "i") - } - } - User.find(criteria) - .select(staff.fields.user) - .sort(sort) - .skip(offset) - .limit(limit) - .exec(function (err, users) { - res.locals.users = users.map(staff.helpers.user) - if (! res.locals.users.length) { - if (initial) { - res.locals.opt.error = "No users found starting with " + initial.toUpperCase() + "" - } - else { - res.locals.opt.error = "No users found" - } - } - next() - }) - }, - - ensureRecentUsers: function(req, res, next){ - var dreq = { query: { sort: 'last_seen', limit: 20, offset: 0 } } - staff.middleware.ensureUsers(dreq, res, next) - }, - - ensureProjects: 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) { - default: - case 'date': - sort = {'updated_at': -1} - break - case 'name': - paginationInfo.sort = "name" - sort = {'slug': 1} - break - } - Project.find(criteria) - .select(staff.fields.project) - .sort(sort) - .skip(offset) - .limit(limit) - .exec(function (err, projects) { - res.locals.projects = projects.map(staff.helpers.project) - next() - }) - }, - - ensureLayouts: 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) { - default: - case 'date': - sort = {'updated_at': -1} - break - case 'name': - paginationInfo.sort = "name" - sort = {'slug': 1} - break - } - Layout.find(criteria) - .select(staff.fields.layout) - .sort(sort) - .skip(offset) - .limit(limit) - .exec(function (err, layouts) { - res.locals.layouts = layouts.map(staff.helpers.layout) - next() - }) - }, - - ensureMedia: 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"] - switch (req.query.sort) { - default: - case 'date': - paginationInfo.sort = "date" - sort = {'created_at': -1} - break - } - Media.find(criteria) - // .select(staff.fields.media) - .sort(sort) - .skip(offset) - .limit(limit) - .exec(function (err, media) { - res.locals.media = media.map(staff.helpers.media) - 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({}).sort({ 'level': -1 }).exec(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) - }, - - ensureProjectsUsers: function(req, res, next){ - if (! res.locals.projects || ! res.locals.projects.length) { return next() } - staff.middleware.ensureObjectsUsers(res.locals.projects, next) - }, - - ensureLayoutsUsers: function(req, res, next){ - if (! res.locals.layouts || ! res.locals.layouts.length) { return next() } - staff.middleware.ensureObjectsUsers(res.locals.layouts, 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(){ - res.locals.mediaUser = res.locals.media.User - next() - }) - }, - - ensureObjectsUsers: function(objects, next){ - if (! objects) { return next () } - var dedupe = {}, user_ids - objects.forEach(function(obj){ - dedupe[ obj.user_id ] = dedupe[ obj.user_id ] || [] - dedupe[ obj.user_id ].push(obj) - }) - user_ids = _.keys(dedupe) - User.find({ _id: { $in: user_ids } }) - .select(staff.fields.user) - .exec(function (err, users) { - if (! users) { return next () } - users.forEach(function(user){ - dedupe[user._id].forEach(function(obj){ - obj.user = user - }) - }) - next() - }) - }, - - ensureProfile: function(req, res, next){ - var username = req.params.username - if (username) { - User.findOne({ username: username }, function (err, user) { - if (user) { - res.locals.profile = req.method == "GET" ? staff.helpers.user(user) : user - } - else { - res.locals.profile = null - } - next() - }) - } - else { - res.locals.profile = null - next() - } - }, - - ensureSingleMedia: function(req, res, next){ - var id = req.params.id - if (id) { - Media.findOne({ _id: id }, function (err, media) { - if (media) { - res.locals.media = req.method == "GET" ? staff.helpers.media(media) : media - } - else { - res.locals.media = null - } - next() - }) - } - else { - res.locals.media = null - next() - } - }, - - ensureUsersCount: function(req, res, next){ - User.count({}, function(err, count){ - res.locals.userCount = count || 0 - next() - }) - }, - - ensureProjectsCount: function(req, res, next){ - Project.count({}, function(err, count){ - res.locals.projectCount = count || 0 - next() - }) - }, - - ensureLayoutsCount: function(req, res, next){ - Layout.count({}, function(err, count){ - res.locals.layoutCount = count || 0 - next() - }) - }, - - ensureMediaCount: function(req, res, next){ - Media.count({}, function(err, count){ - res.locals.mediaCount = count || 0 - next() - }) - }, - - ensureProfileProjectCount: function(req, res, next){ - if (! res.locals.profile) { return next() } - Project.count({ user_id: res.locals.profile._id}, function(err, count){ - res.locals.profile.projectCount = count || 0 - next() - }) - }, - - ensureProfileMediaCount: function(req, res, next){ - if (! res.locals.profile) { return next() } - Media.count({ user_id: res.locals.profile._id}, function(err, count){ - res.locals.profile.mediaCount = count || 0 - next() - }) - }, - - ensureProfileProjects: function(req, res, next){ - if (! res.locals.profile) { return next() } - Project.find({ user_id: res.locals.profile._id }, staff.fields.project, function(err, projects){ - res.locals.projects = projects.map(staff.helpers.project) - next() - }) - }, - - ensureProfileMedia: function(req, res, next){ - if (! res.locals.profile) { return next() } - req.criteria = { user_id: res.locals.profile._id } - staff.middleware.ensureMedia(req, res, next) - }, - - ensureProject: function(req, res, next){ - res.locals.project = req.project - next() - }, - - ensureProjectUser: function(req, res, next){ - if (! res.locals.project) { return next() } - User.findOne({ _id: res.locals.project.user_id }, staff.fields.user, function(err, user){ - res.locals.projectUser = staff.helpers.user(user) || staff.defaults.user - next() - }) - }, - - ensureProjectCollaborators: function(req, res, next){ - if (! res.locals.project) { - res.locals.collaborators = [] - return next() - } - Collaborator.find({ project_id: res.locals.project._id}, function(err, collaborators){ - res.locals.collaborators = collaborators || [] - next() - }) - }, - - ensureLayout: function(req, res, next){ - res.locals.layout = req.layout - next() - }, - ensureLayoutUser: function(req, res, next){ - if (! res.locals.layout) { return next() } - User.findOne({ _id: res.locals.layout.user_id }, staff.fields.user, function(err, user){ - res.locals.layoutUser = staff.helpers.user(user) || staff.defaults.user - next() - }) - }, - - }, - - helpers: { - user: function(user){ - var last_seen = moment( user.last_seen || user.updated_at || user.created_at ) - user = user.toObject() - user.last_seen = last_seen.format("YYYY/MM/DD HH:MM") + " " + last_seen.fromNow() - user.last_charged = user.last_charged && moment( user.last_charged ).format("YYYY/MM/DD HH:MM") - user.created_ip = util.num2ip( user.created_ip ) - user.last_ip = util.num2ip( user.last_ip ) - return user - }, - - 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 - }, - - layout: function(layout){ - layout = layout.toObject() - layout.date = moment( layout.updated_at || layout.created_at ).format("M/DD/YYYY hh:mm a") - layout.user = {} - return layout - }, - - media: function(media){ - media = media.toObject() - media.date = moment( media.updated_at || media.created_at ).format("M/DD/YYYY hh:mm a") - 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){ - app.get('/staff', - middleware.ensureAuthenticated, - middleware.ensureIsStaff, - - staff.middleware.ensureRecentUsers, - staff.middleware.ensureUsersCount, - staff.middleware.ensureProjectsCount, - staff.middleware.ensureMediaCount, - - staff.index - ); - - // - // users - - app.get('/staff/users', - middleware.ensureAuthenticated, - middleware.ensureIsStaff, - - staff.middleware.ensureUsersCount, - staff.middleware.ensureUsers, - - staff.users.index - ); - app.get('/staff/users/:username', - middleware.ensureAuthenticated, - middleware.ensureIsStaff, - - staff.middleware.ensureProfile, - staff.middleware.ensureProfileProjectCount, - staff.middleware.ensureProfileMediaCount, - staff.middleware.ensureProfileProjects, - - staff.users.show - ); - app.get('/staff/users/:username/media', - middleware.ensureAuthenticated, - middleware.ensureIsStaff, - - staff.middleware.ensureProfile, - staff.middleware.ensureProfileMedia, - staff.middleware.ensureProfileMediaCount, - - staff.users.media - ); - app.put('/staff/users/:username/bless', - middleware.ensureAuthenticated, - middleware.ensureIsStaff, - - staff.middleware.ensureProfile, - - staff.users.bless - ); - - if (app.get('env') === 'development') { - app.get('/staff/authorize', - middleware.ensureAuthenticated, - staff.users.blessSelf - ); - } - - // - // projects - - app.get('/staff/projects', - middleware.ensureAuthenticated, - middleware.ensureIsStaff, - - staff.middleware.ensureProjectsCount, - - staff.middleware.ensureProjects, - staff.middleware.ensureProjectsUsers, - - staff.projects.index - ); - app.get('/staff/projects/:slug', - middleware.ensureAuthenticated, - middleware.ensureIsStaff, - - middleware.ensureProject, - staff.middleware.ensureProject, - staff.middleware.ensureProjectUser, - staff.middleware.ensureProjectCollaborators, - - staff.projects.show - ); - app.put('/staff/projects/:slug/feature', - middleware.ensureAuthenticated, - middleware.ensureIsStaff, - - middleware.ensureProject, - staff.middleware.ensureProject, - - staff.projects.feature - ); - - // - // layouts - - app.get('/staff/layouts', - middleware.ensureAuthenticated, - middleware.ensureIsStaff, - - staff.middleware.ensureLayoutsCount, - - staff.middleware.ensureLayouts, - staff.middleware.ensureLayoutsUsers, - - staff.layouts.index - ); - app.get('/staff/layouts/:slug', - middleware.ensureAuthenticated, - middleware.ensureIsStaff, - - middleware.ensureLayout, - staff.middleware.ensureLayout, - staff.middleware.ensureLayoutUser, - - staff.layouts.show - ); - app.put('/staff/layouts/:slug/stock', - middleware.ensureAuthenticated, - middleware.ensureIsStaff, - - middleware.ensureLayout, - staff.middleware.ensureLayout, - - staff.layouts.make_stock - ); - - // - // media - - app.get('/staff/media', - middleware.ensureAuthenticated, - middleware.ensureIsStaff, - - staff.middleware.ensureMediaCount, - - staff.middleware.ensureMedia, - staff.middleware.ensureMediaUsers, - - staff.media.index - ); - app.get('/staff/media/:id', - middleware.ensureAuthenticated, - middleware.ensureIsStaff, - - staff.middleware.ensureSingleMedia, - staff.middleware.ensureMediaUser, - - 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){ - var info = res.locals.pagination - info.query = "sort=" + info.sort + "&limit=" + info.limit - info.first_page = 0 - info.last_page = Math.max(0, info.max - info.limit) - info.sortOptions = info.sortOptions - if (info.offset > 0) { - info.prev_page = Math.max(0, info.offset - info.limit) - } - else { - info.prev_page = -1 - } - if (info.count == info.limit && info.offset + info.limit < info.max) { - info.next_page = info.offset + info.limit - } - else { - info.next_page = -1 - } - }, - - index: function(req, res){ - res.render('staff/index') - }, - - // /staff/users/ - // /staff/users/:username - users: { - index: function(req, res){ - res.locals.pagination.count = res.locals.users.length - res.locals.pagination.max = res.locals.userCount - staff.paginate(req, res) - res.render('staff/users/index') - }, - show: function(req, res){ - if (res.locals.profile) { - res.render('staff/users/show', { - profileJSON: util.escape( JSON.stringify( res.locals.profile ) ) - }) - } - else { - res.render('staff/users/show_404') - } - }, - media: function(req, res){ - if (res.locals.profile) { - res.locals.pagination.count = res.locals.media.length - res.locals.pagination.max = res.locals.profile.mediaCount - staff.paginate(req, res) - res.render('staff/users/media') - } - else { - res.render('staff/users/show_404') - } - }, - blessSelf: function(req, res){ - req.user.isStaff = true - req.user.save(function(err, user){ - res.json({ state: user.isStaff }) - }) - }, - bless: function(req, res){ - res.locals.profile.isStaff = req.body.state == "true" - res.locals.profile.save(function(err, user){ - res.json({ state: user.isStaff }) - }) - }, - }, - - // /staff/projects/ - // /staff/projects/:name - projects: { - index: function(req, res){ - res.locals.pagination.count = res.locals.projects.length - res.locals.pagination.max = res.locals.projectCount - staff.paginate(req, res) - res.render('staff/projects/index') - }, - show: function(req, res){ - if (res.locals.project) { - res.render('staff/projects/show', { - projectJSON: util.escape( JSON.stringify( res.locals.project ) ), - projectUserJSON: util.escape( JSON.stringify( res.locals.projectUser ) ), - collaboratorsJSON: util.escape( JSON.stringify( res.locals.collaborators ) ), - }) - } - else { - res.render('staff/projects/show_404') - } - }, - feature: function(req, res){ - res.locals.project.featured = req.body.state == "true" - res.locals.project.save(function(err, project){ - res.json({ state: project.featured }) - }) - }, - }, - - // /staff/layouts/ - // /staff/layouts/:name - layouts: { - index: function(req, res){ - res.locals.pagination.count = res.locals.layouts.length - res.locals.pagination.max = res.locals.layoutCount - staff.paginate(req, res) - res.render('staff/layouts/index') - }, - show: function(req, res){ - if (res.locals.layout) { - res.render('staff/layouts/show', { - }) - } - else { - res.render('staff/layouts/show_404') - } - }, - make_stock: function(req, res){ - res.locals.layout.is_stock = req.body.state == "true" - res.locals.layout.save(function(err, layout){ - res.json({ state: layout.is_stock }) - }) - }, - }, - - - media: { - index: function(req, res){ - res.locals.pagination.count = res.locals.media.length - res.locals.pagination.max = res.locals.mediaCount - staff.paginate(req, res) - res.render('staff/media/index') - }, - show: function(req, res){ - if (res.locals.media) { - res.render('staff/media/show', { - mediaJSON: util.escape( JSON.stringify( res.locals.media ) ), - mediaUserJSON: util.escape( JSON.stringify( res.locals.mediaUser ) ), - }) - } - else { - 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()) - - data.permissions = {} - permissions.forEach(function(field){ - data.permissions[field] = data["permissions_" + field].length == 2 - }) - - new Plan (data).save(function(err, doc){ - if (err || ! doc) { return res.json({ error: err }) } - middleware.updatePlans() - 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 }) } - middleware.updatePlans() - 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/staff/defaults.js b/server/lib/views/staff/defaults.js new file mode 100644 index 0000000..4d86c41 --- /dev/null +++ b/server/lib/views/staff/defaults.js @@ -0,0 +1,6 @@ +module.exports = { + user: { + _id: "", username: "", displayName: "", + created_at: "", updated_at: "", created_ip: "", last_ip: "", + }, +} diff --git a/server/lib/views/staff/fields.js b/server/lib/views/staff/fields.js new file mode 100644 index 0000000..57eea7e --- /dev/null +++ b/server/lib/views/staff/fields.js @@ -0,0 +1,9 @@ +module.exports = { + user: "_id username displayName photo created_at updated_at last_seen created_ip last_ip", + project: "_id name slug user_id privacy layout_type created_at updated_at", + layout: "_id name slug user_id layout_type 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 sculpture collaborators no_logo", +} diff --git a/server/lib/views/staff/helpers.js b/server/lib/views/staff/helpers.js new file mode 100644 index 0000000..57383f4 --- /dev/null +++ b/server/lib/views/staff/helpers.js @@ -0,0 +1,52 @@ + +var util = require('../../util'), + _ = require('lodash'), + moment = require('moment'); + +module.exports = { + user: function(user){ + var last_seen = moment( user.last_seen || user.updated_at || user.created_at ) + user = user.toObject() + user.last_seen = last_seen.format("YYYY/MM/DD HH:MM") + " " + last_seen.fromNow() + user.last_charged = user.last_charged && moment( user.last_charged ).format("YYYY/MM/DD HH:MM") + user.created_ip = util.num2ip( user.created_ip ) + user.last_ip = util.num2ip( user.last_ip ) + return user + }, + + 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 + }, + + layout: function(layout){ + layout = layout.toObject() + layout.date = moment( layout.updated_at || layout.created_at ).format("M/DD/YYYY hh:mm a") + layout.user = {} + return layout + }, + + media: function(media){ + media = media.toObject() + media.date = moment( media.updated_at || media.created_at ).format("M/DD/YYYY hh:mm a") + 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 + }, +} diff --git a/server/lib/views/staff/index.js b/server/lib/views/staff/index.js new file mode 100644 index 0000000..6a56238 --- /dev/null +++ b/server/lib/views/staff/index.js @@ -0,0 +1,452 @@ +/* jshint node: true */ + +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'), + Layout = require('../../schemas/Layout'), + config = require('../../../../config'), + middleware = require('../../middleware'), + util = require('../../util'), + _ = require('lodash'), + moment = require('moment'); + + +var staff = module.exports = { + + fields: require('./fields'), + defaults: require('./defaults'), + middleware: require('./middleware'), + helpers: require('./helpers'), + + route: function(app){ + app.get('/staff', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + staff.middleware.ensureRecentUsers, + staff.middleware.ensureUsersCount, + staff.middleware.ensureProjectsCount, + staff.middleware.ensureMediaCount, + + staff.index + ); + + // + // users + + app.get('/staff/users', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + staff.middleware.ensureUsersCount, + staff.middleware.ensureUsers, + + staff.users.index + ); + app.get('/staff/users/:username', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + staff.middleware.ensureProfile, + staff.middleware.ensureProfileProjectCount, + staff.middleware.ensureProfileMediaCount, + staff.middleware.ensureProfileProjects, + + staff.users.show + ); + app.get('/staff/users/:username/media', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + staff.middleware.ensureProfile, + staff.middleware.ensureProfileMedia, + staff.middleware.ensureProfileMediaCount, + + staff.users.media + ); + app.put('/staff/users/:username/bless', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + staff.middleware.ensureProfile, + + staff.users.bless + ); + + if (app.get('env') === 'development') { + app.get('/staff/authorize', + middleware.ensureAuthenticated, + staff.users.blessSelf + ); + } + + // + // projects + + app.get('/staff/projects', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + staff.middleware.ensureProjectsCount, + + staff.middleware.ensureProjects, + staff.middleware.ensureProjectsUsers, + + staff.projects.index + ); + app.get('/staff/projects/:slug', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + middleware.ensureProject, + staff.middleware.ensureProject, + staff.middleware.ensureProjectUser, + staff.middleware.ensureProjectCollaborators, + + staff.projects.show + ); + app.put('/staff/projects/:slug/feature', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + middleware.ensureProject, + staff.middleware.ensureProject, + + staff.projects.feature + ); + + // + // layouts + + app.get('/staff/layouts', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + staff.middleware.ensureLayoutsCount, + + staff.middleware.ensureLayouts, + staff.middleware.ensureLayoutsUsers, + + staff.layouts.index + ); + app.get('/staff/layouts/:slug', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + middleware.ensureLayout, + staff.middleware.ensureLayout, + staff.middleware.ensureLayoutUser, + + staff.layouts.show + ); + app.put('/staff/layouts/:slug/stock', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + middleware.ensureLayout, + staff.middleware.ensureLayout, + + staff.layouts.make_stock + ); + + // + // media + + app.get('/staff/media', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + staff.middleware.ensureMediaCount, + + staff.middleware.ensureMedia, + staff.middleware.ensureMediaUsers, + + staff.media.index + ); + app.get('/staff/media/:id', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + staff.middleware.ensureSingleMedia, + staff.middleware.ensureMediaUser, + + 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){ + var info = res.locals.pagination + info.query = "sort=" + info.sort + "&limit=" + info.limit + info.first_page = 0 + info.last_page = Math.max(0, info.max - info.limit) + info.sortOptions = info.sortOptions + if (info.offset > 0) { + info.prev_page = Math.max(0, info.offset - info.limit) + } + else { + info.prev_page = -1 + } + if (info.count == info.limit && info.offset + info.limit < info.max) { + info.next_page = info.offset + info.limit + } + else { + info.next_page = -1 + } + }, + + index: function(req, res){ + res.render('staff/index') + }, + + // /staff/users/ + // /staff/users/:username + users: { + index: function(req, res){ + res.locals.pagination.count = res.locals.users.length + res.locals.pagination.max = res.locals.userCount + staff.paginate(req, res) + res.render('staff/users/index') + }, + show: function(req, res){ + if (res.locals.profile) { + res.render('staff/users/show', { + profileJSON: util.escape( JSON.stringify( res.locals.profile ) ) + }) + } + else { + res.render('staff/users/show_404') + } + }, + media: function(req, res){ + if (res.locals.profile) { + res.locals.pagination.count = res.locals.media.length + res.locals.pagination.max = res.locals.profile.mediaCount + staff.paginate(req, res) + res.render('staff/users/media') + } + else { + res.render('staff/users/show_404') + } + }, + blessSelf: function(req, res){ + req.user.isStaff = true + req.user.save(function(err, user){ + res.json({ state: user.isStaff }) + }) + }, + bless: function(req, res){ + res.locals.profile.isStaff = req.body.state == "true" + res.locals.profile.save(function(err, user){ + res.json({ state: user.isStaff }) + }) + }, + }, + + // /staff/projects/ + // /staff/projects/:name + projects: { + index: function(req, res){ + res.locals.pagination.count = res.locals.projects.length + res.locals.pagination.max = res.locals.projectCount + staff.paginate(req, res) + res.render('staff/projects/index') + }, + show: function(req, res){ + if (res.locals.project) { + res.render('staff/projects/show', { + projectJSON: util.escape( JSON.stringify( res.locals.project ) ), + projectUserJSON: util.escape( JSON.stringify( res.locals.projectUser ) ), + collaboratorsJSON: util.escape( JSON.stringify( res.locals.collaborators ) ), + }) + } + else { + res.render('staff/projects/show_404') + } + }, + feature: function(req, res){ + res.locals.project.featured = req.body.state == "true" + res.locals.project.save(function(err, project){ + res.json({ state: project.featured }) + }) + }, + }, + + // /staff/layouts/ + // /staff/layouts/:name + layouts: { + index: function(req, res){ + res.locals.pagination.count = res.locals.layouts.length + res.locals.pagination.max = res.locals.layoutCount + staff.paginate(req, res) + res.render('staff/layouts/index') + }, + show: function(req, res){ + if (res.locals.layout) { + res.render('staff/layouts/show', { + }) + } + else { + res.render('staff/layouts/show_404') + } + }, + make_stock: function(req, res){ + res.locals.layout.is_stock = req.body.state == "true" + res.locals.layout.save(function(err, layout){ + res.json({ state: layout.is_stock }) + }) + }, + }, + + + media: { + index: function(req, res){ + res.locals.pagination.count = res.locals.media.length + res.locals.pagination.max = res.locals.mediaCount + staff.paginate(req, res) + res.render('staff/media/index') + }, + show: function(req, res){ + if (res.locals.media) { + res.render('staff/media/show', { + mediaJSON: util.escape( JSON.stringify( res.locals.media ) ), + mediaUserJSON: util.escape( JSON.stringify( res.locals.mediaUser ) ), + }) + } + else { + 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()) + + data.permissions = {} + permissions.forEach(function(field){ + data.permissions[field] = data["permissions_" + field].length == 2 + }) + + new Plan (data).save(function(err, doc){ + if (err || ! doc) { return res.json({ error: err }) } + middleware.updatePlans() + 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 }) } + middleware.updatePlans() + 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/staff/middleware.js b/server/lib/views/staff/middleware.js new file mode 100644 index 0000000..5c74d0b --- /dev/null +++ b/server/lib/views/staff/middleware.js @@ -0,0 +1,421 @@ + +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'), + Layout = require('../../schemas/Layout'), + util = require('../../util'), + fields = require('./fields'), + helpers = require('./helpers'), + defaults = require('./defaults'), + _ = require('lodash'), + moment = require('moment'); + + +var middleware = module.exports = { + + ensureUsers: 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 initial = util.sanitize(req.query.initial) + var sort + paginationInfo.sort = req.query.sort + paginationInfo.sortOptions = ["date", "last_seen", "username"] + switch (req.query.sort) { + case 'date': + sort = {'created_at': -1} + break + case 'last_seen': + sort = {'last_seen': -1} + break + case 'username': + default: + sort = {'username': 1} + paginationInfo.sort = "username" + break + } + if (initial) { + if (initial == "?") { + criteria.username = new RegExp('^[$a-zA-Z]', "i") + } + else { + criteria.username = new RegExp('^' + initial, "i") + } + } + User.find(criteria) + .select(fields.user) + .sort(sort) + .skip(offset) + .limit(limit) + .exec(function (err, users) { + res.locals.users = users.map(helpers.user) + if (! res.locals.users.length) { + if (initial) { + res.locals.opt.error = "No users found starting with " + initial.toUpperCase() + "" + } + else { + res.locals.opt.error = "No users found" + } + } + next() + }) + }, + + ensureRecentUsers: function(req, res, next){ + var dreq = { query: { sort: 'last_seen', limit: 20, offset: 0 } } + middleware.ensureUsers(dreq, res, next) + }, + + ensureProjects: 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) { + default: + case 'date': + sort = {'updated_at': -1} + break + case 'name': + paginationInfo.sort = "name" + sort = {'slug': 1} + break + } + Project.find(criteria) + .select(fields.project) + .sort(sort) + .skip(offset) + .limit(limit) + .exec(function (err, projects) { + res.locals.projects = projects.map(helpers.project) + next() + }) + }, + + ensureLayouts: 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) { + default: + case 'date': + sort = {'updated_at': -1} + break + case 'name': + paginationInfo.sort = "name" + sort = {'slug': 1} + break + } + Layout.find(criteria) + .select(fields.layout) + .sort(sort) + .skip(offset) + .limit(limit) + .exec(function (err, layouts) { + res.locals.layouts = layouts.map(helpers.layout) + next() + }) + }, + + ensureMedia: 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"] + switch (req.query.sort) { + default: + case 'date': + paginationInfo.sort = "date" + sort = {'created_at': -1} + break + } + Media.find(criteria) + // .select(fields.media) + .sort(sort) + .skip(offset) + .limit(limit) + .exec(function (err, media) { + res.locals.media = media.map(helpers.media) + 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(fields.project) + .sort(sort) + .skip(offset) + .limit(limit) + .exec(function (err, subscriptions) { + res.locals.subscriptions = subscriptions.map(helpers.subscription) + next() + }) + }, + + ensurePlans: function(req, res, next){ + Plan.find({}).sort({ 'level': -1 }).exec(function (err, plans) { + res.locals.plans = (plans || []).map(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 } } + middleware.ensureProjects(dreq, res, next) + }, + + ensureProjectsUsers: function(req, res, next){ + if (! res.locals.projects || ! res.locals.projects.length) { return next() } + middleware.ensureObjectsUsers(res.locals.projects, next) + }, + + ensureLayoutsUsers: function(req, res, next){ + if (! res.locals.layouts || ! res.locals.layouts.length) { return next() } + middleware.ensureObjectsUsers(res.locals.layouts, next) + }, + + ensureSubscriptionsUsers: function(req, res, next){ + if (! res.locals.subscriptions || ! res.locals.subscriptions.length) { return next() } + middleware.ensureObjectsUsers(res.locals.subscriptions, next) + }, + + ensureMediaUsers: function(req, res, next){ + if (! res.locals.media || ! res.locals.media.length) { return next() } + middleware.ensureObjectsUsers(res.locals.media, next) + }, + + ensureSubscriptionUser: function(req, res, next){ + if (! res.locals.subscription) { return next() } + middleware.ensureObjectsUsers([ res.locals.subscription ], function(){ + next() + }) + }, + + ensureMediaUser: function(req, res, next){ + if (! res.locals.media) { return next() } + middleware.ensureObjectsUsers([ res.locals.media ], function(){ + res.locals.mediaUser = res.locals.media.User + next() + }) + }, + + ensureObjectsUsers: function(objects, next){ + if (! objects) { return next () } + var dedupe = {}, user_ids + objects.forEach(function(obj){ + dedupe[ obj.user_id ] = dedupe[ obj.user_id ] || [] + dedupe[ obj.user_id ].push(obj) + }) + user_ids = _.keys(dedupe) + User.find({ _id: { $in: user_ids } }) + .select(fields.user) + .exec(function (err, users) { + if (! users) { return next () } + users.forEach(function(user){ + dedupe[user._id].forEach(function(obj){ + obj.user = user + }) + }) + next() + }) + }, + + ensureProfile: function(req, res, next){ + var username = req.params.username + if (username) { + User.findOne({ username: username }, function (err, user) { + if (user) { + res.locals.profile = req.method == "GET" ? helpers.user(user) : user + } + else { + res.locals.profile = null + } + next() + }) + } + else { + res.locals.profile = null + next() + } + }, + + ensureSingleMedia: function(req, res, next){ + var id = req.params.id + if (id) { + Media.findOne({ _id: id }, function (err, media) { + if (media) { + res.locals.media = req.method == "GET" ? helpers.media(media) : media + } + else { + res.locals.media = null + } + next() + }) + } + else { + res.locals.media = null + next() + } + }, + + ensureUsersCount: function(req, res, next){ + User.count({}, function(err, count){ + res.locals.userCount = count || 0 + next() + }) + }, + + ensureProjectsCount: function(req, res, next){ + Project.count({}, function(err, count){ + res.locals.projectCount = count || 0 + next() + }) + }, + + ensureLayoutsCount: function(req, res, next){ + Layout.count({}, function(err, count){ + res.locals.layoutCount = count || 0 + next() + }) + }, + + ensureMediaCount: function(req, res, next){ + Media.count({}, function(err, count){ + res.locals.mediaCount = count || 0 + next() + }) + }, + + ensureProfileProjectCount: function(req, res, next){ + if (! res.locals.profile) { return next() } + Project.count({ user_id: res.locals.profile._id}, function(err, count){ + res.locals.profile.projectCount = count || 0 + next() + }) + }, + + ensureProfileMediaCount: function(req, res, next){ + if (! res.locals.profile) { return next() } + Media.count({ user_id: res.locals.profile._id}, function(err, count){ + res.locals.profile.mediaCount = count || 0 + next() + }) + }, + + ensureProfileProjects: function(req, res, next){ + if (! res.locals.profile) { return next() } + Project.find({ user_id: res.locals.profile._id }, fields.project, function(err, projects){ + res.locals.projects = projects.map(helpers.project) + next() + }) + }, + + ensureProfileMedia: function(req, res, next){ + if (! res.locals.profile) { return next() } + req.criteria = { user_id: res.locals.profile._id } + middleware.ensureMedia(req, res, next) + }, + + ensureProject: function(req, res, next){ + res.locals.project = req.project + next() + }, + + ensureProjectUser: function(req, res, next){ + if (! res.locals.project) { return next() } + User.findOne({ _id: res.locals.project.user_id }, fields.user, function(err, user){ + res.locals.projectUser = helpers.user(user) || defaults.user + next() + }) + }, + + ensureProjectCollaborators: function(req, res, next){ + if (! res.locals.project) { + res.locals.collaborators = [] + return next() + } + Collaborator.find({ project_id: res.locals.project._id}, function(err, collaborators){ + res.locals.collaborators = collaborators || [] + next() + }) + }, + + ensureLayout: function(req, res, next){ + res.locals.layout = req.layout + next() + }, + ensureLayoutUser: function(req, res, next){ + if (! res.locals.layout) { return next() } + User.findOne({ _id: res.locals.layout.user_id }, fields.user, function(err, user){ + res.locals.layoutUser = helpers.user(user) || defaults.user + next() + }) + }, + +} \ No newline at end of file diff --git a/views/staff/projects/index.ejs b/views/staff/projects/index.ejs index 1d309ce..e4ba469 100644 --- a/views/staff/projects/index.ejs +++ b/views/staff/projects/index.ejs @@ -7,7 +7,7 @@
      [[ include ../_pagination ]] -[[ include ../_layouts ]] +[[ include ../_projects ]] [[ include ../_pagination ]] [[ include ../_footer ]] -- cgit v1.2.3-70-g09d2 From dd4f0178c7bcb5d14e1308e3877c5ab02eddf000 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Wed, 12 Aug 2015 12:37:49 -0400 Subject: modify webhook to support custom plans --- .../javascripts/ui/site/EditSubscriptionModal.js | 1 + server/lib/api/subscription.js | 1 + server/lib/schemas/Subscription.js | 1 + server/lib/schemas/User.js | 1 + server/lib/views/staff/middleware.js | 2 +- server/lib/webhook/webhook.js | 24 ++++++++++++++++------ views/staff/subscriptions/index.ejs | 3 +++ 7 files changed, 26 insertions(+), 7 deletions(-) (limited to 'server/lib/views') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index 3a20234..1033114 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -96,6 +96,7 @@ var EditSubscriptionModal = ModalView.extend({ free: 0, basic: 1, pro: 2, + custom: 3, }, loaded: false, diff --git a/server/lib/api/subscription.js b/server/lib/api/subscription.js index 9c2d6ef..c2fff4c 100644 --- a/server/lib/api/subscription.js +++ b/server/lib/api/subscription.js @@ -16,6 +16,7 @@ var plan_levels = { free: 0, basic: 1, pro: 2, + custom: 3, } var subscription = module.exports = { diff --git a/server/lib/schemas/Subscription.js b/server/lib/schemas/Subscription.js index 355bbe2..bf43e8b 100644 --- a/server/lib/schemas/Subscription.js +++ b/server/lib/schemas/Subscription.js @@ -9,6 +9,7 @@ var mongoose = require('mongoose'), var SubscriptionSchema = new mongoose.Schema({ user_id: { type: mongoose.Schema.ObjectId, index: true }, + plan_code: { type: String, default: "" }, plan_type: { type: String, default: "free" }, plan_period: { type: String, default: "monthly" }, diff --git a/server/lib/schemas/User.js b/server/lib/schemas/User.js index 4b6ff39..e6e7f03 100644 --- a/server/lib/schemas/User.js +++ b/server/lib/schemas/User.js @@ -55,6 +55,7 @@ var UserSchema = new mongoose.Schema({ default: "", }, + plan_code: { type: String, default: "" }, plan_level: { type: Number, default: 0 }, plan_type: { type: String, default: "free" }, last_charged: { type: Date, default: null }, diff --git a/server/lib/views/staff/middleware.js b/server/lib/views/staff/middleware.js index 5c74d0b..1ea98e9 100644 --- a/server/lib/views/staff/middleware.js +++ b/server/lib/views/staff/middleware.js @@ -40,7 +40,7 @@ var middleware = module.exports = { } if (initial) { if (initial == "?") { - criteria.username = new RegExp('^[$a-zA-Z]', "i") + criteria.username = new RegExp('^[^a-zA-Z]', "i") } else { criteria.username = new RegExp('^' + initial, "i") diff --git a/server/lib/webhook/webhook.js b/server/lib/webhook/webhook.js index 58a13ca..bd51dac 100644 --- a/server/lib/webhook/webhook.js +++ b/server/lib/webhook/webhook.js @@ -26,10 +26,11 @@ var xml_bodyparser = require('express-xml-bodyparser'); var parser = new xml2js.Parser(); var subscribe = module.exports = { - plan_level: { + plan_levels: { free: 0, basic: 1, pro: 2, + custom: 3, }, callbacks: { @@ -62,19 +63,30 @@ var subscribe = module.exports = { Subscription.findOne({ "uuid": uuid }, function(err, old_subscriber){ // if (err) return; - var plan = subscrip.plan[0].plan_code[0].split("-") - var plan_type = plan[0] - var plan_period = plan[1] + var plan, plan_type, plan_code + var plan_code = subscrip.plan[0].plan_code[0] + if (plan_code.indexOf("-") !== -1) { + plan = plan_code.split("-") + plan_type = plan[0] + plan_period = plan[1] + } + else { + plan_type = "custom" + plan_period = "monthly" + } + + user.plan_code = plan_code user.plan_type = plan_type - user.plan_level = subscribe.plan_level[plan_type] + user.plan_level = subscribe.plan_levels[plan_type] var subscriber = old_subscriber || new Subscription () subscriber.uuid = uuid subscriber.user_id = user._id + subscriber.plan_code = plan_code subscriber.plan_type = plan_type subscriber.plan_period = plan_period - subscriber.plan_level = subscribe.plan_level[plan_type] + subscriber.plan_level = subscribe.plan_levels[plan_type] subscriber.add_ons = [] var add_ons = subscrip.subscription_add_ons[0].subscription_add_on if (add_ons) { diff --git a/views/staff/subscriptions/index.ejs b/views/staff/subscriptions/index.ejs index 3efffb5..adf148c 100644 --- a/views/staff/subscriptions/index.ejs +++ b/views/staff/subscriptions/index.ejs @@ -26,6 +26,9 @@
      [[- subscription.user.last_seen ]] + [[- subscription.plan_code ]] +
      -- cgit v1.2.3-70-g09d2 From cc3d0bf036dc934494bf517ebae88bd8544b9b06 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Wed, 12 Aug 2015 13:27:07 -0400 Subject: add artist privilege --- .../javascripts/ui/site/EditSubscriptionModal.js | 1 + public/assets/javascripts/ui/site/StaffView.js | 23 +++++++++++++++++++++- server/lib/schemas/User.js | 1 + server/lib/views/staff/index.js | 16 ++++++++++++++- server/lib/webhook/webhook.js | 1 + views/staff/users/show.ejs | 11 ++++++++++- 6 files changed, 50 insertions(+), 3 deletions(-) (limited to 'server/lib/views') diff --git a/public/assets/javascripts/ui/site/EditSubscriptionModal.js b/public/assets/javascripts/ui/site/EditSubscriptionModal.js index 1033114..c1dc9f8 100644 --- a/public/assets/javascripts/ui/site/EditSubscriptionModal.js +++ b/public/assets/javascripts/ui/site/EditSubscriptionModal.js @@ -97,6 +97,7 @@ var EditSubscriptionModal = ModalView.extend({ basic: 1, pro: 2, custom: 3, + artist: 4, }, loaded: false, diff --git a/public/assets/javascripts/ui/site/StaffView.js b/public/assets/javascripts/ui/site/StaffView.js index 59649e3..97f86c2 100644 --- a/public/assets/javascripts/ui/site/StaffView.js +++ b/public/assets/javascripts/ui/site/StaffView.js @@ -5,12 +5,14 @@ var StaffView = View.extend({ "click #toggle-staff": "toggleStaff", "click #toggle-featured": "toggleFeatured", "click #toggle-stock": "toggleStock", + "click #toggle-artist": "toggleArtist", }, initialize: function() { this.$toggleStaff = $("#toggle-staff") this.$toggleFeatured = $("#toggle-featured") this.$toggleStock = $("#toggle-stock") + this.$toggleArtist = $("#toggle-artist") this.$mediaEmbed = $("#media-embed") if (this.$toggleStaff.length && this.$toggleStaff.data().isstaff) { this.$toggleStaff.html("Is Staff") @@ -21,6 +23,9 @@ var StaffView = View.extend({ if (this.$toggleStock.length && this.$toggleStock.data().stock) { this.$toggleStock.html("Layout is Stock") } + if (this.$toggleArtist.length && this.$toggleArtist.data().isartist) { + this.$toggleArtist.html("Is Artist") + } if (this.$mediaEmbed.length) { var media = this.$mediaEmbed.data() this.$mediaEmbed.html( Parser.tag( media ) ) @@ -75,7 +80,6 @@ var StaffView = View.extend({ }, toggleStock: function(){ - console.log("stock") var state = ! this.$toggleStock.data().stock $.ajax({ type: "put", @@ -93,4 +97,21 @@ var StaffView = View.extend({ }) }, + toggleArtist: function(){ + var state = ! this.$toggleArtist.data().isartist + $.ajax({ + type: "put", + dataType: "json", + url: window.location.href + "/artist", + data: { + state: state, + _csrf: $("#_csrf").val(), + }, + success: function(data){ + this.$toggleArtist.data("stock", data.state) + this.$toggleArtist.html(data.state ? "Is Artist" : "Make Artist") + $("#isArtist").html(data.state ? "yes" : "no") + }.bind(this) + }) + }, }) diff --git a/server/lib/schemas/User.js b/server/lib/schemas/User.js index e6e7f03..829b360 100644 --- a/server/lib/schemas/User.js +++ b/server/lib/schemas/User.js @@ -67,6 +67,7 @@ var UserSchema = new mongoose.Schema({ twitterName: { type: String, default: "" }, facebookUrl: { type: String, default: "" }, isStaff: { type: Boolean, default: false }, + isArtist: { type: Boolean, default: false }, subscription_id: { type: mongoose.Schema.ObjectId }, created_at: { type: Date }, updated_at: { type: Date }, diff --git a/server/lib/views/staff/index.js b/server/lib/views/staff/index.js index 6a56238..033fc88 100644 --- a/server/lib/views/staff/index.js +++ b/server/lib/views/staff/index.js @@ -75,7 +75,15 @@ var staff = module.exports = { staff.users.bless ); - + app.put('/staff/users/:username/artist', + middleware.ensureAuthenticated, + middleware.ensureIsStaff, + + staff.middleware.ensureProfile, + + staff.users.make_artist + ); + if (app.get('env') === 'development') { app.get('/staff/authorize', middleware.ensureAuthenticated, @@ -304,6 +312,12 @@ var staff = module.exports = { res.json({ state: user.isStaff }) }) }, + make_artist: function(req, res){ + res.locals.profile.isArtist = req.body.state == "true" + res.locals.profile.save(function(err, user){ + res.json({ state: user.isArtist }) + }) + }, }, // /staff/projects/ diff --git a/server/lib/webhook/webhook.js b/server/lib/webhook/webhook.js index bd51dac..896d836 100644 --- a/server/lib/webhook/webhook.js +++ b/server/lib/webhook/webhook.js @@ -31,6 +31,7 @@ var subscribe = module.exports = { basic: 1, pro: 2, custom: 3, + artist: 4, }, callbacks: { diff --git a/views/staff/users/show.ejs b/views/staff/users/show.ejs index e441109..a434b57 100644 --- a/views/staff/users/show.ejs +++ b/views/staff/users/show.ejs @@ -35,7 +35,7 @@ plan - [[- profile.plan_type ]] + [[- profile.plan_code ]] @@ -101,12 +101,21 @@ [[- profile.isStaff ? "yes" : "no" ]] + + + is artist? + + + [[- profile.isArtist ? "yes" : "no" ]] + +

      [[ if (String(user._id) != String(profile._id)) { ]] + [[ } ]]
      -- cgit v1.2.3-70-g09d2 From 599b43df07f092b35d25e7adac11db3c3b3d9c76 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Mon, 17 Aug 2015 12:23:39 -0400 Subject: BlueprintEditor --- public/assets/javascripts/ui/_router.js | 7 +- .../javascripts/ui/blueprint/BlueprintEditor.js | 155 +++++++++++++++++++++ .../javascripts/ui/blueprint/BlueprintView.js | 18 +-- server/index.js | 3 + server/lib/views/index.js | 4 + views/blueprint.ejs | 1 + views/controls/blueprint/editor.ejs | 53 ------- views/controls/blueprint/scaler.ejs | 48 +++++++ views/partials/scripts.ejs | 1 + 9 files changed, 227 insertions(+), 63 deletions(-) create mode 100644 public/assets/javascripts/ui/blueprint/BlueprintEditor.js create mode 100644 views/controls/blueprint/scaler.ejs (limited to 'server/lib/views') diff --git a/public/assets/javascripts/ui/_router.js b/public/assets/javascripts/ui/_router.js index 857377c..177e86f 100644 --- a/public/assets/javascripts/ui/_router.js +++ b/public/assets/javascripts/ui/_router.js @@ -38,6 +38,9 @@ var SiteRouter = Router.extend({ "/layout": 'layoutPicker', "/layout/:name": 'layoutEditor', + "/blueprint": 'blueprintEditor', + "/blueprint/:name": 'blueprintEditor', + "/project": 'projectPicker', "/project/new": 'newProject', "/project/new/:layout": 'projectNewWithLayout', @@ -160,13 +163,13 @@ var SiteRouter = Router.extend({ this.readerView.load(name) }, - blueprintEditor: function(e){ + blueprintEditor: function(e, name){ environment.init = environment.minimal app.launch() if (app.unsupported) return this.blueprintView = app.controller = new BlueprintView () - this.blueprintView.load() + this.blueprintView.load(name) }, signup: function(e){ diff --git a/public/assets/javascripts/ui/blueprint/BlueprintEditor.js b/public/assets/javascripts/ui/blueprint/BlueprintEditor.js new file mode 100644 index 0000000..c781495 --- /dev/null +++ b/public/assets/javascripts/ui/blueprint/BlueprintEditor.js @@ -0,0 +1,155 @@ + +var wall_height = 180 +var shapes = new ShapeList +var last_point = new vec2 (0,0) + +var BlueprintEditor = View.extend(AnimatedView.prototype).extend({ + + initialize: function(opt){ + this.parent = opt.parent + + map = new Map ({ + type: "ortho", + el: document.querySelector("#orthographic"), + width: window.innerWidth/2, + height: window.innerHeight, + zoom: -2, + zoom_min: -6.2, + zoom_max: 1, + }) + map.ui.add_tool("arrow", new ArrowTool) + map.ui.add_tool("polyline", new PolylineTool) + map.ui.add_tool("ortho-polyline", new OrthoPolylineTool) + map.ui.add_tool("eraser", new EraserTool) + map.ui.add_tool("position", new PositionTool) + map.ui.placing = false + +/* + $(window).resize(function(){ + scene.width = window.innerWidth/2 + scene.height = window.innerHeight + map.canvas.width = map.dimensions.a = window.innerWidth/2 + map.canvas.height = map.dimensions.b = window.innerHeight/2 + }) +*/ + + var PerspectiveToolbar = new Toolbar (".persp-hud") + PerspectiveToolbar.add("orbit-mode", function(){ + controls.toggle(true) + movements.lock() + }) + PerspectiveToolbar.add("keyboard-mode", function(){ + controls.toggle(false) + movements.unlock() + movements.gravity(true) + cam.rotationX = 0 + cam.rotationY = -cam.rotationY + cam.x = 0 + cam.y = viewHeight + 100 + cam.z = 0 + }) + + var OrthographicToolbar = new Toolbar (".ortho-hud") + OrthographicToolbar.add("arrow-mode", function(){ + map.ui.set_tool("arrow") + }) + OrthographicToolbar.add("polyline-mode", function(){ + map.ui.set_tool("polyline") + }) + OrthographicToolbar.add("ortho-polyline-mode", function(){ + map.ui.set_tool("ortho-polyline") + }) + OrthographicToolbar.add("eraser-mode", function(){ + map.ui.set_tool("eraser") + }) + OrthographicToolbar.pick("ortho-polyline-mode") + }, + + animate: function(t, dt){ + map.update(t) + + movements.update(dt) + controls.update() + scene.update() + + map.draw.ctx.save() + map.draw.translate() + + floorplan.draw(map.draw.ctx, true) + + map.draw.coords() + + if (shapes.workline) { + shapes.workline.draw(map.draw.ctx) + if (map.ui.placing && last_point) { + shapes.workline.draw_line( map.draw.ctx, last_point ) + } + } + + shapes.forEach(function(shape){ + shape.draw(map.draw.ctx) + }) + + map.draw.ctx.strokeStyle = "#f00"; + map.draw.x_at(0,0) + map.draw.mouse(map.ui.mouse.cursor) + map.draw.camera(scene.camera) + + map.draw.ctx.restore() + }, + +}) + +function build () { + scene = new MX.Scene().addTo("#perspective") + scene.camera.radius = 20 + + viewHeight = 100 + + scene.width = window.innerWidth/2 + scene.height = window.innerHeight + scene.perspective = window.innerHeight + + cam = scene.camera + movements = new MX.Movements(cam, viewHeight) + movements.init() + movements.lock() + movements.velocity(8) + app.on("move", function(pos){ + cam.x = pos.x + cam.y = pos.y + cam.z = pos.z + }) + + floorplan = new MX.Image({ + src: "https://s3.amazonaws.com/luckyplop/fbf4295da80f1f66c5e4a248f2ea3e1ce7a22c3d.jpg", + keepImage: true, + rotationX: -PI/2, + rotationY: PI, + }) + scene.add(floorplan) + + // recenter perspective view by rightclicking map + floorplan.el.addEventListener("contextmenu", function(e){ + e.preventDefault() + var offset = offsetFromPoint(e, this) + var x = (offset.left - 0.5) * floorplan.width * floorplan.scale + var z = (offset.top - 0.5) * floorplan.height * floorplan.scale + controls.opt.center.x = -x + controls.opt.center.y = 0 + controls.opt.center.z = -z + }, true) + + scene.update() + + controls = new MX.OrbitCamera({ + el: scene.el, + radius: 3000, + radiusRange: [ 10, 10000 ], + rotationX: PI/4, + rotationY: PI/2, + }) + controls.init() + + animate(0) +} diff --git a/public/assets/javascripts/ui/blueprint/BlueprintView.js b/public/assets/javascripts/ui/blueprint/BlueprintView.js index 6b204e5..0a06fda 100644 --- a/public/assets/javascripts/ui/blueprint/BlueprintView.js +++ b/public/assets/javascripts/ui/blueprint/BlueprintView.js @@ -1,7 +1,9 @@ var BlueprintView = View.extend({ el: "#blueprintView", - + + action: "/api/layout/", + events: { }, @@ -16,14 +18,14 @@ var BlueprintView = View.extend({ }, load: function(name){ -// if (! name || name == "new") { + if (! name || name == "new") { // this.ready({ isNew: true, _id: "new", name: "" }) -// return -// } -// -// name = sanitize(name) -// -// $.get(this.action + name, this.ready.bind(this)) + return + } + + name = sanitize(name) + + $.get(this.action + name, this.ready.bind(this)) }, ready: function(data){ diff --git a/server/index.js b/server/index.js index 0028888..078db8e 100644 --- a/server/index.js +++ b/server/index.js @@ -127,6 +127,9 @@ site.route = function () { app.get('/layout', middleware.ensureAuthenticated, middleware.ensureIsStaff, views.modal) app.get('/layout/:name', middleware.ensureAuthenticated, middleware.ensureIsStaff, views.builder) + app.get('/blueprint', middleware.ensureAuthenticated, middleware.ensureIsStaff, views.blueprint) + app.get('/blueprint/:name', middleware.ensureAuthenticated, middleware.ensureIsStaff, views.blueprint) + app.get('/join/:nonce', middleware.ensureAuthenticated, api.collaborator.join) app.get('/api/collaborator/:slug/index', middleware.ensureAuthenticated, middleware.ensureProject, api.collaborator.index) app.post('/api/collaborator/:slug/create', middleware.ensureAuthenticated, middleware.ensureProject, api.collaborator.create) diff --git a/server/lib/views/index.js b/server/lib/views/index.js index 5241ddb..523f628 100644 --- a/server/lib/views/index.js +++ b/server/lib/views/index.js @@ -84,6 +84,10 @@ var views = module.exports = { res.render('builder') }, + blueprint: function (req, res) { + res.render('blueprint') + }, + modal: function (req, res) { res.render('modal'); }, diff --git a/views/blueprint.ejs b/views/blueprint.ejs index 371d66f..7e13318 100644 --- a/views/blueprint.ejs +++ b/views/blueprint.ejs @@ -16,6 +16,7 @@ [[ include controls/builder/toolbar ]] [[ include controls/builder/settings ]] [[ include controls/blueprint/editor ]] + [[ include controls/blueprint/scaler ]]
    diff --git a/views/controls/blueprint/editor.ejs b/views/controls/blueprint/editor.ejs index e18f501..5334f85 100644 --- a/views/controls/blueprint/editor.ejs +++ b/views/controls/blueprint/editor.ejs @@ -1,8 +1,4 @@