diff --git a/E-Compendium-Release-0.1.7.apk b/E-Compendium-Release-0.1.7.apk new file mode 100644 index 0000000..89e0801 Binary files /dev/null and b/E-Compendium-Release-0.1.7.apk differ diff --git a/Gruntfile.js b/Gruntfile.js index 82c3e0f..44630f8 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -54,7 +54,7 @@ module.exports = function (grunt) { production: { constants: { CONST: { - "apiBase": "https://ccra1.kondeo.com:3000/", + "apiBase": "https://ccracodes.com:3000/", "stripePK": "pk_live_zgdVMyeOlyq0g7vQuRliqEDE", "version": "<%= pkg.version %>" } @@ -63,7 +63,7 @@ module.exports = function (grunt) { default: { constants: { CONST: { - "apiBase": "https://ccra1.kondeo.com:3000/", + "apiBase": "https://ccracodes.com:3000/", "stripePK": "pk_live_zgdVMyeOlyq0g7vQuRliqEDE", "version": "<%= pkg.version %>" } diff --git a/app/scripts/controllers/menu.js b/app/scripts/controllers/menu.js index a287141..d38bccb 100644 --- a/app/scripts/controllers/menu.js +++ b/app/scripts/controllers/menu.js @@ -23,28 +23,36 @@ angular.module('starter') loadingSpinner.stopLoading(); $scope.setConfig(data) }, function(error){ - //Our custom Error Handler - var handlers = [ - { - status: 426, - title: "APPLICATION UNSUPPORTED", - text: "Your application version is no longer supported. There will likely be bugs and crashes. Please update to the newest version in the App Store.", - callback: function(response) { - $scope.setConfig(response.data) - } - }, - { - status: 449, - title: "Please Update", - text: "You are running an old version of this app. Please update to the newest version in the App Store, or you may start experiencing bugs.", - callback: function(response) { - $scope.setConfig(response.data) - } - } - ] - - //Send to the notification handler - Notifications.error(error, handlers); + //Check if alert for versioning has already been sprung + if(sessionStorage.getItem("versionAlerted")){ + loadingSpinner.stopLoading(); + $scope.setConfig(error.data) + } else { + //Alert the user to their version and mark as alerted + sessionStorage.setItem("versionAlerted", true); + //Our custom Error Handler + var handlers = [ + { + status: 426, + title: "APPLICATION UNSUPPORTED", + text: "Your application version is no longer supported. There will likely be bugs and crashes. Please update to the newest version in the App Store.", + callback: function(response) { + $scope.setConfig(response.data) + } + }, + { + status: 449, + title: "Please Update", + text: "You are running an old version of this app. Please update to the newest version in the App Store, or you may start experiencing bugs.", + callback: function(response) { + $scope.setConfig(response.data) + } + } + ] + + //Send to the notification handler + Notifications.error(error, handlers); + } }); $scope.settings = {}; @@ -148,9 +156,9 @@ angular.module('starter') //Alert the user their subscription is Ending //inform user there subscription is ending - Notifications.show("Subscription Ending Soon!", "Please notice that your subscription shall be ending: " + - moment(subDate.subscription).format("dddd, MMMM Do YYYY") + - ". Please visit the menu, and select (Manage Subscription) to extend your subscription."); + // Notifications.show("Subscription Ending Soon!", "Please notice that your subscription shall be ending: " + + // moment(subDate.subscription).format("dddd, MMMM Do YYYY") + + // ". Please visit the menu, and select (Manage Subscription) to extend your subscription."); //Set the alerted to true //Save their subscription Date diff --git a/app/scripts/controllers/register.js b/app/scripts/controllers/register.js index 3c9af6d..e9a494b 100644 --- a/app/scripts/controllers/register.js +++ b/app/scripts/controllers/register.js @@ -16,10 +16,14 @@ angular.module('starter') //If our card is validated $scope.cardValidated = false; + $scope.isMember = false; + //Check if we are logged in, //If we are then fill the subscription information $scope.initPage = function() { + loadingSpinner.stopLoading(); + if(localStorage.getItem("admin")) { //inform them of their admin powers @@ -45,10 +49,13 @@ angular.module('starter') }; User.get(payload, function(data) { + $scope.autoPay = data.subscriptionId; //Stop loading loadingSpinner.stopLoading(); + $scope.isMember = data.memberPrice; + //Auto fill their email for them $scope.registerData.email = data.email; @@ -69,8 +76,7 @@ angular.module('starter') } //Lastly, get the price - $scope.price; - $scope.priceText = "Getting Prices..."; + $scope.prices; var payload = { @@ -80,28 +86,13 @@ angular.module('starter') loadingSpinner.startLoading(); Price.get(payload, function(response) { - - //Stop loading loadingSpinner.stopLoading(); - //Check if we should get the price of a new user - //or extension - if($scope.loggedIn()) { - - //Set the price - $scope.price = response.RENEW; - - //Set the text - $scope.priceText = "Extend Subscription for 1 Year - $" + ($scope.price / 100); - } - else { - - //Set the price - $scope.price = response.NEW; + //Set the price + $scope.prices = response; - //Set the text - $scope.priceText = "Create Subscription - $" + ($scope.price / 100); - } + //Set the text + $scope.updatePrices(); }, //errors function(response) { @@ -111,7 +102,31 @@ angular.module('starter') }) } - $scope.initPage(); + + if(!$scope.loggedIn()){ + loadingSpinner.startLoading(); + $timeout(function(){ + loadingSpinner.stopLoading(); + $scope.initPage(); + }, 250); + } else { + $scope.initPage(); + } + + + $scope.updatePrices = function(){ + if(!$scope.registerData.ccraMember) { + //Set the text + $scope.priceText = "Subscribe - $" + ($scope.prices.STANDARD / 100) + " AutoBilled Monthly"; + } else { + //Set the text + $scope.priceText = "Subscribe at Member Price - $" + ($scope.prices.MEMBER / 100) + " AutoBilled Monthly"; + } + } + + $scope.setMember = function(){ + $scope.isMember = $scope.registerData.ccraMember; + } //Functions for the Form @@ -344,6 +359,25 @@ angular.module('starter') $ionicHistory.goBack(); } + $scope.unsubscribe = function() { + //Start loading + loadingSpinner.startLoading(); + + User.cancel({ + token: localStorage.getItem("session_token") + }, function(){ + //Stop loading + loadingSpinner.stopLoading(); + + //User is no longer subscribed to autopay, so change interface + $scope.autoPay = false; + }, function(){ + //Stop loading + loadingSpinner.stopLoading(); + Notifications.show("Error!", "Something went wrong. Please reload the app."); + }); + } + //Create the user $scope.registerUser = function() { @@ -400,6 +434,11 @@ angular.module('starter') password: $scope.registerData.password } + if($scope.registerData.ccraMember){ + payload.memberUsername = $scope.registerData.memberUsername; + payload.memberPassword = $scope.registerData.memberPassword; + } + //Submitting Now! User.register(payload, function(data) { @@ -419,6 +458,8 @@ angular.module('starter') sessionStorage.setItem("weekAlerted", false); sessionStorage.setItem("monthAlerted", false); + $scope.autoPay = true; + //Move them back to the index, no history $ionicHistory.nextViewOptions({ disableBack: true @@ -426,7 +467,7 @@ angular.module('starter') $state.go('app.index'); //Alert them of success! - Notifications.show("Success!", "You have successfully registered! Your account is valid for a year (valid unitl: " + moment(data.subscription).format("MMM Do, YYYY") + "), and can be extended. Enjoy!"); + Notifications.show("Success!", "You have successfully registered! Your card will be automatically billed each month to extend your subscription. Enjoy!"); }, //Errors @@ -453,6 +494,26 @@ angular.module('starter') //Display alert, and show card errors $scope.cardError = true; } + }, + { + status: 424, + title: "Membership Inactive", + text: "The membership for the information you provided is no longer active. Please renew your CCRA membership, or subscribe without membership.", + callback: function() { + + //Display alert, and show card errors + $scope.memberError = true; + } + }, + { + status: 417, + title: "Membership Username/Password Incorrect", + text: "Please check your membership information.", + callback: function() { + + //Display alert, and show card errors + $scope.memberError = true; + } } ] @@ -511,8 +572,13 @@ angular.module('starter') password: $scope.registerData.password } + if($scope.registerData.ccraMember){ + payload.memberUsername = $scope.registerData.memberUsername; + payload.memberPassword = $scope.registerData.memberPassword; + } + //Submitting Now! - User.renew(payload, function(data) { + User.resub(payload, function(data) { //Stop loading loadingSpinner.stopLoading(); @@ -529,6 +595,8 @@ angular.module('starter') sessionStorage.setItem("weekAlerted", false); sessionStorage.setItem("monthAlerted", false); + $scope.autoPay = true; + //Move them back to the index, no history $ionicHistory.nextViewOptions({ disableBack: true @@ -536,7 +604,7 @@ angular.module('starter') $state.go('app.index'); //Alert them of success! - Notifications.show("Success!", "You have successfully registered! Your account is valid for a year (valid unitl: " + moment(data.subscription).format("MMM Do, YYYY") + "), and can be extended. Enjoy!"); + Notifications.show("Success!", "You have successfully registered! Your card will be automatically billed each month to extend your subscription. Enjoy!"); }, //Errors @@ -564,6 +632,26 @@ angular.module('starter') //Display alert, and show card errors $scope.cardError = true; } + }, + { + status: 424, + title: "Membership Inactive", + text: "The membership for the information you provided is no longer active. Please renew your CCRA membership, or subscribe without membership.", + callback: function() { + + //Display alert, and show card errors + $scope.memberError = true; + } + }, + { + status: 417, + title: "Membership Username/Password Incorrect", + text: "Please check your membership information.", + callback: function() { + + //Display alert, and show card errors + $scope.memberError = true; + } } ]; diff --git a/app/scripts/services/user.js b/app/scripts/services/user.js index 82e732d..8fa78ea 100644 --- a/app/scripts/services/user.js +++ b/app/scripts/services/user.js @@ -15,10 +15,16 @@ angular.module('starter') isArray: false }, - renew: { + resub: { method: 'POST', - params: { Id: 'renew' }, - isArray: false + isArray: false, + url: CONST.apiBase + 'users/sub/add' + }, + + cancel: { + method: 'POST', + isArray: false, + url: CONST.apiBase + 'users/sub/cancel' }, get: { diff --git a/app/styles/main.scss b/app/styles/main.scss index c16c920..0b129b7 100644 --- a/app/styles/main.scss +++ b/app/styles/main.scss @@ -183,3 +183,17 @@ $dark: #444 !default; text-align: center; } } + +.center { + text-align: center; +} +.hint { + font-size: 12px !important; +} +.ccraMembership{ + margin-left: 40px; +} +.button-subscribe{ + word-wrap: break-word; + white-space: normal; +} diff --git a/app/templates/register.html b/app/templates/register.html index 6628f33..33691dd 100644 --- a/app/templates/register.html +++ b/app/templates/register.html @@ -1,6 +1,6 @@ -
+ @@ -36,8 +36,10 @@
-
- Your current subscription is valid until: {{subscription}} +
+ Your current subscription is valid until:
+ {{subscription}}
+ But is NOT being autorenewed.
+ I am a CCRA member +
+ + +
+
+ +
+
+

You are currently subscribed, and are being charged ${{prices.STANDARD/100}}${{prices.MEMBER/100}} monthly (CCRA Member Price).

+

Your current subscription is paid until {{subscription}} and is auto-renewing.



+ + +

If you cancel your subscription, you will still keep your remaining subscription time.
+ You may use this button to change credit card information if needed.

+
+
diff --git a/backend/app.js b/backend/app.js index 74c6ab5..5f48f14 100644 --- a/backend/app.js +++ b/backend/app.js @@ -25,6 +25,7 @@ var users = require('./models/users'); var routes = require('./routes/index'); var users = require('./routes/users'); var pages = require('./routes/pages'); +var stripeHooks = require('./routes/stripeHooks'); var app = express(); @@ -46,6 +47,7 @@ app.use(express.static(path.join(__dirname, 'public'))); app.use('/', routes); app.use('/users', users); app.use('/pages', pages); +app.use('/stripe', stripeHooks); // catch 404 and forward to error handler app.use(function(req, res, next) { diff --git a/backend/config/constants.json b/backend/config/constants.json index fe86c2f..4cc1839 100644 --- a/backend/config/constants.json +++ b/backend/config/constants.json @@ -1,12 +1,12 @@ { "VERSION": { - "NUMBER": 1000, - "DEPRICATED": 999, - "LAST_COMPATIBLE": 998 + "NUMBER": "0.1.7", + "DEPRICATED": "0.1.6", + "LAST_COMPATIBLE": "0.1.7" }, "SUBSCRIPTION_PRICE": { - "NEW": 1000, - "RENEW": 700 + "STANDARD": 999, + "MEMBER": 499 }, "SERVER": { "URL": "https://dev.kondeo.com" diff --git a/backend/config/keys-template.json b/backend/config/keys-template.json index db94a9a..98d2a40 100644 --- a/backend/config/keys-template.json +++ b/backend/config/keys-template.json @@ -10,5 +10,8 @@ "apiKey": "", "domain": "kondeo.com", "alias": "support@kondeo.com" + }, + "memberClicks": { + "apiKey": "" } } diff --git a/backend/models/users.js b/backend/models/users.js index 7dfb329..2de78c4 100644 --- a/backend/models/users.js +++ b/backend/models/users.js @@ -26,6 +26,16 @@ var User = new mongoose.Schema({ type: Date, default: null }, + subscriptionId: { + type: String + }, + stripeId: { + type: String + }, + memberPrice: { + type: Boolean, + default: false + }, admin: { type: Boolean, default: false diff --git a/backend/package.json b/backend/package.json index 06299b1..4844cac 100644 --- a/backend/package.json +++ b/backend/package.json @@ -19,8 +19,9 @@ "mongoosastic": "^3.6.0", "mongoose": "^4.2.5", "morgan": "~1.6.1", + "request": "^2.72.0", "semver": "^5.1.0", "serve-favicon": "~2.3.0", - "stripe": "^4.2.0" + "stripe": "^4.6.0" } } diff --git a/backend/routes/index.js b/backend/routes/index.js index 05b3731..8a5e84f 100644 --- a/backend/routes/index.js +++ b/backend/routes/index.js @@ -1,6 +1,7 @@ var express = require('express'), router = express.Router(), - CONST = require('../config/constants.json'); + CONST = require('../config/constants.json'), + semver = require('semver'); /* GET home page. */ router.get('/', function(req, res, next) { @@ -12,10 +13,10 @@ router.get('/prices', function(req, res, next) { }); router.get('/client', function(req, res, next) { - //CLIENT OUT OF DATE - if(req.query.build < CONST.VERSION.LAST_COMPATIBLE){ res.status(426).json(CONST.CLIENT) } - //CLIENT BEING DEPRICATED SOON - else if(req.query.build <= CONST.VERSION.DEPRICATED){ res.status(449).json(CONST.CLIENT) } + //CLIENT OUT OF DATE - Semver client version is less than last compat + if(semver.lt(req.query.version, CONST.VERSION.LAST_COMPATIBLE)){ res.status(426).json(CONST.CLIENT) } + //CLIENT BEING DEPRICATED SOON - Semver client version is less than or equal to DEPRICATED + else if(semver.lte(req.query.version, CONST.VERSION.DEPRICATED)){ res.status(449).json(CONST.CLIENT) } //CLIENT VERSION OK else { res.status(200).json(CONST.CLIENT) } }); diff --git a/backend/routes/stripeHooks.js b/backend/routes/stripeHooks.js new file mode 100644 index 0000000..93d6b1a --- /dev/null +++ b/backend/routes/stripeHooks.js @@ -0,0 +1,56 @@ +var express = require('express'), + router = express.Router(), + mongoose = require('mongoose'), + StripeService = require('../services/stripe.js'), + CONST = require('../config/constants.json'), + User = mongoose.model('User'); + +/* GET home page. */ +router.post('/', function(req, res, next) { + + StripeService.verifyEvent(req.body.id, function(){ + if(req.body.type == "customer.subscription.deleted"){ + console.log("User unsubscribe event") + cancelUser(req.body.data.object.customer, req.body.data.object.id); + } + + res.status(200).send("ok"); + }, function(err){ + console.log("FAKE API/WEBHOOK ACCESS"); + console.log(err) + res.status(401).send("Not Allowed."); + }); +}); + +function cancelUser(stripeId, subscriptionId){ + User.findOne({ + stripeId: stripeId, + subscriptionId: subscriptionId + }) + .select('subscription subscriptionId stripeId') + .exec(function(err, user) { + if (err) { + console.log("ALERT! Database error!") + console.log(err); + } else if (!user) { + console.log("User already unsubscribed manually") + } else { + var setUser = { + $unset: {subscriptionId: 1, memberPrice: 1 } + } + + User.update({ + _id: user._id + }, setUser) + .exec(function(err, user) { + if (err) { + console.log({ + msg: "Could not update user" + }); + } + }); + } + }); +} + +module.exports = router; diff --git a/backend/routes/users.js b/backend/routes/users.js index fd0c32d..f972895 100644 --- a/backend/routes/users.js +++ b/backend/routes/users.js @@ -4,6 +4,7 @@ var express = require('express'), moment = require('moment'), crypto = require('crypto'), CONST = require('../config/constants.json'), + keys = require('../config/keys.json'), MailService = require('../services/mailgun.js'), StripeService = require('../services/stripe.js'), SessionService = require('../services/sessions.js'), @@ -40,41 +41,57 @@ router.post('/register', function(req, res) { msg: "Email taken!" }); } else { - StripeService.charge(req.body.cardToken, CONST.SUBSCRIPTION_PRICE.NEW, function(charge){ - //Create a random salt - var salt = crypto.randomBytes(128).toString('base64'); - //Create a unique hash from the provided password and salt - var hash = crypto.pbkdf2Sync(req.body.password, salt, 10000, 512); - //Create a new user with the assembled information - var subscriptionDate = moment().add(1, 'y'); - var newUser = new User({ - email: (req.body.email.toLowerCase()).trim(), - password: hash, - salt: salt, - subscription: subscriptionDate.toDate() - }).save(function(err, newUser) { - if (err) { - console.log("Error saving user to DB!"); - res.status(500).json({ - msg: "Error saving user to DB!" - }); - } else { - SessionService.generateSession(newUser._id, "user", function(token){ - //All good, give the user their token - res.status(201).json({ - token: token, - subscription: subscriptionDate.toDate() - }); - }, function(err){ - res.status(err.status).json(err); - }); - } + var plan = "standard"; + if(req.body.memberUsername || req.body.memberPassword){ + checkMembership(req.body.memberUsername, req.body.memberPassword, finalizeReg, function(err){ + res.status(err.status).send(err.msg); }); - }, function(err){ - res.status(402).json({ - msg: "Card was declined!" + } else { + finalizeReg(false); + } + + function finalizeReg(isMember){ + if(isMember) plan = "member"; + + StripeService.createCustomer(req.body.cardToken, plan, (req.body.email.toLowerCase()).trim(), function(customer){ + //Create a random salt + var salt = crypto.randomBytes(128).toString('base64'); + //Create a unique hash from the provided password and salt + var hash = crypto.pbkdf2Sync(req.body.password, salt, 10000, 512); + //Create a new user with the assembled information + var subscriptionDate = moment().add(1, 'month'); + var newUser = new User({ + email: (req.body.email.toLowerCase()).trim(), + password: hash, + salt: salt, + subscription: subscriptionDate.toDate(), + subscriptionId: customer.subscriptions.data[0].id, + stripeId: customer.id, + isMember: isMember + }).save(function(err, newUser) { + if (err) { + console.log("Error saving user to DB!"); + res.status(500).json({ + msg: "Error saving user to DB!" + }); + } else { + SessionService.generateSession(newUser._id, "user", function(token){ + //All good, give the user their token + res.status(201).json({ + token: token, + subscription: subscriptionDate.toDate() + }); + }, function(err){ + res.status(err.status).json(err); + }); + } + }); + }, function(err){ + res.status(402).json({ + msg: "Card was declined!" + }); }); - }); + } } }); } @@ -135,7 +152,7 @@ router.post('/login', function(req, res, next) { }); }); -router.post('/renew', function(req, res, next) { +router.post('/sub/add', function(req, res, next) { if(!(req.body.cardToken && req.body.email && req.body.password)){ @@ -148,7 +165,7 @@ router.post('/renew', function(req, res, next) { User.findOne({ email: (req.body.email.toLowerCase()).trim() }) - .select('password salt subscription') + .select('password salt subscription subscriptionId stripeId') .exec(function(err, user) { if (err) { res.status(500).json({ @@ -158,25 +175,146 @@ router.post('/renew', function(req, res, next) { res.status(401).json({ msg: "Wrong email!" }); + } else if(user.subscriptionId){ + console.log("User already has active sub") + res.status(400).json({ + msg: "Already has active subscription" + }); } else { //Hash the requested password and salt var hash = crypto.pbkdf2Sync(req.body.password, user.salt, 10000, 512); //Compare to stored hash if (hash == user.password) { - StripeService.charge(req.body.cardToken, CONST.SUBSCRIPTION_PRICE.RENEW, function(charge){ + var isMember = false; + + var plan = "standard"; + if(req.body.memberUsername || req.body.memberPassword){ + checkMembership(req.body.memberUsername, req.body.memberPassword, clearSubs, function(err){ + res.status(err.status).send(err.msg); + }); + } else { + clearSubs(false); + } - var updatedUser = {}; + function clearSubs(membership){ + isMember = membership; + if(isMember) plan = "member"; + if(user.subscriptionId){ + StripeService.unsubscribe(user.subscriptionId, getStripeId, function(){ + res.status(500).json({ + msg: "Could not unsubscribe from old subscription!" + }); + }); + } else { + getStripeId(); + } + } + + function getStripeId(){ + if(!user.stripeId){ + StripeService.createCustomer(null, null, (req.body.email.toLowerCase()).trim(), function(customer){ + console.log(customer) + newSub(customer.id); + }, function(err){ + res.status(402).json({ + msg: "Card was declined!" + }); + }); + } else { + newSub(user.stripeId); + } + } + + function newSub(stripeId){ + StripeService.updateCard(stripeId, req.body.cardToken, function(customer){ + StripeService.subscribe(stripeId, plan, function(subscription){ + + var updatedUser = {}; + + var origSub = moment(user.subscription); + var today = moment(); + + var newSub = moment.max(origSub, today).add(1, 'month'); + + updatedUser.subscription = newSub.toDate(); + updatedUser.subscriptionId = subscription.id; + updatedUser.memberPrice = isMember; + if(!user.stripeId) updatedUser.stripeId = stripeId; + + var setUser = { + $set: updatedUser + } + + User.update({ + _id: user._id + }, setUser) + .exec(function(err, user) { + if (err) { + console.log({ + msg: "Could not update user" + }); + } + }); + + SessionService.generateSession(user._id, "user", function(token){ + //All good, give the user their token + res.status(200).json({ + token: token, + subscription: newSub.toDate() + }); + }, function(err){ + res.status(err.status).json(err); + }); + }, function(err){ + console.log("card declined") + console.log(err) + res.status(402).json({ + msg: "Card was declined!" + }); + }); + }, function(err){ + console.log(err) + res.status(402).json({ + msg: "Card was declined!" + }); + }); + } + } else { + res.status(401).json({ + msg: "Password is incorrect!" + }); + } + } + }); +}); - var origSub = moment(user.subscription); - var today = moment(); +router.post('/sub/cancel', function(req, res, next) { + if(!(req.body.token)){ + return res.status(412).json({ + msg: "Route requisites not met." + }); + } - var newSub = moment.max(origSub, today).add(1, 'y'); + SessionService.validateSession(req.body.token, "user", function(accountId) { - updatedUser.subscription = newSub.toDate(); + //Find a user with the username requested. Select salt and password + User.findById(accountId) + .select('subscription subscriptionId') + .exec(function(err, user) { + if (err) { + res.status(500).json({ + msg: "Couldn't search the database for user!" + }); + } else if (!user) { + res.status(401).json({ + msg: "Wrong email!" + }); + } else { + StripeService.unsubscribe(user.subscriptionId, function(confirmation){ var setUser = { - $set: updatedUser + $unset: {subscriptionId: 1, memberPrice: 1 } } User.update({ @@ -190,33 +328,25 @@ router.post('/renew', function(req, res, next) { } }); - SessionService.generateSession(user._id, "user", function(token){ - //All good, give the user their token - res.status(200).json({ - token: token, - subscription: newSub.toDate() - }); - }, function(err){ - res.status(err.status).json(err); - }); + //All good, give the user their token + res.status(200).send("ok"); }, function(err){ - res.status(412).json({ - msg: "Card was declined!" + res.status(500).json({ + msg: "Could not unsubscribe user!" }); }); - } else { - res.status(401).json({ - msg: "Password is incorrect!" - }); } - } + }); + + }, function(err){ + res.status(err.status).json(err); }); }); router.get('/self/:token', function(req, res, next) { SessionService.validateSession(req.params.token, "user", function(accountId) { User.findById(accountId) - .select('name email subscription admin') + .select('name email subscription subscriptionId memberPrice admin') .exec(function(err, user) { if (err) { res.status(500).json({ @@ -321,4 +451,47 @@ router.post('/forgot', function(req, res, next) { } }); +function checkMembership(username, password, success, fail){ + var membership = false; + + var request = require('request'); + + // Set the headers + var headers = { + 'User-Agent': 'Super Agent/0.0.1', + 'Content-Type': 'application/x-www-form-urlencoded', + 'Authorization': keys.memberClicks.apiKey, + 'Accept': 'application/json' + } + + // Configure the request + var options = { + url: 'https://ccra.memberclicks.net/services/auth', + method: 'POST', + headers: headers, + qs: {'username': username, 'password': password, 'apiKey': keys.memberClicks.apiKey} + } + + // Start the request + request(options, function (error, response, body) { + if (!error && response.statusCode == 200) { + // Print out the response body + var data = JSON.parse(body); + if(data.active){ + success(true); + } else { + fail({ + status: 424, + msg: "CCRA Membership no longer active." + }); + } + } else { + fail({ + status: 417, + msg: "CCRA Membership credentials incorrect." + }); + } + }); +} + module.exports = router; diff --git a/backend/services/stripe.js b/backend/services/stripe.js index 5cb3039..0906f03 100644 --- a/backend/services/stripe.js +++ b/backend/services/stripe.js @@ -24,3 +24,59 @@ exports.charge = function(card, amount, success, fail) { } }); }; + +exports.createCustomer = function(card, plan, email, success, fail){ + var payload = { + email: email + } + if (plan != null) payload.plan = plan; + if (card != null) payload.source = card; + stripe.customers.create(payload, function(err, customer) { + if (err && err.type === 'StripeCardError') { + fail({ + msg: "Card was declined!" + }); + } else if (err) { + console.log("Stripe charge error"); + console.log(err); + fail({ + msg: "Charge could not be completed!" + }); + } else { + success(customer); + } + }); +}; + +exports.updateCard = function(stripeId, card, success, fail){ + stripe.customers.update(stripeId, { + source: card + }, function(err, customer){ + if(err) fail(err); + else success(customer); + }); +}; + +exports.subscribe = function(stripeId, plan, success, fail){ + stripe.subscriptions.create({ + customer: stripeId, + plan: plan + }, function(err, subscription) { + if(err) fail(err); + else success(subscription); + }); +}; + +exports.unsubscribe = function(subscriptionId, success, fail){ + stripe.subscriptions.del(subscriptionId, function(err, confirmation) { + if(err) fail(err); + else success(confirmation); + }); +}; + +exports.verifyEvent = function(eventId, success, fail){ + stripe.events.retrieve(eventId, function(err, event) { + if(err) fail(err); + else success(event); + }); +}; diff --git a/bower.json b/bower.json index 30c6f63..47f59ab 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "CCRAECompendium", - "version": "0.1.6", + "version": "0.1.7", "dependencies": { "angular-animate": "1.5.3", "angular-hotkeys": "chieffancypants/angular-hotkeys#~1.6.0", diff --git a/config.xml b/config.xml index c9ef16c..8bf2206 100644 --- a/config.xml +++ b/config.xml @@ -1,5 +1,5 @@ - + Compendium CCRA ECompendium diff --git a/package.json b/package.json index 965a027..28458be 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "CCRAECompendium", - "version": "0.1.6", + "version": "0.1.7", "private": true, "dependencies": { "moment": "^2.11.1" @@ -64,6 +64,9 @@ } ], "cordovaPlatforms": [ - "android" + { + "platform": "android", + "locator": "browser" + } ] }