mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-01-06 15:42:52 +01:00
Merge branch 'master' of https://github.com/NodeBB/NodeBB
This commit is contained in:
@@ -90,11 +90,11 @@
|
||||
"nodebb-plugin-spam-be-gone": "0.6.1",
|
||||
"nodebb-rewards-essentials": "0.0.13",
|
||||
"nodebb-theme-lavender": "5.0.9",
|
||||
"nodebb-theme-persona": "9.1.27",
|
||||
"nodebb-theme-persona": "9.1.28",
|
||||
"nodebb-theme-slick": "1.2.23",
|
||||
"nodebb-theme-vanilla": "10.1.25",
|
||||
"nodebb-widget-essentials": "4.0.14",
|
||||
"nodemailer": "^5.0.0",
|
||||
"nodemailer": "^6.0.0",
|
||||
"passport": "^0.4.0",
|
||||
"passport-local": "1.0.0",
|
||||
"pg": "^7.4.0",
|
||||
@@ -135,10 +135,10 @@
|
||||
"@commitlint/cli": "7.5.2",
|
||||
"@commitlint/config-angular": "7.5.0",
|
||||
"coveralls": "3.0.3",
|
||||
"eslint": "5.15.1",
|
||||
"eslint": "5.15.3",
|
||||
"eslint-config-airbnb-base": "13.1.0",
|
||||
"eslint-plugin-import": "2.16.0",
|
||||
"grunt": "1.0.3",
|
||||
"grunt": "1.0.4",
|
||||
"grunt-contrib-watch": "1.1.0",
|
||||
"husky": "1.3.1",
|
||||
"jsdom": "14.0.0",
|
||||
@@ -171,4 +171,4 @@
|
||||
"url": "https://github.com/barisusakli"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,20 +5,20 @@
|
||||
"mark_all_read": "اجعل كل التنبيهات مقروءة",
|
||||
"back_to_home": "عودة إلى %1",
|
||||
"outgoing_link": "رابط خارجي",
|
||||
"outgoing_link_message": "You are now leaving %1",
|
||||
"outgoing_link_message": "أنت تغادر اﻻن %1",
|
||||
"continue_to": "استمر إلى %1",
|
||||
"return_to": "عودة إى %1",
|
||||
"new_notification": "You have a new notification",
|
||||
"new_notification": "لديك تنبيه جديد",
|
||||
"you_have_unread_notifications": "لديك تنبيهات غير مقروءة.",
|
||||
"all": "All",
|
||||
"topics": "Topics",
|
||||
"replies": "Replies",
|
||||
"chat": "Chats",
|
||||
"follows": "Follows",
|
||||
"upvote": "Upvotes",
|
||||
"all": "الكل",
|
||||
"topics": "مواضيع",
|
||||
"replies": "ردود",
|
||||
"chat": "محادثات",
|
||||
"follows": "متابعون",
|
||||
"upvote": "الموافقين",
|
||||
"new-flags": "New Flags",
|
||||
"my-flags": "Flags assigned to me",
|
||||
"bans": "Bans",
|
||||
"bans": "الحظر",
|
||||
"new_message_from": "رسالة جديدة من <strong>%1</strong>",
|
||||
"upvoted_your_post_in": "<strong>%1</strong> أضاف صوتًا إيجابيا إلى مشاركتك في <strong>%2</strong>.",
|
||||
"upvoted_your_post_in_dual": "<strong>%1</strong> and <strong>%2</strong> have upvoted your post in <strong>%3</strong>.",
|
||||
@@ -47,10 +47,10 @@
|
||||
"email-confirm-error-message": "حدث خطأ أثناء التحقق من عنوان بريدك الإلكتروني. ربما رمز التفعيل خاطئ أو انتهت صلاحيته.",
|
||||
"email-confirm-sent": "تم إرسال بريد التفعيل.",
|
||||
"none": "None",
|
||||
"notification_only": "Notification Only",
|
||||
"email_only": "Email Only",
|
||||
"notification_and_email": "Notification & Email",
|
||||
"notificationType_upvote": "When someone upvotes your post",
|
||||
"notification_only": "التنبيهات فقط",
|
||||
"email_only": "البريد الالكتروني فقط",
|
||||
"notification_and_email": "التنبيهات والبريد اﻻلكتروني",
|
||||
"notificationType_upvote": "عندما يوافقك احدهم على منشورك",
|
||||
"notificationType_new-topic": "When someone you follow posts a topic",
|
||||
"notificationType_new-reply": "When a new reply is posted in a topic you are watching",
|
||||
"notificationType_follow": "When someone starts following you",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"validate-email": "Validate Email",
|
||||
"send-validation-email": "Send Validation Email",
|
||||
"password-reset-email": "Send Password Reset Email",
|
||||
"force-password-reset": "Force Password Reset & Log User Out",
|
||||
"ban": "Ban User(s)",
|
||||
"temp-ban": "Ban User(s) Temporarily",
|
||||
"unban": "Unban User(s)",
|
||||
@@ -81,7 +82,9 @@
|
||||
"alerts.confirm-remove-moderator": "Do you really want to remove this moderator?",
|
||||
"alerts.remove-moderator-success": "User is no longer moderator.",
|
||||
"alerts.confirm-validate-email": "Do you want to validate email(s) of these user(s)?",
|
||||
"alerts.confirm-force-password-reset": "Are you sure you want to force the password reset and log out these user(s)?",
|
||||
"alerts.validate-email-success": "Emails validated",
|
||||
"alerts.validate-force-password-reset-success": "User(s) passwords have been reset and their existing sessions have been revoked.",
|
||||
"alerts.password-reset-confirm": "Do you want to send password reset email(s) to these user(s)?",
|
||||
"alerts.confirm-delete": "<b>Warning!</b><br/>Do you really want to delete user(s)?<br/> This action is not reversable! Only the user account will be deleted, their posts and topics will remain.",
|
||||
"alerts.delete-success": "User(s) Deleted!",
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
{
|
||||
"global": "Global",
|
||||
"global.no-users": "No user-specific global privileges.",
|
||||
"global": "グローバル",
|
||||
"global.no-users": "ユーザー固有のグローバル特権はありません。",
|
||||
|
||||
"chat": "Chat",
|
||||
"upload-images": "Upload Images",
|
||||
"upload-files": "Upload Files",
|
||||
"signature": "Signature",
|
||||
"chat": "チャット",
|
||||
"upload-images": "画像をアップロード",
|
||||
"upload-files": "ファイルをアップロード",
|
||||
"signature": "署名",
|
||||
"ban": "Ban",
|
||||
"search-content": "Search Content",
|
||||
"search-users": "Search Users",
|
||||
"search-tags": "Search Tags",
|
||||
"view-users": "View Users",
|
||||
"view-tags": "View Tags",
|
||||
"view-groups": "View Groups",
|
||||
"allow-local-login": "Local Login",
|
||||
"allow-group-creation": "Group Create",
|
||||
"search-content": "コンテンツを検索",
|
||||
"search-users": "ユーザー検索",
|
||||
"search-tags": "タグ検索",
|
||||
"view-users": "ユーザーを表示",
|
||||
"view-tags": "タグを表示",
|
||||
"view-groups": "グループを表示",
|
||||
"allow-local-login": "ローカルログイン",
|
||||
"allow-group-creation": "グループを作成",
|
||||
|
||||
"find-category": "Find Category",
|
||||
"access-category": "Access Category",
|
||||
"access-topics": "Access Topics",
|
||||
"create-topics": "Create Topics",
|
||||
"reply-to-topics": "Reply to Topics",
|
||||
"find-category": "カテゴリを検索",
|
||||
"access-category": "カテゴリにアクセス",
|
||||
"access-topics": "トピックスにアクセス",
|
||||
"create-topics": "トピックスを作成",
|
||||
"reply-to-topics": "トピックスに返信",
|
||||
"tag-topics": "Tag Topics",
|
||||
"edit-posts": "Edit Posts",
|
||||
"view-edit-history": "View Edit History",
|
||||
|
||||
@@ -175,6 +175,19 @@ define('admin/manage/users', ['translator', 'benchpress'], function (translator,
|
||||
});
|
||||
});
|
||||
|
||||
$('.force-password-reset').on('click', function () {
|
||||
var uids = getSelectedUids();
|
||||
if (!uids.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
bootbox.confirm('[[admin/manage/users:alerts.confirm-force-password-reset]]', function (confirm) {
|
||||
if (confirm) {
|
||||
socket.emit('admin.user.forcePasswordReset', uids, done('[[admin/manage/users:alerts.validate-force-password-reset-success]]'));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.delete-user').on('click', function () {
|
||||
var uids = getSelectedUids();
|
||||
if (!uids.length) {
|
||||
|
||||
@@ -20,6 +20,10 @@ define('admin/modules/colorpicker', function () {
|
||||
$(colpkr).css('z-index', 1051);
|
||||
},
|
||||
});
|
||||
|
||||
$(window).one('action:ajaxify.start', function () {
|
||||
$this.ColorPickerHide();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -87,18 +87,20 @@ define('admin/settings/email', ['ace/ace', 'admin/settings'], function (ace) {
|
||||
return app.alertError(err.message);
|
||||
}
|
||||
|
||||
now = new Date(now);
|
||||
var date = new Date(now.timestamp);
|
||||
var offset = (new Date().getTimezoneOffset() - now.offset) / 60;
|
||||
date.setHours(date.getHours() + offset);
|
||||
|
||||
$('#serverTime').text(now.toString());
|
||||
$('#serverTime').text(date.toLocaleTimeString());
|
||||
|
||||
now.setHours(parseInt(hour, 10), 0, 0, 0);
|
||||
date.setHours(parseInt(hour, 10) - offset, 0, 0, 0);
|
||||
|
||||
// If adjusted time is in the past, move to next day
|
||||
if (now.getTime() < Date.now()) {
|
||||
now.setDate(now.getDate() + 1);
|
||||
if (date.getTime() < Date.now()) {
|
||||
date.setDate(date.getDate() + 1);
|
||||
}
|
||||
|
||||
$('#nextDigestTime').text(now.toString());
|
||||
$('#nextDigestTime').text(date.toLocaleString());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -134,9 +134,9 @@ app.cacheBuster = null;
|
||||
|
||||
// Re-render top bar menu
|
||||
var toRender = {
|
||||
'slideout-menu': $('.slideout-menu'),
|
||||
menu: $('#header-menu .container'),
|
||||
'chats-menu': $('#chats-menu'),
|
||||
'slideout-menu': $('.slideout-menu'),
|
||||
};
|
||||
Promise.all(Object.keys(toRender).map(function (tpl) {
|
||||
return Benchpress.render('partials/' + tpl, data.header).then(function (render) {
|
||||
@@ -157,6 +157,8 @@ app.cacheBuster = null;
|
||||
app.handleSearch();
|
||||
}
|
||||
|
||||
handleStatusChange();
|
||||
|
||||
$(window).trigger('action:app.updateHeader');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -273,13 +273,20 @@ function continueLogin(req, res, next) {
|
||||
if (passwordExpiry && passwordExpiry < Date.now()) {
|
||||
winston.verbose('[auth] Triggering password reset for uid ' + userData.uid + ' due to password policy');
|
||||
req.session.passwordExpired = true;
|
||||
user.reset.generate(userData.uid, function (err, code) {
|
||||
|
||||
async.series({
|
||||
code: async.apply(user.reset.generate, userData.uid),
|
||||
buildHeader: async.apply(middleware.buildHeader, req, res),
|
||||
header: async.apply(middleware.generateHeader, req, res, {}),
|
||||
}, function (err, payload) {
|
||||
if (err) {
|
||||
return helpers.noScriptErrors(req, res, err.message, 403);
|
||||
}
|
||||
|
||||
res.status(200).send({
|
||||
next: nconf.get('relative_path') + '/reset/' + code,
|
||||
next: nconf.get('relative_path') + '/reset/' + payload.code,
|
||||
header: payload.header,
|
||||
config: res.locals.config,
|
||||
});
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -62,10 +62,10 @@ Controllers.reset = function (req, res, next) {
|
||||
};
|
||||
|
||||
if (req.params.code) {
|
||||
// Save to session and redirect
|
||||
req.session.reset_code = req.params.code;
|
||||
res.redirect(nconf.get('relative_path') + '/reset');
|
||||
} else if (req.session.reset_code) {
|
||||
}
|
||||
|
||||
if (req.session.reset_code) {
|
||||
// Validate and save to local variable before removing from session
|
||||
user.reset.validate(req.session.reset_code, function (err, valid) {
|
||||
if (err) {
|
||||
|
||||
@@ -69,6 +69,7 @@ function loadConfig(configFile) {
|
||||
nconf.set('base_templates_path', path.join(nconf.get('themes_path'), 'nodebb-theme-persona/templates'));
|
||||
|
||||
nconf.set('upload_path', path.resolve(nconf.get('base_dir'), nconf.get('upload_path')));
|
||||
nconf.set('upload_url', '/assets/uploads');
|
||||
|
||||
if (nconf.get('url')) {
|
||||
nconf.set('url_parsed', url.parse(nconf.get('url')));
|
||||
|
||||
@@ -126,6 +126,25 @@ User.sendPasswordResetEmail = function (socket, uids, callback) {
|
||||
}, callback);
|
||||
};
|
||||
|
||||
User.forcePasswordReset = function (socket, uids, callback) {
|
||||
if (!Array.isArray(uids)) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
}
|
||||
|
||||
uids = uids.filter(uid => parseInt(uid, 10));
|
||||
|
||||
async.each(uids, function (uid, next) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
user.setUserField(uid, 'passwordExpiry', Date.now(), next);
|
||||
},
|
||||
function (next) {
|
||||
user.auth.revokeAllSessions(uid, next);
|
||||
},
|
||||
], next);
|
||||
}, callback);
|
||||
};
|
||||
|
||||
User.deleteUsers = function (socket, uids, callback) {
|
||||
deleteUsers(socket, uids, function (uid, next) {
|
||||
user.deleteAccount(uid, next);
|
||||
|
||||
@@ -62,7 +62,12 @@ function leaveCurrentRoom(socket) {
|
||||
|
||||
SocketMeta.getServerTime = function (socket, data, callback) {
|
||||
// Returns server time in milliseconds
|
||||
callback(null, Date.now());
|
||||
const now = new Date();
|
||||
|
||||
callback(null, {
|
||||
timestamp: now.getTime(),
|
||||
offset: now.getTimezoneOffset(),
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = SocketMeta;
|
||||
|
||||
@@ -99,7 +99,6 @@ function setupConfigs() {
|
||||
nconf.set('use_port', !!urlObject.port);
|
||||
nconf.set('relative_path', relativePath);
|
||||
nconf.set('port', nconf.get('PORT') || nconf.get('port') || urlObject.port || (nconf.get('PORT_ENV_VAR') ? nconf.get(nconf.get('PORT_ENV_VAR')) : false) || 4567);
|
||||
nconf.set('upload_url', '/assets/uploads');
|
||||
}
|
||||
|
||||
function printStartupInfo() {
|
||||
|
||||
@@ -20,7 +20,32 @@
|
||||
<br />
|
||||
|
||||
<div class="plugins row">
|
||||
<div class="col-lg-9">
|
||||
<div class="acp-sidebar col-lg-3 col-lg-push-9">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">[[admin/extend/plugins:plugin-search]]</div>
|
||||
<div class="panel-body">
|
||||
<input autofocus class="form-control" type="text" id="plugin-search" placeholder="[[admin/extend/plugins:plugin-search-placeholder]]"/><br/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">[[admin/extend/plugins:reorder-plugins]]</div>
|
||||
<div class="panel-body">
|
||||
<button class="btn btn-default btn-block" id="plugin-order"><i class="fa fa-exchange"></i> [[admin/extend/plugins:order-active]]</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">[[admin/extend/plugins:dev-interested]]</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
[[admin/extend/plugins:docs-info]]
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-9 col-lg-pull-3">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade active in" id="installed">
|
||||
<ul class="installed">
|
||||
@@ -48,32 +73,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-3 acp-sidebar">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">[[admin/extend/plugins:plugin-search]]</div>
|
||||
<div class="panel-body">
|
||||
<input autofocus class="form-control" type="text" id="plugin-search" placeholder="[[admin/extend/plugins:plugin-search-placeholder]]"/><br/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">[[admin/extend/plugins:reorder-plugins]]</div>
|
||||
<div class="panel-body">
|
||||
<button class="btn btn-default btn-block" id="plugin-order"><i class="fa fa-exchange"></i> [[admin/extend/plugins:order-active]]</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">[[admin/extend/plugins:dev-interested]]</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
[[admin/extend/plugins:docs-info]]
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="modal fade" id="order-active-plugins-modal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<li><a href="#" class="validate-email"><i class="fa fa-fw fa-check"></i> [[admin/manage/users:validate-email]]</a></li>
|
||||
<li><a href="#" class="send-validation-email"><i class="fa fa-fw fa-mail-forward"></i> [[admin/manage/users:send-validation-email]]</a></li>
|
||||
<li><a href="#" class="password-reset-email"><i class="fa fa-fw fa-key"></i> [[admin/manage/users:password-reset-email]]</a></li>
|
||||
<li><a href="#" class="force-password-reset"><i class="fa fa-fw fa-unlock-alt"></i> [[admin/manage/users:force-password-reset]]</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="#" class="ban-user"><i class="fa fa-fw fa-gavel"></i> [[admin/manage/users:ban]]</a></li>
|
||||
<li><a href="#" class="ban-user-temporary"><i class="fa fa-fw fa-clock-o"></i>[[admin/manage/users:temp-ban]]</a></li>
|
||||
|
||||
Reference in New Issue
Block a user