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 @@
- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

For a full list of icons, please consult: