v1.18.x
barisusakli 10 years ago
parent de228fa67d
commit 57c2418157

@ -9,7 +9,7 @@
"maximumPostLength": 32767,
"allowGuestSearching": 0,
"allowTopicsThumbnail": 0,
"allowRegistration": 1,
"registrationType": "normal",
"allowLocalLogin": 1,
"allowAccountDelete": 1,
"allowFileUploads": 0,

@ -7,6 +7,7 @@
"welcome.text1": "Thank you for registering with %1!",
"welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.",
"welcome.text3": "An administrator has accepted your registration application. You can login with your username/password now.",
"welcome.cta": "Click here to confirm your email address",
"reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.",

@ -22,6 +22,7 @@
"user_posted_topic": "<strong>%1</strong> has posted a new topic: <strong>%2</strong>",
"user_mentioned_you_in": "<strong>%1</strong> mentioned you in <strong>%2</strong>",
"user_started_following_you": "<strong>%1</strong> started following you.",
"new_register": "<strong>%1</strong> sent a registration request.",
"email-confirmed": "Email Confirmed",
"email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.",

@ -14,5 +14,6 @@
"register_now_button": "Register Now",
"alternative_registration": "Alternative Registration",
"terms_of_use": "Terms of Use",
"agree_to_terms_of_use": "I agree to the Terms of Use"
"agree_to_terms_of_use": "I agree to the Terms of Use",
"registration-added-to-queue": "Your registration has been added to the approval queue. You will receive an email when it is accepted by an administrator."
}

@ -0,0 +1,28 @@
"use strict";
/* global config, socket, define, templates, bootbox, app, ajaxify, */
define('admin/manage/registration', function() {
var Registration = {};
Registration.init = function() {
$('.users-list').on('click', '[data-action]', function(ev) {
var $this = this;
var parent = $(this).parents('[data-username]');
var action = $(this).attr('data-action');
var username = parent.attr('data-username');
var method = action === 'accept' ? 'admin.user.acceptRegistration' : 'admin.user.rejectRegistration';
socket.emit(method, {username: username}, function(err) {
if (err) {
return app.alertError(err.message);
}
parent.remove();
});
return false;
});
};
return Registration;
});

