diff --git a/app/config/passport.js b/app/config/passport.js
index 9a3e072..b87fa07 100644
--- a/app/config/passport.js
+++ b/app/config/passport.js
@@ -25,28 +25,28 @@ module.exports = passport => {
},
(req, accessToken, refreshToken, profile, done) => {
- User.findOne({'google.id': profile.id}, (err, user) => {
-
- const name = {
- first: profile.name.givenName,
- last: profile.name.familyName
- },
- email = profile.emails[0].value,
- photo = profile.photos[0] && !profile._json.image.isDefault
- ? profile.photos[0].value.replace("?sz=50", "?sz=200")
- : strings.userPhotoUrl,
-
- google = {
- id: profile.id,
- accessToken: User.encryptAccessToken(accessToken),
- refreshToken
- },
- ip = req.clientIp;
+ const name = {
+ first: profile.name.givenName,
+ last: profile.name.familyName
+ },
+ email = profile.emails[0].value,
+ photo = profile.photos[0] && !profile._json.image.isDefault
+ ? profile.photos[0].value.replace("?sz=50", "?sz=200")
+ : strings.userPhotoUrl,
+
+ google = {
+ id: profile.id,
+ accessToken: User.encryptAccessToken(accessToken),
+ refreshToken
+ },
+ ip = req.clientIp;
+
+ User.findOne({'email': email}, (err, user) => {
if (err) return done(err);
if (!user) {
-
+ console.log('did not find user creating new')
user = new User({name, photo, email, google, ip});
user.save(err => {
if (err) console.log(err);
@@ -54,7 +54,7 @@ module.exports = passport => {
});
} else {
-
+ console.log('user already exists')
User.findByIdAndUpdate(user._id, {
'google.accessToken': User.encryptAccessToken(accessToken),
'google.refreshToken': refreshToken,
diff --git a/app/models/user.js b/app/models/user.js
index f7f5df3..1663e5f 100644
--- a/app/models/user.js
+++ b/app/models/user.js
@@ -1,17 +1,26 @@
-var mongoose = require('mongoose');
-var Schema = mongoose.Schema;
-var crypto = require('crypto');
+const mongoose = require('mongoose');
+const Schema = mongoose.Schema;
+const crypto = require('crypto');
+const mongooseDelete = require('mongoose-delete');
-var keys = require.main.require('./app/config/keys');
-var strings = require.main.require('./app/config/strings');
+const keys = require.main.require('./app/config/keys');
+const strings = require.main.require('./app/config/strings');
-var UserSchema = new Schema({
+// Make email and phone docs unique except for those that are flagged as deleted
+const uniquePartialIndex = {
+ unique: true,
+ partialFilterExpression: {
+ deleted: false
+ }
+};
+
+const UserSchema = new Schema({
name: {
first: {type: String, required: true},
last: {type: String, required: true}
},
- email: {type: String, unique: true, sparse: true},
- phone: {type: String, unique: true, sparse: true},
+ email: {type: String},
+ phone: {type: String},
photo: {type: String, default: strings.userPhotoUrl},
google: {
id: {type: String},
@@ -44,6 +53,10 @@ UserSchema.statics.decryptAccessToken = function(cipher) {
.update(cipher, 'hex', 'utf-8');
};
+UserSchema.plugin(mongooseDelete, {overrideMethods: true});
+
+UserSchema.index({email: 1, phone: 1}, uniquePartialIndex);
+
var User = mongoose.model('User', UserSchema);
module.exports = User;
\ No newline at end of file
diff --git a/app/routes/fact.routes.js b/app/routes/fact.routes.js
index c993467..67717ac 100644
--- a/app/routes/fact.routes.js
+++ b/app/routes/fact.routes.js
@@ -79,7 +79,7 @@ router.get('/:factID', async (req, res) => {
});
// Submit a fact
-router.post('/submitted', async (req, res) => {
+router.post('/', async (req, res) => {
if (!req.user) {
return res.status(401).json({message: strings.unauthenticated});
}
diff --git a/app/routes/recipient.routes.js b/app/routes/recipient.routes.js
index f135add..b8bce42 100644
--- a/app/routes/recipient.routes.js
+++ b/app/routes/recipient.routes.js
@@ -139,7 +139,7 @@ router.get('/:number/conversation', async (req, res) => {
if (results[0]) {
return res.status(200).json(results[1]);
} else {
- return res.status(401).json({message: "You aren't facting this person"});
+ return res.status(403).json({message: "You aren't facting this person"});
}
}
diff --git a/app/routes/user.routes.js b/app/routes/user.routes.js
index c1dd489..5162358 100644
--- a/app/routes/user.routes.js
+++ b/app/routes/user.routes.js
@@ -12,6 +12,25 @@ router.get('/me', (req, res) => {
return res.status(401).json(false);
});
+router.delete('/me', async (req, res) => {
+ // Confirm intention to delete by checking inputted email
+ if (!req.user)
+ return res.status(401).json({message: strings.unauthenticated});
+
+ if (req.user.email !== req.query.verificationEmail)
+ return res.status(403).json({message: 'Email addresses do not match'});
+
+
+ try {
+ await User.delete({_id: req.user._id});
+ return res.status(200).json({message: 'Account deleted'});
+ }
+ catch (err) {
+ return res.status(200).json({message: err.message || 'Failed to delete account', err});
+ }
+
+});
+
router.put('/me/settings', async (req, res) => {
if (!req.user) return res.status(401).json({message: strings.unauthenticated});
@@ -55,7 +74,7 @@ router.post('/me/profile/phone/verification-code', async (req, res) => {
router.put('/me/profile/phone', async (req, res) => {
if (!req.user) return res.status(401).json({message: strings.unauthenticated});
- if (!req.body.verificationCode) return res.status(401).json({message: strings.noVerificationCode});
+ if (!req.body.verificationCode) return res.status(403).json({message: strings.noVerificationCode});
const submittedCode = req.body.verificationCode.trim();
const verificationCode = await VerificationCode.findOne({code: submittedCode});
diff --git a/docs/setup.md b/docs/setup.md
index 9b50f49..a3ce3f1 100644
--- a/docs/setup.md
+++ b/docs/setup.md
@@ -110,7 +110,9 @@
4. Send SMS
- Number: `%RECIPIENT`
- Message: `%DAILYFACT`
- 5. End For
+ 5. Wait
+ - Seconds: 2
+ 6. End For
6. Go back to the Profiles tab and create an event based profile for "Recieved Text Any"
7. Create a task for this profile called "CatBot Single"
8. This task will include these actions:
diff --git a/public/js/controllers/profile.js b/public/js/controllers/profile.js
index c6ef017..c6b76de 100644
--- a/public/js/controllers/profile.js
+++ b/public/js/controllers/profile.js
@@ -1,13 +1,14 @@
/* global angular */
var app = angular.module('catfacts');
-app.controller('ProfileCtrl', ['$scope', '$rootScope', 'ApiService', function($scope, $rootScope, ApiService) {
+app.controller('ProfileCtrl', ['$scope', '$rootScope', 'ApiService', '$state', '$mdDialog', '$mdMedia',
+ function($scope, $rootScope, ApiService, $state, $mdDialog, $mdMedia) {
$scope.newPhone = $rootScope.authenticatedUser ? $rootScope.authenticatedUser.phone : undefined;
$scope.editField = $scope.editStep = null;
- $scope.updatePhone = function(editStep) {
+ $scope.updatePhone = editStep => {
switch (editStep) {
case null:
$scope.editField = 'phone';
@@ -19,7 +20,7 @@ app.controller('ProfileCtrl', ['$scope', '$rootScope', 'ApiService', function($s
$scope.editStep = 'verify';
$rootScope.toast({message: "A verification code has been sent to your phone"});
}, err => {
- $rootScope.toast({message: err.message || "Couldn't create verification code, try again later."});
+ $rootScope.toast({message: err.message || "Couldn't create verification code, try again later"});
});
break;
@@ -31,11 +32,40 @@ app.controller('ProfileCtrl', ['$scope', '$rootScope', 'ApiService', function($s
$scope.newPhone = $scope.verificationCode = '';
$rootScope.toast({message: "New phone number saved"});
}, err => {
- $rootScope.toast({message: err.message || "Couldn't update phone number, try again later."});
+ $rootScope.toast({message: err.message || "Couldn't update phone number, try again later"});
});
break;
}
};
+
+ $scope.openDeleteAccountDialog = ev => {
+ $mdDialog.show({
+ controller: ['$scope', '$mdDialog', function($scope, $mdDialog) {
+
+ $scope.deleteAccount = () => {
+ ApiService.deleteAccount({verificationEmail: $scope.email}).then(data => {
+ $rootScope.authenticatedUser = undefined;
+ $mdDialog.hide(data);
+ }, err => {
+ $rootScope.toast({message: err.data.message || "Failed to delete account"});
+ });
+ };
+
+ $scope.cancel = $mdDialog.cancel;
+ }],
+ templateUrl: 'views/partials/delete-account.html',
+ parent: angular.element(document.body),
+ targetEvent: ev,
+ clickOutsideToClose: true,
+ fullscreen: $mdMedia('xs'),
+ scope: $scope,
+ preserveScope: true,
+
+ }).then(data => {
+ $rootScope.toast({message: "Your account has been deleted"});
+ $state.go('facts');
+ });
+ };
}]);
\ No newline at end of file
diff --git a/public/js/services/api.service.js b/public/js/services/api.service.js
index a539de6..e87ac0c 100644
--- a/public/js/services/api.service.js
+++ b/public/js/services/api.service.js
@@ -9,6 +9,10 @@ app.service('ApiService', ['$rootScope', '$http', '$location', function($rootSco
return $http.get('/users/me');
};
+ this.deleteAccount = function({verificationEmail}) {
+ return $http.delete('/users/me', {params: {verificationEmail}});
+ };
+
this.updateUserSettings = function(data) {
return $http.put('/users/me/settings', data).then(data => console.log(data), err => console.log(err));
};
diff --git a/public/views/partials/delete-account.html b/public/views/partials/delete-account.html
new file mode 100644
index 0000000..5eb5270
--- /dev/null
+++ b/public/views/partials/delete-account.html
@@ -0,0 +1,25 @@
+ This action cannot be undone
+ Permanently delete your account?
+
+
+
Remove your account from Cat Facts
-