mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 11:05:54 +01:00 
			
		
		
		
	refactored user.js
took out notifications, email and reset code to separate files
This commit is contained in:
		| @@ -17,7 +17,7 @@ SocketMeta.reconnected = function(socket) { | |||||||
|  |  | ||||||
| 	if (uid) { | 	if (uid) { | ||||||
| 		topics.pushUnreadCount(uid); | 		topics.pushUnreadCount(uid); | ||||||
| 		user.pushNotifCount(uid); | 		user.notifications.pushCount(uid); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (process.env.NODE_ENV === 'development') { | 	if (process.env.NODE_ENV === 'development') { | ||||||
|   | |||||||
| @@ -206,7 +206,7 @@ var async = require('async'), | |||||||
| 				postData = data; | 				postData = data; | ||||||
| 				threadTools.notifyFollowers(tid, postData.pid, uid); | 				threadTools.notifyFollowers(tid, postData.pid, uid); | ||||||
|  |  | ||||||
| 				user.sendPostNotificationToFollowers(uid, tid, postData.pid); | 				user.notifications.sendPostNotificationToFollowers(uid, tid, postData.pid); | ||||||
|  |  | ||||||
| 				next(); | 				next(); | ||||||
| 			}, | 			}, | ||||||
| @@ -878,7 +878,7 @@ var async = require('async'), | |||||||
|  |  | ||||||
| 		user.notifications.getUnreadByUniqueId(uid, 'topic:' + tid, function(err, nids) { | 		user.notifications.getUnreadByUniqueId(uid, 'topic:' + tid, function(err, nids) { | ||||||
| 			notifications.mark_read_multiple(nids, uid, function() { | 			notifications.mark_read_multiple(nids, uid, function() { | ||||||
| 				user.pushNotifCount(uid); | 				user.notifications.pushCount(uid); | ||||||
| 			}); | 			}); | ||||||
| 		}); | 		}); | ||||||
| 	}; | 	}; | ||||||
|   | |||||||
							
								
								
									
										312
									
								
								src/user.js
									
									
									
									
									
								
							
							
						
						
									
										312
									
								
								src/user.js
									
									
									
									
									
								
							| @@ -13,13 +13,16 @@ var bcrypt = require('bcryptjs'), | |||||||
| 	db = require('./database'), | 	db = require('./database'), | ||||||
| 	meta = require('./meta'), | 	meta = require('./meta'), | ||||||
| 	groups = require('./groups'), | 	groups = require('./groups'), | ||||||
| 	notifications = require('./notifications'), |  | ||||||
| 	topics = require('./topics'), | 	topics = require('./topics'), | ||||||
| 	events = require('./events'), | 	events = require('./events'), | ||||||
| 	Emailer = require('./emailer'); | 	Emailer = require('./emailer'); | ||||||
|  |  | ||||||
| (function(User) { | (function(User) { | ||||||
|  |  | ||||||
|  | 	User.email = require('./useremail'); | ||||||
|  | 	User.notifications = require('./usernotifications'); | ||||||
|  | 	User.reset = require('./userreset'); | ||||||
|  |  | ||||||
| 	User.create = function(userData, callback) { | 	User.create = function(userData, callback) { | ||||||
| 		userData = userData || {}; | 		userData = userData || {}; | ||||||
| 		userData.userslug = utils.slugify(userData.username); | 		userData.userslug = utils.slugify(userData.username); | ||||||
| @@ -753,26 +756,7 @@ var bcrypt = require('bcryptjs'), | |||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  |  | ||||||
| 	User.sendPostNotificationToFollowers = function(uid, tid, pid) { |  | ||||||
| 		User.getUserField(uid, 'username', function(err, username) { |  | ||||||
| 			db.getSetMembers('followers:' + uid, function(err, followers) { |  | ||||||
| 				if (followers && followers.length) { |  | ||||||
| 					topics.getTopicField(tid, 'slug', function(err, slug) { |  | ||||||
| 						var message = '<strong>' + username + '</strong> made a new post'; |  | ||||||
|  |  | ||||||
| 						notifications.create({ |  | ||||||
| 							text: message, |  | ||||||
| 							path: nconf.get('relative_path') + '/topic/' + slug + '#' + pid, |  | ||||||
| 							uniqueId: 'topic:' + tid, |  | ||||||
| 							from: uid |  | ||||||
| 						}, function(nid) { |  | ||||||
| 							notifications.push(nid, followers); |  | ||||||
| 						}); |  | ||||||
| 					}); |  | ||||||
| 				} |  | ||||||
| 			}); |  | ||||||
| 		}); |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	User.isFollowing = function(uid, theirid, callback) { | 	User.isFollowing = function(uid, theirid, callback) { | ||||||
| 		db.isSetMember('following:' + uid, theirid, callback); | 		db.isSetMember('following:' + uid, theirid, callback); | ||||||
| @@ -841,102 +825,6 @@ var bcrypt = require('bcryptjs'), | |||||||
| 		groups.isMemberByGroupName(uid, 'administrators', callback); | 		groups.isMemberByGroupName(uid, 'administrators', callback); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	User.reset = { |  | ||||||
| 		validate: function(socket, code, callback) { |  | ||||||
|  |  | ||||||
| 			db.getObjectField('reset:uid', code, function(err, uid) { |  | ||||||
| 				if (err) { |  | ||||||
| 					return callback(err); |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				if (uid !== null) { |  | ||||||
| 					db.getObjectField('reset:expiry', code, function(err, expiry) { |  | ||||||
| 						if (err) { |  | ||||||
| 							return callback(err); |  | ||||||
| 						} |  | ||||||
|  |  | ||||||
| 						if (parseInt(expiry, 10) >= Date.now() / 1000) { |  | ||||||
| 							callback(null, true); |  | ||||||
| 						} else { |  | ||||||
| 							// Expired, delete from db |  | ||||||
| 							db.deleteObjectField('reset:uid', code); |  | ||||||
| 							db.deleteObjectField('reset:expiry', code); |  | ||||||
| 							callback(null, false); |  | ||||||
| 						} |  | ||||||
| 					}); |  | ||||||
| 				} else { |  | ||||||
| 					callback(null, false); |  | ||||||
| 				} |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		send: function(socket, email, callback) { |  | ||||||
| 			User.getUidByEmail(email, function(err, uid) { |  | ||||||
| 				if(err) { |  | ||||||
| 					return callback(err); |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				if(!uid) { |  | ||||||
| 					return callback(new Error('invalid-email')); |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				// Generate a new reset code |  | ||||||
| 				var reset_code = utils.generateUUID(); |  | ||||||
| 				db.setObjectField('reset:uid', reset_code, uid); |  | ||||||
| 				db.setObjectField('reset:expiry', reset_code, (60 * 60) + Math.floor(Date.now() / 1000)); |  | ||||||
|  |  | ||||||
| 				var reset_link = nconf.get('url') + '/reset/' + reset_code; |  | ||||||
|  |  | ||||||
| 				Emailer.send('reset', uid, { |  | ||||||
| 					'site_title': (meta.config.title || 'NodeBB'), |  | ||||||
| 					'reset_link': reset_link, |  | ||||||
|  |  | ||||||
| 					subject: 'Password Reset Requested - ' + (meta.config.title || 'NodeBB') + '!', |  | ||||||
| 					template: 'reset', |  | ||||||
| 					uid: uid |  | ||||||
| 				}); |  | ||||||
|  |  | ||||||
| 				callback(null); |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		commit: function(socket, code, password, callback) { |  | ||||||
| 			this.validate(socket, code, function(err, validated) { |  | ||||||
| 				if(err) { |  | ||||||
| 					return callback(err); |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				if (validated) { |  | ||||||
| 					db.getObjectField('reset:uid', code, function(err, uid) { |  | ||||||
| 						if (err) { |  | ||||||
| 							return callback(err); |  | ||||||
| 						} |  | ||||||
|  |  | ||||||
| 						User.hashPassword(password, function(err, hash) { |  | ||||||
| 							User.setUserField(uid, 'password', hash); |  | ||||||
| 							events.logPasswordReset(uid); |  | ||||||
| 						}); |  | ||||||
|  |  | ||||||
| 						db.deleteObjectField('reset:uid', code); |  | ||||||
| 						db.deleteObjectField('reset:expiry', code); |  | ||||||
|  |  | ||||||
| 						callback(null); |  | ||||||
| 					}); |  | ||||||
| 				} |  | ||||||
| 			}); |  | ||||||
| 		} |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	User.pushNotifCount = function(uid) { |  | ||||||
| 		var	websockets = require('./socket.io'); |  | ||||||
|  |  | ||||||
| 		User.notifications.getUnreadCount(uid, function(err, count) { |  | ||||||
| 			if (!err) { |  | ||||||
| 				websockets.in('uid_' + uid).emit('event:notifications.updateCount', count); |  | ||||||
| 			} else { |  | ||||||
| 				winston.warn('[User.pushNotifCount] Count not retrieve unread notifications count to push to uid ' + uid + '\'s client(s)'); |  | ||||||
| 			} |  | ||||||
| 		}); |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	User.logIP = function(uid, ip) { | 	User.logIP = function(uid, ip) { | ||||||
| 		db.sortedSetAdd('uid:' + uid + ':ip', +new Date(), ip || 'Unknown'); | 		db.sortedSetAdd('uid:' + uid + ':ip', +new Date(), ip || 'Unknown'); | ||||||
| 	}; | 	}; | ||||||
| @@ -953,197 +841,5 @@ var bcrypt = require('bcryptjs'), | |||||||
| 		}); | 		}); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	User.email = { |  | ||||||
| 		verify: function(uid, email) { |  | ||||||
| 			if (!plugins.hasListeners('action:email.send')) { |  | ||||||
| 				return; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			var confirm_code = utils.generateUUID(), |  | ||||||
| 				confirm_link = nconf.get('url') + '/confirm/' + confirm_code; |  | ||||||
|  |  | ||||||
| 			async.series([ |  | ||||||
| 				function(next) { |  | ||||||
| 					db.setObject('confirm:' + confirm_code, { |  | ||||||
| 						email: email, |  | ||||||
| 						uid: uid |  | ||||||
| 					}, next); |  | ||||||
| 				}, |  | ||||||
| 				function(next) { |  | ||||||
| 					db.expireAt('confirm:' + confirm_code, Math.floor(Date.now() / 1000 + 60 * 60 * 2), next); |  | ||||||
| 				} |  | ||||||
| 			], function(err) { |  | ||||||
| 				// Send intro email w/ confirm code |  | ||||||
| 				User.getUserField(uid, 'username', function(err, username) { |  | ||||||
| 					Emailer.send('welcome', uid, { |  | ||||||
| 						'site_title': (meta.config.title || 'NodeBB'), |  | ||||||
| 						username: username, |  | ||||||
| 						'confirm_link': confirm_link, |  | ||||||
|  |  | ||||||
| 						subject: 'Welcome to ' + (meta.config.title || 'NodeBB') + '!', |  | ||||||
| 						template: 'welcome', |  | ||||||
| 						uid: uid |  | ||||||
| 					}); |  | ||||||
| 				}); |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		exists: function(email, callback) { |  | ||||||
| 			User.getUidByEmail(email, function(err, exists) { |  | ||||||
| 				callback(err, !!exists); |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		confirm: function(code, callback) { |  | ||||||
| 			db.getObject('confirm:' + code, function(err, confirmObj) { |  | ||||||
| 				if (err) { |  | ||||||
| 					return callback({ |  | ||||||
| 						status:'error' |  | ||||||
| 					}); |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				if (confirmObj && confirmObj.uid && confirmObj.email) { |  | ||||||
| 					db.setObjectField('email:confirmed', confirmObj.email, '1', function() { |  | ||||||
| 						callback({ |  | ||||||
| 							status: 'ok' |  | ||||||
| 						}); |  | ||||||
| 					}); |  | ||||||
| 				} else { |  | ||||||
| 					callback({ |  | ||||||
| 						status: 'not_ok' |  | ||||||
| 					}); |  | ||||||
| 				} |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		available: function(email, callback) { |  | ||||||
| 			db.isObjectField('email:uid', email, function(err, exists) { |  | ||||||
| 				callback(err, !exists); |  | ||||||
| 			}); |  | ||||||
| 		} |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	User.notifications = { |  | ||||||
| 		get: function(uid, callback) { |  | ||||||
|  |  | ||||||
| 			function getNotifications(set, start, stop, iterator, done) { |  | ||||||
| 				db.getSortedSetRevRange(set, start, stop, function(err, nids) { |  | ||||||
| 					if(err) { |  | ||||||
| 						return done(err); |  | ||||||
| 					} |  | ||||||
|  |  | ||||||
| 					if(!nids || nids.length === 0) { |  | ||||||
| 						return done(null, []); |  | ||||||
| 					} |  | ||||||
|  |  | ||||||
| 					if (nids.length > maxNotifs) { |  | ||||||
| 						nids.length = maxNotifs; |  | ||||||
| 					} |  | ||||||
|  |  | ||||||
| 					async.map(nids, function(nid, next) { |  | ||||||
| 						notifications.get(nid, uid, function(notif_data) { |  | ||||||
| 							if(typeof iterator === 'function') { |  | ||||||
| 								iterator(notif_data); |  | ||||||
| 							} |  | ||||||
|  |  | ||||||
| 							next(null, notif_data); |  | ||||||
| 						}); |  | ||||||
| 					}, done); |  | ||||||
| 				}); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			var maxNotifs = 15; |  | ||||||
|  |  | ||||||
| 			async.parallel({ |  | ||||||
| 				unread: function(next) { |  | ||||||
| 					getNotifications('uid:' + uid + ':notifications:unread', 0, 9, function(notif_data) { |  | ||||||
| 						if (notif_data) { |  | ||||||
| 							notif_data.readClass = !notif_data.read ? 'label-warning' : ''; |  | ||||||
| 						} |  | ||||||
| 					}, next); |  | ||||||
| 				}, |  | ||||||
| 				read: function(next) { |  | ||||||
| 					getNotifications('uid:' + uid + ':notifications:read', 0, 9, null, next); |  | ||||||
| 				} |  | ||||||
| 			}, function(err, notifications) { |  | ||||||
| 				if(err) { |  | ||||||
| 					return callback(err); |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				// Remove empties |  | ||||||
| 				notifications.read = notifications.read.filter(function(notifObj) { |  | ||||||
| 					return notifObj; |  | ||||||
| 				}); |  | ||||||
| 				notifications.unread = notifications.unread.filter(function(notifObj) { |  | ||||||
| 					return notifObj; |  | ||||||
| 				}); |  | ||||||
|  |  | ||||||
| 				// Limit the number of notifications to `maxNotifs`, prioritising unread notifications |  | ||||||
| 				if (notifications.read.length + notifications.unread.length > maxNotifs) { |  | ||||||
| 					notifications.read.length = maxNotifs - notifications.unread.length; |  | ||||||
| 				} |  | ||||||
|  |  | ||||||
| 				callback(null, notifications); |  | ||||||
| 			}); |  | ||||||
| 		}, |  | ||||||
| 		getAll: function(uid, limit, before, callback) { |  | ||||||
| 			var	now = new Date(); |  | ||||||
|  |  | ||||||
| 			if (!limit || parseInt(limit, 10) <= 0) { |  | ||||||
| 				limit = 25; |  | ||||||
| 			} |  | ||||||
| 			if (before) { |  | ||||||
| 				before = new Date(parseInt(before, 10)); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			var args1 = ['uid:' + uid + ':notifications:read', before ? before.getTime(): now.getTime(), -Infinity, 'LIMIT', 0, limit]; |  | ||||||
| 			var args2 = ['uid:' + uid + ':notifications:unread', before ? before.getTime(): now.getTime(), -Infinity, 'LIMIT', 0, limit]; |  | ||||||
|  |  | ||||||
| 			db.getSortedSetRevRangeByScore(args1, function(err, results1) { |  | ||||||
| 				db.getSortedSetRevRangeByScore(args2, function(err, results2) { |  | ||||||
|  |  | ||||||
| 					var nids = results1.concat(results2); |  | ||||||
| 					async.map(nids, function(nid, next) { |  | ||||||
| 						notifications.get(nid, uid, function(notif_data) { |  | ||||||
| 							next(null, notif_data); |  | ||||||
| 						}); |  | ||||||
| 					}, function(err, notifs) { |  | ||||||
| 						notifs = notifs.filter(function(notif) { |  | ||||||
| 							return notif !== null; |  | ||||||
| 						}).sort(function(a, b) { |  | ||||||
| 							return parseInt(b.datetime, 10) - parseInt(a.datetime, 10); |  | ||||||
| 						}).map(function(notif) { |  | ||||||
| 							notif.datetimeISO = utils.toISOString(notif.datetime); |  | ||||||
| 							notif.readClass = !notif.read ? 'label-warning' : ''; |  | ||||||
|  |  | ||||||
| 							return notif; |  | ||||||
| 						}); |  | ||||||
|  |  | ||||||
| 						callback(err, notifs); |  | ||||||
| 					}); |  | ||||||
| 				}); |  | ||||||
| 			}); |  | ||||||
|  |  | ||||||
| 		}, |  | ||||||
| 		getUnreadCount: function(uid, callback) { |  | ||||||
| 			db.sortedSetCount('uid:' + uid + ':notifications:unread', -Infinity, Infinity, callback); |  | ||||||
| 		}, |  | ||||||
| 		getUnreadByUniqueId: function(uid, uniqueId, callback) { |  | ||||||
| 			db.getSortedSetRange('uid:' + uid + ':notifications:unread', 0, -1, function(err, nids) { |  | ||||||
|  |  | ||||||
| 				async.filter(nids, function(nid, next) { |  | ||||||
| 					notifications.get(nid, uid, function(notifObj) { |  | ||||||
| 						if(!notifObj) { |  | ||||||
| 							return next(false); |  | ||||||
| 						} |  | ||||||
|  |  | ||||||
| 						if (notifObj.uniqueId === uniqueId) { |  | ||||||
| 							next(true); |  | ||||||
| 						} else { |  | ||||||
| 							next(false); |  | ||||||
| 						} |  | ||||||
| 					}); |  | ||||||
| 				}, function(nids) { |  | ||||||
| 					callback(null, nids); |  | ||||||
| 				}); |  | ||||||
| 			}); |  | ||||||
| 		} |  | ||||||
| 	}; |  | ||||||
| }(exports)); | }(exports)); | ||||||
|   | |||||||
							
								
								
									
										89
									
								
								src/useremail.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								src/useremail.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,89 @@ | |||||||
|  |  | ||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | var async = require('async'), | ||||||
|  | 	nconf = require('nconf'), | ||||||
|  | 	winston = require('winston'), | ||||||
|  |  | ||||||
|  | 	user = require('./user'), | ||||||
|  | 	utils = require('./../public/src/utils'), | ||||||
|  | 	plugins = require('./plugins'), | ||||||
|  | 	db = require('./database'), | ||||||
|  | 	meta = require('./meta'), | ||||||
|  | 	emailer = require('./emailer'); | ||||||
|  |  | ||||||
|  | (function(UserEmail) { | ||||||
|  |  | ||||||
|  | 	UserEmail.exists = function(email, callback) { | ||||||
|  | 		user.getUidByEmail(email, function(err, exists) { | ||||||
|  | 			callback(err, !!exists); | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	UserEmail.available = function(email, callback) { | ||||||
|  | 		db.isObjectField('email:uid', email, function(err, exists) { | ||||||
|  | 			callback(err, !exists); | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	UserEmail.verify = function(uid, email) { | ||||||
|  | 		if (!plugins.hasListeners('action:email.send')) { | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		var confirm_code = utils.generateUUID(), | ||||||
|  | 			confirm_link = nconf.get('url') + '/confirm/' + confirm_code; | ||||||
|  |  | ||||||
|  | 		async.series([ | ||||||
|  | 			function(next) { | ||||||
|  | 				db.setObject('confirm:' + confirm_code, { | ||||||
|  | 					email: email, | ||||||
|  | 					uid: uid | ||||||
|  | 				}, next); | ||||||
|  | 			}, | ||||||
|  | 			function(next) { | ||||||
|  | 				db.expireAt('confirm:' + confirm_code, Math.floor(Date.now() / 1000 + 60 * 60 * 2), next); | ||||||
|  | 			} | ||||||
|  | 		], function(err) { | ||||||
|  | 			// Send intro email w/ confirm code | ||||||
|  | 			user.getUserField(uid, 'username', function(err, username) { | ||||||
|  | 				if (err) { | ||||||
|  | 					return winston.error(err.message); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				emailer.send('welcome', uid, { | ||||||
|  | 					site_title: (meta.config.title || 'NodeBB'), | ||||||
|  | 					username: username, | ||||||
|  | 					confirm_link: confirm_link, | ||||||
|  |  | ||||||
|  | 					subject: 'Welcome to ' + (meta.config.title || 'NodeBB') + '!', | ||||||
|  | 					template: 'welcome', | ||||||
|  | 					uid: uid | ||||||
|  | 				}); | ||||||
|  | 			}); | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	UserEmail.confirm = function(code, callback) { | ||||||
|  | 		db.getObject('confirm:' + code, function(err, confirmObj) { | ||||||
|  | 			if (err) { | ||||||
|  | 				return callback({ | ||||||
|  | 					status:'error' | ||||||
|  | 				}); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (confirmObj && confirmObj.uid && confirmObj.email) { | ||||||
|  | 				db.setObjectField('email:confirmed', confirmObj.email, '1', function() { | ||||||
|  | 					callback({ | ||||||
|  | 						status: 'ok' | ||||||
|  | 					}); | ||||||
|  | 				}); | ||||||
|  | 			} else { | ||||||
|  | 				callback({ | ||||||
|  | 					status: 'not_ok' | ||||||
|  | 				}); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | }(exports)); | ||||||
							
								
								
									
										174
									
								
								src/usernotifications.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								src/usernotifications.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,174 @@ | |||||||
|  |  | ||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | var async = require('async'), | ||||||
|  | 	nconf = require('nconf'), | ||||||
|  | 	winston = require('winston'), | ||||||
|  |  | ||||||
|  | 	user = require('./user'), | ||||||
|  | 	utils = require('./../public/src/utils'), | ||||||
|  | 	db = require('./database'), | ||||||
|  | 	notifications = require('./notifications'), | ||||||
|  | 	topics = require('./topics'), | ||||||
|  | 	websockets = require('./socket.io'); | ||||||
|  |  | ||||||
|  | (function(UserNotifications) { | ||||||
|  |  | ||||||
|  | 	UserNotifications.get = function(uid, callback) { | ||||||
|  | 		function getNotifications(set, start, stop, iterator, done) { | ||||||
|  | 			db.getSortedSetRevRange(set, start, stop, function(err, nids) { | ||||||
|  | 				if(err) { | ||||||
|  | 					return done(err); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if(!nids || nids.length === 0) { | ||||||
|  | 					return done(null, []); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (nids.length > maxNotifs) { | ||||||
|  | 					nids.length = maxNotifs; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				async.map(nids, function(nid, next) { | ||||||
|  | 					notifications.get(nid, uid, function(notif_data) { | ||||||
|  | 						if(typeof iterator === 'function') { | ||||||
|  | 							iterator(notif_data); | ||||||
|  | 						} | ||||||
|  |  | ||||||
|  | 						next(null, notif_data); | ||||||
|  | 					}); | ||||||
|  | 				}, done); | ||||||
|  | 			}); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		var maxNotifs = 15; | ||||||
|  |  | ||||||
|  | 		async.parallel({ | ||||||
|  | 			unread: function(next) { | ||||||
|  | 				getNotifications('uid:' + uid + ':notifications:unread', 0, 9, function(notif_data) { | ||||||
|  | 					if (notif_data) { | ||||||
|  | 						notif_data.readClass = !notif_data.read ? 'label-warning' : ''; | ||||||
|  | 					} | ||||||
|  | 				}, next); | ||||||
|  | 			}, | ||||||
|  | 			read: function(next) { | ||||||
|  | 				getNotifications('uid:' + uid + ':notifications:read', 0, 9, null, next); | ||||||
|  | 			} | ||||||
|  | 		}, function(err, notifications) { | ||||||
|  | 			function filterDeleted(notifObj) { | ||||||
|  | 				return !!notifObj; | ||||||
|  | 			} | ||||||
|  | 			if(err) { | ||||||
|  | 				return callback(err); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			notifications.read = notifications.read.filter(filterDeleted); | ||||||
|  | 			notifications.unread = notifications.unread.filter(filterDeleted); | ||||||
|  |  | ||||||
|  | 			// Limit the number of notifications to `maxNotifs`, prioritising unread notifications | ||||||
|  | 			if (notifications.read.length + notifications.unread.length > maxNotifs) { | ||||||
|  | 				notifications.read.length = maxNotifs - notifications.unread.length; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			callback(null, notifications); | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	UserNotifications.getAll = function(uid, limit, before, callback) { | ||||||
|  | 		var	now = new Date(); | ||||||
|  |  | ||||||
|  | 		if (!limit || parseInt(limit, 10) <= 0) { | ||||||
|  | 			limit = 25; | ||||||
|  | 		} | ||||||
|  | 		if (before) { | ||||||
|  | 			before = new Date(parseInt(before, 10)); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		var args1 = ['uid:' + uid + ':notifications:read', before ? before.getTime(): now.getTime(), -Infinity, 'LIMIT', 0, limit]; | ||||||
|  | 		var args2 = ['uid:' + uid + ':notifications:unread', before ? before.getTime(): now.getTime(), -Infinity, 'LIMIT', 0, limit]; | ||||||
|  |  | ||||||
|  | 		db.getSortedSetRevRangeByScore(args1, function(err, results1) { | ||||||
|  | 			db.getSortedSetRevRangeByScore(args2, function(err, results2) { | ||||||
|  |  | ||||||
|  | 				var nids = results1.concat(results2); | ||||||
|  | 				async.map(nids, function(nid, next) { | ||||||
|  | 					notifications.get(nid, uid, function(notif_data) { | ||||||
|  | 						next(null, notif_data); | ||||||
|  | 					}); | ||||||
|  | 				}, function(err, notifs) { | ||||||
|  | 					notifs = notifs.filter(function(notif) { | ||||||
|  | 						return notif !== null; | ||||||
|  | 					}).sort(function(a, b) { | ||||||
|  | 						return parseInt(b.datetime, 10) - parseInt(a.datetime, 10); | ||||||
|  | 					}).map(function(notif) { | ||||||
|  | 						notif.datetimeISO = utils.toISOString(notif.datetime); | ||||||
|  | 						notif.readClass = !notif.read ? 'label-warning' : ''; | ||||||
|  |  | ||||||
|  | 						return notif; | ||||||
|  | 					}); | ||||||
|  |  | ||||||
|  | 					callback(err, notifs); | ||||||
|  | 				}); | ||||||
|  | 			}); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	UserNotifications.getUnreadCount = function(uid, callback) { | ||||||
|  | 		db.sortedSetCount('uid:' + uid + ':notifications:unread', -Infinity, Infinity, callback); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	UserNotifications.getUnreadByUniqueId = function(uid, uniqueId, callback) { | ||||||
|  | 		db.getSortedSetRange('uid:' + uid + ':notifications:unread', 0, -1, function(err, nids) { | ||||||
|  |  | ||||||
|  | 			async.filter(nids, function(nid, next) { | ||||||
|  | 				notifications.get(nid, uid, function(notifObj) { | ||||||
|  | 					if(!notifObj) { | ||||||
|  | 						return next(false); | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					if (notifObj.uniqueId === uniqueId) { | ||||||
|  | 						next(true); | ||||||
|  | 					} else { | ||||||
|  | 						next(false); | ||||||
|  | 					} | ||||||
|  | 				}); | ||||||
|  | 			}, function(nids) { | ||||||
|  | 				callback(null, nids); | ||||||
|  | 			}); | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	UserNotifications.sendPostNotificationToFollowers = function(uid, tid, pid) { | ||||||
|  | 		user.getUserField(uid, 'username', function(err, username) { | ||||||
|  | 			db.getSetMembers('followers:' + uid, function(err, followers) { | ||||||
|  | 				if (followers && followers.length) { | ||||||
|  | 					topics.getTopicField(tid, 'slug', function(err, slug) { | ||||||
|  | 						var message = '<strong>' + username + '</strong> made a new post'; | ||||||
|  |  | ||||||
|  | 						notifications.create({ | ||||||
|  | 							text: message, | ||||||
|  | 							path: nconf.get('relative_path') + '/topic/' + slug + '#' + pid, | ||||||
|  | 							uniqueId: 'topic:' + tid, | ||||||
|  | 							from: uid | ||||||
|  | 						}, function(nid) { | ||||||
|  | 							notifications.push(nid, followers); | ||||||
|  | 						}); | ||||||
|  | 					}); | ||||||
|  | 				} | ||||||
|  | 			}); | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	UserNotifications.pushCount = function(uid) { | ||||||
|  |  | ||||||
|  | 		UserNotifications.getUnreadCount(uid, function(err, count) { | ||||||
|  | 			if (err) { | ||||||
|  | 				return winston.warn('[User.pushNotifCount] Count not retrieve unread notifications count to push to uid ' + uid + '\'s client(s)'); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			websockets.in('uid_' + uid).emit('event:notifications.updateCount', count); | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | }(exports)); | ||||||
							
								
								
									
										92
									
								
								src/userreset.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/userreset.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | |||||||
|  |  | ||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | var async = require('async'), | ||||||
|  | 	nconf = require('nconf'), | ||||||
|  |  | ||||||
|  | 	user = require('./user'), | ||||||
|  | 	utils = require('./../public/src/utils'), | ||||||
|  |  | ||||||
|  | 	db = require('./database'), | ||||||
|  | 	meta = require('./meta'), | ||||||
|  | 	events = require('./events'), | ||||||
|  | 	emailer = require('./emailer'); | ||||||
|  |  | ||||||
|  | (function(UserReset) { | ||||||
|  |  | ||||||
|  | 	UserReset.validate = function(socket, code, callback) { | ||||||
|  | 		db.getObjectField('reset:uid', code, function(err, uid) { | ||||||
|  | 			if (err || !uid) { | ||||||
|  | 				return callback(err, false); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			db.getObjectField('reset:expiry', code, function(err, expiry) { | ||||||
|  | 				if (err) { | ||||||
|  | 					return callback(err); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				if (parseInt(expiry, 10) >= Date.now() / 1000) { | ||||||
|  | 					callback(null, true); | ||||||
|  | 				} else { | ||||||
|  | 					// Expired, delete from db | ||||||
|  | 					db.deleteObjectField('reset:uid', code); | ||||||
|  | 					db.deleteObjectField('reset:expiry', code); | ||||||
|  | 					callback(null, false); | ||||||
|  | 				} | ||||||
|  | 			}); | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	UserReset.send = function(socket, email, callback) { | ||||||
|  | 		user.getUidByEmail(email, function(err, uid) { | ||||||
|  | 			if(err || !uid) { | ||||||
|  | 				return callback(err || new Error('invalid-email')); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Generate a new reset code | ||||||
|  | 			var reset_code = utils.generateUUID(); | ||||||
|  | 			db.setObjectField('reset:uid', reset_code, uid); | ||||||
|  | 			db.setObjectField('reset:expiry', reset_code, (60 * 60) + Math.floor(Date.now() / 1000)); | ||||||
|  |  | ||||||
|  | 			var reset_link = nconf.get('url') + '/reset/' + reset_code; | ||||||
|  |  | ||||||
|  | 			emailer.send('reset', uid, { | ||||||
|  | 				site_title: (meta.config.title || 'NodeBB'), | ||||||
|  | 				reset_link: reset_link, | ||||||
|  |  | ||||||
|  | 				subject: 'Password Reset Requested - ' + (meta.config.title || 'NodeBB') + '!', | ||||||
|  | 				template: 'reset', | ||||||
|  | 				uid: uid | ||||||
|  | 			}); | ||||||
|  |  | ||||||
|  | 			callback(); | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	UserReset.commit = function(socket, code, password, callback) { | ||||||
|  | 		UserReset.validate(socket, code, function(err, validated) { | ||||||
|  | 			if(err) { | ||||||
|  | 				return callback(err); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (validated) { | ||||||
|  | 				db.getObjectField('reset:uid', code, function(err, uid) { | ||||||
|  | 					if (err) { | ||||||
|  | 						return callback(err); | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					user.hashPassword(password, function(err, hash) { | ||||||
|  | 						user.setUserField(uid, 'password', hash); | ||||||
|  | 						events.logPasswordReset(uid); | ||||||
|  | 					}); | ||||||
|  |  | ||||||
|  | 					db.deleteObjectField('reset:uid', code); | ||||||
|  | 					db.deleteObjectField('reset:expiry', code); | ||||||
|  |  | ||||||
|  | 					callback(null); | ||||||
|  | 				}); | ||||||
|  | 			} | ||||||
|  | 		}); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | }(exports)); | ||||||
		Reference in New Issue
	
	Block a user