@ -69,7 +69,15 @@ define('forum/register', ['csrf', 'translator'], function(csrf, translator) {
'x-csrf-token': csrf.get()
},
success: function(data, status) {
window.location.href = data;
registerBtn.removeClass('disabled');
if (!data) {
return;
}
if (data.referrer) {
window.location.href = data.referrer;
} else if (data.message) {
app.alert({message: data.message, timeout: 20000});
}
},
error: function(data, status) {
var errorEl = $('#register-error-notify');
@ -84,7 +92,7 @@ define('forum/register', ['csrf', 'translator'], function(csrf, translator) {
});
});
if(agreeTerms.length) {
if (agreeTerms.length) {
agreeTerms.on('click', function() {
if ($(this).prop('checked')) {
register.removeAttr('disabled');

@ -30,6 +30,15 @@ usersController.banned = function(req, res, next) {
getUsers('users:banned', req, res, next);
};
usersController.registrationQueue = function(req, res, next) {
user.getRegistrationQueue(0, -1, function(err, data) {
if (err) {
return next(err);
}
res.render('admin/manage/registration', {users: data});
})
};
function getUsers(set, req, res, next) {
user.getUsersFromSet(set, req.uid, 0, 49, function(err, users) {
if (err) {

@ -16,7 +16,9 @@ var async = require('async'),
authenticationController = {};
authenticationController.register = function(req, res, next) {
if (parseInt(meta.config.allowRegistration, 10) === 0) {
var registrationType = meta.config.registrationType || 'normal';
if (registrationType === 'disabled') {
return res.sendStatus(403);
}
@ -53,7 +55,26 @@ authenticationController.register = function(req, res, next) {
plugins.fireHook('filter:register.check', {req: req, res: res, userData: userData}, next);
},
function(data, next) {
user.create(data.userData, next);
if (registrationType === 'normal') {
registerAndLoginUser(req, res, userData, next);
} else if (registrationType === 'admin-approval') {
addToApprovalQueue(req, res, userData, next);
}
}
], function(err, data) {
if (err) {
return res.status(400).send(err.message);
}
res.json(data);
});
};
function registerAndLoginUser(req, res, userData, callback) {
var uid;
async.waterfall([
function(next) {
user.create(userData, next);
},
function(_uid, next) {
uid = _uid;
@ -64,16 +85,22 @@ authenticationController.register = function(req, res, next) {
user.notifications.sendWelcomeNotification(uid);
plugins.fireHook('filter:register.complete', {uid: uid, referrer: req.body.referrer}, next);
}
], function(err, data) {
if (err) {
return res.status(400).send(err.message);
plugins.fireHook('filter:register.complete', {uid: uid, referrer: req.body.referrer || nconf.get('relative_path') + '/'}, next);
}
], callback);
}
res.status(200).send(data.referrer ? data.referrer : nconf.get('relative_path') + '/');
});
};
function addToApprovalQueue(req, res, userData, callback) {
async.waterfall([
function(next) {
userData.ip = req.ip;
user.addToApprovalQueue(userData, next);
},
function(next) {
next(null, {message: '[[register:registration-added-to-queue]]'});
}
], callback);
}
authenticationController.login = function(req, res, next) {
// Handle returnTo data

@ -77,11 +77,13 @@ Controllers.login = function(req, res, next) {
loginStrategies = require('../routes/authentication').getLoginStrategies(),
emailersPresent = plugins.hasListeners('action:email.send');
var registrationType = meta.config.registrationType || 'normal';
data.alternate_logins = loginStrategies.length > 0;
data.authentication = loginStrategies;
data.showResetLink = emailersPresent;
data.allowLocalLogin = parseInt(meta.config.allowLocalLogin, 10) === 1 || parseInt(req.query.local, 10) === 1;
data.allowRegistration = parseInt(meta.config.allowRegistration, 10) === 1;
data.allowRegistration = registrationType === 'normal' || registrationType === 'admin-approval';
data.allowLoginWith = '[[login:' + (meta.config.allowLoginWith || 'username-email') + ']]';
data.breadcrumbs = helpers.buildBreadcrumbs([{text: '[[global:login]]'}]);
data.error = req.flash('error')[0];
@ -90,7 +92,9 @@ Controllers.login = function(req, res, next) {
};
Controllers.register = function(req, res, next) {
if (parseInt(meta.config.allowRegistration, 10) === 0) {
var registrationType = meta.config.registrationType || 'normal';
if (registrationType === 'disabled') {
return helpers.notFound(req, res);
}

@ -80,7 +80,7 @@ middleware.redirectToLoginIfGuest = function(req, res, next) {
if (!req.user || parseInt(req.user.uid, 10) === 0) {
return redirectToLogin(req, res);
}
next();
};
@ -191,16 +191,17 @@ middleware.buildHeader = function(req, res, next) {
};
middleware.renderHeader = function(req, res, callback) {
var registrationType = meta.config.registrationType || 'normal'
var templateValues = {
bootswatchCSS: meta.config['theme:src'],
title: meta.config.title || '',
description: meta.config.description || '',
'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '',
'brand:logo': meta.config['brand:logo'] || '',
'brand:logo:display': meta.config['brand:logo']?'':'hide',
allowRegistration: meta.config.allowRegistration === undefined || parseInt(meta.config.allowRegistration, 10) === 1,
searchEnabled: plugins.hasListeners('filter:search.query')
};
bootswatchCSS: meta.config['theme:src'],
title: meta.config.title || '',
description: meta.config.description || '',
'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '',
'brand:logo': meta.config['brand:logo'] || '',
'brand:logo:display': meta.config['brand:logo']?'':'hide',
allowRegistration: registrationType === 'normal' || registrationType === 'admin-approval',
searchEnabled: plugins.hasListeners('filter:search.query')
};
for (var key in res.locals.config) {
if (res.locals.config.hasOwnProperty(key)) {

@ -58,6 +58,7 @@ function addRoutes(router, middleware, controllers) {
router.get('/manage/users/sort-posts', controllers.admin.users.sortByPosts);
router.get('/manage/users/sort-reputation', controllers.admin.users.sortByReputation);
router.get('/manage/users/banned', controllers.admin.users.banned);
router.get('/manage/users/registration', controllers.admin.users.registrationQueue);
router.get('/manage/groups', controllers.admin.groups.list);
router.get('/manage/groups/:name', controllers.admin.groups.get);

@ -241,4 +241,13 @@ User.search = function(socket, data, callback) {
});
};
User.acceptRegistration = function(socket, data, callback) {
user.acceptRegistration(data.username, callback);
};
User.rejectRegistration = function(socket, data, callback) {
user.rejectRegistration(data.username, callback);
};
module.exports = User;

@ -30,6 +30,7 @@ var async = require('async'),
require('./user/search')(User);
require('./user/jobs')(User);
require('./user/picture')(User);
require('./user/approval')(User);
User.getUserField = function(uid, field, callback) {
User.getUserFields(uid, [field], function(err, user) {

@ -0,0 +1,139 @@
'use strict';
var async = require('async'),
nconf = require('nconf'),
db = require('./../database'),
meta = require('../meta'),
emailer = require('../emailer'),
notifications = require('../notifications'),
translator = require('../../public/src/modules/translator'),
utils = require('../../public/src/utils');
module.exports = function(User) {
User.addToApprovalQueue = function(userData, callback) {
userData.userslug = utils.slugify(userData.username);
async.waterfall([
function(next) {
User.isDataValid(userData, next);
},
function(next) {
User.hashPassword(userData.password, next);
},
function(hashedPassword, next) {
var data = {
username: userData.username,
email: userData.email,
ip: userData.ip,
hashedPassword: hashedPassword
};
db.setObject('registration:queue:name:' + userData.username, data, next);
},
function(next) {
db.sortedSetAdd('registration:queue', Date.now(), userData.username, next);
},
function(next) {
sendNotificationToAdmins(userData.username, next);
}
], callback);
};
function sendNotificationToAdmins(username, callback) {
notifications.create({
bodyShort: '[[notifications:new_register, ' + username + ']]',
nid: 'new_register' + username,
path: '/admin/manage/users/registration'
}, function(err, notification) {
if (err) {
return callback(err);
}
if (notification) {
notifications.pushGroup(notification, 'administrators', callback);
} else {
callback();
}
});
}
User.acceptRegistration = function(username, callback) {
var uid;
var userData;
async.waterfall([
function(next) {
db.getObject('registration:queue:name:' + username, next);
},
function(_userData, next) {
if (!_userData) {
return callback(new Error('[[error:invalid-data]]'));
}
userData = _userData;
User.create(userData, next);
},
function(_uid, next) {
uid = _uid;
User.setUserField(uid, 'password', userData.hashedPassword, next);
},
function(next) {
var title = meta.config.title || meta.config.browserTitle || 'NodeBB';
translator.translate('[[email:welcome-to, ' + title + ']]', meta.config.defaultLang, function(subject) {
var data = {
site_title: title,
username: username,
subject: subject,
template: 'registration_accepted',
uid: uid
};
emailer.send('registration_accepted', uid, data, next);
});
},
function(next) {
User.notifications.sendWelcomeNotification(uid, next);
},
function(next) {
removeFromQueue(username, next);
}
], callback);
};
User.rejectRegistration = function(username, callback) {
removeFromQueue(username, callback);
};
function removeFromQueue(username, callback) {
async.parallel([
async.apply(db.sortedSetRemove, 'registration:queue', username),
async.apply(db.delete, 'registration:queue:name:' + username)
], callback);
}
User.getRegistrationQueue = function(start, stop, callback) {
var data;
async.waterfall([
function(next) {
db.getSortedSetRevRangeWithScores('registration:queue', start, stop, next);
},
function(_data, next) {
data = _data;
var keys = data.filter(Boolean).map(function(user) {
return 'registration:queue:name:' + user.value;
});
db.getObjects(keys, next);
},
function(users, next) {
users.forEach(function(user, index) {
if (user) {
user.timestamp = utils.toISOString(data[index].score);
}
});
next(null, users);
}
], callback);
};
};

@ -20,7 +20,7 @@ module.exports = function(User) {
data.email = validator.escape(data.email.trim());
}
isDataValid(data, function(err) {
User.isDataValid(data, function(err) {
if (err) {
return callback(err);
}
@ -155,7 +155,7 @@ module.exports = function(User) {
});
};
function isDataValid(userData, callback) {
User.isDataValid = function(userData, callback) {
async.parallel({
emailValid: function(next) {
if (userData.email) {
@ -186,8 +186,10 @@ module.exports = function(User) {
next();
}
}
}, callback);
}
}, function(err, results) {
callback(err);
});
};
function renameUsername(userData, callback) {
meta.userOrGroupExists(userData.userslug, function(err, exists) {

@ -289,9 +289,10 @@ var async = require('async'),
});
};
UserNotifications.sendWelcomeNotification = function(uid) {
UserNotifications.sendWelcomeNotification = function(uid, callback) {
callback = callback || function() {};
if (!meta.config.welcomeNotification) {
return;
return callback();
}
var path = meta.config.welcomeLink ? meta.config.welcomeLink : '#';
@ -301,8 +302,13 @@ var async = require('async'),
path: path,
nid: 'welcome_' + uid
}, function(err, notification) {
if (!err && notification) {
notifications.push(notification, [uid]);
if (err) {
return callback(err);
}
if (notification) {
notifications.push(notification, [uid], callback);
} else {
callback();
}
});
};

@ -0,0 +1,40 @@
<div class="registration">
<div class="col-lg-9">
<div class="panel panel-default">
<div class="panel-heading"><i class="fa fa-group"></i> Registration Queue</div>
<div class="panel-body">
<table class="table table-striped users-list">
<tr>
<th>Name</th>
<th>Email</th>
<th>IP</th>
<th>Time</th>
<th></th>
</tr>
<!-- BEGIN users -->
<tr data-username="{users.username}">
<td>
{users.username}
</td>
<td>
{users.email}
</td>
<td>
{users.ip}
</td>
<td>
<span class="timeago" title="{users.timestamp}"></span>
</td>
<td>
<div class="btn-group pull-right">
<button class="btn btn-success btn-xs" data-action="accept"><i class="fa fa-check"></i></button>
<button class="btn btn-danger btn-xs" data-action="delete"><i class="fa fa-times"></i></button>
</div>
</td>
</tr>
<!-- END users -->
</table>
</div>
</div>
</div>
</div>

@ -8,6 +8,7 @@
<li class=''><a href='{config.relative_path}/admin/manage/users/sort-posts'>Top Posters</a></li>
<li class=''><a href='{config.relative_path}/admin/manage/users/sort-reputation'>Most Reputation</a></li>
<li class=''><a href='{config.relative_path}/admin/manage/users/banned'>Banned</a></li>
<li class=''><a href='{config.relative_path}/admin/manage/users/registration'>Registration Queue</a></li>
<li class=''><a href='{config.relative_path}/admin/manage/users/search'>User Search</a></li>

@ -4,11 +4,6 @@
<div class="panel-heading">User List</div>
<div class="panel-body">
<form role="form">
<div class="checkbox">
<label>
<input type="checkbox" data-field="allowRegistration" checked> <strong>Allow local registration</strong>
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" data-field="allowLocalLogin" checked> <strong>Allow local login</strong>
@ -38,6 +33,15 @@
<option value="email">Email Only</option>
</select>
</div>
<div class="form-group">
<label>Registration Type</label>
<select class="form-control" data-field="registrationType">
<option value="normal">Normal</option>
<option value="admin-approval">Admin Approval</option>
<option value="disabled">No registration</option>
</select>
</div>
</form>
</div>
</div>

@ -0,0 +1,12 @@
<p>[[email:greeting_with_name, {username}]],</p>
<p>
<strong>[[email:welcome.text1, {site_title}]]</strong>
</p>
<p>[[email:welcome.text3]]</p>
<p>
[[email:closing]]<br />
<strong>{site_title}</strong>
</p>

@ -0,0 +1,9 @@
[[email:greeting_with_name, {username}]],
[[email:welcome.text1, {site_title}]]
[[email:welcome.text3]]
[[email:closing]]
{site_title}
Loading…
Cancel
Save