Skip to content

Instantly share code, notes, and snippets.

@Hendrixer
Last active February 7, 2022 07:39
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Hendrixer/8869852 to your computer and use it in GitHub Desktop.
Save Hendrixer/8869852 to your computer and use it in GitHub Desktop.
Forgot password feature with Node, Epxress, Mongo
# for API and DB endpoints
user = require './controllers/userController'
mainFeed = require './controllers/mainFeedController'
{isLoggedIn} = require './middleWare'
{alreadyLoggedOut} = require './middleWare'
module.exports = (app, passport) ->
#=========================
# Routes here!!
#=========================
# serves splash! Change splash to a real splash and not signup/sign in
app.get '/', user.index
# Signup new users route
app.post '/signup', passport.authenticate('local-signup'), (req, res) ->
res.json 201, req.user
# log in returning users
app.post '/login', passport.authenticate('local-login'), (req, res) ->
res.json req.user
# log current user out the session
app.get '/logout', alreadyLoggedOut, user.logout
# delete user out from app and DB, no comming back
app.delete '/users/delete', isLoggedIn, user.deleteUser
app.post '/user/forgot/password', user.forgotPassword
app.get '/user/reset/:token?', user.resetPassword
# this route will accept new password from user and update it
# app.post '/user/reset/:token?', user.updatePassword
# users stream route
app.get '/api/users/:from?/:to?', isLoggedIn, mainFeed.allUsersActivity
# get current users stats
app.get '/api/user/:from?/:to?', isLoggedIn, user.userActivity
app.get '/api/compare/:userid?', isLoggedIn, mainFeed.compare
# this is no the same as the isLogged in middleware
# this route lets the front end know on the fly if the user is auth
# the isLoggedIn middleware is to let the server know who is auth or not
# isLoggedIn sends back an additional '401' for angular
# to intercept if no auth
app.get '/loggedin', user.loggedIn
# /api/user/2014-01-20
#================================
# fitbit api here
#================================
# auth with fitbit
app.get '/connect/fitbit', isLoggedIn, passport.authorize 'fitbit',
display: 'touch'
# fitbit call back route/ authorize not authenticate here, small diff
# must use (req, res) callback here for this to work prop with authorize
app.get '/connect/fitbit/callback', isLoggedIn,
passport.authorize('fitbit', failureRedirect: '/login'), (req, res) ->
res.redirect '#/main/stream'
'use strict'
Q = require 'q'
mongoose = require 'mongoose'
nodemailer = require 'nodemailer'
uuid = require 'node-uuid'
UserSchema = new mongoose.Schema(
username:
type: String
unique: true
required: true
email:
type: String
unique: true
required: true
# Should make seperate schema for token here and associate it with the user
# this will allow us to have an expiring reset token for reset token
pass_reset:
type: String
password:
type: String
required: true
salt: String
createdAt:
type: Date
default: Date.now
updatedAt:
type: Date
default: Date.now
pro: Boolean
groups:
[{type: mongoose.Schema.ObjectId, ref: 'Group'}]
authData:
fitbit:
avatar: String
access_token: String
access_token_secret: String
)
###
Static methods to increase flow and tedious queries
###
# Find user by email, mainly used in password reset but not soley
UserSchema.statics.findByEmail = (email) ->
defer = Q.defer()
@findOne 'email': email, (err, user) ->
if err then defer.reject err
if user then defer.resolve user
# FIXME
if not user then console.log 'no user by that email'
defer.promise
UserSchema.statics.resetPassword = (user) ->
User = mongoose.model 'User'
defer = Q.defer()
# get set up the given user's _id to search
id = user._id
# define what fields will be updated and with what values
update =
pass_reset: uuid.v4() # genrates a v4 random uuid
# define options on the query, this one will return the reset
# token that was just updated
options =
select:
'pass_reset': true
console.log 'id', id, 'update', update, 'options', options
User.findByIdAndUpdate id, update, options, (err, reset_token) ->
if err then defer.reject err
if reset_token
userAndEmail =
email: user.email
reset: reset_token
username: user.username
defer.resolve userAndEmail
if not reset_token then console.log 'could not get reset_token'
defer.promise
UserSchema.statics.emailPassword = (user) ->
# create a reusable transport method with nodemailer
defer = Q.defer()
smtpTransport = nodemailer.createTransport(
'SMTP', {service: 'Gmail', auth: {
user: 'willscottmoss@gmail.com'
pass: 'ballin35'
}
}
)
console.log 'reset', user.reset.pass_reset
# setup email options to be sent can HTML if need be, All Unicode
mailOptions =
'from': 'Scott Moss <scottmoss35@gmail.com>'
'to': user.email
'subject': 'Sweatr reset password'
'html': "<h1> Hello #{user.username}!</h1>"+
"<p> Here is the link to reset your password </p>" +
"<a href=http://localhost:3000/user/reset/"+
"#{user.reset.pass_reset} >Reset</a>"
smtpTransport.sendMail mailOptions, (err, response) ->
if err then defer.reject err
if response then defer.resolve response
defer.promise
module.exports = mongoose.model 'User', UserSchema
User = require '../../models/user'
Stats = require '../../models/stat'
moment = require 'moment'
{getDailyActivities} = require './helpers'
{saveStats} = require './helpers'
{dateRange} = require './helpers'
module.exports =
#==========================
# static assets
#==========================
index: (req, res) ->
# by default express will send index.html on GET '/'
# so this is just optional
# send back splash/landing instead
# of jsut login/signup
res.sendfile('index.html')
#==========================
# CRUD ops
#==========================
# logout helper
logout: (req, res) ->
id = req.user._id
User.findById id, (err, user) ->
if err
throw new Error err, ' cannot find user to log'
if user
user.lastLoggedIn = Date.now()
user.save (err) ->
throw new Error err if err
req.logout()
res.redirect '/'
# get curent user on the fly if need it, should not need this, security issue
getUser: (req, res) ->
id = req.params.id
res.send 401 if id isnt String req.user._id # can only get logged in user
User.findById id, (err, user) ->
if err
throw new Error err, 'User.findOne error '
if not user
# user isn't in the db
res.send 204
if user
res.json user
# method to retrieve forgotten password. User posts email
# generate access-token (should expire), email user link
# to update password, access token is attached as param to
# link. Check the access-token, if valid, then accept the
# new password and redirect somewhere
forgotPassword: (req, res) ->
email = req.body.email
User.findByEmail(email)
.then(User.resetPassword)
.then(User.emailPassword)
.then (response) ->
console.log 'sent message', response
res.send 200
.fail (err) ->
console.log 'err somewhere in reset pass', err
res.send 500
resetPassword: (req, res) ->
# send a redirect to an angular template instead of a pure html file
# this will allow for proper design and control over the password rest form
res.sendfile 'password.html',
root:"#{__dirname}/../../../../public/"
userActivity: (req, res) ->
# define the DB query to get results
today = moment().subtract('days', 1).format 'YYYY-MM-DD'
query = user: req.user._id
dateRange today, today, query
Stats.find query, (err, stats) ->
if err
throw new Error err, 'error getting api/user data'
else if stats.length
# if stats, send back reqested range of stats along with user data
data =
username: req.user.username
pic: req.user.authData.fitbit.avatar
stats: stats[0]
res.json data
else if !stats.length
# if no stats in db, go to fitbit and get 7 days
# worth of stats and save to db
date = moment().subtract('days', 7)
toDate = moment().subtract('days', 1)
query =
'user': query.user
'date': today
while date <= toDate
# helper function that goes to fitbit and gets a weeks data set
getDailyActivities req, res, date.format('YYYY-MM-DD'), saveStats
date = date.add 'days', 1
deleteUser: (req, res) ->
id = req.user._id
User.findById id, (err, user) ->
if err
throw new Error err, 'could not find user to delete'
if not user
# user is not in DB anyways..
res.send 204
else
user.remove (err, user) -> # remove user record
if err
throw new Error err, 'could not delete user'
req.logout()
res.redirect '/'
# helper to protect angular routes on client
loggedIn: (req, res) ->
res.send if req.isAuthenticated() then req.user else "0"
@hvarshney2
Copy link

fdgsdgf

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment