diff --git a/loader.js b/loader.js
index e853fa562c..56e4864289 100644
--- a/loader.js
+++ b/loader.js
@@ -29,7 +29,8 @@ var pidFilePath = __dirname + '/pidfile',
css: {
cache: undefined,
acpCache: undefined
- }
+ },
+ templatesCompiled: false
};
Loader.init = function(callback) {
@@ -86,21 +87,10 @@ Loader.addWorkerEvents = function(worker) {
if (message && typeof message === 'object' && message.action) {
switch (message.action) {
case 'ready':
- if (Loader.js.target['nodebb.min.js'] && Loader.js.target['nodebb.min.js'].cache && !worker.isPrimary) {
+ if (Loader.js.target['nodebb.min.js'] && Loader.js.target['acp.min.js'] && !worker.isPrimary) {
worker.send({
action: 'js-propagate',
- cache: Loader.js.target['nodebb.min.js'].cache,
- map: Loader.js.target['nodebb.min.js'].map,
- target: 'nodebb.min.js'
- });
- }
-
- if (Loader.js.target['acp.min.js'] && Loader.js.target['acp.min.js'].cache && !worker.isPrimary) {
- worker.send({
- action: 'js-propagate',
- cache: Loader.js.target['acp.min.js'].cache,
- map: Loader.js.target['acp.min.js'].map,
- target: 'acp.min.js'
+ data: Loader.js.target
});
}
@@ -112,6 +102,12 @@ Loader.addWorkerEvents = function(worker) {
});
}
+ if (Loader.templatesCompiled && !worker.isPrimary) {
+ worker.send({
+ action: 'templates:compiled'
+ });
+ }
+
break;
case 'restart':
@@ -141,6 +137,8 @@ Loader.addWorkerEvents = function(worker) {
}, worker.pid);
break;
case 'templates:compiled':
+ Loader.templatesCompiled = true;
+
Loader.notifyWorkers({
action: 'templates:compiled',
}, worker.pid);
diff --git a/package.json b/package.json
index efef09598a..0f9cd8e808 100644
--- a/package.json
+++ b/package.json
@@ -47,17 +47,17 @@
"morgan": "^1.3.2",
"mousetrap": "^1.5.3",
"nconf": "~0.8.2",
- "nodebb-plugin-composer-default": "4.0.10",
+ "nodebb-plugin-composer-default": "4.0.11",
"nodebb-plugin-dbsearch": "1.0.2",
"nodebb-plugin-emoji-extended": "1.1.1",
"nodebb-plugin-emoji-one": "1.1.5",
- "nodebb-plugin-markdown": "6.0.0",
- "nodebb-plugin-mentions": "1.1.2",
+ "nodebb-plugin-markdown": "6.0.1",
+ "nodebb-plugin-mentions": "1.1.3",
"nodebb-plugin-soundpack-default": "0.1.6",
"nodebb-plugin-spam-be-gone": "0.4.9",
"nodebb-rewards-essentials": "0.0.9",
"nodebb-theme-lavender": "3.0.13",
- "nodebb-theme-persona": "4.1.10",
+ "nodebb-theme-persona": "4.1.11",
"nodebb-theme-vanilla": "5.1.3",
"nodebb-widget-essentials": "2.0.10",
"nodemailer": "2.0.0",
@@ -117,4 +117,4 @@
"url": "https://github.com/barisusakli"
}
]
-}
\ No newline at end of file
+}
diff --git a/public/language/ar/category.json b/public/language/ar/category.json
index ab98dae089..d36d7a6977 100644
--- a/public/language/ar/category.json
+++ b/public/language/ar/category.json
@@ -2,13 +2,13 @@
"category": "فئة",
"subcategories": "فئة فرعية",
"new_topic_button": "موضوع جديد",
- "guest-login-post": "يجب عليك تسجيل الدخول للرد",
+ "guest-login-post": "سجل بالدخول للرد",
"no_topics": "لا توجد مواضيع في هذه الفئةلم لا تحاول إنشاء موضوع؟
",
"browsing": "تصفح",
"no_replies": "لم يرد أحد",
"no_new_posts": "لا يوجد مشاركات جديدة.",
"share_this_category": "انشر هذه الفئة",
- "watch": "متابعة",
+ "watch": "تابع",
"ignore": "تجاهل",
"watching": "Watching",
"ignoring": "Ignoring",
diff --git a/public/src/app.js b/public/src/app.js
index d4a88929b1..8875bd2d64 100644
--- a/public/src/app.js
+++ b/public/src/app.js
@@ -56,8 +56,8 @@ app.cacheBuster = null;
socket.removeAllListeners('event:nodebb.ready');
socket.on('event:nodebb.ready', function(data) {
- if (!app.cacheBusters || app.cacheBusters['cache-buster'] !== data['cache-buster']) {
- app.cacheBusters = data;
+ if (!app.cacheBuster || app.cacheBuster !== data['cache-buster']) {
+ app.cacheBuster = data['cache-buster'];
app.alert({
alert_id: 'forum_updated',
@@ -351,6 +351,7 @@ app.cacheBuster = null;
if (!utils.isTouchDevice()) {
$(this).tooltip({
placement: 'bottom',
+ trigger: 'hover',
title: $(this).attr('title')
});
}
@@ -359,6 +360,7 @@ app.cacheBuster = null;
if (!utils.isTouchDevice()) {
$('#search-form').parent().tooltip({
placement: 'bottom',
+ trigger: 'hover',
title: $('#search-button i').attr('title')
});
}
@@ -366,6 +368,7 @@ app.cacheBuster = null;
if (!utils.isTouchDevice()) {
$('#user_dropdown').tooltip({
placement: 'bottom',
+ trigger: 'hover',
title: $('#user_dropdown').attr('title')
});
}
diff --git a/public/src/client/account/settings.js b/public/src/client/account/settings.js
index c7d28c885b..1060492bf0 100644
--- a/public/src/client/account/settings.js
+++ b/public/src/client/account/settings.js
@@ -113,7 +113,7 @@ define('forum/account/settings', ['forum/account/header', 'components'], functio
// This is done via DELETE because a user shouldn't be able to
// revoke his own session! This is what logout is for
$.ajax({
- url: config.relative_path + '/user/' + ajaxify.data.userslug + '/session/' + uuid,
+ url: config.relative_path + '/api/user/' + ajaxify.data.userslug + '/session/' + uuid,
method: 'delete',
headers: {
'x-csrf-token': config.csrf_token
@@ -121,7 +121,15 @@ define('forum/account/settings', ['forum/account/header', 'components'], functio
}).done(function() {
parentEl.remove();
}).fail(function(err) {
- app.alertError(err.responseText);
+ try {
+ var errorObj = JSON.parse(err.responseText);
+ if (errorObj.loggedIn === false) {
+ window.location.href = config.relative_path + '/login?error=' + errorObj.title;
+ }
+ app.alertError(errorObj.title);
+ } catch (e) {
+ app.alertError('[[error:invalid-data]]');
+ }
});
}
});
diff --git a/public/src/client/category.js b/public/src/client/category.js
index 10816286d9..fc4e7e21f3 100644
--- a/public/src/client/category.js
+++ b/public/src/client/category.js
@@ -61,6 +61,7 @@ define('forum/category', [
handleIgnoreWatch(cid);
$(window).trigger('action:topics.loaded', {topics: ajaxify.data.topics});
+ $(window).trigger('action:category.loaded', {cid: ajaxify.data.cid});
};
function handleIgnoreWatch(cid) {
diff --git a/public/src/client/recent.js b/public/src/client/recent.js
index 1f6536327d..973819d44d 100644
--- a/public/src/client/recent.js
+++ b/public/src/client/recent.js
@@ -133,7 +133,7 @@ define('forum/recent', ['forum/infinitescroll', 'components'], function(infinite
infinitescroll.loadMore('topics.loadMoreFromSet', {
after: $('[component="category"]').attr('data-nextstart'),
- set: 'topics:recent'
+ set: $('[component="category"]').attr('data-set') ? $('[component="category"]').attr('data-set') : 'topics:recent'
}, function(data, done) {
if (data.topics && data.topics.length) {
Recent.onTopicsLoaded('recent', data.topics, false, done);
diff --git a/public/src/client/topic.js b/public/src/client/topic.js
index ce320309f2..da4e5456e8 100644
--- a/public/src/client/topic.js
+++ b/public/src/client/topic.js
@@ -260,7 +260,7 @@ define('forum/topic', [
Topic.replaceURLTimeout = 0;
if (history.replaceState) {
- var search = (window.location.search ? window.location.search : '');
+ var search = (window.location.search && !/^\?page=\d+$/.test(window.location.search) ? window.location.search : '');
history.replaceState({
url: newUrl + search
}, null, window.location.protocol + '//' + window.location.host + RELATIVE_PATH + '/' + newUrl + search);
diff --git a/public/src/modules/iconSelect.js b/public/src/modules/iconSelect.js
index b1f8a30112..00804d1616 100644
--- a/public/src/modules/iconSelect.js
+++ b/public/src/modules/iconSelect.js
@@ -17,6 +17,9 @@ define('iconSelect', function() {
}
templates.parse('partials/fontawesome', {}, function(html) {
+ html = $(html);
+ html.find('.fa-icons').prepend($(''));
+
var picker = bootbox.dialog({
onEscape: true,
backdrop: true,
diff --git a/public/vendor/fontawesome/fonts/FontAwesome.otf b/public/vendor/fontawesome/fonts/FontAwesome.otf
index 3ed7f8b48a..d4de13e832 100644
Binary files a/public/vendor/fontawesome/fonts/FontAwesome.otf and b/public/vendor/fontawesome/fonts/FontAwesome.otf differ
diff --git a/public/vendor/fontawesome/fonts/fontawesome-webfont.eot b/public/vendor/fontawesome/fonts/fontawesome-webfont.eot
index 9b6afaedc0..c7b00d2ba8 100644
Binary files a/public/vendor/fontawesome/fonts/fontawesome-webfont.eot and b/public/vendor/fontawesome/fonts/fontawesome-webfont.eot differ
diff --git a/public/vendor/fontawesome/fonts/fontawesome-webfont.svg b/public/vendor/fontawesome/fonts/fontawesome-webfont.svg
index d05688e9e2..8b66187fe0 100644
--- a/public/vendor/fontawesome/fonts/fontawesome-webfont.svg
+++ b/public/vendor/fontawesome/fonts/fontawesome-webfont.svg
@@ -169,7 +169,7 @@
-
+
@@ -178,7 +178,7 @@
-
+
@@ -363,7 +363,7 @@
-
+
@@ -484,7 +484,7 @@
-
+
@@ -626,7 +626,7 @@
-
+
@@ -641,15 +641,45 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/vendor/fontawesome/fonts/fontawesome-webfont.ttf b/public/vendor/fontawesome/fonts/fontawesome-webfont.ttf
index 26dea7951a..f221e50a2e 100644
Binary files a/public/vendor/fontawesome/fonts/fontawesome-webfont.ttf and b/public/vendor/fontawesome/fonts/fontawesome-webfont.ttf differ
diff --git a/public/vendor/fontawesome/fonts/fontawesome-webfont.woff b/public/vendor/fontawesome/fonts/fontawesome-webfont.woff
index dc35ce3c2c..6e7483cf61 100644
Binary files a/public/vendor/fontawesome/fonts/fontawesome-webfont.woff and b/public/vendor/fontawesome/fonts/fontawesome-webfont.woff differ
diff --git a/public/vendor/fontawesome/fonts/fontawesome-webfont.woff2 b/public/vendor/fontawesome/fonts/fontawesome-webfont.woff2
index 500e517253..7eb74fd127 100644
Binary files a/public/vendor/fontawesome/fonts/fontawesome-webfont.woff2 and b/public/vendor/fontawesome/fonts/fontawesome-webfont.woff2 differ
diff --git a/public/vendor/fontawesome/less/font-awesome.less b/public/vendor/fontawesome/less/font-awesome.less
index c35d3eeb90..c44e5f466a 100644
--- a/public/vendor/fontawesome/less/font-awesome.less
+++ b/public/vendor/fontawesome/less/font-awesome.less
@@ -1,5 +1,5 @@
/*!
- * Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome
+ * Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
*/
@@ -15,3 +15,4 @@
@import "rotated-flipped.less";
@import "stacked.less";
@import "icons.less";
+@import "screen-reader.less";
diff --git a/public/vendor/fontawesome/less/icons.less b/public/vendor/fontawesome/less/icons.less
index ca60abd7e1..ba21b222d6 100644
--- a/public/vendor/fontawesome/less/icons.less
+++ b/public/vendor/fontawesome/less/icons.less
@@ -438,7 +438,7 @@
.@{fa-css-prefix}-stumbleupon:before { content: @fa-var-stumbleupon; }
.@{fa-css-prefix}-delicious:before { content: @fa-var-delicious; }
.@{fa-css-prefix}-digg:before { content: @fa-var-digg; }
-.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; }
+.@{fa-css-prefix}-pied-piper-pp:before { content: @fa-var-pied-piper-pp; }
.@{fa-css-prefix}-pied-piper-alt:before { content: @fa-var-pied-piper-alt; }
.@{fa-css-prefix}-drupal:before { content: @fa-var-drupal; }
.@{fa-css-prefix}-joomla:before { content: @fa-var-joomla; }
@@ -488,6 +488,7 @@
.@{fa-css-prefix}-life-ring:before { content: @fa-var-life-ring; }
.@{fa-css-prefix}-circle-o-notch:before { content: @fa-var-circle-o-notch; }
.@{fa-css-prefix}-ra:before,
+.@{fa-css-prefix}-resistance:before,
.@{fa-css-prefix}-rebel:before { content: @fa-var-rebel; }
.@{fa-css-prefix}-ge:before,
.@{fa-css-prefix}-empire:before { content: @fa-var-empire; }
@@ -695,3 +696,38 @@
.@{fa-css-prefix}-bluetooth:before { content: @fa-var-bluetooth; }
.@{fa-css-prefix}-bluetooth-b:before { content: @fa-var-bluetooth-b; }
.@{fa-css-prefix}-percent:before { content: @fa-var-percent; }
+.@{fa-css-prefix}-gitlab:before { content: @fa-var-gitlab; }
+.@{fa-css-prefix}-wpbeginner:before { content: @fa-var-wpbeginner; }
+.@{fa-css-prefix}-wpforms:before { content: @fa-var-wpforms; }
+.@{fa-css-prefix}-envira:before { content: @fa-var-envira; }
+.@{fa-css-prefix}-universal-access:before { content: @fa-var-universal-access; }
+.@{fa-css-prefix}-wheelchair-alt:before { content: @fa-var-wheelchair-alt; }
+.@{fa-css-prefix}-question-circle-o:before { content: @fa-var-question-circle-o; }
+.@{fa-css-prefix}-blind:before { content: @fa-var-blind; }
+.@{fa-css-prefix}-audio-description:before { content: @fa-var-audio-description; }
+.@{fa-css-prefix}-volume-control-phone:before { content: @fa-var-volume-control-phone; }
+.@{fa-css-prefix}-braille:before { content: @fa-var-braille; }
+.@{fa-css-prefix}-assistive-listening-systems:before { content: @fa-var-assistive-listening-systems; }
+.@{fa-css-prefix}-asl-interpreting:before,
+.@{fa-css-prefix}-american-sign-language-interpreting:before { content: @fa-var-american-sign-language-interpreting; }
+.@{fa-css-prefix}-deafness:before,
+.@{fa-css-prefix}-hard-of-hearing:before,
+.@{fa-css-prefix}-deaf:before { content: @fa-var-deaf; }
+.@{fa-css-prefix}-glide:before { content: @fa-var-glide; }
+.@{fa-css-prefix}-glide-g:before { content: @fa-var-glide-g; }
+.@{fa-css-prefix}-signing:before,
+.@{fa-css-prefix}-sign-language:before { content: @fa-var-sign-language; }
+.@{fa-css-prefix}-low-vision:before { content: @fa-var-low-vision; }
+.@{fa-css-prefix}-viadeo:before { content: @fa-var-viadeo; }
+.@{fa-css-prefix}-viadeo-square:before { content: @fa-var-viadeo-square; }
+.@{fa-css-prefix}-snapchat:before { content: @fa-var-snapchat; }
+.@{fa-css-prefix}-snapchat-ghost:before { content: @fa-var-snapchat-ghost; }
+.@{fa-css-prefix}-snapchat-square:before { content: @fa-var-snapchat-square; }
+.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; }
+.@{fa-css-prefix}-first-order:before { content: @fa-var-first-order; }
+.@{fa-css-prefix}-yoast:before { content: @fa-var-yoast; }
+.@{fa-css-prefix}-themeisle:before { content: @fa-var-themeisle; }
+.@{fa-css-prefix}-google-plus-circle:before,
+.@{fa-css-prefix}-google-plus-official:before { content: @fa-var-google-plus-official; }
+.@{fa-css-prefix}-fa:before,
+.@{fa-css-prefix}-font-awesome:before { content: @fa-var-font-awesome; }
diff --git a/public/vendor/fontawesome/less/mixins.less b/public/vendor/fontawesome/less/mixins.less
index d5a43a145a..beef231d0e 100644
--- a/public/vendor/fontawesome/less/mixins.less
+++ b/public/vendor/fontawesome/less/mixins.less
@@ -12,15 +12,49 @@
}
.fa-icon-rotate(@degrees, @rotation) {
- filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation);
+ -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
-webkit-transform: rotate(@degrees);
-ms-transform: rotate(@degrees);
transform: rotate(@degrees);
}
.fa-icon-flip(@horiz, @vert, @rotation) {
- filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation, mirror=1);
+ -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)";
-webkit-transform: scale(@horiz, @vert);
-ms-transform: scale(@horiz, @vert);
transform: scale(@horiz, @vert);
}
+
+
+// Only display content to screen readers. A la Bootstrap 4.
+//
+// See: http://a11yproject.com/posts/how-to-hide-content/
+
+.sr-only() {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0,0,0,0);
+ border: 0;
+}
+
+// Use in conjunction with .sr-only to only display content when it's focused.
+//
+// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
+//
+// Credit: HTML5 Boilerplate
+
+.sr-only-focusable() {
+ &:active,
+ &:focus {
+ position: static;
+ width: auto;
+ height: auto;
+ margin: 0;
+ overflow: visible;
+ clip: auto;
+ }
+}
diff --git a/public/vendor/fontawesome/less/path.less b/public/vendor/fontawesome/less/path.less
index 9211e66597..835be41f81 100644
--- a/public/vendor/fontawesome/less/path.less
+++ b/public/vendor/fontawesome/less/path.less
@@ -9,7 +9,7 @@
url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
-// src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
+ // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts
font-weight: normal;
font-style: normal;
}
diff --git a/public/vendor/fontawesome/less/screen-reader.less b/public/vendor/fontawesome/less/screen-reader.less
new file mode 100644
index 0000000000..11c188196d
--- /dev/null
+++ b/public/vendor/fontawesome/less/screen-reader.less
@@ -0,0 +1,5 @@
+// Screen Readers
+// -------------------------
+
+.sr-only { .sr-only(); }
+.sr-only-focusable { .sr-only-focusable(); }
diff --git a/public/vendor/fontawesome/less/variables.less b/public/vendor/fontawesome/less/variables.less
index 34d4041cc7..a2019dcadc 100644
--- a/public/vendor/fontawesome/less/variables.less
+++ b/public/vendor/fontawesome/less/variables.less
@@ -4,9 +4,9 @@
@fa-font-path: "./vendor/fontawesome/fonts";
@fa-font-size-base: 14px;
@fa-line-height-base: 1;
-//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.5.0/fonts"; // for referencing Bootstrap CDN font files directly
+//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.6.3/fonts"; // for referencing Bootstrap CDN font files directly
@fa-css-prefix: fa;
-@fa-version: "4.5.0";
+@fa-version: "4.6.3";
@fa-border-color: #eee;
@fa-inverse: #fff;
@fa-li-width: (30em / 14);
@@ -20,6 +20,7 @@
@fa-var-align-right: "\f038";
@fa-var-amazon: "\f270";
@fa-var-ambulance: "\f0f9";
+@fa-var-american-sign-language-interpreting: "\f2a3";
@fa-var-anchor: "\f13d";
@fa-var-android: "\f17b";
@fa-var-angellist: "\f209";
@@ -50,8 +51,11 @@
@fa-var-arrows-alt: "\f0b2";
@fa-var-arrows-h: "\f07e";
@fa-var-arrows-v: "\f07d";
+@fa-var-asl-interpreting: "\f2a3";
+@fa-var-assistive-listening-systems: "\f2a2";
@fa-var-asterisk: "\f069";
@fa-var-at: "\f1fa";
+@fa-var-audio-description: "\f29e";
@fa-var-automobile: "\f1b9";
@fa-var-backward: "\f04a";
@fa-var-balance-scale: "\f24e";
@@ -86,6 +90,7 @@
@fa-var-bitbucket-square: "\f172";
@fa-var-bitcoin: "\f15a";
@fa-var-black-tie: "\f27e";
+@fa-var-blind: "\f29d";
@fa-var-bluetooth: "\f293";
@fa-var-bluetooth-b: "\f294";
@fa-var-bold: "\f032";
@@ -94,6 +99,7 @@
@fa-var-book: "\f02d";
@fa-var-bookmark: "\f02e";
@fa-var-bookmark-o: "\f097";
+@fa-var-braille: "\f2a1";
@fa-var-briefcase: "\f0b1";
@fa-var-btc: "\f15a";
@fa-var-bug: "\f188";
@@ -196,6 +202,8 @@
@fa-var-dashboard: "\f0e4";
@fa-var-dashcube: "\f210";
@fa-var-database: "\f1c0";
+@fa-var-deaf: "\f2a4";
+@fa-var-deafness: "\f2a4";
@fa-var-dedent: "\f03b";
@fa-var-delicious: "\f1a5";
@fa-var-desktop: "\f108";
@@ -217,6 +225,7 @@
@fa-var-envelope: "\f0e0";
@fa-var-envelope-o: "\f003";
@fa-var-envelope-square: "\f199";
+@fa-var-envira: "\f299";
@fa-var-eraser: "\f12d";
@fa-var-eur: "\f153";
@fa-var-euro: "\f153";
@@ -231,6 +240,7 @@
@fa-var-eye: "\f06e";
@fa-var-eye-slash: "\f070";
@fa-var-eyedropper: "\f1fb";
+@fa-var-fa: "\f2b4";
@fa-var-facebook: "\f09a";
@fa-var-facebook-f: "\f09a";
@fa-var-facebook-official: "\f230";
@@ -265,6 +275,7 @@
@fa-var-fire: "\f06d";
@fa-var-fire-extinguisher: "\f134";
@fa-var-firefox: "\f269";
+@fa-var-first-order: "\f2b0";
@fa-var-flag: "\f024";
@fa-var-flag-checkered: "\f11e";
@fa-var-flag-o: "\f11d";
@@ -277,6 +288,7 @@
@fa-var-folder-open: "\f07c";
@fa-var-folder-open-o: "\f115";
@fa-var-font: "\f031";
+@fa-var-font-awesome: "\f2b4";
@fa-var-fonticons: "\f280";
@fa-var-fort-awesome: "\f286";
@fa-var-forumbee: "\f211";
@@ -300,11 +312,16 @@
@fa-var-github: "\f09b";
@fa-var-github-alt: "\f113";
@fa-var-github-square: "\f092";
+@fa-var-gitlab: "\f296";
@fa-var-gittip: "\f184";
@fa-var-glass: "\f000";
+@fa-var-glide: "\f2a5";
+@fa-var-glide-g: "\f2a6";
@fa-var-globe: "\f0ac";
@fa-var-google: "\f1a0";
@fa-var-google-plus: "\f0d5";
+@fa-var-google-plus-circle: "\f2b3";
+@fa-var-google-plus-official: "\f2b3";
@fa-var-google-plus-square: "\f0d4";
@fa-var-google-wallet: "\f1ee";
@fa-var-graduation-cap: "\f19d";
@@ -325,6 +342,7 @@
@fa-var-hand-scissors-o: "\f257";
@fa-var-hand-spock-o: "\f259";
@fa-var-hand-stop-o: "\f256";
+@fa-var-hard-of-hearing: "\f2a4";
@fa-var-hashtag: "\f292";
@fa-var-hdd-o: "\f0a0";
@fa-var-header: "\f1dc";
@@ -397,6 +415,7 @@
@fa-var-long-arrow-left: "\f177";
@fa-var-long-arrow-right: "\f178";
@fa-var-long-arrow-up: "\f176";
+@fa-var-low-vision: "\f2a8";
@fa-var-magic: "\f0d0";
@fa-var-magnet: "\f076";
@fa-var-mail-forward: "\f064";
@@ -468,8 +487,9 @@
@fa-var-photo: "\f03e";
@fa-var-picture-o: "\f03e";
@fa-var-pie-chart: "\f200";
-@fa-var-pied-piper: "\f1a7";
+@fa-var-pied-piper: "\f2ae";
@fa-var-pied-piper-alt: "\f1a8";
+@fa-var-pied-piper-pp: "\f1a7";
@fa-var-pinterest: "\f0d2";
@fa-var-pinterest-p: "\f231";
@fa-var-pinterest-square: "\f0d3";
@@ -490,6 +510,7 @@
@fa-var-qrcode: "\f029";
@fa-var-question: "\f128";
@fa-var-question-circle: "\f059";
+@fa-var-question-circle-o: "\f29c";
@fa-var-quote-left: "\f10d";
@fa-var-quote-right: "\f10e";
@fa-var-ra: "\f1d0";
@@ -507,6 +528,7 @@
@fa-var-repeat: "\f01e";
@fa-var-reply: "\f112";
@fa-var-reply-all: "\f122";
+@fa-var-resistance: "\f1d0";
@fa-var-retweet: "\f079";
@fa-var-rmb: "\f157";
@fa-var-road: "\f018";
@@ -544,8 +566,10 @@
@fa-var-shopping-basket: "\f291";
@fa-var-shopping-cart: "\f07a";
@fa-var-sign-in: "\f090";
+@fa-var-sign-language: "\f2a7";
@fa-var-sign-out: "\f08b";
@fa-var-signal: "\f012";
+@fa-var-signing: "\f2a7";
@fa-var-simplybuilt: "\f215";
@fa-var-sitemap: "\f0e8";
@fa-var-skyatlas: "\f216";
@@ -554,6 +578,9 @@
@fa-var-sliders: "\f1de";
@fa-var-slideshare: "\f1e7";
@fa-var-smile-o: "\f118";
+@fa-var-snapchat: "\f2ab";
+@fa-var-snapchat-ghost: "\f2ac";
+@fa-var-snapchat-square: "\f2ad";
@fa-var-soccer-ball-o: "\f1e3";
@fa-var-sort: "\f0dc";
@fa-var-sort-alpha-asc: "\f15d";
@@ -616,6 +643,7 @@
@fa-var-th: "\f00a";
@fa-var-th-large: "\f009";
@fa-var-th-list: "\f00b";
+@fa-var-themeisle: "\f2b2";
@fa-var-thumb-tack: "\f08d";
@fa-var-thumbs-down: "\f165";
@fa-var-thumbs-o-down: "\f088";
@@ -655,6 +683,7 @@
@fa-var-umbrella: "\f0e9";
@fa-var-underline: "\f0cd";
@fa-var-undo: "\f0e2";
+@fa-var-universal-access: "\f29a";
@fa-var-university: "\f19c";
@fa-var-unlink: "\f127";
@fa-var-unlock: "\f09c";
@@ -673,11 +702,14 @@
@fa-var-venus-double: "\f226";
@fa-var-venus-mars: "\f228";
@fa-var-viacoin: "\f237";
+@fa-var-viadeo: "\f2a9";
+@fa-var-viadeo-square: "\f2aa";
@fa-var-video-camera: "\f03d";
@fa-var-vimeo: "\f27d";
@fa-var-vimeo-square: "\f194";
@fa-var-vine: "\f1ca";
@fa-var-vk: "\f189";
+@fa-var-volume-control-phone: "\f2a0";
@fa-var-volume-down: "\f027";
@fa-var-volume-off: "\f026";
@fa-var-volume-up: "\f028";
@@ -687,11 +719,14 @@
@fa-var-weixin: "\f1d7";
@fa-var-whatsapp: "\f232";
@fa-var-wheelchair: "\f193";
+@fa-var-wheelchair-alt: "\f29b";
@fa-var-wifi: "\f1eb";
@fa-var-wikipedia-w: "\f266";
@fa-var-windows: "\f17a";
@fa-var-won: "\f159";
@fa-var-wordpress: "\f19a";
+@fa-var-wpbeginner: "\f297";
+@fa-var-wpforms: "\f298";
@fa-var-wrench: "\f0ad";
@fa-var-xing: "\f168";
@fa-var-xing-square: "\f169";
@@ -702,6 +737,7 @@
@fa-var-yc-square: "\f1d4";
@fa-var-yelp: "\f1e9";
@fa-var-yen: "\f157";
+@fa-var-yoast: "\f2b1";
@fa-var-youtube: "\f167";
@fa-var-youtube-play: "\f16a";
@fa-var-youtube-square: "\f166";
diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js
index bb575a3c76..bc301b1873 100644
--- a/src/controllers/authentication.js
+++ b/src/controllers/authentication.js
@@ -63,6 +63,16 @@ authenticationController.register = function(req, res, next) {
registerAndLoginUser(req, res, userData, next);
} else if (registrationType === 'admin-approval') {
addToApprovalQueue(req, userData, next);
+ } else if (registrationType === 'admin-approval-ip') {
+ db.sortedSetCard('ip:' + req.ip + ':uid', function(err, count) {
+ if (err) {
+ next(err);
+ } else if (count) {
+ addToApprovalQueue(req, userData, next);
+ } else {
+ registerAndLoginUser(req, res, userData, next);
+ }
+ });
}
}
], function(err, data) {
@@ -94,11 +104,7 @@ function registerAndLoginUser(req, res, userData, callback) {
} else {
userData.register = true;
req.session.registration = userData;
- if (res.locals.isAPI) {
- return res.json({ referrer: nconf.get('relative_path') + '/register/complete' });
- } else {
- return res.redirect(nconf.get('relative_path') + '/register/complete');
- }
+ return res.json({ referrer: nconf.get('relative_path') + '/register/complete' });
}
});
},
diff --git a/src/controllers/category.js b/src/controllers/category.js
index f2bc7510c6..6c74519c1a 100644
--- a/src/controllers/category.js
+++ b/src/controllers/category.js
@@ -75,18 +75,19 @@ categoryController.get = function(req, res, callback) {
topicIndex = 0;
}
- var set = 'cid:' + cid + ':tids',
- reverse = false;
-
- if (settings.categoryTopicSort === 'newest_to_oldest') {
+ var set = 'cid:' + cid + ':tids';
+ var reverse = false;
+ // `sort` qs has priority over user setting
+ var sort = req.query.sort || settings.categoryTopicSort;
+ if (sort === 'newest_to_oldest') {
reverse = true;
- } else if (settings.categoryTopicSort === 'most_posts') {
+ } else if (sort === 'most_posts') {
reverse = true;
set = 'cid:' + cid + ':tids:posts';
}
- var start = (currentPage - 1) * settings.topicsPerPage + topicIndex,
- stop = start + settings.topicsPerPage - 1;
+ var start = (currentPage - 1) * settings.topicsPerPage + topicIndex;
+ var stop = start + settings.topicsPerPage - 1;
next(null, {
cid: cid,
@@ -192,7 +193,7 @@ categoryController.get = function(req, res, callback) {
categoryData['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1;
categoryData.rssFeedUrl = nconf.get('relative_path') + '/category/' + categoryData.cid + '.rss';
categoryData.title = categoryData.name;
- categoryData.pagination = pagination.create(currentPage, pageCount);
+ categoryData.pagination = pagination.create(currentPage, pageCount, req.query);
categoryData.pagination.rel.forEach(function(rel) {
rel.href = nconf.get('url') + '/category/' + categoryData.slug + rel.href;
res.locals.linkTags.push(rel);
diff --git a/src/controllers/index.js b/src/controllers/index.js
index cb87d32ac8..bd6daa6581 100644
--- a/src/controllers/index.js
+++ b/src/controllers/index.js
@@ -108,12 +108,14 @@ Controllers.login = function(req, res, next) {
var errorText;
if (req.query.error === 'csrf-invalid') {
errorText = '[[error:csrf-invalid]]';
+ } else if (req.query.error) {
+ errorText = req.query.error;
}
data.alternate_logins = loginStrategies.length > 0;
data.authentication = loginStrategies;
data.allowLocalLogin = parseInt(meta.config.allowLocalLogin, 10) === 1 || parseInt(req.query.local, 10) === 1;
- data.allowRegistration = registrationType === 'normal' || registrationType === 'admin-approval';
+ data.allowRegistration = registrationType === 'normal' || registrationType === 'admin-approval' || registrationType === 'admin-approval-ip';
data.allowLoginWith = '[[login:' + allowLoginWith + ']]';
data.breadcrumbs = helpers.buildBreadcrumbs([{text: '[[global:login]]'}]);
data.error = req.flash('error')[0] || errorText;
diff --git a/src/controllers/recent.js b/src/controllers/recent.js
index fe9355c533..512a034512 100644
--- a/src/controllers/recent.js
+++ b/src/controllers/recent.js
@@ -54,6 +54,7 @@ recentController.get = function(req, res, next) {
var data = {};
data.topics = topics;
data.nextStart = stop + 1;
+ data.set = 'topics:recent';
data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1;
data.rssFeedUrl = nconf.get('relative_path') + '/recent.rss';
data.title = '[[pages:recent]]';
diff --git a/src/controllers/topics.js b/src/controllers/topics.js
index 1e41cfe981..9d106a85f2 100644
--- a/src/controllers/topics.js
+++ b/src/controllers/topics.js
@@ -19,7 +19,6 @@ var topicsController = {};
topicsController.get = function(req, res, callback) {
var tid = req.params.topic_id;
- var sort = req.query.sort;
var currentPage = parseInt(req.query.page, 10) || 1;
var pageCount = 1;
var userPrivileges;
@@ -76,18 +75,13 @@ topicsController.get = function(req, res, callback) {
var set = 'tid:' + tid + ':posts';
var reverse = false;
-
// `sort` qs has priority over user setting
+ var sort = req.query.sort || settings.topicPostSort;
if (sort === 'newest_to_oldest') {
reverse = true;
} else if (sort === 'most_votes') {
reverse = true;
set = 'tid:' + tid + ':posts:votes';
- } else if (settings.topicPostSort === 'newest_to_oldest') {
- reverse = true;
- } else if (settings.topicPostSort === 'most_votes') {
- reverse = true;
- set = 'tid:' + tid + ':posts:votes';
}
var postIndex = 0;
@@ -97,7 +91,9 @@ topicsController.get = function(req, res, callback) {
req.params.post_index = 0;
}
if (!settings.usePagination) {
- currentPage = 1;
+ if (req.params.post_index !== 0) {
+ currentPage = 1;
+ }
if (reverse) {
postIndex = Math.max(0, postCount - (req.params.post_index || postCount) - Math.ceil(settings.postsPerPage / 2));
} else {
@@ -268,7 +264,7 @@ topicsController.get = function(req, res, callback) {
data.postDeleteDuration = parseInt(meta.config.postDeleteDuration, 10) || 0;
data.scrollToMyPost = settings.scrollToMyPost;
data.rssFeedUrl = nconf.get('relative_path') + '/topic/' + data.tid + '.rss';
- data.pagination = pagination.create(currentPage, pageCount);
+ data.pagination = pagination.create(currentPage, pageCount, req.query);
data.pagination.rel.forEach(function(rel) {
rel.href = nconf.get('url') + '/topic/' + data.slug + rel.href;
res.locals.linkTags.push(rel);
diff --git a/src/controllers/uploads.js b/src/controllers/uploads.js
index 374152e388..11c75fd7f9 100644
--- a/src/controllers/uploads.js
+++ b/src/controllers/uploads.js
@@ -104,7 +104,7 @@ function resizeImage(fileObj, callback) {
image.size(fullPath, next);
},
function (imageData, next) {
- if (imageData.width < parseInt(meta.config.maximumImageWidth, 10) || 760) {
+ if (imageData.width < (parseInt(meta.config.maximumImageWidth, 10) || 760)) {
return callback(null, fileObj);
}
diff --git a/src/groups/membership.js b/src/groups/membership.js
index b570d1fbe7..3e18979f96 100644
--- a/src/groups/membership.js
+++ b/src/groups/membership.js
@@ -153,11 +153,7 @@ module.exports = function(Groups) {
path: '/groups/' + utils.slugify(groupName)
}),
function (notification, next) {
- if (!notification) {
- return next();
- }
-
- notifications.push(notification, [uid]);
+ notifications.push(notification, [uid], next);
}
], callback);
};
diff --git a/src/groups/update.js b/src/groups/update.js
index 27d2cddc00..f30addc42f 100644
--- a/src/groups/update.js
+++ b/src/groups/update.js
@@ -17,54 +17,63 @@ module.exports = function(Groups) {
return callback(err || new Error('[[error:no-group]]'));
}
- var payload = {
- description: values.description || '',
- icon: values.icon || '',
- labelColor: values.labelColor || '#000000'
- };
-
- if (values.hasOwnProperty('userTitle')) {
- payload.userTitle = values.userTitle || '';
- }
-
- if (values.hasOwnProperty('userTitleEnabled')) {
- payload.userTitleEnabled = values.userTitleEnabled ? '1' : '0';
- }
-
- if (values.hasOwnProperty('hidden')) {
- payload.hidden = values.hidden ? '1' : '0';
- }
-
- if (values.hasOwnProperty('private')) {
- payload.private = values.private ? '1' : '0';
- }
-
- if (values.hasOwnProperty('disableJoinRequests')) {
- payload.disableJoinRequests = values.disableJoinRequests ? '1' : '0';
- }
-
- async.series([
- async.apply(checkNameChange, groupName, values.name),
- async.apply(updatePrivacy, groupName, values.private),
- function(next) {
- if (values.hasOwnProperty('hidden')) {
- updateVisibility(groupName, values.hidden, next);
- } else {
- next();
- }
- },
- async.apply(db.setObject, 'group:' + groupName, payload),
- async.apply(renameGroup, groupName, values.name)
- ], function(err) {
+ plugins.fireHook('filter:group.update', {
+ groupName: groupName,
+ values: values
+ }, function(err) {
if (err) {
return callback(err);
}
- plugins.fireHook('action:group.update', {
- name: groupName,
- values: values
+ var payload = {
+ description: values.description || '',
+ icon: values.icon || '',
+ labelColor: values.labelColor || '#000000'
+ };
+
+ if (values.hasOwnProperty('userTitle')) {
+ payload.userTitle = values.userTitle || '';
+ }
+
+ if (values.hasOwnProperty('userTitleEnabled')) {
+ payload.userTitleEnabled = values.userTitleEnabled ? '1' : '0';
+ }
+
+ if (values.hasOwnProperty('hidden')) {
+ payload.hidden = values.hidden ? '1' : '0';
+ }
+
+ if (values.hasOwnProperty('private')) {
+ payload.private = values.private ? '1' : '0';
+ }
+
+ if (values.hasOwnProperty('disableJoinRequests')) {
+ payload.disableJoinRequests = values.disableJoinRequests ? '1' : '0';
+ }
+
+ async.series([
+ async.apply(checkNameChange, groupName, values.name),
+ async.apply(updatePrivacy, groupName, values.private),
+ function(next) {
+ if (values.hasOwnProperty('hidden')) {
+ updateVisibility(groupName, values.hidden, next);
+ } else {
+ next();
+ }
+ },
+ async.apply(db.setObject, 'group:' + groupName, payload),
+ async.apply(renameGroup, groupName, values.name)
+ ], function(err) {
+ if (err) {
+ return callback(err);
+ }
+
+ plugins.fireHook('action:group.update', {
+ name: groupName,
+ values: values
+ });
+ callback();
});
- callback();
});
});
};
diff --git a/src/messaging/notifications.js b/src/messaging/notifications.js
index 61f4f5d9ce..e58c3dc660 100644
--- a/src/messaging/notifications.js
+++ b/src/messaging/notifications.js
@@ -2,12 +2,12 @@
var async = require('async');
var nconf = require('nconf');
+var winston = require('winston');
var user = require('../user');
var emailer = require('../emailer');
var notifications = require('../notifications');
var meta = require('../meta');
-var utils = require('../../public/src/utils');
var sockets = require('../socket.io');
module.exports = function(Messaging) {
@@ -78,27 +78,46 @@ module.exports = function(Messaging) {
}
});
- if (parseInt(meta.config.disableEmailSubscriptions, 10) === 1) {
- return callback();
+ sendNotificationEmails(uids, messageObj);
+ });
+ }
+
+ function sendNotificationEmails(uids, messageObj) {
+ if (parseInt(meta.config.disableEmailSubscriptions, 10) === 1) {
+ return;
+ }
+
+ async.parallel({
+ userData: function(next) {
+ user.getUsersFields(uids, ['uid', 'username', 'userslug'], next);
+ },
+ settings: function(next) {
+ user.getMultipleUserSettings(uids, next);
+ }
+ }, function(err, results) {
+ if (err) {
+ return winston.error(err);
}
- user.getMultipleUserSettings(uids, function(err, userSettings) {
+ results.userData = results.userData.filter(function(userData, index) {
+ return userData && results.userSettings[index] && results.userSettings[index].sendChatNotifications;
+ });
+
+ async.each(results.userData, function(userData, next) {
+ emailer.send('notif_chat', userData.uid, {
+ subject: '[[email:notif.chat.subject, ' + messageObj.fromUser.username + ']]',
+ summary: '[[notifications:new_message_from, ' + messageObj.fromUser.username + ']]',
+ message: messageObj,
+ site_title: meta.config.title || 'NodeBB',
+ url: nconf.get('url'),
+ roomId: messageObj.roomId,
+ username: userData.username,
+ userslug: userData.userslug
+ }, next);
+ }, function(err) {
if (err) {
- return callback(err);
+ winston.error(err);
}
- userSettings = userSettings.filter(function(settings) {
- return settings && settings.sendChatNotifications;
- });
- async.each(userSettings, function(settings, next) {
- emailer.send('notif_chat', settings.uid, {
- subject: '[[email:notif.chat.subject, ' + messageObj.fromUser.username + ']]',
- summary: '[[notifications:new_message_from, ' + messageObj.fromUser.username + ']]',
- message: messageObj,
- site_title: meta.config.title || 'NodeBB',
- url: nconf.get('url'),
- roomId: messageObj.roomId
- }, next);
- }, callback);
});
});
}
diff --git a/src/meta/js.js b/src/meta/js.js
index fb8cb6023a..7a0a57c86b 100644
--- a/src/meta/js.js
+++ b/src/meta/js.js
@@ -116,7 +116,7 @@ module.exports = function(Meta) {
winston.error('[meta/js] Encountered error while bridging modules:' + err.message);
}
- winston.verbose('[meta/js] ' + numBridged + ' of ' + Meta.js.scripts.modules.length + ' modules bridged');
+ winston.verbose('[meta/js] ' + numBridged + ' of ' + Object.keys(Meta.js.scripts.modules).length + ' modules bridged');
callback(err);
});
};
diff --git a/src/middleware/header.js b/src/middleware/header.js
index dccefcddf7..ef73610b92 100644
--- a/src/middleware/header.js
+++ b/src/middleware/header.js
@@ -57,7 +57,7 @@ module.exports = function(app, middleware) {
'brand:logo:url': meta.config['brand:logo:url'] || '',
'brand:logo:alt': meta.config['brand:logo:alt'] || '',
'brand:logo:display': meta.config['brand:logo']?'':'hide',
- allowRegistration: registrationType === 'normal' || registrationType === 'admin-approval',
+ allowRegistration: registrationType === 'normal' || registrationType === 'admin-approval' || registrationType === 'admin-approval-ip',
searchEnabled: plugins.hasListeners('filter:search.query'),
config: res.locals.config,
relative_path: nconf.get('relative_path'),
diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js
index cbede05028..a1c98b0c3d 100644
--- a/src/middleware/middleware.js
+++ b/src/middleware/middleware.js
@@ -287,7 +287,7 @@ middleware.requireUser = function(req, res, next) {
return next();
}
- res.render('403', {title: '[[global:403.title]]'});
+ res.status(403).render('403', {title: '[[global:403.title]]'});
};
middleware.privateUploads = function(req, res, next) {
diff --git a/src/notifications.js b/src/notifications.js
index f95eb52248..1d466f374b 100644
--- a/src/notifications.js
+++ b/src/notifications.js
@@ -163,7 +163,7 @@ var utils = require('../public/src/utils');
Notifications.push = function(notification, uids, callback) {
callback = callback || function() {};
- if (!notification.nid) {
+ if (!notification || !notification.nid) {
return callback();
}
diff --git a/src/routes/accounts.js b/src/routes/accounts.js
index e60d2bcc99..5bd0a474e3 100644
--- a/src/routes/accounts.js
+++ b/src/routes/accounts.js
@@ -28,7 +28,7 @@ module.exports = function (app, middleware, controllers) {
setupPageRoute(app, '/user/:userslug/info', middleware, accountMiddlewares, controllers.accounts.info.get);
setupPageRoute(app, '/user/:userslug/settings', middleware, accountMiddlewares, controllers.accounts.settings.get);
- app.delete('/user/:userslug/session/:uuid', accountMiddlewares, controllers.accounts.session.revoke);
+ app.delete('/api/user/:userslug/session/:uuid', [middleware.requireUser, middleware.exposeUid], controllers.accounts.session.revoke);
setupPageRoute(app, '/notifications', middleware, [middleware.authenticate], controllers.accounts.notifications.get);
setupPageRoute(app, '/chats/:roomid?', middleware, [middleware.authenticate], controllers.accounts.chats.get);
diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js
index d1b0321960..a290238e21 100644
--- a/src/socket.io/admin.js
+++ b/src/socket.io/admin.js
@@ -1,41 +1,39 @@
"use strict";
-var async = require('async'),
- winston = require('winston'),
+var async = require('async');
+var winston = require('winston');
+var nconf = require('nconf');
+var meta = require('../meta');
+var plugins = require('../plugins');
+var widgets = require('../widgets');
+var user = require('../user');
+var logger = require('../logger');
+var events = require('../events');
+var emailer = require('../emailer');
+var db = require('../database');
+var analytics = require('../analytics');
+var index = require('./index');
- meta = require('../meta'),
- plugins = require('../plugins'),
- widgets = require('../widgets'),
- user = require('../user'),
-
- logger = require('../logger'),
- events = require('../events'),
- emailer = require('../emailer'),
- db = require('../database'),
- analytics = require('../analytics'),
- index = require('./index'),
-
-
- SocketAdmin = {
- user: require('./admin/user'),
- categories: require('./admin/categories'),
- groups: require('./admin/groups'),
- tags: require('./admin/tags'),
- rewards: require('./admin/rewards'),
- navigation: require('./admin/navigation'),
- rooms: require('./admin/rooms'),
- social: require('./admin/social'),
- themes: {},
- plugins: {},
- widgets: {},
- config: {},
- settings: {},
- email: {},
- analytics: {},
- logs: {},
- errors: {}
- };
+var SocketAdmin = {
+ user: require('./admin/user'),
+ categories: require('./admin/categories'),
+ groups: require('./admin/groups'),
+ tags: require('./admin/tags'),
+ rewards: require('./admin/rewards'),
+ navigation: require('./admin/navigation'),
+ rooms: require('./admin/rooms'),
+ social: require('./admin/social'),
+ themes: {},
+ plugins: {},
+ widgets: {},
+ config: {},
+ settings: {},
+ email: {},
+ analytics: {},
+ logs: {},
+ errors: {}
+};
SocketAdmin.before = function(socket, method, data, next) {
if (!socket.uid) {
@@ -92,6 +90,9 @@ SocketAdmin.themes.set = function(socket, data, callback) {
}
var wrappedCallback = function(err) {
+ if (err) {
+ return callback(err);
+ }
meta.themes.set(data, callback);
};
if (data.type === 'bootswatch') {
@@ -205,7 +206,8 @@ SocketAdmin.email.test = function(socket, data, callback) {
var site_title = meta.config.title || 'NodeBB';
emailer.send(data.template, socket.uid, {
subject: '[' + site_title + '] Test Email',
- site_title: site_title
+ site_title: site_title,
+ url: nconf.get('url')
}, callback);
};
diff --git a/src/socket.io/posts/edit.js b/src/socket.io/posts/edit.js
index e5ad7a0afb..56cddd8c6b 100644
--- a/src/socket.io/posts/edit.js
+++ b/src/socket.io/posts/edit.js
@@ -49,8 +49,8 @@ module.exports = function(SocketPosts) {
type: 'topic-rename',
uid: socket.uid,
ip: socket.ip,
- oldTitle: result.topic.oldTitle,
- newTitle: result.topic.title
+ oldTitle: validator.escape(String(result.topic.oldTitle)),
+ newTitle: validator.escape(String(result.topic.title))
});
}
diff --git a/src/socket.io/posts/tools.js b/src/socket.io/posts/tools.js
index 5c59b28918..bcb7e59642 100644
--- a/src/socket.io/posts/tools.js
+++ b/src/socket.io/posts/tools.js
@@ -1,8 +1,11 @@
'use strict';
var async = require('async');
+var winston = require('winston');
+var validator = require('validator');
var posts = require('../../posts');
+var topics = require('../../topics');
var events = require('../../events');
var websockets = require('../index');
var socketTopics = require('../topics');
@@ -106,11 +109,17 @@ module.exports = function(SocketPosts) {
websockets.in('topic_' + data.tid).emit('event:post_purged', data.pid);
- events.log({
- type: 'post-purge',
- uid: socket.uid,
- pid: data.pid,
- ip: socket.ip
+ topics.getTopicField(data.tid, 'title', function(err, title) {
+ if (err) {
+ return winston.error(err);
+ }
+ events.log({
+ type: 'post-purge',
+ uid: socket.uid,
+ pid: data.pid,
+ ip: socket.ip,
+ title: validator.escape(String(title))
+ });
});
callback();
diff --git a/src/socket.io/topics/tools.js b/src/socket.io/topics/tools.js
index f3d9ad4688..2ba98271ae 100644
--- a/src/socket.io/topics/tools.js
+++ b/src/socket.io/topics/tools.js
@@ -1,6 +1,9 @@
'use strict';
var async = require('async');
+var winston = require('winston');
+var validator = require('validator');
+
var topics = require('../../topics');
var events = require('../../events');
var privileges = require('../../privileges');
@@ -94,11 +97,17 @@ module.exports = function(SocketTopics) {
socketHelpers.emitToTopicAndCategory(event, data);
if (action === 'delete' || action === 'restore' || action === 'purge') {
- events.log({
- type: 'topic-' + action,
- uid: socket.uid,
- ip: socket.ip,
- tid: tid
+ topics.getTopicField(tid, 'title', function(err, title) {
+ if (err) {
+ return winston.error(err);
+ }
+ events.log({
+ type: 'topic-' + action,
+ uid: socket.uid,
+ ip: socket.ip,
+ tid: tid,
+ title: validator.escape(String(title))
+ });
});
}
diff --git a/src/views/admin/settings/user.tpl b/src/views/admin/settings/user.tpl
index 33972e267c..575a4a07f9 100644
--- a/src/views/admin/settings/user.tpl
+++ b/src/views/admin/settings/user.tpl
@@ -124,6 +124,7 @@