mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-03 20:45:58 +01:00
Merge remote-tracking branch 'origin/master' into user-icons
Conflicts: public/src/client/account/edit.js src/middleware/middleware.js src/socket.io/meta.js src/socket.io/user/picture.js src/user.js src/views/admin/manage/group.tpl
This commit is contained in:
18
package.json
18
package.json
@@ -15,7 +15,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "~1.4.2",
|
"async": "~1.4.2",
|
||||||
"bcryptjs": "~2.2.1",
|
"bcryptjs": "~2.3.0",
|
||||||
"body-parser": "^1.9.0",
|
"body-parser": "^1.9.0",
|
||||||
"colors": "^1.1.0",
|
"colors": "^1.1.0",
|
||||||
"compression": "^1.1.0",
|
"compression": "^1.1.0",
|
||||||
@@ -39,18 +39,18 @@
|
|||||||
"mkdirp": "~0.5.0",
|
"mkdirp": "~0.5.0",
|
||||||
"mmmagic": "^0.4.0",
|
"mmmagic": "^0.4.0",
|
||||||
"morgan": "^1.3.2",
|
"morgan": "^1.3.2",
|
||||||
"nconf": "~0.7.1",
|
"nconf": "~0.8.2",
|
||||||
"nodebb-plugin-composer-default": "1.0.16",
|
"nodebb-plugin-composer-default": "1.0.19",
|
||||||
"nodebb-plugin-dbsearch": "0.2.17",
|
"nodebb-plugin-dbsearch": "0.2.17",
|
||||||
"nodebb-plugin-emoji-extended": "0.4.14",
|
"nodebb-plugin-emoji-extended": "0.4.15",
|
||||||
"nodebb-plugin-markdown": "4.0.6",
|
"nodebb-plugin-markdown": "4.0.6",
|
||||||
"nodebb-plugin-mentions": "1.0.6",
|
"nodebb-plugin-mentions": "1.0.8",
|
||||||
"nodebb-plugin-soundpack-default": "0.1.4",
|
"nodebb-plugin-soundpack-default": "0.1.4",
|
||||||
"nodebb-plugin-spam-be-gone": "0.4.2",
|
"nodebb-plugin-spam-be-gone": "0.4.2",
|
||||||
"nodebb-rewards-essentials": "0.0.5",
|
"nodebb-rewards-essentials": "0.0.5",
|
||||||
"nodebb-theme-lavender": "2.0.6",
|
"nodebb-theme-lavender": "2.0.8",
|
||||||
"nodebb-theme-persona": "3.0.45",
|
"nodebb-theme-persona": "3.0.56",
|
||||||
"nodebb-theme-vanilla": "4.0.20",
|
"nodebb-theme-vanilla": "4.0.24",
|
||||||
"nodebb-widget-essentials": "2.0.2",
|
"nodebb-widget-essentials": "2.0.2",
|
||||||
"npm": "^2.1.4",
|
"npm": "^2.1.4",
|
||||||
"passport": "^0.3.0",
|
"passport": "^0.3.0",
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
"underscore.deep": "^0.5.1",
|
"underscore.deep": "^0.5.1",
|
||||||
"validator": "^4.0.5",
|
"validator": "^4.0.5",
|
||||||
"winston": "^1.0.1",
|
"winston": "^1.0.1",
|
||||||
"xregexp": "~2.0.0"
|
"xregexp": "~3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"mocha": "~1.13.0",
|
"mocha": "~1.13.0",
|
||||||
|
|||||||
@@ -77,7 +77,8 @@
|
|||||||
"group-name-too-short": "Group name too short",
|
"group-name-too-short": "Group name too short",
|
||||||
"group-already-exists": "Group already exists",
|
"group-already-exists": "Group already exists",
|
||||||
"group-name-change-not-allowed": "Group name change not allowed",
|
"group-name-change-not-allowed": "Group name change not allowed",
|
||||||
"group-already-member": "You are already part of this group",
|
"group-already-member": "Already part of this group",
|
||||||
|
"group-not-member": "Not a member of this group",
|
||||||
"group-needs-owner": "This group requires at least one owner",
|
"group-needs-owner": "This group requires at least one owner",
|
||||||
"group-already-invited": "This user has already been invited",
|
"group-already-invited": "This user has already been invited",
|
||||||
"group-already-requested": "Your membership request has already been submitted",
|
"group-already-requested": "Your membership request has already been submitted",
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
"composer.discard": "Are you sure you wish to discard this post?",
|
"composer.discard": "Are you sure you wish to discard this post?",
|
||||||
"composer.submit_and_lock": "Submit and Lock",
|
"composer.submit_and_lock": "Submit and Lock",
|
||||||
"composer.toggle_dropdown": "Toggle Dropdown",
|
"composer.toggle_dropdown": "Toggle Dropdown",
|
||||||
|
"composer.uploading": "Uploading %1",
|
||||||
|
|
||||||
"bootbox.ok": "OK",
|
"bootbox.ok": "OK",
|
||||||
"bootbox.cancel": "Cancel",
|
"bootbox.cancel": "Cancel",
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
|
|
||||||
"new_message_from": "New message from <strong>%1</strong>",
|
"new_message_from": "New message from <strong>%1</strong>",
|
||||||
"upvoted_your_post_in": "<strong>%1</strong> has upvoted your post in <strong>%2</strong>.",
|
"upvoted_your_post_in": "<strong>%1</strong> has upvoted your post in <strong>%2</strong>.",
|
||||||
"moved_your_post": "<strong>%1</strong> has moved your post.",
|
"moved_your_post": "<strong>%1</strong> has moved your post to <strong>%2</strong>",
|
||||||
"moved_your_topic": "<strong>%1</strong> has moved your topic.",
|
"moved_your_topic": "<strong>%1</strong> has moved <strong>%2</strong>",
|
||||||
"favourited_your_post_in": "<strong>%1</strong> has favourited your post in <strong>%2</strong>.",
|
"favourited_your_post_in": "<strong>%1</strong> has favourited your post in <strong>%2</strong>.",
|
||||||
"user_flagged_post_in": "<strong>%1</strong> flagged a post in <strong>%2</strong>",
|
"user_flagged_post_in": "<strong>%1</strong> flagged a post in <strong>%2</strong>",
|
||||||
"user_posted_to" : "<strong>%1</strong> has posted a reply to: <strong>%2</strong>",
|
"user_posted_to" : "<strong>%1</strong> has posted a reply to: <strong>%2</strong>",
|
||||||
|
|||||||
@@ -29,6 +29,9 @@
|
|||||||
"chat": "Chatting with %1",
|
"chat": "Chatting with %1",
|
||||||
|
|
||||||
"account/edit": "Editing \"%1\"",
|
"account/edit": "Editing \"%1\"",
|
||||||
|
"account/edit/password": "Editing password of \"%1\"",
|
||||||
|
"account/edit/username": "Editing username of \"%1\"",
|
||||||
|
"account/edit/email": "Editing email of \"%1\"",
|
||||||
"account/following": "People %1 follows",
|
"account/following": "People %1 follows",
|
||||||
"account/followers": "People who follow %1",
|
"account/followers": "People who follow %1",
|
||||||
"account/posts": "Posts made by %1",
|
"account/posts": "Posts made by %1",
|
||||||
|
|||||||
@@ -32,7 +32,6 @@
|
|||||||
"bookmark_instructions" : "Click here to return to the last unread post in this thread.",
|
"bookmark_instructions" : "Click here to return to the last unread post in this thread.",
|
||||||
|
|
||||||
"flag_title": "Flag this post for moderation",
|
"flag_title": "Flag this post for moderation",
|
||||||
"flag_confirm": "Are you sure you want to flag this post?",
|
|
||||||
"flag_success": "This post has been flagged for moderation.",
|
"flag_success": "This post has been flagged for moderation.",
|
||||||
"deleted_message": "This topic has been deleted. Only users with topic management privileges can see it.",
|
"deleted_message": "This topic has been deleted. Only users with topic management privileges can see it.",
|
||||||
|
|
||||||
@@ -117,5 +116,10 @@
|
|||||||
"most_votes": "Most votes",
|
"most_votes": "Most votes",
|
||||||
"most_posts": "Most posts",
|
"most_posts": "Most posts",
|
||||||
|
|
||||||
"stale_topic_warning": "The topic you are replying to is quite old. Would you like to create a new topic instead, and reference this one in your reply?"
|
"stale_topic_warning": "The topic you are replying to is quite old. Would you like to create a new topic instead, and reference this one in your reply?",
|
||||||
|
|
||||||
|
"spam": "Spam",
|
||||||
|
"offensive": "Offensive",
|
||||||
|
"custom-flag-reason": "Enter a flagging reason"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,8 @@
|
|||||||
|
|
||||||
"profile_update_success": "Profile has been updated successfully!",
|
"profile_update_success": "Profile has been updated successfully!",
|
||||||
"change_picture": "Change Picture",
|
"change_picture": "Change Picture",
|
||||||
|
"change_username": "Change Username",
|
||||||
|
"change_email": "Change Email",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"default_picture": "Default Icon",
|
"default_picture": "Default Icon",
|
||||||
"uploaded_picture": "Uploaded Picture",
|
"uploaded_picture": "Uploaded Picture",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#navigation {
|
#navigation {
|
||||||
|
|
||||||
|
|
||||||
#active-navigation {
|
#active-navigation {
|
||||||
.active {
|
.active {
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
@@ -23,6 +24,9 @@
|
|||||||
.iconPicker i {
|
.iconPicker i {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.form-group {
|
||||||
|
min-height: 80px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
|
|||||||
@@ -1,5 +1,20 @@
|
|||||||
.group {
|
.group {
|
||||||
.current_members {
|
[component="groups/members"] {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
tbody {
|
||||||
|
max-height: 500px;
|
||||||
|
display: block;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-bottom: 100px;
|
||||||
|
.member-name {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
.border-radius(3px);
|
.border-radius(3px);
|
||||||
|
|
||||||
&.disabled {
|
&.disabled {
|
||||||
-webkit-filter: grayscale(30%);
|
background-color: #888!important;
|
||||||
.opacity(0.5);
|
.opacity(0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,8 @@
|
|||||||
function selectMenuItem(url) {
|
function selectMenuItem(url) {
|
||||||
url = url
|
url = url
|
||||||
.replace(/\/\d+$/, '')
|
.replace(/\/\d+$/, '')
|
||||||
.split('/').slice(0, 3).join('/');
|
.split('/').slice(0, 3).join('/')
|
||||||
|
.split('?')[0];
|
||||||
|
|
||||||
// If index is requested, load the dashboard
|
// If index is requested, load the dashboard
|
||||||
if (url === 'admin') {
|
if (url === 'admin') {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
/*global define, socket, app, bootbox, templates, ajaxify, RELATIVE_PATH, Sortable */
|
/*global define, socket, app, bootbox, templates, ajaxify, Sortable */
|
||||||
|
|
||||||
define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-serializeobject.min'], function() {
|
define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-serializeobject.min'], function() {
|
||||||
var Categories = {}, newCategoryId = -1, sortables;
|
var Categories = {}, newCategoryId = -1, sortables;
|
||||||
@@ -17,12 +17,17 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri
|
|||||||
|
|
||||||
// Enable/Disable toggle events
|
// Enable/Disable toggle events
|
||||||
$('.categories').on('click', 'button[data-action="toggle"]', function() {
|
$('.categories').on('click', 'button[data-action="toggle"]', function() {
|
||||||
var self = $(this),
|
var $this = $(this),
|
||||||
rowEl = self.parents('li'),
|
cid = $this.attr('data-cid'),
|
||||||
cid = rowEl.attr('data-cid'),
|
parentEl = $this.parents('li[data-cid="' + cid + '"]'),
|
||||||
disabled = rowEl.hasClass('disabled');
|
disabled = parentEl.hasClass('disabled');
|
||||||
|
|
||||||
Categories.toggle(cid, disabled);
|
var children = parentEl.find('li[data-cid]').map(function() {
|
||||||
|
return $(this).attr('data-cid');
|
||||||
|
}).get();
|
||||||
|
|
||||||
|
Categories.toggle([cid].concat(children), !disabled);
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -94,14 +99,16 @@ define('admin/manage/categories', ['vendor/jquery/serializeObject/jquery.ba-seri
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Categories.toggle = function(cid, disabled) {
|
Categories.toggle = function(cids, disabled) {
|
||||||
var payload = {};
|
var payload = {};
|
||||||
|
|
||||||
|
cids.forEach(function(cid) {
|
||||||
payload[cid] = {
|
payload[cid] = {
|
||||||
disabled: disabled ? 1 : 0
|
disabled: disabled ? 1 : 0
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
socket.emit('admin.categories.update', payload, function(err, result) {
|
socket.emit('admin.categories.update', payload, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return app.alertError(err.message);
|
return app.alertError(err.message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ define('admin/manage/category', [
|
|||||||
}
|
}
|
||||||
|
|
||||||
categories = categories.filter(function(category) {
|
categories = categories.filter(function(category) {
|
||||||
return category && parseInt(category.cid, 10) !== parseInt(ajaxify.data.category.cid, 10);
|
return category && !category.disabled && parseInt(category.cid, 10) !== parseInt(ajaxify.data.category.cid, 10);
|
||||||
});
|
});
|
||||||
|
|
||||||
templates.parse('partials/category_list', {
|
templates.parse('partials/category_list', {
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
/*global define, templates, socket, ajaxify, app, admin, bootbox, utils, config */
|
/*global define, templates, socket, ajaxify, app, bootbox, translator */
|
||||||
|
|
||||||
define('admin/manage/group', [
|
define('admin/manage/group', [
|
||||||
|
'forum/groups/memberlist',
|
||||||
'iconSelect',
|
'iconSelect',
|
||||||
'admin/modules/colorpicker'
|
'admin/modules/colorpicker'
|
||||||
], function(iconSelect, colorpicker) {
|
], function(memberList, iconSelect, colorpicker) {
|
||||||
var Groups = {};
|
var Groups = {};
|
||||||
|
|
||||||
Groups.init = function() {
|
Groups.init = function() {
|
||||||
var groupDetailsSearch = $('#group-details-search'),
|
var groupDetailsSearch = $('#group-details-search'),
|
||||||
groupDetailsSearchResults = $('#group-details-search-results'),
|
groupDetailsSearchResults = $('#group-details-search-results'),
|
||||||
groupMembersEl = $('ul.current_members'),
|
|
||||||
groupIcon = $('#group-icon'),
|
groupIcon = $('#group-icon'),
|
||||||
changeGroupUserTitle = $('#change-group-user-title'),
|
changeGroupUserTitle = $('#change-group-user-title'),
|
||||||
changeGroupLabelColor = $('#change-group-label-color'),
|
changeGroupLabelColor = $('#change-group-label-color'),
|
||||||
@@ -20,6 +20,8 @@ define('admin/manage/group', [
|
|||||||
|
|
||||||
var groupName = ajaxify.data.group.name;
|
var groupName = ajaxify.data.group.name;
|
||||||
|
|
||||||
|
memberList.init();
|
||||||
|
|
||||||
changeGroupUserTitle.keyup(function() {
|
changeGroupUserTitle.keyup(function() {
|
||||||
groupLabelPreview.text(changeGroupUserTitle.val());
|
groupLabelPreview.text(changeGroupUserTitle.val());
|
||||||
});
|
});
|
||||||
@@ -46,10 +48,16 @@ define('admin/manage/group', [
|
|||||||
}
|
}
|
||||||
|
|
||||||
groupDetailsSearchResults.empty();
|
groupDetailsSearchResults.empty();
|
||||||
|
|
||||||
for (x = 0; x < numResults; x++) {
|
for (x = 0; x < numResults; x++) {
|
||||||
foundUser = $('<li />');
|
foundUser = $('<li />');
|
||||||
foundUser
|
foundUser
|
||||||
.attr({title: results.users[x].username, 'data-uid': results.users[x].uid})
|
.attr({title: results.users[x].username,
|
||||||
|
'data-uid': results.users[x].uid,
|
||||||
|
'data-username': results.users[x].username,
|
||||||
|
'data-userslug': results.users[x].userslug,
|
||||||
|
'data-picture': results.users[x].picture
|
||||||
|
})
|
||||||
.append($('<img />').attr('src', results.users[x].picture))
|
.append($('<img />').attr('src', results.users[x].picture))
|
||||||
.append($('<span />').html(results.users[x].username));
|
.append($('<span />').html(results.users[x].username));
|
||||||
|
|
||||||
@@ -64,43 +72,72 @@ define('admin/manage/group', [
|
|||||||
|
|
||||||
groupDetailsSearchResults.on('click', 'li[data-uid]', function() {
|
groupDetailsSearchResults.on('click', 'li[data-uid]', function() {
|
||||||
var userLabel = $(this),
|
var userLabel = $(this),
|
||||||
uid = parseInt(userLabel.attr('data-uid'), 10),
|
uid = parseInt(userLabel.attr('data-uid'), 10);
|
||||||
members = [];
|
|
||||||
|
|
||||||
groupMembersEl.find('li[data-uid]').each(function() {
|
|
||||||
members.push(parseInt($(this).attr('data-uid'), 10));
|
|
||||||
});
|
|
||||||
|
|
||||||
if (members.indexOf(uid) === -1) {
|
|
||||||
socket.emit('admin.groups.join', {
|
socket.emit('admin.groups.join', {
|
||||||
groupName: groupName,
|
groupName: groupName,
|
||||||
uid: uid
|
uid: uid
|
||||||
}, function(err, data) {
|
}, function(err) {
|
||||||
if (!err) {
|
if (err) {
|
||||||
groupMembersEl.append(userLabel.clone(true));
|
return app.alertError(err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var member = {
|
||||||
|
uid: userLabel.attr('data-uid'),
|
||||||
|
username: userLabel.attr('data-username'),
|
||||||
|
userslug: userLabel.attr('data-userslug'),
|
||||||
|
picture: userLabel.attr('data-picture')
|
||||||
|
};
|
||||||
|
|
||||||
|
templates.parse('partials/groups/memberlist', 'members', {group: {isOwner: ajaxify.data.group.isOwner, members: [member]}}, function(html) {
|
||||||
|
translator.translate(html, function(html) {
|
||||||
|
$('[component="groups/members"] tr').first().before(html);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
groupMembersEl.on('click', 'li[data-uid]', function() {
|
$('[component="groups/members"]').on('click', '[data-action]', function() {
|
||||||
var uid = $(this).attr('data-uid');
|
var btnEl = $(this),
|
||||||
|
userRow = btnEl.parents('[data-uid]'),
|
||||||
|
ownerFlagEl = userRow.find('.member-name i'),
|
||||||
|
isOwner = !ownerFlagEl.hasClass('invisible') ? true : false,
|
||||||
|
uid = userRow.attr('data-uid'),
|
||||||
|
action = btnEl.attr('data-action');
|
||||||
|
|
||||||
|
switch(action) {
|
||||||
|
case 'toggleOwnership':
|
||||||
|
socket.emit('groups.' + (isOwner ? 'rescind' : 'grant'), {
|
||||||
|
toUid: uid,
|
||||||
|
groupName: groupName
|
||||||
|
}, function(err) {
|
||||||
|
if (err) {
|
||||||
|
return app.alertError(err.message);
|
||||||
|
}
|
||||||
|
ownerFlagEl.toggleClass('invisible');
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'kick':
|
||||||
bootbox.confirm('Are you sure you want to remove this user?', function(confirm) {
|
bootbox.confirm('Are you sure you want to remove this user?', function(confirm) {
|
||||||
if (!confirm) {
|
if (!confirm) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.emit('admin.groups.leave', {
|
socket.emit('admin.groups.leave', {
|
||||||
groupName: groupName,
|
uid: uid,
|
||||||
uid: uid
|
groupName: groupName
|
||||||
}, function(err, data) {
|
}, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return app.alertError(err.message);
|
return app.alertError(err.message);
|
||||||
}
|
}
|
||||||
groupMembersEl.find('li[data-uid="' + uid + '"]').remove();
|
userRow.slideUp().remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#group-icon').on('click', function() {
|
$('#group-icon').on('click', function() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
/*global define, socket, app, admin, utils, bootbox, RELATIVE_PATH*/
|
/*global define, socket, app, utils, bootbox*/
|
||||||
|
|
||||||
define('admin/manage/tags', [
|
define('admin/manage/tags', [
|
||||||
'forum/infinitescroll',
|
'forum/infinitescroll',
|
||||||
@@ -25,12 +25,12 @@ define('admin/manage/tags', [
|
|||||||
}
|
}
|
||||||
|
|
||||||
timeoutId = setTimeout(function() {
|
timeoutId = setTimeout(function() {
|
||||||
socket.emit('topics.searchAndLoadTags', {query: $('#tag-search').val()}, function(err, tags) {
|
socket.emit('topics.searchAndLoadTags', {query: $('#tag-search').val()}, function(err, result) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return app.alertError(err.message);
|
return app.alertError(err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
infinitescroll.parseAndTranslate('admin/manage/tags', 'tags', {tags: tags}, function(html) {
|
infinitescroll.parseAndTranslate('admin/manage/tags', 'tags', {tags: result.tags}, function(html) {
|
||||||
$('.tag-list').html(html);
|
$('.tag-list').html(html);
|
||||||
utils.makeNumbersHumanReadable(html.find('.human-readable-number'));
|
utils.makeNumbersHumanReadable(html.find('.human-readable-number'));
|
||||||
timeoutId = 0;
|
timeoutId = 0;
|
||||||
@@ -43,7 +43,7 @@ define('admin/manage/tags', [
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleModify() {
|
function handleModify() {
|
||||||
$('#modify').on('click', function(ev) {
|
$('#modify').on('click', function() {
|
||||||
var tagsToModify = $('.tag-row.selected');
|
var tagsToModify = $('.tag-row.selected');
|
||||||
if (!tagsToModify.length) {
|
if (!tagsToModify.length) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ $(document).ready(function() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.enterRoom('');
|
app.leaveCurrentRoom();
|
||||||
|
|
||||||
$(window).off('scroll');
|
$(window).off('scroll');
|
||||||
|
|
||||||
@@ -56,6 +56,7 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
url = ajaxify.start(url, quiet);
|
url = ajaxify.start(url, quiet);
|
||||||
|
|
||||||
|
$('body').removeClass(ajaxify.data.bodyClass);
|
||||||
$('#footer, #content').removeClass('hide').addClass('ajaxifying');
|
$('#footer, #content').removeClass('hide').addClass('ajaxifying');
|
||||||
|
|
||||||
ajaxify.loadData(url, function(err, data) {
|
ajaxify.loadData(url, function(err, data) {
|
||||||
@@ -141,6 +142,7 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
templates.parse(tpl_url, data, function(template) {
|
templates.parse(tpl_url, data, function(template) {
|
||||||
translator.translate(template, function(translatedTemplate) {
|
translator.translate(template, function(translatedTemplate) {
|
||||||
|
$('body').addClass(data.bodyClass);
|
||||||
$('#content').html(translatedTemplate);
|
$('#content').html(translatedTemplate);
|
||||||
|
|
||||||
ajaxify.end(url, tpl_url);
|
ajaxify.end(url, tpl_url);
|
||||||
@@ -222,9 +224,7 @@ $(document).ready(function() {
|
|||||||
|
|
||||||
$(window).trigger('action:ajaxify.dataLoaded', {url: url, data: data});
|
$(window).trigger('action:ajaxify.dataLoaded', {url: url, data: data});
|
||||||
|
|
||||||
if (callback) {
|
|
||||||
callback(null, data);
|
callback(null, data);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
error: function(data, textStatus) {
|
error: function(data, textStatus) {
|
||||||
if (data.status === 0 && textStatus === 'error') {
|
if (data.status === 0 && textStatus === 'error') {
|
||||||
|
|||||||
@@ -71,12 +71,14 @@ app.cacheBuster = null;
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
require(['taskbar', 'helpers'], function(taskbar, helpers) {
|
require(['taskbar', 'helpers', 'forum/pagination'], function(taskbar, helpers, pagination) {
|
||||||
taskbar.init();
|
taskbar.init();
|
||||||
|
|
||||||
// templates.js helpers
|
// templates.js helpers
|
||||||
helpers.register();
|
helpers.register();
|
||||||
|
|
||||||
|
pagination.init();
|
||||||
|
|
||||||
$(window).trigger('action:app.load');
|
$(window).trigger('action:app.load');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -143,14 +145,25 @@ app.cacheBuster = null;
|
|||||||
'icon:text': app.user['icon:text']
|
'icon:text': app.user['icon:text']
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
app.alertError(err.message);
|
return app.alertError(err.message);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
app.currentRoom = room;
|
app.currentRoom = room;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
app.leaveCurrentRoom = function() {
|
||||||
|
if (!socket) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
socket.emit('meta.rooms.leaveCurrent', function(err) {
|
||||||
|
if (err) {
|
||||||
|
return app.alertError(err.message);
|
||||||
|
}
|
||||||
|
app.currentRoom = '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function highlightNavigationLink() {
|
function highlightNavigationLink() {
|
||||||
var path = window.location.pathname;
|
var path = window.location.pathname;
|
||||||
$('#main-nav li').removeClass('active');
|
$('#main-nav li').removeClass('active');
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/* globals define, ajaxify, socket, app, config, utils, bootbox */
|
/* globals define, ajaxify, socket, app, config, templates, bootbox */
|
||||||
|
|
||||||
define('forum/account/edit', ['forum/account/header', 'uploader', 'translator'], function(header, uploader, translator) {
|
define('forum/account/edit', ['forum/account/header', 'uploader', 'translator'], function(header, uploader, translator) {
|
||||||
var AccountEdit = {},
|
var AccountEdit = {},
|
||||||
uploadedPicture = '',
|
uploadedPicture = '',
|
||||||
selectedImageType = '',
|
selectedImageType = '';
|
||||||
currentEmail;
|
|
||||||
|
|
||||||
AccountEdit.init = function() {
|
AccountEdit.init = function() {
|
||||||
uploadedPicture = ajaxify.data.uploadedpicture;
|
uploadedPicture = ajaxify.data.uploadedpicture;
|
||||||
@@ -23,12 +22,9 @@ define('forum/account/edit', ['forum/account/header', 'uploader', 'translator'],
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
currentEmail = $('#inputEmail').val();
|
|
||||||
|
|
||||||
handleImageChange();
|
handleImageChange();
|
||||||
handleAccountDelete();
|
handleAccountDelete();
|
||||||
handleEmailConfirm();
|
handleEmailConfirm();
|
||||||
handlePasswordChange();
|
|
||||||
updateSignature();
|
updateSignature();
|
||||||
updateAboutMe();
|
updateAboutMe();
|
||||||
};
|
};
|
||||||
@@ -36,8 +32,6 @@ define('forum/account/edit', ['forum/account/header', 'uploader', 'translator'],
|
|||||||
function updateProfile() {
|
function updateProfile() {
|
||||||
var userData = {
|
var userData = {
|
||||||
uid: $('#inputUID').val(),
|
uid: $('#inputUID').val(),
|
||||||
username: $('#inputUsername').val(),
|
|
||||||
email: $('#inputEmail').val(),
|
|
||||||
fullname: $('#inputFullname').val(),
|
fullname: $('#inputFullname').val(),
|
||||||
website: $('#inputWebsite').val(),
|
website: $('#inputWebsite').val(),
|
||||||
birthday: $('#inputBirthday').val(),
|
birthday: $('#inputBirthday').val(),
|
||||||
@@ -57,27 +51,13 @@ define('forum/account/edit', ['forum/account/header', 'uploader', 'translator'],
|
|||||||
$('#user-current-picture').attr('src', data.picture);
|
$('#user-current-picture').attr('src', data.picture);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.userslug) {
|
updateHeader(data.picture);
|
||||||
var oldslug = $('.account-username-box').attr('data-userslug');
|
|
||||||
$('.account-username-box a').each(function() {
|
|
||||||
$(this).attr('href', $(this).attr('href').replace(oldslug, data.userslug));
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.account-username-box').attr('data-userslug', data.userslug);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentEmail !== data.email) {
|
|
||||||
currentEmail = data.email;
|
|
||||||
$('#confirm-email').removeClass('hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
updateHeader(data.picture, userData.username, data.userslug);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateHeader(picture, username, userslug) {
|
function updateHeader(picture) {
|
||||||
require(['components'], function(components) {
|
require(['components'], function(components) {
|
||||||
if (parseInt(ajaxify.data.theirid, 10) !== parseInt(ajaxify.data.yourid, 10)) {
|
if (parseInt(ajaxify.data.theirid, 10) !== parseInt(ajaxify.data.yourid, 10)) {
|
||||||
return;
|
return;
|
||||||
@@ -88,11 +68,6 @@ define('forum/account/edit', ['forum/account/header', 'uploader', 'translator'],
|
|||||||
if (picture) {
|
if (picture) {
|
||||||
components.get('header/userpicture').attr('src', picture);
|
components.get('header/userpicture').attr('src', picture);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (username && userslug) {
|
|
||||||
components.get('header/profilelink').attr('href', config.relative_path + '/user/' + userslug);
|
|
||||||
components.get('header/username').text(username);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,88 +248,6 @@ define('forum/account/edit', ['forum/account/header', 'uploader', 'translator'],
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePasswordChange() {
|
|
||||||
var currentPassword = $('#inputCurrentPassword');
|
|
||||||
var password_notify = $('#password-notify');
|
|
||||||
var password_confirm_notify = $('#password-confirm-notify');
|
|
||||||
var password = $('#inputNewPassword');
|
|
||||||
var password_confirm = $('#inputNewPasswordAgain');
|
|
||||||
var passwordvalid = false;
|
|
||||||
var passwordsmatch = false;
|
|
||||||
|
|
||||||
function onPasswordChanged() {
|
|
||||||
if (password.val().length < config.minimumPasswordLength) {
|
|
||||||
showError(password_notify, '[[user:change_password_error_length]]');
|
|
||||||
passwordvalid = false;
|
|
||||||
} else if (!utils.isPasswordValid(password.val())) {
|
|
||||||
showError(password_notify, '[[user:change_password_error]]');
|
|
||||||
passwordvalid = false;
|
|
||||||
} else {
|
|
||||||
showSuccess(password_notify);
|
|
||||||
passwordvalid = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onPasswordConfirmChanged() {
|
|
||||||
if (password.val() !== password_confirm.val()) {
|
|
||||||
showError(password_confirm_notify, '[[user:change_password_error_match]]');
|
|
||||||
passwordsmatch = false;
|
|
||||||
} else {
|
|
||||||
if (password.val()) {
|
|
||||||
showSuccess(password_confirm_notify);
|
|
||||||
} else {
|
|
||||||
password_confirm_notify.parent().removeClass('alert-success alert-danger');
|
|
||||||
password_confirm_notify.children().show();
|
|
||||||
password_confirm_notify.find('.msg').html('');
|
|
||||||
}
|
|
||||||
|
|
||||||
passwordsmatch = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
password.on('blur', onPasswordChanged);
|
|
||||||
password_confirm.on('blur', onPasswordConfirmChanged);
|
|
||||||
|
|
||||||
$('#changePasswordBtn').on('click', function() {
|
|
||||||
onPasswordChanged();
|
|
||||||
onPasswordConfirmChanged();
|
|
||||||
|
|
||||||
var btn = $(this);
|
|
||||||
if ((passwordvalid && passwordsmatch) || app.user.isAdmin) {
|
|
||||||
btn.addClass('disabled').find('i').removeClass('hide');
|
|
||||||
socket.emit('user.changePassword', {
|
|
||||||
'currentPassword': currentPassword.val(),
|
|
||||||
'newPassword': password.val(),
|
|
||||||
'uid': ajaxify.data.theirid
|
|
||||||
}, function(err) {
|
|
||||||
btn.removeClass('disabled').find('i').addClass('hide');
|
|
||||||
currentPassword.val('');
|
|
||||||
password.val('');
|
|
||||||
password_confirm.val('');
|
|
||||||
passwordsmatch = false;
|
|
||||||
passwordvalid = false;
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
onPasswordChanged();
|
|
||||||
onPasswordConfirmChanged();
|
|
||||||
return app.alertError(err.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
app.alertSuccess('[[user:change_password_success]]');
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (!passwordsmatch) {
|
|
||||||
app.alertError('[[user:change_password_error_match]]');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!passwordvalid) {
|
|
||||||
app.alertError('[[user:change_password_error]]');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeUserPicture(type, callback) {
|
function changeUserPicture(type, callback) {
|
||||||
socket.emit('user.changePicture', {
|
socket.emit('user.changePicture', {
|
||||||
type: type,
|
type: type,
|
||||||
@@ -384,24 +277,6 @@ define('forum/account/edit', ['forum/account/header', 'uploader', 'translator'],
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function showError(element, msg) {
|
|
||||||
translator.translate(msg, function(msg) {
|
|
||||||
element.find('.error').html(msg).removeClass('hide').siblings().addClass('hide');
|
|
||||||
|
|
||||||
element.parent()
|
|
||||||
.removeClass('alert-success')
|
|
||||||
.addClass('alert-danger');
|
|
||||||
element.show();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function showSuccess(element) {
|
|
||||||
element.find('.success').removeClass('hide').siblings().addClass('hide');
|
|
||||||
element.parent()
|
|
||||||
.removeClass('alert-danger')
|
|
||||||
.addClass('alert-success');
|
|
||||||
element.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
return AccountEdit;
|
return AccountEdit;
|
||||||
});
|
});
|
||||||
39
public/src/client/account/edit/email.js
Normal file
39
public/src/client/account/edit/email.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* globals define, ajaxify, socket, app */
|
||||||
|
|
||||||
|
define('forum/account/edit/email', ['forum/account/header'], function(header) {
|
||||||
|
var AccountEditEmail = {};
|
||||||
|
|
||||||
|
AccountEditEmail.init = function() {
|
||||||
|
header.init();
|
||||||
|
|
||||||
|
$('#submitBtn').on('click', function () {
|
||||||
|
var userData = {
|
||||||
|
uid: $('#inputUID').val(),
|
||||||
|
email: $('#inputNewEmail').val(),
|
||||||
|
password: $('#inputCurrentPassword').val()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!userData.email) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var btn = $(this);
|
||||||
|
btn.addClass('disabled').find('i').removeClass('hide');
|
||||||
|
|
||||||
|
socket.emit('user.changeUsernameEmail', userData, function(err) {
|
||||||
|
btn.removeClass('disabled').find('i').addClass('hide');
|
||||||
|
if (err) {
|
||||||
|
return app.alertError(err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
ajaxify.go('user/' + ajaxify.data.userslug);
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return AccountEditEmail;
|
||||||
|
});
|
||||||
116
public/src/client/account/edit/password.js
Normal file
116
public/src/client/account/edit/password.js
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* globals define, ajaxify, socket, app, config, utils */
|
||||||
|
|
||||||
|
define('forum/account/edit/password', ['forum/account/header', 'translator'], function(header, translator) {
|
||||||
|
var AccountEditPassword = {};
|
||||||
|
|
||||||
|
AccountEditPassword.init = function() {
|
||||||
|
header.init();
|
||||||
|
|
||||||
|
handlePasswordChange();
|
||||||
|
};
|
||||||
|
|
||||||
|
function handlePasswordChange() {
|
||||||
|
var currentPassword = $('#inputCurrentPassword');
|
||||||
|
var password_notify = $('#password-notify');
|
||||||
|
var password_confirm_notify = $('#password-confirm-notify');
|
||||||
|
var password = $('#inputNewPassword');
|
||||||
|
var password_confirm = $('#inputNewPasswordAgain');
|
||||||
|
var passwordvalid = false;
|
||||||
|
var passwordsmatch = false;
|
||||||
|
|
||||||
|
function onPasswordChanged() {
|
||||||
|
if (password.val().length < config.minimumPasswordLength) {
|
||||||
|
showError(password_notify, '[[user:change_password_error_length]]');
|
||||||
|
passwordvalid = false;
|
||||||
|
} else if (!utils.isPasswordValid(password.val())) {
|
||||||
|
showError(password_notify, '[[user:change_password_error]]');
|
||||||
|
passwordvalid = false;
|
||||||
|
} else {
|
||||||
|
showSuccess(password_notify);
|
||||||
|
passwordvalid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPasswordConfirmChanged() {
|
||||||
|
if (password.val() !== password_confirm.val()) {
|
||||||
|
showError(password_confirm_notify, '[[user:change_password_error_match]]');
|
||||||
|
passwordsmatch = false;
|
||||||
|
} else {
|
||||||
|
if (password.val()) {
|
||||||
|
showSuccess(password_confirm_notify);
|
||||||
|
} else {
|
||||||
|
password_confirm_notify.parent().removeClass('alert-success alert-danger');
|
||||||
|
password_confirm_notify.children().show();
|
||||||
|
password_confirm_notify.find('.msg').html('');
|
||||||
|
}
|
||||||
|
|
||||||
|
passwordsmatch = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
password.on('blur', onPasswordChanged);
|
||||||
|
password_confirm.on('blur', onPasswordConfirmChanged);
|
||||||
|
|
||||||
|
$('#changePasswordBtn').on('click', function() {
|
||||||
|
onPasswordChanged();
|
||||||
|
onPasswordConfirmChanged();
|
||||||
|
|
||||||
|
var btn = $(this);
|
||||||
|
if ((passwordvalid && passwordsmatch) || app.user.isAdmin) {
|
||||||
|
btn.addClass('disabled').find('i').removeClass('hide');
|
||||||
|
socket.emit('user.changePassword', {
|
||||||
|
'currentPassword': currentPassword.val(),
|
||||||
|
'newPassword': password.val(),
|
||||||
|
'uid': ajaxify.data.theirid
|
||||||
|
}, function(err) {
|
||||||
|
btn.removeClass('disabled').find('i').addClass('hide');
|
||||||
|
currentPassword.val('');
|
||||||
|
password.val('');
|
||||||
|
password_confirm.val('');
|
||||||
|
passwordsmatch = false;
|
||||||
|
passwordvalid = false;
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
onPasswordChanged();
|
||||||
|
onPasswordConfirmChanged();
|
||||||
|
return app.alertError(err.message);
|
||||||
|
}
|
||||||
|
ajaxify.go('user/' + ajaxify.data.userslug);
|
||||||
|
app.alertSuccess('[[user:change_password_success]]');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (!passwordsmatch) {
|
||||||
|
app.alertError('[[user:change_password_error_match]]');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!passwordvalid) {
|
||||||
|
app.alertError('[[user:change_password_error]]');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showError(element, msg) {
|
||||||
|
translator.translate(msg, function(msg) {
|
||||||
|
element.find('.error').html(msg).removeClass('hide').siblings().addClass('hide');
|
||||||
|
|
||||||
|
element.parent()
|
||||||
|
.removeClass('alert-success')
|
||||||
|
.addClass('alert-danger');
|
||||||
|
element.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showSuccess(element) {
|
||||||
|
element.find('.success').removeClass('hide').siblings().addClass('hide');
|
||||||
|
element.parent()
|
||||||
|
.removeClass('alert-danger')
|
||||||
|
.addClass('alert-success');
|
||||||
|
element.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
return AccountEditPassword;
|
||||||
|
});
|
||||||
43
public/src/client/account/edit/username.js
Normal file
43
public/src/client/account/edit/username.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* globals define, ajaxify, socket, app, utils, config */
|
||||||
|
|
||||||
|
define('forum/account/edit/username', ['forum/account/header'], function(header) {
|
||||||
|
var AccountEditUsername = {};
|
||||||
|
|
||||||
|
AccountEditUsername.init = function() {
|
||||||
|
header.init();
|
||||||
|
|
||||||
|
$('#submitBtn').on('click', function updateUsername() {
|
||||||
|
var userData = {
|
||||||
|
uid: $('#inputUID').val(),
|
||||||
|
username: $('#inputNewUsername').val(),
|
||||||
|
password: $('#inputCurrentPassword').val()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!userData.username) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var btn = $(this);
|
||||||
|
btn.addClass('disabled').find('i').removeClass('hide');
|
||||||
|
socket.emit('user.changeUsernameEmail', userData, function(err) {
|
||||||
|
btn.removeClass('disabled').find('i').addClass('hide');
|
||||||
|
if (err) {
|
||||||
|
return app.alertError(err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
var userslug = utils.slugify(userData.username);
|
||||||
|
if (userData.username && userslug && parseInt(userData.uid, 10) === parseInt(app.user.uid, 10)) {
|
||||||
|
$('[component="header/profilelink"]').attr('href', config.relative_path + '/user/' + userslug);
|
||||||
|
$('[component="header/username"]').text(userData.username);
|
||||||
|
}
|
||||||
|
|
||||||
|
ajaxify.go('user/' + userslug);
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return AccountEditUsername;
|
||||||
|
});
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
/* global define, config, templates, app, utils, ajaxify, socket */
|
/* global define, config, templates, app, utils, ajaxify, socket */
|
||||||
|
|
||||||
define('forum/category', [
|
define('forum/category', [
|
||||||
'forum/pagination',
|
|
||||||
'forum/infinitescroll',
|
'forum/infinitescroll',
|
||||||
'share',
|
'share',
|
||||||
'navigator',
|
'navigator',
|
||||||
@@ -10,13 +9,12 @@ define('forum/category', [
|
|||||||
'sort',
|
'sort',
|
||||||
'components',
|
'components',
|
||||||
'translator'
|
'translator'
|
||||||
|
], function(infinitescroll, share, navigator, categoryTools, sort, components, translator) {
|
||||||
], function(pagination, infinitescroll, share, navigator, categoryTools, sort, components, translator) {
|
|
||||||
var Category = {};
|
var Category = {};
|
||||||
|
|
||||||
$(window).on('action:ajaxify.start', function(ev, data) {
|
$(window).on('action:ajaxify.start', function(ev, data) {
|
||||||
if (ajaxify.currentPage !== data.url) {
|
if (ajaxify.currentPage !== data.url) {
|
||||||
navigator.hide();
|
navigator.disable();
|
||||||
|
|
||||||
removeListeners();
|
removeListeners();
|
||||||
}
|
}
|
||||||
@@ -41,12 +39,12 @@ define('forum/category', [
|
|||||||
|
|
||||||
sort.handleSort('categoryTopicSort', 'user.setCategorySort', 'category/' + ajaxify.data.slug);
|
sort.handleSort('categoryTopicSort', 'user.setCategorySort', 'category/' + ajaxify.data.slug);
|
||||||
|
|
||||||
enableInfiniteLoadingOrPagination();
|
|
||||||
|
|
||||||
if (!config.usePagination) {
|
if (!config.usePagination) {
|
||||||
navigator.init('[component="category/topic"]', ajaxify.data.topic_count, Category.toTop, Category.toBottom, Category.navigatorCallback);
|
navigator.init('[component="category/topic"]', ajaxify.data.topic_count, Category.toTop, Category.toBottom, Category.navigatorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enableInfiniteLoadingOrPagination();
|
||||||
|
|
||||||
$('[component="category"]').on('click', '[component="topic/header"]', function() {
|
$('[component="category"]').on('click', '[component="topic/header"]', function() {
|
||||||
var clickedIndex = $(this).parents('[data-index]').attr('data-index');
|
var clickedIndex = $(this).parents('[data-index]').attr('data-index');
|
||||||
$('[component="category/topic"]').each(function(index, el) {
|
$('[component="category/topic"]').each(function(index, el) {
|
||||||
@@ -112,7 +110,7 @@ define('forum/category', [
|
|||||||
|
|
||||||
if (config.usePagination) {
|
if (config.usePagination) {
|
||||||
var page = Math.ceil((parseInt(bookmarkIndex, 10) + 1) / config.topicsPerPage);
|
var page = Math.ceil((parseInt(bookmarkIndex, 10) + 1) / config.topicsPerPage);
|
||||||
if (parseInt(page, 10) !== pagination.currentPage) {
|
if (parseInt(page, 10) !== ajaxify.data.pagination.currentPage) {
|
||||||
pagination.loadPage(page, function() {
|
pagination.loadPage(page, function() {
|
||||||
Category.scrollToTopic(bookmarkIndex, clickedIndex, 400);
|
Category.scrollToTopic(bookmarkIndex, clickedIndex, 400);
|
||||||
});
|
});
|
||||||
@@ -175,8 +173,7 @@ define('forum/category', [
|
|||||||
if (!config.usePagination) {
|
if (!config.usePagination) {
|
||||||
infinitescroll.init($('[component="category"]'), Category.loadMoreTopics);
|
infinitescroll.init($('[component="category"]'), Category.loadMoreTopics);
|
||||||
} else {
|
} else {
|
||||||
navigator.hide();
|
navigator.disable();
|
||||||
pagination.init(ajaxify.data.currentPage, ajaxify.data.pageCount);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ define('forum/chats', ['components', 'string', 'sounds', 'forum/infinitescroll',
|
|||||||
|
|
||||||
Chats.switchChat = function(uid, username) {
|
Chats.switchChat = function(uid, username) {
|
||||||
if (!$('[component="chat/messages"]').length) {
|
if (!$('[component="chat/messages"]').length) {
|
||||||
ajaxify.go('chats/' + username);
|
return ajaxify.go('chats/' + utils.slugify(username));
|
||||||
}
|
}
|
||||||
|
|
||||||
var contactEl = $('.chats-list [data-uid="' + uid + '"]');
|
var contactEl = $('.chats-list [data-uid="' + uid + '"]');
|
||||||
|
|||||||
@@ -7,21 +7,13 @@ define('forum/footer', ['notifications', 'chat', 'components', 'translator'], fu
|
|||||||
Chat.prepareDOM();
|
Chat.prepareDOM();
|
||||||
translator.prepareDOM();
|
translator.prepareDOM();
|
||||||
|
|
||||||
function updateUnreadTopicCount(err, count) {
|
function updateUnreadTopicCount(count) {
|
||||||
if (err) {
|
|
||||||
return console.warn('Error updating unread count', err);
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#unread-count i')
|
$('#unread-count i')
|
||||||
.toggleClass('unread-count', count > 0)
|
.toggleClass('unread-count', count > 0)
|
||||||
.attr('data-content', count > 20 ? '20+' : count);
|
.attr('data-content', count > 20 ? '20+' : count);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateUnreadChatCount(err, count) {
|
function updateUnreadChatCount(count) {
|
||||||
if (err) {
|
|
||||||
return console.warn('Error updating unread count', err);
|
|
||||||
}
|
|
||||||
|
|
||||||
components.get('chat/icon')
|
components.get('chat/icon')
|
||||||
.toggleClass('unread-count', count > 0)
|
.toggleClass('unread-count', count > 0)
|
||||||
.attr('data-content', count > 20 ? '20+' : count);
|
.attr('data-content', count > 20 ? '20+' : count);
|
||||||
@@ -62,11 +54,20 @@ define('forum/footer', ['notifications', 'chat', 'components', 'translator'], fu
|
|||||||
socket.on('event:new_post', onNewPost);
|
socket.on('event:new_post', onNewPost);
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.on('event:unread.updateCount', updateUnreadTopicCount);
|
if (app.user.uid) {
|
||||||
socket.emit('user.getUnreadCount', updateUnreadTopicCount);
|
socket.emit('user.getUnreadCounts', function(err, data) {
|
||||||
|
if (err) {
|
||||||
|
return app.alert(err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUnreadTopicCount(data.unreadTopicCount);
|
||||||
|
updateUnreadChatCount(data.unreadChatCount);
|
||||||
|
Notifications.updateNotifCount(data.unreadNotificationCount);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.on('event:unread.updateCount', updateUnreadTopicCount);
|
||||||
socket.on('event:unread.updateChatCount', updateUnreadChatCount);
|
socket.on('event:unread.updateChatCount', updateUnreadChatCount);
|
||||||
socket.emit('user.getUnreadChatCount', updateUnreadChatCount);
|
|
||||||
|
|
||||||
initUnreadTopics();
|
initUnreadTopics();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,17 +1,22 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
/* globals define, socket, ajaxify, app, bootbox, RELATIVE_PATH, utils */
|
/* globals define, socket, ajaxify, app, bootbox, utils */
|
||||||
|
|
||||||
|
define('forum/groups/details', [
|
||||||
|
'forum/groups/memberlist',
|
||||||
|
'iconSelect',
|
||||||
|
'components',
|
||||||
|
'vendor/colorpicker/colorpicker',
|
||||||
|
'vendor/jquery/draggable-background/backgroundDraggable'
|
||||||
|
], function(memberList, iconSelect, components) {
|
||||||
|
|
||||||
define('forum/groups/details', ['iconSelect', 'components', 'forum/infinitescroll', 'vendor/colorpicker/colorpicker', 'vendor/jquery/draggable-background/backgroundDraggable'], function(iconSelect, components, infinitescroll) {
|
|
||||||
var Details = {
|
var Details = {
|
||||||
cover: {}
|
cover: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
var searchInterval;
|
|
||||||
var groupName;
|
var groupName;
|
||||||
|
|
||||||
Details.init = function() {
|
Details.init = function() {
|
||||||
var detailsPage = components.get('groups/container'),
|
var detailsPage = components.get('groups/container');
|
||||||
settingsFormEl = detailsPage.find('form');
|
|
||||||
|
|
||||||
groupName = ajaxify.data.group.name;
|
groupName = ajaxify.data.group.name;
|
||||||
|
|
||||||
@@ -20,8 +25,8 @@ define('forum/groups/details', ['iconSelect', 'components', 'forum/infinitescrol
|
|||||||
Details.initialiseCover();
|
Details.initialiseCover();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMemberSearch();
|
memberList.init();
|
||||||
handleMemberInfiniteScroll();
|
|
||||||
handleMemberInvitations();
|
handleMemberInvitations();
|
||||||
|
|
||||||
components.get('groups/activity').find('.content img:not(.not-responsive)').addClass('img-responsive');
|
components.get('groups/activity').find('.content img:not(.not-responsive)').addClass('img-responsive');
|
||||||
@@ -291,44 +296,6 @@ define('forum/groups/details', ['iconSelect', 'components', 'forum/infinitescrol
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function handleMemberSearch() {
|
|
||||||
$('[component="groups/members/search"]').on('keyup', function() {
|
|
||||||
var query = $(this).val();
|
|
||||||
if (searchInterval) {
|
|
||||||
clearInterval(searchInterval);
|
|
||||||
searchInterval = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
searchInterval = setTimeout(function() {
|
|
||||||
socket.emit('groups.searchMembers', {groupName: groupName, query: query}, function(err, results) {
|
|
||||||
if (err) {
|
|
||||||
return app.alertError(err.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
infinitescroll.parseAndTranslate('groups/details', 'members', {
|
|
||||||
group: {
|
|
||||||
members: results.users,
|
|
||||||
isOwner: ajaxify.data.group.isOwner
|
|
||||||
}
|
|
||||||
}, function(html) {
|
|
||||||
$('[component="groups/members"] tbody').html(html);
|
|
||||||
$('[component="groups/members"]').attr('data-nextstart', 20);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, 250);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleMemberInfiniteScroll() {
|
|
||||||
$('[component="groups/members"] tbody').on('scroll', function() {
|
|
||||||
var $this = $(this);
|
|
||||||
var bottom = ($this[0].scrollHeight - $this.height()) * 0.9;
|
|
||||||
if ($this.scrollTop() > bottom) {
|
|
||||||
loadMoreMembers();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleMemberInvitations() {
|
function handleMemberInvitations() {
|
||||||
if (ajaxify.data.group.isOwner) {
|
if (ajaxify.data.group.isOwner) {
|
||||||
var searchInput = $('[component="groups/members/invite"]');
|
var searchInput = $('[component="groups/members/invite"]');
|
||||||
@@ -349,48 +316,5 @@ define('forum/groups/details', ['iconSelect', 'components', 'forum/infinitescrol
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadMoreMembers() {
|
|
||||||
|
|
||||||
var members = $('[component="groups/members"]');
|
|
||||||
if (members.attr('loading')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
members.attr('loading', 1);
|
|
||||||
socket.emit('groups.loadMoreMembers', {
|
|
||||||
groupName: groupName,
|
|
||||||
after: members.attr('data-nextstart')
|
|
||||||
}, function(err, data) {
|
|
||||||
if (err) {
|
|
||||||
return app.alertError(err.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data && data.users.length) {
|
|
||||||
onMembersLoaded(data.users, function() {
|
|
||||||
members.removeAttr('loading');
|
|
||||||
members.attr('data-nextstart', data.nextStart);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
members.removeAttr('loading');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function onMembersLoaded(users, callback) {
|
|
||||||
users = users.filter(function(user) {
|
|
||||||
return !$('[component="groups/members"] [data-uid="' + user.uid + '"]').length;
|
|
||||||
});
|
|
||||||
|
|
||||||
infinitescroll.parseAndTranslate('groups/details', 'members', {
|
|
||||||
group: {
|
|
||||||
members: users,
|
|
||||||
isOwner: ajaxify.data.group.isOwner
|
|
||||||
}
|
|
||||||
}, function(html) {
|
|
||||||
$('[component="groups/members"] tbody').append(html);
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return Details;
|
return Details;
|
||||||
});
|
});
|
||||||
97
public/src/client/groups/memberlist.js
Normal file
97
public/src/client/groups/memberlist.js
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
"use strict";
|
||||||
|
/* globals define, socket, ajaxify, app */
|
||||||
|
|
||||||
|
define('forum/groups/memberlist', ['components', 'forum/infinitescroll'], function(components, infinitescroll) {
|
||||||
|
|
||||||
|
var MemberList = {};
|
||||||
|
var searchInterval;
|
||||||
|
var groupName;
|
||||||
|
|
||||||
|
MemberList.init = function() {
|
||||||
|
groupName = ajaxify.data.group.name;
|
||||||
|
|
||||||
|
handleMemberSearch();
|
||||||
|
handleMemberInfiniteScroll();
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleMemberSearch() {
|
||||||
|
$('[component="groups/members/search"]').on('keyup', function() {
|
||||||
|
var query = $(this).val();
|
||||||
|
if (searchInterval) {
|
||||||
|
clearInterval(searchInterval);
|
||||||
|
searchInterval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchInterval = setTimeout(function() {
|
||||||
|
socket.emit('groups.searchMembers', {groupName: groupName, query: query}, function(err, results) {
|
||||||
|
if (err) {
|
||||||
|
return app.alertError(err.message);
|
||||||
|
}
|
||||||
|
parseAndTranslate(results.users, function(html) {
|
||||||
|
$('[component="groups/members"] tbody').html(html);
|
||||||
|
$('[component="groups/members"]').attr('data-nextstart', 20);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, 250);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMemberInfiniteScroll() {
|
||||||
|
$('[component="groups/members"] tbody').on('scroll', function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var bottom = ($this[0].scrollHeight - $this.innerHeight()) * 0.9;
|
||||||
|
|
||||||
|
if ($this.scrollTop() > bottom) {
|
||||||
|
loadMoreMembers();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadMoreMembers() {
|
||||||
|
var members = $('[component="groups/members"]');
|
||||||
|
if (members.attr('loading')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
members.attr('loading', 1);
|
||||||
|
socket.emit('groups.loadMoreMembers', {
|
||||||
|
groupName: groupName,
|
||||||
|
after: members.attr('data-nextstart')
|
||||||
|
}, function(err, data) {
|
||||||
|
if (err) {
|
||||||
|
return app.alertError(err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data && data.users.length) {
|
||||||
|
onMembersLoaded(data.users, function() {
|
||||||
|
members.removeAttr('loading');
|
||||||
|
members.attr('data-nextstart', data.nextStart);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
members.removeAttr('loading');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMembersLoaded(users, callback) {
|
||||||
|
users = users.filter(function(user) {
|
||||||
|
return !$('[component="groups/members"] [data-uid="' + user.uid + '"]').length;
|
||||||
|
});
|
||||||
|
|
||||||
|
parseAndTranslate(users, function(html) {
|
||||||
|
$('[component="groups/members"] tbody').append(html);
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseAndTranslate(users, callback) {
|
||||||
|
infinitescroll.parseAndTranslate('groups/details', 'members', {
|
||||||
|
group: {
|
||||||
|
members: users,
|
||||||
|
isOwner: ajaxify.data.group.isOwner
|
||||||
|
}
|
||||||
|
}, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
return MemberList;
|
||||||
|
});
|
||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
/* globals define, socket, app */
|
/* globals define, socket, app */
|
||||||
|
|
||||||
define('forum/notifications', ['components', 'notifications'], function(components, notifs) {
|
define('forum/notifications', ['components', 'notifications', 'forum/infinitescroll'], function(components, notifs, infinitescroll) {
|
||||||
var Notifications = {};
|
var Notifications = {};
|
||||||
|
|
||||||
Notifications.init = function() {
|
Notifications.init = function() {
|
||||||
var listEl = $('.notifications-list');
|
var listEl = $('.notifications-list');
|
||||||
listEl.on('click', '[component="notifications/item/link"]', function(e) {
|
listEl.on('click', '[component="notifications/item/link"]', function() {
|
||||||
var nid = $(this).parents('[data-nid]').attr('data-nid');
|
var nid = $(this).parents('[data-nid]').attr('data-nid');
|
||||||
socket.emit('notifications.markRead', nid, function(err) {
|
socket.emit('notifications.markRead', nid, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -28,7 +28,32 @@ define('forum/notifications', ['components', 'notifications'], function(componen
|
|||||||
notifs.updateNotifCount(0);
|
notifs.updateNotifCount(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
infinitescroll.init(loadMoreNotifications);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function loadMoreNotifications(direction) {
|
||||||
|
if (direction < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var notifList = $('.notifications-list');
|
||||||
|
infinitescroll.loadMore('notifications.loadMore', {
|
||||||
|
after: notifList.attr('data-nextstart')
|
||||||
|
}, function(data, done) {
|
||||||
|
if (!data) {
|
||||||
|
return done();
|
||||||
|
}
|
||||||
|
notifList.attr('data-nextstart', data.nextStart);
|
||||||
|
if (!data.notifications || !data.notifications.length) {
|
||||||
|
return done();
|
||||||
|
}
|
||||||
|
infinitescroll.parseAndTranslate('notifications', 'notifications', {notifications: data.notifications}, function(html) {
|
||||||
|
notifList.append(html);
|
||||||
|
html.find('.timeago').timeago();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return Notifications;
|
return Notifications;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,14 +4,8 @@
|
|||||||
define('forum/pagination', function() {
|
define('forum/pagination', function() {
|
||||||
var pagination = {};
|
var pagination = {};
|
||||||
|
|
||||||
pagination.currentPage = 0;
|
pagination.init = function() {
|
||||||
pagination.pageCount = 0;
|
$('body').on('click', '.pagination .select-page', function(e) {
|
||||||
|
|
||||||
pagination.init = function(currentPage, pageCount) {
|
|
||||||
pagination.currentPage = parseInt(currentPage, 10);
|
|
||||||
pagination.pageCount = parseInt(pageCount, 10);
|
|
||||||
|
|
||||||
$('.pagination').on('click', '.select-page', function(e) {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
bootbox.prompt('Enter page number:', function(pageNum) {
|
bootbox.prompt('Enter page number:', function(pageNum) {
|
||||||
pagination.loadPage(pageNum);
|
pagination.loadPage(pageNum);
|
||||||
@@ -22,10 +16,14 @@ define('forum/pagination', function() {
|
|||||||
pagination.loadPage = function(page, callback) {
|
pagination.loadPage = function(page, callback) {
|
||||||
callback = callback || function() {};
|
callback = callback || function() {};
|
||||||
page = parseInt(page, 10);
|
page = parseInt(page, 10);
|
||||||
if (!utils.isNumber(page) || page < 1 || page > pagination.pageCount) {
|
if (!utils.isNumber(page) || page < 1 || page > ajaxify.data.pagination.pageCount) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var url = window.location.pathname.slice(1).split('/').slice(0, 3).join('/') + '?page=' + page;
|
|
||||||
|
var query = utils.params();
|
||||||
|
query.page = page;
|
||||||
|
|
||||||
|
var url = window.location.pathname + '?' + $.param(query);
|
||||||
ajaxify.go(url, callback);
|
ajaxify.go(url, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ define('forum/tags', ['forum/infinitescroll'], function(infinitescroll) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
return app.alertError(err.message);
|
return app.alertError(err.message);
|
||||||
}
|
}
|
||||||
onTagsLoaded(results, true, function() {
|
onTagsLoaded(results.tags, true, function() {
|
||||||
timeoutId = 0;
|
timeoutId = 0;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
/* globals define, app, socket, config, ajaxify, RELATIVE_PATH, utils */
|
/* globals define, app, socket, config, ajaxify, RELATIVE_PATH, utils */
|
||||||
|
|
||||||
define('forum/topic', [
|
define('forum/topic', [
|
||||||
'forum/pagination',
|
|
||||||
'forum/infinitescroll',
|
'forum/infinitescroll',
|
||||||
'forum/topic/threadTools',
|
'forum/topic/threadTools',
|
||||||
'forum/topic/postTools',
|
'forum/topic/postTools',
|
||||||
@@ -14,13 +13,13 @@ define('forum/topic', [
|
|||||||
'navigator',
|
'navigator',
|
||||||
'sort',
|
'sort',
|
||||||
'components'
|
'components'
|
||||||
], function(pagination, infinitescroll, threadTools, postTools, events, browsing, posts, navigator, sort, components) {
|
], function(infinitescroll, threadTools, postTools, events, browsing, posts, navigator, sort, components) {
|
||||||
var Topic = {},
|
var Topic = {},
|
||||||
currentUrl = '';
|
currentUrl = '';
|
||||||
|
|
||||||
$(window).on('action:ajaxify.start', function(ev, data) {
|
$(window).on('action:ajaxify.start', function(ev, data) {
|
||||||
if (ajaxify.currentPage !== data.url) {
|
if (ajaxify.currentPage !== data.url) {
|
||||||
navigator.hide();
|
navigator.disable();
|
||||||
components.get('navbar/title').find('span').text('').hide();
|
components.get('navbar/title').find('span').text('').hide();
|
||||||
app.removeAlert('bookmark');
|
app.removeAlert('bookmark');
|
||||||
|
|
||||||
@@ -147,7 +146,7 @@ define('forum/topic', [
|
|||||||
if (components.get('post/anchor', postIndex).length) {
|
if (components.get('post/anchor', postIndex).length) {
|
||||||
return navigator.scrollToPostIndex(postIndex, true);
|
return navigator.scrollToPostIndex(postIndex, true);
|
||||||
}
|
}
|
||||||
} else if (bookmark && (!config.usePagination || (config.usePagination && pagination.currentPage === 1)) && ajaxify.data.postcount > 10) {
|
} else if (bookmark && (!config.usePagination || (config.usePagination && ajaxify.data.pagination.currentPage === 1)) && ajaxify.data.postcount > 5) {
|
||||||
app.alert({
|
app.alert({
|
||||||
alert_id: 'bookmark',
|
alert_id: 'bookmark',
|
||||||
message: '[[topic:bookmark_instructions]]',
|
message: '[[topic:bookmark_instructions]]',
|
||||||
@@ -217,13 +216,10 @@ define('forum/topic', [
|
|||||||
if (!config.usePagination) {
|
if (!config.usePagination) {
|
||||||
infinitescroll.init($('[component="topic"]'), posts.loadMorePosts);
|
infinitescroll.init($('[component="topic"]'), posts.loadMorePosts);
|
||||||
} else {
|
} else {
|
||||||
navigator.hide();
|
navigator.disable();
|
||||||
|
|
||||||
pagination.init(parseInt(ajaxify.data.currentPage, 10), parseInt(ajaxify.data.pageCount, 10));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function updateTopicTitle() {
|
function updateTopicTitle() {
|
||||||
if ($(window).scrollTop() > 50) {
|
if ($(window).scrollTop() > 50) {
|
||||||
components.get('navbar/title').find('span').text(ajaxify.data.title).show();
|
components.get('navbar/title').find('span').text(ajaxify.data.title).show();
|
||||||
@@ -281,7 +277,7 @@ define('forum/topic', [
|
|||||||
var bookmarkKey = 'topic:' + ajaxify.data.tid + ':bookmark';
|
var bookmarkKey = 'topic:' + ajaxify.data.tid + ':bookmark';
|
||||||
var currentBookmark = ajaxify.data.bookmark || localStorage.getItem(bookmarkKey);
|
var currentBookmark = ajaxify.data.bookmark || localStorage.getItem(bookmarkKey);
|
||||||
|
|
||||||
if (!currentBookmark || parseInt(index, 10) > parseInt(currentBookmark, 10)) {
|
if (ajaxify.data.postcount > 5 && (!currentBookmark || parseInt(index, 10) > parseInt(currentBookmark, 10))) {
|
||||||
if (app.user.uid) {
|
if (app.user.uid) {
|
||||||
socket.emit('topics.bookmark', {
|
socket.emit('topics.bookmark', {
|
||||||
'tid': ajaxify.data.tid,
|
'tid': ajaxify.data.tid,
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ define('forum/topic/events', [
|
|||||||
function onPostPurged(pid) {
|
function onPostPurged(pid) {
|
||||||
components.get('post', 'pid', pid).fadeOut(500, function() {
|
components.get('post', 'pid', pid).fadeOut(500, function() {
|
||||||
$(this).remove();
|
$(this).remove();
|
||||||
|
posts.showBottomPostBar();
|
||||||
});
|
});
|
||||||
|
|
||||||
postTools.updatePostCount();
|
postTools.updatePostCount();
|
||||||
|
|||||||
64
public/src/client/topic/flag.js
Normal file
64
public/src/client/topic/flag.js
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/* globals define, app, socket, templates, translator */
|
||||||
|
|
||||||
|
define('forum/topic/flag', [], function() {
|
||||||
|
|
||||||
|
var Flag = {},
|
||||||
|
flagModal,
|
||||||
|
flagCommit;
|
||||||
|
|
||||||
|
Flag.showFlagModal = function(pid) {
|
||||||
|
parseModal(function(html) {
|
||||||
|
flagModal = $(html);
|
||||||
|
|
||||||
|
flagModal.on('hidden.bs.modal', function() {
|
||||||
|
flagModal.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
flagCommit = flagModal.find('#flag-post-commit');
|
||||||
|
|
||||||
|
flagModal.on('click', '.flag-reason', function() {
|
||||||
|
flagPost(pid, $(this).text());
|
||||||
|
});
|
||||||
|
|
||||||
|
flagCommit.on('click', function() {
|
||||||
|
flagPost(pid, flagModal.find('#flag-reason-custom').val());
|
||||||
|
});
|
||||||
|
|
||||||
|
flagModal.modal('show');
|
||||||
|
|
||||||
|
flagModal.find('#flag-reason-custom').on('keyup blur change', checkFlagButtonEnable);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function parseModal(callback) {
|
||||||
|
templates.parse('partials/modals/flag_post_modal', {}, function(html) {
|
||||||
|
translator.translate(html, callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function flagPost(pid, reason) {
|
||||||
|
if (!pid || !reason) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
socket.emit('posts.flag', {pid: pid, reason: reason}, function(err) {
|
||||||
|
if (err) {
|
||||||
|
return app.alertError(err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
flagModal.modal('hide');
|
||||||
|
app.alertSuccess('[[topic:flag_success]]');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkFlagButtonEnable() {
|
||||||
|
if (flagModal.find('#flag-reason-custom').val()) {
|
||||||
|
flagCommit.removeAttr('disabled');
|
||||||
|
} else {
|
||||||
|
flagCommit.attr('disabled', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Flag;
|
||||||
|
});
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/* globals define, app, ajaxify, bootbox, socket, templates, utils */
|
/* globals define, app, ajaxify, bootbox, socket, templates, utils, config */
|
||||||
|
|
||||||
define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator'], function(share, navigator, components, translator) {
|
define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator'], function(share, navigator, components, translator) {
|
||||||
|
|
||||||
@@ -15,6 +15,8 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator
|
|||||||
share.addShareHandlers(topicName);
|
share.addShareHandlers(topicName);
|
||||||
|
|
||||||
addVoteHandler();
|
addVoteHandler();
|
||||||
|
|
||||||
|
PostTools.updatePostCount(ajaxify.data.postcount);
|
||||||
};
|
};
|
||||||
|
|
||||||
PostTools.toggle = function(pid, isDeleted) {
|
PostTools.toggle = function(pid, isDeleted) {
|
||||||
@@ -28,20 +30,16 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator
|
|||||||
postEl.find('[component="post/purge"]').toggleClass('hidden', !isDeleted);
|
postEl.find('[component="post/purge"]').toggleClass('hidden', !isDeleted);
|
||||||
};
|
};
|
||||||
|
|
||||||
PostTools.updatePostCount = function() {
|
PostTools.updatePostCount = function(postCount) {
|
||||||
socket.emit('topics.postcount', ajaxify.data.tid, function(err, postCount) {
|
|
||||||
if (!err) {
|
|
||||||
var postCountEl = components.get('topic/post-count');
|
var postCountEl = components.get('topic/post-count');
|
||||||
postCountEl.html(postCount).attr('title', postCount);
|
postCountEl.html(postCount).attr('title', postCount);
|
||||||
utils.makeNumbersHumanReadable(postCountEl);
|
utils.makeNumbersHumanReadable(postCountEl);
|
||||||
navigator.setCount(postCount);
|
navigator.setCount(postCount);
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function addVoteHandler() {
|
function addVoteHandler() {
|
||||||
components.get('topic').on('mouseenter', '[data-pid] .votes', function() {
|
components.get('topic').on('mouseenter', '[data-pid] [component="post/vote-count"]', function() {
|
||||||
loadDataAndCreateTooltip($(this));
|
loadDataAndCreateTooltip($(this).parent());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,6 +53,13 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createTooltip(el, data) {
|
function createTooltip(el, data) {
|
||||||
|
function doCreateTooltip(title) {
|
||||||
|
el.attr('title', title).tooltip('fixTitle').tooltip('show');
|
||||||
|
el.on('hidden.bs.tooltip', function() {
|
||||||
|
el.tooltip('destroy');
|
||||||
|
el.off('hidden.bs.tooltip');
|
||||||
|
});
|
||||||
|
}
|
||||||
var usernames = data.usernames;
|
var usernames = data.usernames;
|
||||||
if (!usernames.length) {
|
if (!usernames.length) {
|
||||||
return;
|
return;
|
||||||
@@ -63,11 +68,11 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator
|
|||||||
usernames = usernames.join(', ').replace(/,/g, '|');
|
usernames = usernames.join(', ').replace(/,/g, '|');
|
||||||
translator.translate('[[topic:users_and_others, ' + usernames + ', ' + data.otherCount + ']]', function(translated) {
|
translator.translate('[[topic:users_and_others, ' + usernames + ', ' + data.otherCount + ']]', function(translated) {
|
||||||
translated = translated.replace(/\|/g, ',');
|
translated = translated.replace(/\|/g, ',');
|
||||||
el.attr('title', translated).tooltip('destroy').tooltip('show');
|
doCreateTooltip(translated);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
usernames = usernames.join(', ');
|
usernames = usernames.join(', ');
|
||||||
el.attr('title', usernames).tooltip('destroy').tooltip('show');
|
doCreateTooltip(usernames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,40 +108,42 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator
|
|||||||
});
|
});
|
||||||
|
|
||||||
postContainer.on('click', '[component="post/flag"]', function() {
|
postContainer.on('click', '[component="post/flag"]', function() {
|
||||||
flagPost(getData($(this), 'data-pid'));
|
var pid = getData($(this), 'data-pid');
|
||||||
|
require(['forum/topic/flag'], function(flag) {
|
||||||
|
flag.showFlagModal(pid);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
postContainer.on('click', '[component="post/edit"]', function(e) {
|
postContainer.on('click', '[component="post/edit"]', function() {
|
||||||
var btn = $(this);
|
var btn = $(this);
|
||||||
$(window).trigger('action:composer.post.edit', {
|
$(window).trigger('action:composer.post.edit', {
|
||||||
pid: getData(btn, 'data-pid')
|
pid: getData(btn, 'data-pid')
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
postContainer.on('click', '[component="post/delete"]', function(e) {
|
postContainer.on('click', '[component="post/delete"]', function() {
|
||||||
togglePostDelete($(this), tid);
|
togglePostDelete($(this), tid);
|
||||||
});
|
});
|
||||||
|
|
||||||
postContainer.on('click', '[component="post/restore"]', function(e) {
|
postContainer.on('click', '[component="post/restore"]', function() {
|
||||||
togglePostDelete($(this), tid);
|
togglePostDelete($(this), tid);
|
||||||
});
|
});
|
||||||
|
|
||||||
postContainer.on('click', '[component="post/purge"]', function(e) {
|
postContainer.on('click', '[component="post/purge"]', function() {
|
||||||
purgePost($(this), tid);
|
purgePost($(this), tid);
|
||||||
});
|
});
|
||||||
|
|
||||||
postContainer.on('click', '[component="post/move"]', function(e) {
|
postContainer.on('click', '[component="post/move"]', function() {
|
||||||
openMovePostModal($(this));
|
openMovePostModal($(this));
|
||||||
});
|
});
|
||||||
|
|
||||||
postContainer.on('click', '[component="post/chat"]', function(e) {
|
postContainer.on('click', '[component="post/chat"]', function() {
|
||||||
openChat($(this));
|
openChat($(this));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onReplyClicked(button, tid, topicName) {
|
function onReplyClicked(button, tid, topicName) {
|
||||||
showStaleWarning(function(proceed) {
|
showStaleWarning(function(proceed) {
|
||||||
console.log('proceed is', proceed);
|
|
||||||
if (!proceed) {
|
if (!proceed) {
|
||||||
var selectionText = '',
|
var selectionText = '',
|
||||||
selection = window.getSelection ? window.getSelection() : document.selection.createRange();
|
selection = window.getSelection ? window.getSelection() : document.selection.createRange();
|
||||||
@@ -363,22 +370,7 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function flagPost(pid) {
|
|
||||||
translator.translate('[[topic:flag_confirm]]', function(message) {
|
|
||||||
bootbox.confirm(message, function(confirm) {
|
|
||||||
if (!confirm) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
socket.emit('posts.flag', pid, function(err) {
|
|
||||||
if (err) {
|
|
||||||
return app.alertError(err.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
app.alertSuccess('[[topic:flag_success]]');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function openChat(button) {
|
function openChat(button) {
|
||||||
var post = button.parents('[data-pid]');
|
var post = button.parents('[data-pid]');
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ define('forum/topic/posts', [
|
|||||||
});
|
});
|
||||||
|
|
||||||
updatePostCounts(data.posts);
|
updatePostCounts(data.posts);
|
||||||
|
ajaxify.data.postcount ++;
|
||||||
|
postTools.updatePostCount(ajaxify.data.postcount);
|
||||||
|
|
||||||
if (config.usePagination) {
|
if (config.usePagination) {
|
||||||
onNewPostPagination(data);
|
onNewPostPagination(data);
|
||||||
@@ -51,15 +53,15 @@ define('forum/topic/posts', [
|
|||||||
|
|
||||||
var posts = data.posts;
|
var posts = data.posts;
|
||||||
|
|
||||||
pagination.pageCount = Math.max(1, Math.ceil((posts[0].topic.postcount - 1) / config.postsPerPage));
|
ajaxify.data.pagination.pageCount = Math.max(1, Math.ceil((posts[0].topic.postcount - 1) / config.postsPerPage));
|
||||||
var direction = config.topicPostSort === 'oldest_to_newest' || config.topicPostSort === 'most_votes' ? 1 : -1;
|
var direction = config.topicPostSort === 'oldest_to_newest' || config.topicPostSort === 'most_votes' ? 1 : -1;
|
||||||
|
|
||||||
var isPostVisible = (pagination.currentPage === pagination.pageCount && direction === 1) || (pagination.currentPage === 1 && direction === -1);
|
var isPostVisible = (ajaxify.data.pagination.currentPage === ajaxify.data.pagination.pageCount && direction === 1) || (ajaxify.data.pagination.currentPage === 1 && direction === -1);
|
||||||
|
|
||||||
if (isPostVisible) {
|
if (isPostVisible) {
|
||||||
createNewPosts(data, components.get('post').not('[data-index=0]'), direction, scrollToPost);
|
createNewPosts(data, components.get('post').not('[data-index=0]'), direction, scrollToPost);
|
||||||
} else if (parseInt(posts[0].uid, 10) === parseInt(app.user.uid, 10)) {
|
} else if (parseInt(posts[0].uid, 10) === parseInt(app.user.uid, 10)) {
|
||||||
pagination.loadPage(pagination.pageCount, scrollToPost);
|
pagination.loadPage(ajaxify.data.pagination.pageCount, scrollToPost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,17 +222,15 @@ define('forum/topic/posts', [
|
|||||||
$this.wrap('<a href="' + $this.attr('src') + '" target="_blank">');
|
$this.wrap('<a href="' + $this.attr('src') + '" target="_blank">');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
postTools.updatePostCount();
|
|
||||||
addBlockquoteEllipses(posts.find('[component="post/content"] > blockquote'));
|
addBlockquoteEllipses(posts.find('[component="post/content"] > blockquote > blockquote'));
|
||||||
hidePostToolsForDeletedPosts(posts);
|
hidePostToolsForDeletedPosts(posts);
|
||||||
showBottomPostBar();
|
Posts.showBottomPostBar();
|
||||||
};
|
};
|
||||||
|
|
||||||
function showBottomPostBar() {
|
Posts.showBottomPostBar = function() {
|
||||||
if (components.get('post').length > 1 || !components.get('post', 'index', 0).length) {
|
$('.bottom-post-bar').toggleClass('hidden', components.get('post').length <= 1 && !!components.get('post', 'index', 0).length);
|
||||||
$('.bottom-post-bar').removeClass('hidden');
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function hidePostToolsForDeletedPosts(posts) {
|
function hidePostToolsForDeletedPosts(posts) {
|
||||||
posts.each(function() {
|
posts.each(function() {
|
||||||
|
|||||||
@@ -10,8 +10,11 @@
|
|||||||
var helpers = {};
|
var helpers = {};
|
||||||
|
|
||||||
helpers.displayMenuItem = function(data, index) {
|
helpers.displayMenuItem = function(data, index) {
|
||||||
var item = data.navigation[index],
|
var item = data.navigation[index];
|
||||||
properties = item.properties;
|
if (!item) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var properties = item.properties;
|
||||||
|
|
||||||
if (properties) {
|
if (properties) {
|
||||||
if ((properties.loggedIn && !data.config.loggedIn) ||
|
if ((properties.loggedIn && !data.config.loggedIn) ||
|
||||||
@@ -37,7 +40,7 @@
|
|||||||
property = tag.property ? 'property="' + tag.property + '" ' : '',
|
property = tag.property ? 'property="' + tag.property + '" ' : '',
|
||||||
content = tag.content ? 'content="' + tag.content.replace(/\n/g, ' ') + '" ' : '';
|
content = tag.content ? 'content="' + tag.content.replace(/\n/g, ' ') + '" ' : '';
|
||||||
|
|
||||||
return '<meta ' + name + property + content + '/>';
|
return '<meta ' + name + property + content + '/>\n\t';
|
||||||
};
|
};
|
||||||
|
|
||||||
helpers.buildLinkTag = function(tag) {
|
helpers.buildLinkTag = function(tag) {
|
||||||
@@ -47,7 +50,7 @@
|
|||||||
href = tag.href ? 'href="' + tag.href + '" ' : '',
|
href = tag.href ? 'href="' + tag.href + '" ' : '',
|
||||||
sizes = tag.sizes ? 'sizes="' + tag.sizes + '" ' : '';
|
sizes = tag.sizes ? 'sizes="' + tag.sizes + '" ' : '';
|
||||||
|
|
||||||
return '<link ' + link + rel + type + sizes + href + '/>';
|
return '<link ' + link + rel + type + sizes + href + '/>\n\t';
|
||||||
};
|
};
|
||||||
|
|
||||||
helpers.stringify = function(obj) {
|
helpers.stringify = function(obj) {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ define('navigator', ['forum/pagination', 'components'], function(pagination, com
|
|||||||
toTop = toTop || function() {};
|
toTop = toTop || function() {};
|
||||||
toBottom = toBottom || function() {};
|
toBottom = toBottom || function() {};
|
||||||
|
|
||||||
$(window).on('scroll', navigator.update);
|
$(window).off('scroll', navigator.update).on('scroll', navigator.update);
|
||||||
|
|
||||||
$('.pagination-block .dropdown-menu').off('click').on('click', function(e) {
|
$('.pagination-block .dropdown-menu').off('click').on('click', function(e) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -74,7 +74,12 @@ define('navigator', ['forum/pagination', 'components'], function(pagination, com
|
|||||||
toggle(true);
|
toggle(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
navigator.hide = function() {
|
navigator.disable = function() {
|
||||||
|
count = 0;
|
||||||
|
index = 1;
|
||||||
|
navigator.selector = navigator.callback = null;
|
||||||
|
$(window).off('scroll', navigator.update);
|
||||||
|
|
||||||
toggle(false);
|
toggle(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -92,13 +97,19 @@ define('navigator', ['forum/pagination', 'components'], function(pagination, com
|
|||||||
|
|
||||||
var middleOfViewport = $(window).scrollTop() + $(window).height() / 2;
|
var middleOfViewport = $(window).scrollTop() + $(window).height() / 2;
|
||||||
|
|
||||||
index = parseInt($(navigator.selector).first().attr('data-index'), 10);
|
index = parseInt($(navigator.selector).first().attr('data-index'), 10) + 1;
|
||||||
|
var previousDistance = Number.MAX_VALUE;
|
||||||
$(navigator.selector).each(function() {
|
$(navigator.selector).each(function() {
|
||||||
index++;
|
var distanceToMiddle = Math.abs(middleOfViewport - $(this).offset().top);
|
||||||
if ($(this).offset().top > middleOfViewport) {
|
|
||||||
|
if (distanceToMiddle > previousDistance) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (distanceToMiddle < previousDistance) {
|
||||||
|
index = parseInt($(this).attr('data-index'), 10) + 1;
|
||||||
|
previousDistance = distanceToMiddle;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (typeof navigator.callback === 'function') {
|
if (typeof navigator.callback === 'function') {
|
||||||
@@ -162,7 +173,7 @@ define('navigator', ['forum/pagination', 'components'], function(pagination, com
|
|||||||
if (config.usePagination) {
|
if (config.usePagination) {
|
||||||
var page = Math.max(1, Math.ceil(postIndex / config.postsPerPage));
|
var page = Math.max(1, Math.ceil(postIndex / config.postsPerPage));
|
||||||
|
|
||||||
if (parseInt(page, 10) !== pagination.currentPage) {
|
if (parseInt(page, 10) !== ajaxify.data.pagination.currentPage) {
|
||||||
pagination.loadPage(page, function() {
|
pagination.loadPage(page, function() {
|
||||||
navigator.scrollToPostIndex(postIndex, highlight, duration);
|
navigator.scrollToPostIndex(postIndex, highlight, duration);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -64,14 +64,6 @@ define('notifications', ['sounds', 'translator', 'components'], function(sound,
|
|||||||
Notifications.updateNotifCount(count);
|
Notifications.updateNotifCount(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.emit('notifications.getCount', function(err, count) {
|
|
||||||
if (!err) {
|
|
||||||
Notifications.updateNotifCount(count);
|
|
||||||
} else {
|
|
||||||
Notifications.updateNotifCount(0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('event:new_notification', function(notifData) {
|
socket.on('event:new_notification', function(notifData) {
|
||||||
app.alert({
|
app.alert({
|
||||||
alert_id: 'new_notif',
|
alert_id: 'new_notif',
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ define('sort', ['components'], function(components) {
|
|||||||
var currentSetting = threadSort.find('a[data-sort="' + config[field] + '"]');
|
var currentSetting = threadSort.find('a[data-sort="' + config[field] + '"]');
|
||||||
currentSetting.find('i').addClass('fa-check');
|
currentSetting.find('i').addClass('fa-check');
|
||||||
|
|
||||||
components.get('topic').on('click', '[component="thread/sort"] a', function() {
|
$('.category, .topic').on('click', '[component="thread/sort"] a', function() {
|
||||||
var newSetting = $(this).attr('data-sort');
|
var newSetting = $(this).attr('data-sort');
|
||||||
socket.emit(method, newSetting, function(err) {
|
socket.emit(method, newSetting, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|||||||
@@ -5,31 +5,30 @@ define('sounds', ['buzz'], function(buzz) {
|
|||||||
var Sounds = {};
|
var Sounds = {};
|
||||||
|
|
||||||
var loadedSounds = {};
|
var loadedSounds = {};
|
||||||
var eventSoundMapping = {};
|
var eventSoundMapping;
|
||||||
var files = {};
|
var files;
|
||||||
|
|
||||||
loadFiles();
|
|
||||||
|
|
||||||
loadMapping();
|
|
||||||
|
|
||||||
socket.on('event:sounds.reloadMapping', loadMapping);
|
socket.on('event:sounds.reloadMapping', loadMapping);
|
||||||
|
|
||||||
function loadFiles() {
|
function loadMapping(callback) {
|
||||||
socket.emit('modules.sounds.getSounds', function(err, sounds) {
|
callback = callback || function() {};
|
||||||
if (err) {
|
|
||||||
return app.alertError('[sounds] Could not initialise!');
|
|
||||||
}
|
|
||||||
|
|
||||||
files = sounds;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadMapping() {
|
|
||||||
socket.emit('modules.sounds.getMapping', function(err, mapping) {
|
socket.emit('modules.sounds.getMapping', function(err, mapping) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return app.alertError('[sounds] Could not load sound mapping!');
|
return app.alertError('[sounds] Could not load sound mapping!');
|
||||||
}
|
}
|
||||||
eventSoundMapping = mapping;
|
eventSoundMapping = mapping;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadData(callback) {
|
||||||
|
socket.emit('modules.sounds.getData', function(err, data) {
|
||||||
|
if (err) {
|
||||||
|
return app.alertError('[sounds] Could not load sound mapping!');
|
||||||
|
}
|
||||||
|
eventSoundMapping = data.mapping;
|
||||||
|
files = data.files;
|
||||||
|
callback();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,22 +37,37 @@ define('sounds', ['buzz'], function(buzz) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadFile(fileName, callback) {
|
function loadFile(fileName, callback) {
|
||||||
if (isSoundLoaded(fileName)) {
|
function createSound() {
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (files && files[fileName]) {
|
if (files && files[fileName]) {
|
||||||
loadedSounds[fileName] = new buzz.sound(files[fileName]);
|
loadedSounds[fileName] = new buzz.sound(files[fileName]);
|
||||||
}
|
}
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isSoundLoaded(fileName)) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!files || !files[fileName]) {
|
||||||
|
return loadData(createSound);
|
||||||
|
}
|
||||||
|
createSound();
|
||||||
|
}
|
||||||
|
|
||||||
Sounds.play = function(name) {
|
Sounds.play = function(name) {
|
||||||
|
function play() {
|
||||||
|
Sounds.playFile(eventSoundMapping[name]);
|
||||||
|
}
|
||||||
|
|
||||||
if (!config.notificationSounds) {
|
if (!config.notificationSounds) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sounds.playFile(eventSoundMapping[name]);
|
if (!eventSoundMapping) {
|
||||||
|
return loadData(play);
|
||||||
|
}
|
||||||
|
|
||||||
|
play();
|
||||||
};
|
};
|
||||||
|
|
||||||
Sounds.playFile = function(fileName) {
|
Sounds.playFile = function(fileName) {
|
||||||
|
|||||||
@@ -381,6 +381,12 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof String.prototype.rtrim != 'function') {
|
||||||
|
String.prototype.rtrim = function() {
|
||||||
|
return this.replace(/\s+$/g, '');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if ('undefined' !== typeof window) {
|
if ('undefined' !== typeof window) {
|
||||||
window.utils = module.exports;
|
window.utils = module.exports;
|
||||||
}
|
}
|
||||||
|
|||||||
20
public/vendor/jquery/timeago/locales/jquery.timeago.it-short.js
vendored
Normal file
20
public/vendor/jquery/timeago/locales/jquery.timeago.it-short.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Italian shortened
|
||||||
|
jQuery.timeago.settings.strings = {
|
||||||
|
prefixAgo: null,
|
||||||
|
prefixFromNow: null,
|
||||||
|
suffixAgo: "",
|
||||||
|
suffixFromNow: "",
|
||||||
|
seconds: "1m",
|
||||||
|
minute: "1m",
|
||||||
|
minutes: "%dm",
|
||||||
|
hour: "1h",
|
||||||
|
hours: "%dh",
|
||||||
|
day: "1g",
|
||||||
|
days: "%dg",
|
||||||
|
month: "1me",
|
||||||
|
months: "%dme",
|
||||||
|
year: "1a",
|
||||||
|
years: "%da",
|
||||||
|
wordSeparator: " ",
|
||||||
|
numbers: []
|
||||||
|
};
|
||||||
@@ -53,17 +53,11 @@ module.exports = function(Categories) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (category.description) {
|
if (category.description) {
|
||||||
plugins.fireHook('filter:parse.raw', category.description, function(err, parsedDescription) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
category.descriptionParsed = parsedDescription;
|
|
||||||
category.description = validator.escape(category.description);
|
category.description = validator.escape(category.description);
|
||||||
callback(null, category);
|
category.descriptionParsed = category.descriptionParsed || category.description;
|
||||||
});
|
|
||||||
} else {
|
|
||||||
callback(null, category);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callback(null, category);
|
||||||
}
|
}
|
||||||
|
|
||||||
Categories.getCategoryField = function(cid, field, callback) {
|
Categories.getCategoryField = function(cid, field, callback) {
|
||||||
|
|||||||
@@ -3,14 +3,13 @@
|
|||||||
|
|
||||||
var async = require('async'),
|
var async = require('async'),
|
||||||
winston = require('winston'),
|
winston = require('winston'),
|
||||||
|
validator = require('validator'),
|
||||||
_ = require('underscore'),
|
_ = require('underscore'),
|
||||||
|
|
||||||
meta = require('../meta'),
|
|
||||||
db = require('../database'),
|
db = require('../database'),
|
||||||
posts = require('../posts'),
|
posts = require('../posts'),
|
||||||
topics = require('../topics'),
|
topics = require('../topics'),
|
||||||
privileges = require('../privileges'),
|
privileges = require('../privileges');
|
||||||
plugins = require('../plugins');
|
|
||||||
|
|
||||||
module.exports = function(Categories) {
|
module.exports = function(Categories) {
|
||||||
Categories.getRecentReplies = function(cid, uid, count, callback) {
|
Categories.getRecentReplies = function(cid, uid, count, callback) {
|
||||||
@@ -38,25 +37,21 @@ module.exports = function(Categories) {
|
|||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function(next) {
|
function(next) {
|
||||||
async.map(categoryData, getRecentTopicPids, next);
|
async.map(categoryData, getRecentTopicTids, next);
|
||||||
},
|
},
|
||||||
function(results, next) {
|
function(results, next) {
|
||||||
var pids = _.flatten(results);
|
var tids = _.flatten(results);
|
||||||
|
|
||||||
pids = pids.filter(function(pid, index, array) {
|
tids = tids.filter(function(tid, index, array) {
|
||||||
return !!pid && array.indexOf(pid) === index;
|
return !!tid && array.indexOf(tid) === index;
|
||||||
});
|
});
|
||||||
privileges.posts.filter('read', pids, uid, next);
|
privileges.topics.filterTids('read', tids, uid, next);
|
||||||
},
|
},
|
||||||
function(pids, next) {
|
function(tids, next) {
|
||||||
if (meta.config.teaserPost === 'first') {
|
getTopics(tids, next);
|
||||||
getMainPosts(pids, uid, next);
|
|
||||||
} else {
|
|
||||||
posts.getPostSummaryByPids(pids, uid, {stripTags: true}, next);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
function(posts, next) {
|
function(topics, next) {
|
||||||
assignPostsToCategories(categoryData, posts);
|
assignTopicsToCategories(categoryData, topics);
|
||||||
|
|
||||||
bubbleUpChildrenPosts(categoryData);
|
bubbleUpChildrenPosts(categoryData);
|
||||||
|
|
||||||
@@ -65,27 +60,84 @@ module.exports = function(Categories) {
|
|||||||
], callback);
|
], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
function getMainPosts(pids, uid, callback) {
|
function getRecentTopicTids(category, callback) {
|
||||||
|
var count = parseInt(category.numRecentReplies, 10);
|
||||||
|
if (!count) {
|
||||||
|
return callback(null, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count === 1) {
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function(next) {
|
function (next) {
|
||||||
var keys = pids.map(function(pid) {
|
db.getSortedSetRevRange('cid:' + category.cid + ':pids', 0, 0, next);
|
||||||
return 'post:' + pid;
|
|
||||||
});
|
|
||||||
db.getObjectsFields(keys, ['tid'], next);
|
|
||||||
},
|
},
|
||||||
function(posts, next) {
|
function (pid, next) {
|
||||||
var keys = posts.map(function(post) {
|
posts.getPostField(pid, 'tid', next);
|
||||||
return 'topic:' + post.tid;
|
|
||||||
});
|
|
||||||
db.getObjectsFields(keys, ['mainPid'], next);
|
|
||||||
},
|
},
|
||||||
function(topics, next) {
|
function (tid, next) {
|
||||||
var mainPids = topics.map(function(topic) {
|
next(null, [tid]);
|
||||||
return topic.mainPid;
|
|
||||||
});
|
|
||||||
posts.getPostSummaryByPids(mainPids, uid, {stripTags: true}, next);
|
|
||||||
}
|
}
|
||||||
], callback);
|
], callback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
async.parallel({
|
||||||
|
pinnedTids: function(next) {
|
||||||
|
db.getSortedSetRevRangeByScore('cid:' + category.cid + ':tids', 0, -1, '+inf', Date.now(), next);
|
||||||
|
},
|
||||||
|
tids: function(next) {
|
||||||
|
db.getSortedSetRevRangeByScore('cid:' + category.cid + ':tids', 0, Math.max(1, count), Date.now(), 0, next);
|
||||||
|
}
|
||||||
|
}, function(err, results) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
results.tids = results.tids.concat(results.pinnedTids);
|
||||||
|
|
||||||
|
callback(null, results.tids);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTopics(tids, callback) {
|
||||||
|
var topicData;
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
topics.getTopicsFields(tids, ['tid', 'mainPid', 'slug', 'title', 'teaserPid', 'cid', 'postcount'], next);
|
||||||
|
},
|
||||||
|
function (_topicData, next) {
|
||||||
|
topicData = _topicData;
|
||||||
|
topicData.forEach(function(topic) {
|
||||||
|
topic.teaserPid = topic.teaserPid || topic.mainPid;
|
||||||
|
});
|
||||||
|
|
||||||
|
topics.getTeasers(topicData, next);
|
||||||
|
},
|
||||||
|
function (teasers, next) {
|
||||||
|
teasers.forEach(function(teaser, index) {
|
||||||
|
if (teaser) {
|
||||||
|
teaser.cid = topicData[index].cid;
|
||||||
|
teaser.tid = teaser.uid = teaser.user.uid = undefined;
|
||||||
|
teaser.topic = {
|
||||||
|
slug: topicData[index].slug,
|
||||||
|
title: validator.escape(topicData[index].title)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
teasers = teasers.filter(Boolean);
|
||||||
|
next(null, teasers);
|
||||||
|
}
|
||||||
|
], callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function assignTopicsToCategories(categories, topics) {
|
||||||
|
categories.forEach(function(category) {
|
||||||
|
category.posts = topics.filter(function(topic) {
|
||||||
|
return topic.cid && parseInt(topic.cid, 10) === parseInt(category.cid, 10);
|
||||||
|
}).sort(function(a, b) {
|
||||||
|
return b.pid - a.pid;
|
||||||
|
}).slice(0, parseInt(category.numRecentReplies, 10));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function bubbleUpChildrenPosts(categoryData) {
|
function bubbleUpChildrenPosts(categoryData) {
|
||||||
@@ -97,7 +149,7 @@ module.exports = function(Categories) {
|
|||||||
getPostsRecursive(category, posts);
|
getPostsRecursive(category, posts);
|
||||||
|
|
||||||
posts.sort(function(a, b) {
|
posts.sort(function(a, b) {
|
||||||
return b.timestamp - a.timestamp;
|
return b.pid - a.pid;
|
||||||
});
|
});
|
||||||
if (posts.length) {
|
if (posts.length) {
|
||||||
category.posts = [posts[0]];
|
category.posts = [posts[0]];
|
||||||
@@ -115,64 +167,6 @@ module.exports = function(Categories) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function assignPostsToCategories(categories, posts) {
|
|
||||||
categories.forEach(function(category) {
|
|
||||||
category.posts = posts.filter(function(post) {
|
|
||||||
return post.category && (parseInt(post.category.cid, 10) === parseInt(category.cid, 10) ||
|
|
||||||
parseInt(post.category.parentCid, 10) === parseInt(category.cid, 10));
|
|
||||||
}).sort(function(a, b) {
|
|
||||||
return b.timestamp - a.timestamp;
|
|
||||||
}).slice(0, parseInt(category.numRecentReplies, 10));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRecentTopicPids(category, callback) {
|
|
||||||
var count = parseInt(category.numRecentReplies, 10);
|
|
||||||
if (!count) {
|
|
||||||
return callback(null, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
db.getSortedSetRevRange('cid:' + category.cid + ':pids', 0, 0, function(err, pids) {
|
|
||||||
if (err || !Array.isArray(pids) || !pids.length) {
|
|
||||||
return callback(err, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count === 1) {
|
|
||||||
return callback(null, pids);
|
|
||||||
}
|
|
||||||
|
|
||||||
async.parallel({
|
|
||||||
pinnedTids: function(next) {
|
|
||||||
db.getSortedSetRevRangeByScore('cid:' + category.cid + ':tids', 0, -1, '+inf', Date.now(), next);
|
|
||||||
},
|
|
||||||
tids: function(next) {
|
|
||||||
db.getSortedSetRevRangeByScore('cid:' + category.cid + ':tids', 0, Math.max(0, count), Date.now(), 0, next);
|
|
||||||
}
|
|
||||||
}, function(err, results) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
results.tids = results.tids.concat(results.pinnedTids);
|
|
||||||
|
|
||||||
async.map(results.tids, topics.getLatestUndeletedPid, function(err, topicPids) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
pids = pids.concat(topicPids).filter(function(pid, index, array) {
|
|
||||||
return !!pid && array.indexOf(pid) === index;
|
|
||||||
}).sort(function(a, b) {
|
|
||||||
return b - a;
|
|
||||||
}).slice(0, count);
|
|
||||||
|
|
||||||
callback(null, pids);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Categories.moveRecentReplies = function(tid, oldCid, cid) {
|
Categories.moveRecentReplies = function(tid, oldCid, cid) {
|
||||||
updatePostCount(tid, oldCid, cid);
|
updatePostCount(tid, oldCid, cid);
|
||||||
topics.getPids(tid, function(err, pids) {
|
topics.getPids(tid, function(err, pids) {
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ module.exports = function(Categories) {
|
|||||||
|
|
||||||
if (key === 'order') {
|
if (key === 'order') {
|
||||||
updateOrder(cid, value, callback);
|
updateOrder(cid, value, callback);
|
||||||
|
} else if (key === 'description') {
|
||||||
|
parseDescription(cid, value, callback);
|
||||||
} else {
|
} else {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
@@ -119,4 +121,13 @@ module.exports = function(Categories) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseDescription(cid, description, callback) {
|
||||||
|
plugins.fireHook('filter:parse.raw', description, function(err, parsedDescription) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
Categories.setCategoryField(cid, 'descriptionParsed', parsedDescription, callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ chatsController.get = function(req, res, callback) {
|
|||||||
// In case a userNAME is passed in instead of a slug, the route should not 404
|
// In case a userNAME is passed in instead of a slug, the route should not 404
|
||||||
var slugified = utils.slugify(req.params.userslug);
|
var slugified = utils.slugify(req.params.userslug);
|
||||||
if (req.params.userslug && req.params.userslug !== slugified) {
|
if (req.params.userslug && req.params.userslug !== slugified) {
|
||||||
return res.redirect(nconf.get('relative_path') + '/chats/' + slugified);
|
return helpers.redirect(res, '/chats/' + slugified);
|
||||||
}
|
}
|
||||||
|
|
||||||
async.parallel({
|
async.parallel({
|
||||||
|
|||||||
@@ -14,6 +14,48 @@ var async = require('async'),
|
|||||||
var editController = {};
|
var editController = {};
|
||||||
|
|
||||||
editController.get = function(req, res, callback) {
|
editController.get = function(req, res, callback) {
|
||||||
|
accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, function(err, userData) {
|
||||||
|
if (err || !userData) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
userData.title = '[[pages:account/edit, ' + userData.username + ']]';
|
||||||
|
userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: '[[user:edit]]'}]);
|
||||||
|
|
||||||
|
res.render('account/edit', userData);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
editController.password = function(req, res, next) {
|
||||||
|
renderRoute('password', req, res, next);
|
||||||
|
};
|
||||||
|
|
||||||
|
editController.username = function(req, res, next) {
|
||||||
|
renderRoute('username', req, res, next);
|
||||||
|
};
|
||||||
|
|
||||||
|
editController.email = function(req, res, next) {
|
||||||
|
renderRoute('email', req, res, next);
|
||||||
|
};
|
||||||
|
|
||||||
|
function renderRoute(name, req, res, next) {
|
||||||
|
getUserData(req, next, function(err, userData) {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
userData.title = '[[pages:account/edit/' + name + ', ' + userData.username + ']]';
|
||||||
|
userData.breadcrumbs = helpers.buildBreadcrumbs([
|
||||||
|
{text: userData.username, url: '/user/' + userData.userslug},
|
||||||
|
{text: '[[user:edit]]', url: '/user/' + userData.userslug + '/edit'},
|
||||||
|
{text: '[[user:' + name + ']]'}
|
||||||
|
]);
|
||||||
|
|
||||||
|
res.render('account/edit/' + name, userData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUserData(req, next, callback) {
|
||||||
var userData;
|
var userData;
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function(next) {
|
function(next) {
|
||||||
@@ -22,7 +64,7 @@ editController.get = function(req, res, callback) {
|
|||||||
function(data, next) {
|
function(data, next) {
|
||||||
userData = data;
|
userData = data;
|
||||||
if (!userData) {
|
if (!userData) {
|
||||||
return callback();
|
return next();
|
||||||
}
|
}
|
||||||
db.getObjectField('user:' + userData.uid, 'password', next);
|
db.getObjectField('user:' + userData.uid, 'password', next);
|
||||||
}
|
}
|
||||||
@@ -33,13 +75,9 @@ editController.get = function(req, res, callback) {
|
|||||||
|
|
||||||
userData['username:disableEdit'] = parseInt(meta.config['username:disableEdit'], 10) === 1;
|
userData['username:disableEdit'] = parseInt(meta.config['username:disableEdit'], 10) === 1;
|
||||||
userData.hasPassword = !!password;
|
userData.hasPassword = !!password;
|
||||||
userData.title = '[[pages:account/edit, ' + userData.username + ']]';
|
callback(null, userData);
|
||||||
userData.breadcrumbs = helpers.buildBreadcrumbs([{text: userData.username, url: '/user/' + userData.userslug}, {text: '[[user:edit]]'}]);
|
|
||||||
|
|
||||||
res.render('account/edit', userData);
|
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
editController.uploadPicture = function (req, res, next) {
|
editController.uploadPicture = function (req, res, next) {
|
||||||
var userPhoto = req.files.files[0];
|
var userPhoto = req.files.files[0];
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ var user = require('../../user'),
|
|||||||
var notificationsController = {};
|
var notificationsController = {};
|
||||||
|
|
||||||
notificationsController.get = function(req, res, next) {
|
notificationsController.get = function(req, res, next) {
|
||||||
user.notifications.getAll(req.uid, 40, function(err, notifications) {
|
user.notifications.getAll(req.uid, 0, 39, function(err, notifications) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
res.render('notifications', {
|
res.render('notifications', {
|
||||||
notifications: notifications,
|
notifications: notifications,
|
||||||
|
nextStart: 40,
|
||||||
title: '[[pages:notifications]]',
|
title: '[[pages:notifications]]',
|
||||||
breadcrumbs: helpers.buildBreadcrumbs([{text: '[[pages:notifications]]'}])
|
breadcrumbs: helpers.buildBreadcrumbs([{text: '[[pages:notifications]]'}])
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ var adminController = {
|
|||||||
navigation: require('./admin/navigation'),
|
navigation: require('./admin/navigation'),
|
||||||
themes: require('./admin/themes'),
|
themes: require('./admin/themes'),
|
||||||
users: require('./admin/users'),
|
users: require('./admin/users'),
|
||||||
uploads: require('./admin/uploads')
|
uploads: require('./admin/uploads'),
|
||||||
|
info: require('./admin/info')
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -59,12 +59,13 @@ groupsController.get = function(req, res, callback) {
|
|||||||
if (!exists) {
|
if (!exists) {
|
||||||
return callback();
|
return callback();
|
||||||
}
|
}
|
||||||
groups.get(groupName, {uid: req.uid}, next);
|
groups.get(groupName, {uid: req.uid, truncateUserList: true, userListCount: 20}, next);
|
||||||
}
|
}
|
||||||
], function(err, group) {
|
], function(err, group) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
group.isOwner = true;
|
||||||
res.render('admin/manage/group', {group: group});
|
res.render('admin/manage/group', {group: group});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
29
src/controllers/admin/info.js
Normal file
29
src/controllers/admin/info.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var os = require('os');
|
||||||
|
|
||||||
|
var infoController = {};
|
||||||
|
|
||||||
|
infoController.get = function(req, res, next) {
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
process: {
|
||||||
|
pid: process.pid,
|
||||||
|
title: process.title,
|
||||||
|
arch: process.arch,
|
||||||
|
platform: process.platform,
|
||||||
|
version: process.version,
|
||||||
|
versions: process.versions,
|
||||||
|
memoryUsage: process.memoryUsage(),
|
||||||
|
uptime: process.uptime()
|
||||||
|
},
|
||||||
|
os: {
|
||||||
|
hostname: os.hostname()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
res.render('admin/development/info', {info: JSON.stringify(data, null, 4)});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = infoController;
|
||||||
@@ -114,7 +114,7 @@ function validateUpload(req, res, next, uploadedFile, allowedTypes) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
res.json({error: '[[error:invalid-image-type, ' + allowedTypes.join(', ') + ']]'});
|
res.json({error: '[[error:invalid-image-type, ' + allowedTypes.join(', ') + ']]'});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ apiController.getConfig = function(req, res, next) {
|
|||||||
config.categoryTopicSort = meta.config.categoryTopicSort || 'newest_to_oldest';
|
config.categoryTopicSort = meta.config.categoryTopicSort || 'newest_to_oldest';
|
||||||
config.csrf_token = req.csrfToken();
|
config.csrf_token = req.csrfToken();
|
||||||
config.searchEnabled = plugins.hasListeners('filter:search.query');
|
config.searchEnabled = plugins.hasListeners('filter:search.query');
|
||||||
|
config.bootswatchSkin = 'default';
|
||||||
|
|
||||||
if (!req.user) {
|
if (!req.user) {
|
||||||
return filterConfig();
|
return filterConfig();
|
||||||
@@ -103,6 +104,7 @@ apiController.getConfig = function(req, res, next) {
|
|||||||
config.topicPostSort = settings.topicPostSort || config.topicPostSort;
|
config.topicPostSort = settings.topicPostSort || config.topicPostSort;
|
||||||
config.categoryTopicSort = settings.categoryTopicSort || config.categoryTopicSort;
|
config.categoryTopicSort = settings.categoryTopicSort || config.categoryTopicSort;
|
||||||
config.topicSearchEnabled = settings.topicSearchEnabled || false;
|
config.topicSearchEnabled = settings.topicSearchEnabled || false;
|
||||||
|
config.bootswatchSkin = settings.bootswatchSkin || config.bootswatchSkin;
|
||||||
|
|
||||||
filterConfig();
|
filterConfig();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -65,6 +65,15 @@ categoriesController.list = function(req, res, next) {
|
|||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.categories.forEach(function(category) {
|
||||||
|
if (category && Array.isArray(category.posts) && category.posts.length) {
|
||||||
|
category.teaser = {
|
||||||
|
url: nconf.get('relative_path') + '/topic/' + category.posts[0].topic.slug + '/' + category.posts[0].index,
|
||||||
|
timestampISO: category.posts[0].timestamp
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
data.title = '[[pages:categories]]';
|
data.title = '[[pages:categories]]';
|
||||||
if (req.path.startsWith('/api/categories') || req.path.startsWith('/categories')) {
|
if (req.path.startsWith('/api/categories') || req.path.startsWith('/categories')) {
|
||||||
data.breadcrumbs = helpers.buildBreadcrumbs([{text: data.title}]);
|
data.breadcrumbs = helpers.buildBreadcrumbs([{text: data.title}]);
|
||||||
@@ -81,7 +90,7 @@ categoriesController.list = function(req, res, next) {
|
|||||||
|
|
||||||
categoriesController.get = function(req, res, callback) {
|
categoriesController.get = function(req, res, callback) {
|
||||||
var cid = req.params.category_id,
|
var cid = req.params.category_id,
|
||||||
page = parseInt(req.query.page, 10) || 1,
|
currentPage = parseInt(req.query.page, 10) || 1,
|
||||||
pageCount = 1,
|
pageCount = 1,
|
||||||
userPrivileges;
|
userPrivileges;
|
||||||
|
|
||||||
@@ -127,7 +136,7 @@ categoriesController.get = function(req, res, callback) {
|
|||||||
return helpers.redirect(res, '/category/' + cid + '/' + req.params.slug + (topicIndex > topicCount ? '/' + topicCount : ''));
|
return helpers.redirect(res, '/category/' + cid + '/' + req.params.slug + (topicIndex > topicCount ? '/' + topicCount : ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.usePagination && (page < 1 || page > pageCount)) {
|
if (settings.usePagination && (currentPage < 1 || currentPage > pageCount)) {
|
||||||
return callback();
|
return callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +144,7 @@ categoriesController.get = function(req, res, callback) {
|
|||||||
topicIndex = Math.max(topicIndex - (settings.topicsPerPage - 1), 0);
|
topicIndex = Math.max(topicIndex - (settings.topicsPerPage - 1), 0);
|
||||||
} else if (!req.query.page) {
|
} else if (!req.query.page) {
|
||||||
var index = Math.max(parseInt((topicIndex || 0), 10), 0);
|
var index = Math.max(parseInt((topicIndex || 0), 10), 0);
|
||||||
page = Math.ceil((index + 1) / settings.topicsPerPage);
|
currentPage = Math.ceil((index + 1) / settings.topicsPerPage);
|
||||||
topicIndex = 0;
|
topicIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +158,7 @@ categoriesController.get = function(req, res, callback) {
|
|||||||
set = 'cid:' + cid + ':tids:posts';
|
set = 'cid:' + cid + ':tids:posts';
|
||||||
}
|
}
|
||||||
|
|
||||||
var start = (page - 1) * settings.topicsPerPage + topicIndex,
|
var start = (currentPage - 1) * settings.topicsPerPage + topicIndex,
|
||||||
stop = start + settings.topicsPerPage - 1;
|
stop = start + settings.topicsPerPage - 1;
|
||||||
|
|
||||||
next(null, {
|
next(null, {
|
||||||
@@ -194,8 +203,11 @@ categoriesController.get = function(req, res, callback) {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
function(categoryData, next) {
|
function(categoryData, next) {
|
||||||
|
if (!categoryData.children.length) {
|
||||||
|
return next(null, categoryData);
|
||||||
|
}
|
||||||
var allCategories = [];
|
var allCategories = [];
|
||||||
categories.flattenCategories(allCategories, [categoryData]);
|
categories.flattenCategories(allCategories, categoryData.children);
|
||||||
categories.getRecentTopicReplies(allCategories, req.uid, function(err) {
|
categories.getRecentTopicReplies(allCategories, req.uid, function(err) {
|
||||||
next(err, categoryData);
|
next(err, categoryData);
|
||||||
});
|
});
|
||||||
@@ -249,12 +261,10 @@ categoriesController.get = function(req, res, callback) {
|
|||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
data.currentPage = page;
|
|
||||||
data.pageCount = pageCount;
|
|
||||||
data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1;
|
data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1;
|
||||||
data.rssFeedUrl = nconf.get('relative_path') + '/category/' + data.cid + '.rss';
|
data.rssFeedUrl = nconf.get('relative_path') + '/category/' + data.cid + '.rss';
|
||||||
data.title = data.name;
|
data.title = data.name;
|
||||||
data.pagination = pagination.create(data.currentPage, data.pageCount);
|
data.pagination = pagination.create(currentPage, pageCount);
|
||||||
data.pagination.rel.forEach(function(rel) {
|
data.pagination.rel.forEach(function(rel) {
|
||||||
rel.href = nconf.get('url') + '/category/' + data.slug + rel.href;
|
rel.href = nconf.get('url') + '/category/' + data.slug + rel.href;
|
||||||
res.locals.linkTags.push(rel);
|
res.locals.linkTags.push(rel);
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var async = require('async'),
|
var async = require('async'),
|
||||||
validator = require('validator'),
|
|
||||||
|
meta = require('../meta'),
|
||||||
plugins = require('../plugins'),
|
plugins = require('../plugins'),
|
||||||
search = require('../search'),
|
search = require('../search'),
|
||||||
categories = require('../categories'),
|
categories = require('../categories'),
|
||||||
@@ -17,6 +18,10 @@ searchController.search = function(req, res, next) {
|
|||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!req.user && parseInt(meta.config.allowGuestSearching, 10) !== 1) {
|
||||||
|
return helpers.notAllowed(req, res);
|
||||||
|
}
|
||||||
|
|
||||||
var page = Math.max(1, parseInt(req.query.page, 10)) || 1;
|
var page = Math.max(1, parseInt(req.query.page, 10)) || 1;
|
||||||
if (req.query.categories && !Array.isArray(req.query.categories)) {
|
if (req.query.categories && !Array.isArray(req.query.categories)) {
|
||||||
req.query.categories = [req.query.categories];
|
req.query.categories = [req.query.categories];
|
||||||
@@ -51,6 +56,7 @@ searchController.search = function(req, res, next) {
|
|||||||
searchData.pagination = pagination.create(page, searchData.pageCount, req.query);
|
searchData.pagination = pagination.create(page, searchData.pageCount, req.query);
|
||||||
searchData.showAsPosts = !req.query.showAs || req.query.showAs === 'posts';
|
searchData.showAsPosts = !req.query.showAs || req.query.showAs === 'posts';
|
||||||
searchData.showAsTopics = req.query.showAs === 'topics';
|
searchData.showAsTopics = req.query.showAs === 'topics';
|
||||||
|
searchData.title = '[[global:header.search]]';
|
||||||
searchData.breadcrumbs = helpers.buildBreadcrumbs([{text: '[[global:search]]'}]);
|
searchData.breadcrumbs = helpers.buildBreadcrumbs([{text: '[[global:search]]'}]);
|
||||||
searchData.expandSearch = !req.params.term;
|
searchData.expandSearch = !req.params.term;
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ var topicsController = {},
|
|||||||
topicsController.get = function(req, res, callback) {
|
topicsController.get = function(req, res, callback) {
|
||||||
var tid = req.params.topic_id,
|
var tid = req.params.topic_id,
|
||||||
sort = req.query.sort,
|
sort = req.query.sort,
|
||||||
|
currentPage = parseInt(req.query.page, 10) || 1,
|
||||||
|
pageCount = 1,
|
||||||
userPrivileges;
|
userPrivileges;
|
||||||
|
|
||||||
if ((req.params.post_index && !utils.isNumber(req.params.post_index)) || !utils.isNumber(tid)) {
|
if ((req.params.post_index && !utils.isNumber(req.params.post_index)) || !utils.isNumber(tid)) {
|
||||||
@@ -56,14 +58,13 @@ topicsController.get = function(req, res, callback) {
|
|||||||
|
|
||||||
var settings = results.settings;
|
var settings = results.settings;
|
||||||
var postCount = parseInt(results.topic.postcount, 10);
|
var postCount = parseInt(results.topic.postcount, 10);
|
||||||
var pageCount = Math.max(1, Math.ceil((postCount - 1) / settings.postsPerPage));
|
pageCount = Math.max(1, Math.ceil((postCount - 1) / settings.postsPerPage));
|
||||||
var page = parseInt(req.query.page, 10) || 1;
|
|
||||||
|
|
||||||
if (utils.isNumber(req.params.post_index) && (req.params.post_index < 1 || req.params.post_index > postCount)) {
|
if (utils.isNumber(req.params.post_index) && (req.params.post_index < 1 || req.params.post_index > postCount)) {
|
||||||
return helpers.redirect(res, '/topic/' + req.params.topic_id + '/' + req.params.slug + (req.params.post_index > postCount ? '/' + postCount : ''));
|
return helpers.redirect(res, '/topic/' + req.params.topic_id + '/' + req.params.slug + (req.params.post_index > postCount ? '/' + postCount : ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.usePagination && (page < 1 || page > pageCount)) {
|
if (settings.usePagination && (currentPage < 1 || currentPage > pageCount)) {
|
||||||
return callback();
|
return callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,10 +106,10 @@ topicsController.get = function(req, res, callback) {
|
|||||||
index = Math.max(0, req.params.post_index - 1) || 0;
|
index = Math.max(0, req.params.post_index - 1) || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
page = Math.max(1, Math.ceil(index / settings.postsPerPage));
|
currentPage = Math.max(1, Math.ceil(index / settings.postsPerPage));
|
||||||
}
|
}
|
||||||
|
|
||||||
var start = (page - 1) * settings.postsPerPage + postIndex,
|
var start = (currentPage - 1) * settings.postsPerPage + postIndex,
|
||||||
stop = start + settings.postsPerPage - 1;
|
stop = start + settings.postsPerPage - 1;
|
||||||
|
|
||||||
topics.getTopicWithPosts(tid, set, req.uid, start, stop, reverse, function (err, topicData) {
|
topics.getTopicWithPosts(tid, set, req.uid, start, stop, reverse, function (err, topicData) {
|
||||||
@@ -120,9 +121,6 @@ topicsController.get = function(req, res, callback) {
|
|||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
topicData.pageCount = pageCount;
|
|
||||||
topicData.currentPage = page;
|
|
||||||
|
|
||||||
topics.modifyByPrivilege(topicData.posts, results.privileges);
|
topics.modifyByPrivilege(topicData.posts, results.privileges);
|
||||||
|
|
||||||
plugins.fireHook('filter:controllers.topic.get', topicData, next);
|
plugins.fireHook('filter:controllers.topic.get', topicData, next);
|
||||||
@@ -238,7 +236,7 @@ topicsController.get = function(req, res, callback) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
rel: 'canonical',
|
rel: 'canonical',
|
||||||
href: nconf.get('url') + '/topic/' + topicData.slug
|
href: nconf.get('url') + '/topic/' + topicData.slug + (currentPage > 1 ? '?page=' + currentPage : '')
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -261,7 +259,7 @@ topicsController.get = function(req, res, callback) {
|
|||||||
data['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1;
|
data['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1;
|
||||||
data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1;
|
data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1;
|
||||||
data.rssFeedUrl = nconf.get('relative_path') + '/topic/' + data.tid + '.rss';
|
data.rssFeedUrl = nconf.get('relative_path') + '/topic/' + data.tid + '.rss';
|
||||||
data.pagination = pagination.create(data.currentPage, data.pageCount);
|
data.pagination = pagination.create(currentPage, pageCount);
|
||||||
data.pagination.rel.forEach(function(rel) {
|
data.pagination.rel.forEach(function(rel) {
|
||||||
rel.href = nconf.get('url') + '/topic/' + data.slug + rel.href;
|
rel.href = nconf.get('url') + '/topic/' + data.slug + rel.href;
|
||||||
res.locals.linkTags.push(rel);
|
res.locals.linkTags.push(rel);
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ usersController.getUsersSortedByPosts = function(req, res, next) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
usersController.getUsersSortedByReputation = function(req, res, next) {
|
usersController.getUsersSortedByReputation = function(req, res, next) {
|
||||||
|
if (parseInt(meta.config['reputation:disabled'], 10) === 1) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
usersController.getUsers('users:reputation', 0, 49, req, res, next);
|
usersController.getUsers('users:reputation', 0, 49, req, res, next);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -217,6 +220,7 @@ usersController.getMap = function(req, res, next) {
|
|||||||
|
|
||||||
res.render('usersMap', {
|
res.render('usersMap', {
|
||||||
rooms: data,
|
rooms: data,
|
||||||
|
'reputation:disabled': parseInt(meta.config['reputation:disabled'], 10) === 1,
|
||||||
title: '[[pages:users/map]]',
|
title: '[[pages:users/map]]',
|
||||||
breadcrumbs: helpers.buildBreadcrumbs([{text: '[[global:users]]', url: '/users'}, {text: '[[global:map]]'}])
|
breadcrumbs: helpers.buildBreadcrumbs([{text: '[[global:users]]', url: '/users'}, {text: '[[global:map]]'}])
|
||||||
});
|
});
|
||||||
@@ -230,6 +234,7 @@ function render(req, res, data, next) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data.templateData.inviteOnly = meta.config.registrationType === 'invite-only';
|
data.templateData.inviteOnly = meta.config.registrationType === 'invite-only';
|
||||||
|
data.templateData['reputation:disabled'] = parseInt(meta.config['reputation:disabled'], 10) === 1;
|
||||||
res.render('users', data.templateData);
|
res.render('users', data.templateData);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -178,25 +178,55 @@
|
|||||||
|
|
||||||
module.info = function(db, callback) {
|
module.info = function(db, callback) {
|
||||||
async.parallel({
|
async.parallel({
|
||||||
serverStats: function(next) {
|
serverStatus: function(next) {
|
||||||
db.command({'serverStatus': 1}, next);
|
db.command({'serverStatus': 1}, next);
|
||||||
},
|
},
|
||||||
stats: function(next) {
|
stats: function(next) {
|
||||||
db.stats({scale:1024}, next);
|
db.command({'dbStats': 1}, next);
|
||||||
|
},
|
||||||
|
listCollections: function(next) {
|
||||||
|
db.listCollections().toArray(function(err, items) {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
async.map(items, function(collection, next) {
|
||||||
|
db.collection(collection.name).stats(next);
|
||||||
|
}, next);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, function(err, results) {
|
}, function(err, results) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
var stats = results.stats;
|
var stats = results.stats;
|
||||||
|
var scale = 1024 * 1024;
|
||||||
|
|
||||||
|
results.listCollections = results.listCollections.map(function(collectionInfo) {
|
||||||
|
return {
|
||||||
|
name: collectionInfo.ns,
|
||||||
|
count: collectionInfo.count,
|
||||||
|
size: collectionInfo.size,
|
||||||
|
avgObjSize: collectionInfo.avgObjSize,
|
||||||
|
storageSize: collectionInfo.storageSize,
|
||||||
|
totalIndexSize: collectionInfo.totalIndexSize,
|
||||||
|
indexSizes: collectionInfo.indexSizes
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
stats.mem = results.serverStatus.mem;
|
||||||
|
stats.collectionData = results.listCollections;
|
||||||
|
stats.network = results.serverStatus.network;
|
||||||
|
stats.raw = JSON.stringify(stats, null, 4);
|
||||||
|
|
||||||
stats.avgObjSize = (stats.avgObjSize / 1024).toFixed(2);
|
stats.avgObjSize = (stats.avgObjSize / 1024).toFixed(2);
|
||||||
stats.dataSize = (stats.dataSize / 1024).toFixed(2);
|
stats.dataSize = (stats.dataSize / scale).toFixed(2);
|
||||||
stats.storageSize = (stats.storageSize / 1024).toFixed(2);
|
stats.storageSize = (stats.storageSize / scale).toFixed(2);
|
||||||
stats.fileSize = (stats.fileSize / 1024).toFixed(2);
|
stats.fileSize = stats.fileSize ? (stats.fileSize / scale).toFixed(2) : 0;
|
||||||
stats.indexSize = (stats.indexSize / 1024).toFixed(2);
|
stats.indexSize = (stats.indexSize / scale).toFixed(2);
|
||||||
stats.mem = results.serverStats.mem;
|
stats.storageEngine = results.serverStatus.storageEngine ? results.serverStatus.storageEngine.name : 'mmapv1';
|
||||||
stats.raw = JSON.stringify(stats, null, 4);
|
stats.host = results.serverStatus.host;
|
||||||
|
stats.version = results.serverStatus.version;
|
||||||
|
stats.uptime = results.serverStatus.uptime;
|
||||||
stats.mongo = true;
|
stats.mongo = true;
|
||||||
|
|
||||||
callback(null, stats);
|
callback(null, stats);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ helpers.toMap = function(data) {
|
|||||||
var map = {};
|
var map = {};
|
||||||
for (var i = 0; i<data.length; ++i) {
|
for (var i = 0; i<data.length; ++i) {
|
||||||
map[data[i]._key] = data[i];
|
map[data[i]._key] = data[i];
|
||||||
|
data[i]._key = undefined;
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ module.exports = function(db, module) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
db.collection('search' + key).find(searchQuery, {limit: limit}).toArray(function(err, results) {
|
db.collection('search' + key).find(searchQuery, {limit: limit, fields:{_id: 0, id: 1}}).toArray(function(err, results) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ module.exports = function(db, module) {
|
|||||||
if (withScores) {
|
if (withScores) {
|
||||||
fields.score = 1;
|
fields.score = 1;
|
||||||
}
|
}
|
||||||
db.collection('objects').find({_key:key}, {fields: fields})
|
db.collection('objects').find({_key: key}, {fields: fields})
|
||||||
.limit(stop - start + 1)
|
.limit(stop - start + 1)
|
||||||
.skip(start)
|
.skip(start)
|
||||||
.sort({score: sort})
|
.sort({score: sort})
|
||||||
|
|||||||
@@ -26,13 +26,13 @@ var async = require('async'),
|
|||||||
|
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
|
|
||||||
if(type === 'upvote' && !unvote) {
|
if (type === 'upvote' && !unvote) {
|
||||||
db.sortedSetAdd('uid:' + uid + ':upvote', now, pid);
|
db.sortedSetAdd('uid:' + uid + ':upvote', now, pid);
|
||||||
} else {
|
} else {
|
||||||
db.sortedSetRemove('uid:' + uid + ':upvote', pid);
|
db.sortedSetRemove('uid:' + uid + ':upvote', pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(type === 'upvote' || unvote) {
|
if (type === 'upvote' || unvote) {
|
||||||
db.sortedSetRemove('uid:' + uid + ':downvote', pid);
|
db.sortedSetRemove('uid:' + uid + ':downvote', pid);
|
||||||
} else {
|
} else {
|
||||||
db.sortedSetAdd('uid:' + uid + ':downvote', now, pid);
|
db.sortedSetAdd('uid:' + uid + ':downvote', now, pid);
|
||||||
@@ -213,7 +213,7 @@ var async = require('async'),
|
|||||||
|
|
||||||
if (voteStatus.upvoted && command === 'downvote' || voteStatus.downvoted && command === 'upvote') { // e.g. User *has* upvoted, and clicks downvote
|
if (voteStatus.upvoted && command === 'downvote' || voteStatus.downvoted && command === 'upvote') { // e.g. User *has* upvoted, and clicks downvote
|
||||||
hook = command;
|
hook = command;
|
||||||
} else if (voteStatus.upvoted || voteStatus.downvoted) { // e.g. User *has* upvotes, clicks upvote (so we "unvote")
|
} else if (voteStatus.upvoted || voteStatus.downvoted) { // e.g. User *has* upvoted, clicks upvote (so we "unvote")
|
||||||
hook = 'unvote';
|
hook = 'unvote';
|
||||||
} else { // e.g. User *has not* voted, clicks upvote
|
} else { // e.g. User *has not* voted, clicks upvote
|
||||||
hook = command;
|
hook = command;
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ file.isFileTypeAllowed = function(path, allowedExtensions, callback) {
|
|||||||
var uploadedFileExtension = mime.extension(mimeType);
|
var uploadedFileExtension = mime.extension(mimeType);
|
||||||
|
|
||||||
if (allowedExtensions.indexOf(uploadedFileExtension) === -1) {
|
if (allowedExtensions.indexOf(uploadedFileExtension) === -1) {
|
||||||
return callback(new Error('[[error:invalid-file-type, ' + allowedExtensions.join(', ') + ']]'));
|
return callback(new Error('[[error:invalid-file-type, ' + allowedExtensions.join(', ') + ']]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
callback();
|
callback();
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ var async = require('async'),
|
|||||||
"dependencies": ["redis@~0.10.1", "connect-redis@~2.0.0"]
|
"dependencies": ["redis@~0.10.1", "connect-redis@~2.0.0"]
|
||||||
},
|
},
|
||||||
"mongo": {
|
"mongo": {
|
||||||
"dependencies": ["mongodb@~2.0.0", "connect-mongo"]
|
"dependencies": ["mongodb@~2.0.0", "connect-mongo@~0.8.2"]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,8 @@ var db = require('./database'),
|
|||||||
touid = params.touid,
|
touid = params.touid,
|
||||||
since = params.since,
|
since = params.since,
|
||||||
isNew = params.isNew,
|
isNew = params.isNew,
|
||||||
count = params.count || parseInt(meta.config.chatMessageInboxSize, 10) || 250;
|
count = params.count || parseInt(meta.config.chatMessageInboxSize, 10) || 250,
|
||||||
|
markRead = params.markRead || true;
|
||||||
|
|
||||||
var uids = sortUids(fromuid, touid),
|
var uids = sortUids(fromuid, touid),
|
||||||
min = params.count ? 0 : Date.now() - (terms[since] || terms.day);
|
min = params.count ? 0 : Date.now() - (terms[since] || terms.day);
|
||||||
@@ -135,6 +136,7 @@ var db = require('./database'),
|
|||||||
getMessages(mids, fromuid, touid, isNew, callback);
|
getMessages(mids, fromuid, touid, isNew, callback);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (markRead) {
|
||||||
notifications.markRead('chat_' + touid + '_' + fromuid, fromuid, function(err) {
|
notifications.markRead('chat_' + touid + '_' + fromuid, fromuid, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
winston.error('[messaging] Could not mark notifications related to this chat as read: ' + err.message);
|
winston.error('[messaging] Could not mark notifications related to this chat as read: ' + err.message);
|
||||||
@@ -142,6 +144,7 @@ var db = require('./database'),
|
|||||||
|
|
||||||
userNotifications.pushCount(fromuid);
|
userNotifications.pushCount(fromuid);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function getMessages(mids, fromuid, touid, isNew, callback) {
|
function getMessages(mids, fromuid, touid, isNew, callback) {
|
||||||
@@ -271,7 +274,8 @@ var db = require('./database'),
|
|||||||
fromuid: fromuid,
|
fromuid: fromuid,
|
||||||
touid: uid,
|
touid: uid,
|
||||||
isNew: false,
|
isNew: false,
|
||||||
count: 1
|
count: 1,
|
||||||
|
markRead: false
|
||||||
}, function(err, teaser) {
|
}, function(err, teaser) {
|
||||||
var teaser = teaser[0];
|
var teaser = teaser[0];
|
||||||
teaser.content = S(teaser.content).stripTags().decodeHTMLEntities().s;
|
teaser.content = S(teaser.content).stripTags().decodeHTMLEntities().s;
|
||||||
@@ -286,7 +290,6 @@ var db = require('./database'),
|
|||||||
|
|
||||||
results.users.forEach(function(user, index) {
|
results.users.forEach(function(user, index) {
|
||||||
if (user && parseInt(user.uid, 10)) {
|
if (user && parseInt(user.uid, 10)) {
|
||||||
Messaging.markRead(uid, uids[index]);
|
|
||||||
user.unread = results.unread[index];
|
user.unread = results.unread[index];
|
||||||
user.status = sockets.isUserOnline(user.uid) ? user.status : 'offline';
|
user.status = sockets.isUserOnline(user.uid) ? user.status : 'offline';
|
||||||
user.teaser = results.teasers[index];
|
user.teaser = results.teasers[index];
|
||||||
@@ -311,7 +314,7 @@ var db = require('./database'),
|
|||||||
if (err) {
|
if (err) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sockets.in('uid_' + uid).emit('event:unread.updateChatCount', null, unreadCount);
|
sockets.in('uid_' + uid).emit('event:unread.updateChatCount', unreadCount);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ var path = require('path'),
|
|||||||
semver = require('semver'),
|
semver = require('semver'),
|
||||||
winston = require('winston'),
|
winston = require('winston'),
|
||||||
|
|
||||||
pkg = require.main.require('./package.json');
|
pkg = require('../../package.json');
|
||||||
|
|
||||||
module.exports = function(Meta) {
|
module.exports = function(Meta) {
|
||||||
Meta.dependencies = {};
|
Meta.dependencies = {};
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ var winston = require('winston'),
|
|||||||
path = require('path'),
|
path = require('path'),
|
||||||
async = require('async'),
|
async = require('async'),
|
||||||
_ = require('underscore'),
|
_ = require('underscore'),
|
||||||
os = require('os'),
|
|
||||||
nconf = require('nconf'),
|
nconf = require('nconf'),
|
||||||
fs = require('fs'),
|
fs = require('fs'),
|
||||||
file = require('../file'),
|
file = require('../file'),
|
||||||
@@ -50,15 +49,32 @@ module.exports = function(Meta) {
|
|||||||
'public/src/client/chats.js',
|
'public/src/client/chats.js',
|
||||||
'public/src/client/infinitescroll.js',
|
'public/src/client/infinitescroll.js',
|
||||||
'public/src/client/pagination.js',
|
'public/src/client/pagination.js',
|
||||||
|
'public/src/client/recent.js',
|
||||||
|
'public/src/client/unread.js',
|
||||||
|
'public/src/client/topic.js',
|
||||||
|
'public/src/client/topic/browsing.js',
|
||||||
|
'public/src/client/topic/events.js',
|
||||||
|
'public/src/client/topic/flag.js',
|
||||||
|
'public/src/client/topic/fork.js',
|
||||||
|
'public/src/client/topic/move.js',
|
||||||
|
'public/src/client/topic/posts.js',
|
||||||
|
'public/src/client/topic/postTools.js',
|
||||||
|
'public/src/client/topic/threadTools.js',
|
||||||
|
'public/src/client/categories.js',
|
||||||
|
'public/src/client/category.js',
|
||||||
|
'public/src/client/categoryTools.js',
|
||||||
|
|
||||||
'public/src/modules/csrf.js',
|
'public/src/modules/csrf.js',
|
||||||
'public/src/modules/translator.js',
|
'public/src/modules/translator.js',
|
||||||
'public/src/modules/notifications.js',
|
'public/src/modules/notifications.js',
|
||||||
'public/src/modules/chat.js',
|
'public/src/modules/chat.js',
|
||||||
'public/src/modules/components.js',
|
'public/src/modules/components.js',
|
||||||
'public/src/modules/composer/formatting.js',
|
'public/src/modules/sort.js',
|
||||||
'public/src/modules/composer/controls.js',
|
'public/src/modules/navigator.js',
|
||||||
'public/src/modules/composer/preview.js',
|
'public/src/modules/topicSelect.js',
|
||||||
'public/src/modules/categories.js',
|
'public/src/modules/share.js',
|
||||||
|
'public/src/modules/search.js',
|
||||||
|
'public/src/modules/alerts.js',
|
||||||
'public/src/modules/taskbar.js',
|
'public/src/modules/taskbar.js',
|
||||||
'public/src/modules/helpers.js',
|
'public/src/modules/helpers.js',
|
||||||
'public/src/modules/sounds.js',
|
'public/src/modules/sounds.js',
|
||||||
@@ -72,8 +88,7 @@ module.exports = function(Meta) {
|
|||||||
async.apply(getPluginScripts), // plugin scripts via filter:scripts.get
|
async.apply(getPluginScripts), // plugin scripts via filter:scripts.get
|
||||||
function(next) { // client scripts via "scripts" config in plugin.json
|
function(next) { // client scripts via "scripts" config in plugin.json
|
||||||
var pluginsScripts = [],
|
var pluginsScripts = [],
|
||||||
pluginDirectories = [],
|
pluginDirectories = [];
|
||||||
clientScripts = [];
|
|
||||||
|
|
||||||
pluginsScripts = plugins.clientScripts.filter(function(path) {
|
pluginsScripts = plugins.clientScripts.filter(function(path) {
|
||||||
if (path.endsWith('.js')) {
|
if (path.endsWith('.js')) {
|
||||||
|
|||||||
@@ -20,14 +20,16 @@ module.exports = function(Meta) {
|
|||||||
Meta.settings.set = function(hash, values, callback) {
|
Meta.settings.set = function(hash, values, callback) {
|
||||||
var key = 'settings:' + hash;
|
var key = 'settings:' + hash;
|
||||||
db.setObject(key, values, function(err) {
|
db.setObject(key, values, function(err) {
|
||||||
if (!err) {
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
plugins.fireHook('action:settings.set', {
|
plugins.fireHook('action:settings.set', {
|
||||||
plugin: hash,
|
plugin: hash,
|
||||||
settings: values
|
settings: values
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
callback.apply(this, arguments);
|
callback();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ module.exports = function(Meta) {
|
|||||||
return callback(null, defaults);
|
return callback(null, defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
callback.apply(null, arguments);
|
callback(null, sounds);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
157
src/middleware/header.js
Normal file
157
src/middleware/header.js
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var async = require('async');
|
||||||
|
var nconf = require('nconf');
|
||||||
|
|
||||||
|
var user = require('../user');
|
||||||
|
var meta = require('../meta');
|
||||||
|
var plugins = require('../plugins');
|
||||||
|
var navigation = require('../navigation');
|
||||||
|
var translator = require('../../public/src/modules/translator');
|
||||||
|
|
||||||
|
var controllers = {
|
||||||
|
api: require('../controllers/api'),
|
||||||
|
helpers: require('../controllers/helpers')
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = function(app, middleware) {
|
||||||
|
|
||||||
|
middleware.buildHeader = function(req, res, next) {
|
||||||
|
res.locals.renderHeader = true;
|
||||||
|
res.locals.isAPI = false;
|
||||||
|
|
||||||
|
middleware.applyCSRF(req, res, function() {
|
||||||
|
async.parallel({
|
||||||
|
config: function(next) {
|
||||||
|
controllers.api.getConfig(req, res, next);
|
||||||
|
},
|
||||||
|
footer: function(next) {
|
||||||
|
app.render('footer', {loggedIn: (req.user ? parseInt(req.user.uid, 10) !== 0 : false)}, next);
|
||||||
|
},
|
||||||
|
plugins: function(next) {
|
||||||
|
plugins.fireHook('filter:middleware.buildHeader', {req: req, locals: res.locals}, next);
|
||||||
|
}
|
||||||
|
}, function(err, results) {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.locals.config = results.config;
|
||||||
|
|
||||||
|
translator.translate(results.footer, results.config.defaultLang, function(parsedTemplate) {
|
||||||
|
res.locals.footer = parsedTemplate;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
middleware.renderHeader = function(req, res, data, callback) {
|
||||||
|
var registrationType = meta.config.registrationType || 'normal';
|
||||||
|
var templateValues = {
|
||||||
|
bootswatchCSS: meta.config['theme:src'],
|
||||||
|
title: meta.config.title || '',
|
||||||
|
description: meta.config.description || '',
|
||||||
|
'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '',
|
||||||
|
'brand:logo': meta.config['brand:logo'] || '',
|
||||||
|
'brand:logo: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',
|
||||||
|
searchEnabled: plugins.hasListeners('filter:search.query'),
|
||||||
|
config: res.locals.config,
|
||||||
|
relative_path: nconf.get('relative_path'),
|
||||||
|
bodyClass: data.bodyClass
|
||||||
|
};
|
||||||
|
|
||||||
|
templateValues.configJSON = JSON.stringify(res.locals.config);
|
||||||
|
|
||||||
|
async.parallel({
|
||||||
|
isAdmin: function(next) {
|
||||||
|
user.isAdministrator(req.uid, next);
|
||||||
|
},
|
||||||
|
user: function(next) {
|
||||||
|
if (req.uid) {
|
||||||
|
user.getUserFields(req.uid, ['username', 'userslug', 'email', 'picture', 'icon:bgColor', 'icon:text', 'status', 'email:confirmed', 'banned'], next);
|
||||||
|
} else {
|
||||||
|
next(null, {
|
||||||
|
username: '[[global:guest]]',
|
||||||
|
userslug: '',
|
||||||
|
picture: meta.config.defaultAvatar,
|
||||||
|
status: 'offline',
|
||||||
|
banned: false,
|
||||||
|
uid: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
navigation: async.apply(navigation.get),
|
||||||
|
tags: async.apply(meta.tags.parse, res.locals.metaTags, res.locals.linkTags)
|
||||||
|
}, function(err, results) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (results.user && parseInt(results.user.banned, 10) === 1) {
|
||||||
|
req.logout();
|
||||||
|
return res.redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
results.user.isAdmin = results.isAdmin;
|
||||||
|
results.user.uid = parseInt(results.user.uid, 10);
|
||||||
|
results.user['email:confirmed'] = parseInt(results.user['email:confirmed'], 10) === 1;
|
||||||
|
|
||||||
|
if (res.locals.config.bootswatchSkin !== 'default') {
|
||||||
|
templateValues.bootswatchCSS = '//maxcdn.bootstrapcdn.com/bootswatch/latest/' + res.locals.config.bootswatchSkin + '/bootstrap.min.css';
|
||||||
|
}
|
||||||
|
|
||||||
|
templateValues.browserTitle = controllers.helpers.buildTitle(data.title);
|
||||||
|
templateValues.navigation = results.navigation;
|
||||||
|
templateValues.metaTags = results.tags.meta;
|
||||||
|
templateValues.linkTags = results.tags.link;
|
||||||
|
templateValues.isAdmin = results.user.isAdmin;
|
||||||
|
templateValues.user = results.user;
|
||||||
|
templateValues.userJSON = JSON.stringify(results.user);
|
||||||
|
templateValues.useCustomCSS = parseInt(meta.config.useCustomCSS, 10) === 1 && meta.config.customCSS;
|
||||||
|
templateValues.customCSS = templateValues.useCustomCSS ? (meta.config.renderedCustomCSS || '') : '';
|
||||||
|
templateValues.useCustomJS = parseInt(meta.config.useCustomJS, 10) === 1;
|
||||||
|
templateValues.customJS = templateValues.useCustomJS ? meta.config.customJS : '';
|
||||||
|
templateValues.maintenanceHeader = parseInt(meta.config.maintenanceMode, 10) === 1 && !results.isAdmin;
|
||||||
|
templateValues.defaultLang = meta.config.defaultLang || 'en_GB';
|
||||||
|
|
||||||
|
templateValues.template = {name: res.locals.template};
|
||||||
|
templateValues.template[res.locals.template] = true;
|
||||||
|
|
||||||
|
if (req.route && req.route.path === '/') {
|
||||||
|
modifyTitle(templateValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins.fireHook('filter:middleware.renderHeader', {templateValues: templateValues, req: req, res: res}, function(err, data) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.render('header', data.templateValues, callback);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function modifyTitle(obj) {
|
||||||
|
var title = controllers.helpers.buildTitle('[[pages:home]]');
|
||||||
|
obj.browserTitle = title;
|
||||||
|
|
||||||
|
if (obj.metaTags) {
|
||||||
|
obj.metaTags.forEach(function(tag, i) {
|
||||||
|
if (tag.property === 'og:title') {
|
||||||
|
obj.metaTags[i].content = title;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -7,21 +7,16 @@ var app,
|
|||||||
async = require('async'),
|
async = require('async'),
|
||||||
path = require('path'),
|
path = require('path'),
|
||||||
csrf = require('csurf'),
|
csrf = require('csurf'),
|
||||||
winston = require('winston'),
|
|
||||||
validator = require('validator'),
|
validator = require('validator'),
|
||||||
nconf = require('nconf'),
|
nconf = require('nconf'),
|
||||||
ensureLoggedIn = require('connect-ensure-login'),
|
ensureLoggedIn = require('connect-ensure-login'),
|
||||||
|
|
||||||
plugins = require('../plugins'),
|
plugins = require('../plugins'),
|
||||||
navigation = require('../navigation'),
|
|
||||||
meta = require('../meta'),
|
meta = require('../meta'),
|
||||||
translator = require('../../public/src/modules/translator'),
|
|
||||||
user = require('../user'),
|
user = require('../user'),
|
||||||
groups = require('../groups'),
|
groups = require('../groups'),
|
||||||
db = require('../database'),
|
|
||||||
categories = require('../categories'),
|
|
||||||
topics = require('../topics'),
|
|
||||||
messaging = require('../messaging'),
|
|
||||||
|
|
||||||
analytics = require('../analytics'),
|
analytics = require('../analytics'),
|
||||||
|
|
||||||
@@ -69,7 +64,7 @@ middleware.pageView = function(req, res, next) {
|
|||||||
middleware.pluginHooks = function(req, res, next) {
|
middleware.pluginHooks = function(req, res, next) {
|
||||||
async.each(plugins.loadedHooks['filter:router.page'] || [], function(hookObj, next) {
|
async.each(plugins.loadedHooks['filter:router.page'] || [], function(hookObj, next) {
|
||||||
hookObj.method(req, res, next);
|
hookObj.method(req, res, next);
|
||||||
}, function(req, res) {
|
}, function() {
|
||||||
// If it got here, then none of the subscribed hooks did anything, or there were no hooks
|
// If it got here, then none of the subscribed hooks did anything, or there were no hooks
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
@@ -87,14 +82,6 @@ middleware.redirectToAccountIfLoggedIn = function(req, res, next) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
middleware.redirectToLoginIfGuest = function(req, res, next) {
|
|
||||||
if (!req.user || parseInt(req.user.uid, 10) === 0) {
|
|
||||||
return redirectToLogin(req, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
|
|
||||||
middleware.validateFiles = function(req, res, next) {
|
middleware.validateFiles = function(req, res, next) {
|
||||||
if (!Array.isArray(req.files.files) || !req.files.files.length) {
|
if (!Array.isArray(req.files.files) || !req.files.files.length) {
|
||||||
return next(new Error(['[[error:invalid-files]]']));
|
return next(new Error(['[[error:invalid-files]]']));
|
||||||
@@ -108,14 +95,6 @@ middleware.prepareAPI = function(req, res, next) {
|
|||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|
||||||
middleware.guestSearchingAllowed = function(req, res, next) {
|
|
||||||
if (!req.user && parseInt(meta.config.allowGuestSearching, 10) !== 1) {
|
|
||||||
return controllers.helpers.notAllowed(req, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
|
|
||||||
middleware.checkGlobalPrivacySettings = function(req, res, next) {
|
middleware.checkGlobalPrivacySettings = function(req, res, next) {
|
||||||
if (!req.user && !!parseInt(meta.config.privateUserInfo, 10)) {
|
if (!req.user && !!parseInt(meta.config.privateUserInfo, 10)) {
|
||||||
return controllers.helpers.notAllowed(req, res);
|
return controllers.helpers.notAllowed(req, res);
|
||||||
@@ -149,11 +128,11 @@ middleware.checkAccountPermissions = function(req, res, next) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
middleware.isAdmin = function(req, res, next) {
|
middleware.isAdmin = function(req, res, next) {
|
||||||
if (!req.user) {
|
if (!req.uid) {
|
||||||
return redirectToLogin(req, res);
|
return controllers.helpers.notAllowed(req, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
user.isAdministrator((req.user && req.user.uid) ? req.user.uid : 0, function (err, isAdmin) {
|
user.isAdministrator(req.uid, function (err, isAdmin) {
|
||||||
if (err || isAdmin) {
|
if (err || isAdmin) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
@@ -168,219 +147,6 @@ middleware.isAdmin = function(req, res, next) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
middleware.buildHeader = function(req, res, next) {
|
|
||||||
res.locals.renderHeader = true;
|
|
||||||
res.locals.isAPI = false;
|
|
||||||
|
|
||||||
middleware.applyCSRF(req, res, function() {
|
|
||||||
async.parallel({
|
|
||||||
config: function(next) {
|
|
||||||
controllers.api.getConfig(req, res, next);
|
|
||||||
},
|
|
||||||
footer: function(next) {
|
|
||||||
app.render('footer', {loggedIn: (req.user ? parseInt(req.user.uid, 10) !== 0 : false)}, next);
|
|
||||||
},
|
|
||||||
plugins: function(next) {
|
|
||||||
plugins.fireHook('filter:middleware.buildHeader', {req: req, locals: res.locals}, next);
|
|
||||||
}
|
|
||||||
}, function(err, results) {
|
|
||||||
if (err) {
|
|
||||||
return next(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
res.locals.config = results.config;
|
|
||||||
|
|
||||||
translator.translate(results.footer, results.config.defaultLang, function(parsedTemplate) {
|
|
||||||
res.locals.footer = parsedTemplate;
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
middleware.renderHeader = function(req, res, data, callback) {
|
|
||||||
var registrationType = meta.config.registrationType || 'normal';
|
|
||||||
var templateValues = {
|
|
||||||
bootswatchCSS: meta.config['theme:src'],
|
|
||||||
title: meta.config.title || '',
|
|
||||||
description: meta.config.description || '',
|
|
||||||
'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '',
|
|
||||||
'brand:logo': meta.config['brand:logo'] || '',
|
|
||||||
'brand:logo: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',
|
|
||||||
searchEnabled: plugins.hasListeners('filter:search.query'),
|
|
||||||
config: res.locals.config,
|
|
||||||
relative_path: nconf.get('relative_path')
|
|
||||||
};
|
|
||||||
|
|
||||||
templateValues.configJSON = JSON.stringify(res.locals.config);
|
|
||||||
|
|
||||||
async.parallel({
|
|
||||||
customCSS: function(next) {
|
|
||||||
templateValues.useCustomCSS = parseInt(meta.config.useCustomCSS, 10) === 1;
|
|
||||||
if (!templateValues.useCustomCSS || !meta.config.customCSS || !meta.config.renderedCustomCSS) {
|
|
||||||
return next(null, '');
|
|
||||||
}
|
|
||||||
next(null, meta.config.renderedCustomCSS);
|
|
||||||
},
|
|
||||||
customJS: function(next) {
|
|
||||||
templateValues.useCustomJS = parseInt(meta.config.useCustomJS, 10) === 1;
|
|
||||||
next(null, templateValues.useCustomJS ? meta.config.customJS : '');
|
|
||||||
},
|
|
||||||
settings: function(next) {
|
|
||||||
if (req.uid) {
|
|
||||||
user.getSettings(req.uid, next);
|
|
||||||
} else {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
title: function(next) {
|
|
||||||
next(null, controllers.helpers.buildTitle(data.title));
|
|
||||||
},
|
|
||||||
isAdmin: function(next) {
|
|
||||||
user.isAdministrator(req.uid, next);
|
|
||||||
},
|
|
||||||
user: function(next) {
|
|
||||||
if (req.uid) {
|
|
||||||
user.getUserFields(req.uid, ['username', 'userslug', 'email', 'picture', 'icon:bgColor', 'icon:text', 'status', 'email:confirmed', 'banned'], next);
|
|
||||||
} else {
|
|
||||||
next(null, {
|
|
||||||
username: '[[global:guest]]',
|
|
||||||
userslug: '',
|
|
||||||
picture: meta.config.defaultAvatar,
|
|
||||||
status: 'offline',
|
|
||||||
banned: false,
|
|
||||||
uid: 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
navigation: async.apply(navigation.get),
|
|
||||||
tags: async.apply(meta.tags.parse, res.locals.metaTags, res.locals.linkTags)
|
|
||||||
}, function(err, results) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (results.user && parseInt(results.user.banned, 10) === 1) {
|
|
||||||
req.logout();
|
|
||||||
return res.redirect('/');
|
|
||||||
}
|
|
||||||
results.user.isAdmin = results.isAdmin || false;
|
|
||||||
results.user.uid = parseInt(results.user.uid, 10);
|
|
||||||
results.user['email:confirmed'] = parseInt(results.user['email:confirmed'], 10) === 1;
|
|
||||||
|
|
||||||
if (results.settings && results.settings.bootswatchSkin && results.settings.bootswatchSkin !== 'default') {
|
|
||||||
templateValues.bootswatchCSS = '//maxcdn.bootstrapcdn.com/bootswatch/latest/' + results.settings.bootswatchSkin + '/bootstrap.min.css';
|
|
||||||
}
|
|
||||||
|
|
||||||
templateValues.browserTitle = results.title;
|
|
||||||
templateValues.navigation = results.navigation;
|
|
||||||
templateValues.metaTags = results.tags.meta;
|
|
||||||
templateValues.linkTags = results.tags.link;
|
|
||||||
templateValues.isAdmin = results.user.isAdmin;
|
|
||||||
templateValues.user = results.user;
|
|
||||||
templateValues.userJSON = JSON.stringify(results.user);
|
|
||||||
templateValues.customCSS = results.customCSS;
|
|
||||||
templateValues.customJS = results.customJS;
|
|
||||||
templateValues.maintenanceHeader = parseInt(meta.config.maintenanceMode, 10) === 1 && !results.isAdmin;
|
|
||||||
templateValues.defaultLang = meta.config.defaultLang || 'en_GB';
|
|
||||||
|
|
||||||
templateValues.template = {name: res.locals.template};
|
|
||||||
templateValues.template[res.locals.template] = true;
|
|
||||||
|
|
||||||
if (req.route && req.route.path === '/') {
|
|
||||||
modifyTitle(templateValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
plugins.fireHook('filter:middleware.renderHeader', {templateValues: templateValues, req: req, res: res}, function(err, data) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
app.render('header', data.templateValues, callback);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
middleware.processRender = function(req, res, next) {
|
|
||||||
// res.render post-processing, modified from here: https://gist.github.com/mrlannigan/5051687
|
|
||||||
var render = res.render;
|
|
||||||
res.render = function(template, options, fn) {
|
|
||||||
var self = this,
|
|
||||||
req = this.req,
|
|
||||||
app = req.app,
|
|
||||||
defaultFn = function(err, str){
|
|
||||||
if (err) {
|
|
||||||
return req.next(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.send(str);
|
|
||||||
};
|
|
||||||
options = options || {};
|
|
||||||
|
|
||||||
if ('function' === typeof options) {
|
|
||||||
fn = options;
|
|
||||||
options = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
options.loggedIn = req.user ? parseInt(req.user.uid, 10) !== 0 : false;
|
|
||||||
options.relative_path = nconf.get('relative_path');
|
|
||||||
options.template = {name: template};
|
|
||||||
options.template[template] = true;
|
|
||||||
res.locals.template = template;
|
|
||||||
|
|
||||||
if ('function' !== typeof fn) {
|
|
||||||
fn = defaultFn;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.locals.isAPI) {
|
|
||||||
if (req.route && req.route.path === '/api/') {
|
|
||||||
options.title = '[[pages:home]]';
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.json(options);
|
|
||||||
}
|
|
||||||
|
|
||||||
var ajaxifyData = encodeURIComponent(JSON.stringify(options));
|
|
||||||
render.call(self, template, options, function(err, str) {
|
|
||||||
if (err) {
|
|
||||||
winston.error(err);
|
|
||||||
return fn(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
str = str + '<input type="hidden" ajaxify-data="' + ajaxifyData + '" />';
|
|
||||||
str = (res.locals.postHeader ? res.locals.postHeader : '') + str + (res.locals.preFooter ? res.locals.preFooter : '');
|
|
||||||
|
|
||||||
if (res.locals.footer) {
|
|
||||||
str = str + res.locals.footer;
|
|
||||||
} else if (res.locals.adminFooter) {
|
|
||||||
str = str + res.locals.adminFooter;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.locals.renderHeader || res.locals.renderAdminHeader) {
|
|
||||||
var method = res.locals.renderHeader ? middleware.renderHeader : middleware.admin.renderHeader;
|
|
||||||
method(req, res, options, function(err, template) {
|
|
||||||
if (err) {
|
|
||||||
return fn(err);
|
|
||||||
}
|
|
||||||
str = template + str;
|
|
||||||
var language = res.locals.config ? res.locals.config.userLang || 'en_GB' : 'en_GB';
|
|
||||||
language = req.query.lang || language;
|
|
||||||
translator.translate(str, language, function(translated) {
|
|
||||||
fn(err, translated);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
fn(err, str);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
|
|
||||||
middleware.routeTouchIcon = function(req, res) {
|
middleware.routeTouchIcon = function(req, res) {
|
||||||
if (meta.config['brand:logo'] && validator.isURL(meta.config['brand:logo'])) {
|
if (meta.config['brand:logo'] && validator.isURL(meta.config['brand:logo'])) {
|
||||||
return res.redirect(meta.config['brand:logo']);
|
return res.redirect(meta.config['brand:logo']);
|
||||||
@@ -403,8 +169,6 @@ middleware.addExpiresHeaders = function(req, res, next) {
|
|||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
middleware.privateTagListing = function(req, res, next) {
|
middleware.privateTagListing = function(req, res, next) {
|
||||||
if (!req.user && parseInt(meta.config.privateTagListing, 10) === 1) {
|
if (!req.user && parseInt(meta.config.privateTagListing, 10) === 1) {
|
||||||
controllers.helpers.notAllowed(req, res);
|
controllers.helpers.notAllowed(req, res);
|
||||||
@@ -414,32 +178,26 @@ middleware.privateTagListing = function(req, res, next) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
middleware.exposeGroupName = function(req, res, next) {
|
middleware.exposeGroupName = function(req, res, next) {
|
||||||
if (!req.params.hasOwnProperty('slug')) { return next(); }
|
expose('groupName', groups.getGroupNameByGroupSlug, 'slug', req, res, next);
|
||||||
|
|
||||||
groups.getGroupNameByGroupSlug(req.params.slug, function(err, groupName) {
|
|
||||||
if (err) {
|
|
||||||
return next(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
res.locals.groupName = groupName;
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
middleware.exposeUid = function(req, res, next) {
|
middleware.exposeUid = function(req, res, next) {
|
||||||
if (req.params.hasOwnProperty('userslug')) {
|
expose('uid', user.getUidByUserslug, 'userslug', req, res, next);
|
||||||
user.getUidByUserslug(req.params.userslug, function(err, uid) {
|
};
|
||||||
|
|
||||||
|
function expose(exposedField, method, field, req, res, next) {
|
||||||
|
if (!req.params.hasOwnProperty(field)) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
method(req.params[field], function(err, id) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
res.locals.uid = uid;
|
res.locals[exposedField] = id;
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
} else {
|
}
|
||||||
next();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
middleware.requireUser = function(req, res, next) {
|
middleware.requireUser = function(req, res, next) {
|
||||||
if (req.user) {
|
if (req.user) {
|
||||||
@@ -449,32 +207,23 @@ middleware.requireUser = function(req, res, next) {
|
|||||||
res.render('403', {title: '[[global:403.title]]'});
|
res.render('403', {title: '[[global:403.title]]'});
|
||||||
};
|
};
|
||||||
|
|
||||||
function redirectToLogin(req, res) {
|
middleware.privateUploads = function(req, res, next) {
|
||||||
req.session.returnTo = nconf.get('relative_path') + req.url.replace(/^\/api/, '');
|
if (req.user || parseInt(meta.config.privateUploads, 10) !== 1) {
|
||||||
return controllers.helpers.redirect(res, '/login');
|
return next();
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function modifyTitle(obj) {
|
|
||||||
var title = controllers.helpers.buildTitle('[[pages:home]]');
|
|
||||||
obj.browserTitle = title;
|
|
||||||
|
|
||||||
if (obj.metaTags) {
|
|
||||||
obj.metaTags.forEach(function(tag, i) {
|
|
||||||
if (tag.property === 'og:title') {
|
|
||||||
obj.metaTags[i].content = title;
|
|
||||||
}
|
}
|
||||||
});
|
if (req.path.startsWith('/uploads/files')) {
|
||||||
|
return res.status(403).json('not-allowed');
|
||||||
}
|
}
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
return title;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = function(webserver) {
|
module.exports = function(webserver) {
|
||||||
app = webserver;
|
app = webserver;
|
||||||
middleware.admin = require('./admin')(webserver);
|
middleware.admin = require('./admin')(webserver);
|
||||||
|
|
||||||
|
require('./header')(app, middleware);
|
||||||
|
require('./render')(middleware);
|
||||||
require('./maintenance')(middleware);
|
require('./maintenance')(middleware);
|
||||||
|
|
||||||
return middleware;
|
return middleware;
|
||||||
|
|||||||
95
src/middleware/render.js
Normal file
95
src/middleware/render.js
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var nconf = require('nconf');
|
||||||
|
var translator = require('../../public/src/modules/translator');
|
||||||
|
|
||||||
|
module.exports = function(middleware) {
|
||||||
|
|
||||||
|
middleware.processRender = function(req, res, next) {
|
||||||
|
// res.render post-processing, modified from here: https://gist.github.com/mrlannigan/5051687
|
||||||
|
var render = res.render;
|
||||||
|
res.render = function(template, options, fn) {
|
||||||
|
var self = this,
|
||||||
|
req = this.req,
|
||||||
|
defaultFn = function(err, str){
|
||||||
|
if (err) {
|
||||||
|
return req.next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.send(str);
|
||||||
|
};
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
if ('function' === typeof options) {
|
||||||
|
fn = options;
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
options.loggedIn = req.user ? parseInt(req.user.uid, 10) !== 0 : false;
|
||||||
|
options.relative_path = nconf.get('relative_path');
|
||||||
|
options.template = {name: template};
|
||||||
|
options.template[template] = true;
|
||||||
|
options.bodyClass = buildBodyClass(req);
|
||||||
|
|
||||||
|
res.locals.template = template;
|
||||||
|
|
||||||
|
if (res.locals.isAPI) {
|
||||||
|
if (req.route && req.route.path === '/api/') {
|
||||||
|
options.title = '[[pages:home]]';
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.json(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('function' !== typeof fn) {
|
||||||
|
fn = defaultFn;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ajaxifyData = encodeURIComponent(JSON.stringify(options));
|
||||||
|
render.call(self, template, options, function(err, str) {
|
||||||
|
if (err) {
|
||||||
|
return fn(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
str = str + '<input type="hidden" ajaxify-data="' + ajaxifyData + '" />';
|
||||||
|
str = (res.locals.postHeader ? res.locals.postHeader : '') + str + (res.locals.preFooter ? res.locals.preFooter : '');
|
||||||
|
|
||||||
|
if (res.locals.footer) {
|
||||||
|
str = str + res.locals.footer;
|
||||||
|
} else if (res.locals.adminFooter) {
|
||||||
|
str = str + res.locals.adminFooter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.locals.renderHeader || res.locals.renderAdminHeader) {
|
||||||
|
var method = res.locals.renderHeader ? middleware.renderHeader : middleware.admin.renderHeader;
|
||||||
|
method(req, res, options, function(err, template) {
|
||||||
|
if (err) {
|
||||||
|
return fn(err);
|
||||||
|
}
|
||||||
|
str = template + str;
|
||||||
|
var language = res.locals.config ? res.locals.config.userLang || 'en_GB' : 'en_GB';
|
||||||
|
language = req.query.lang || language;
|
||||||
|
translator.translate(str, language, function(translated) {
|
||||||
|
fn(err, translated);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
fn(err, str);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
function buildBodyClass(req) {
|
||||||
|
var clean = req.path.replace(/^\/api/, '').replace(/^\//, '');
|
||||||
|
var parts = clean.split('/').slice(0, 3);
|
||||||
|
parts.forEach(function(p, index) {
|
||||||
|
parts[index] = index ? parts[index - 1] + '-' + p : 'page-' + (p || 'home');
|
||||||
|
});
|
||||||
|
|
||||||
|
return parts.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
@@ -7,6 +7,7 @@ var admin = {},
|
|||||||
db = require('../database'),
|
db = require('../database'),
|
||||||
translator = require('../../public/src/modules/translator');
|
translator = require('../../public/src/modules/translator');
|
||||||
|
|
||||||
|
var navigationCache = null;
|
||||||
|
|
||||||
admin.save = function(data, callback) {
|
admin.save = function(data, callback) {
|
||||||
var order = Object.keys(data),
|
var order = Object.keys(data),
|
||||||
@@ -23,6 +24,7 @@ admin.save = function(data, callback) {
|
|||||||
return JSON.stringify(data);
|
return JSON.stringify(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
navigationCache = null;
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function(next) {
|
function(next) {
|
||||||
db.delete('navigation:enabled', next);
|
db.delete('navigation:enabled', next);
|
||||||
@@ -41,10 +43,19 @@ admin.getAdmin = function(callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
admin.get = function(callback) {
|
admin.get = function(callback) {
|
||||||
|
if (navigationCache) {
|
||||||
|
return callback(null, navigationCache);
|
||||||
|
}
|
||||||
|
|
||||||
db.getSortedSetRange('navigation:enabled', 0, -1, function(err, data) {
|
db.getSortedSetRange('navigation:enabled', 0, -1, function(err, data) {
|
||||||
callback(err, data.map(function(item, idx) {
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
navigationCache = data.map(function(item, idx) {
|
||||||
return JSON.parse(item)[idx];
|
return JSON.parse(item)[idx];
|
||||||
}));
|
});
|
||||||
|
|
||||||
|
callback(null, navigationCache);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
|
|
||||||
var navigation = {},
|
var navigation = {},
|
||||||
plugins = require('../plugins'),
|
|
||||||
db = require('../database'),
|
|
||||||
admin = require('./admin'),
|
admin = require('./admin'),
|
||||||
translator = require('../../public/src/modules/translator');
|
translator = require('../../public/src/modules/translator');
|
||||||
|
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ var async = require('async'),
|
|||||||
return callback();
|
return callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
db.getObject('notification:' + nid, function(err, notification) {
|
db.getObject('notifications:' + nid, function(err, notification) {
|
||||||
if (err || !notification) {
|
if (err || !notification) {
|
||||||
return callback(err || new Error('[[error:no-notification]]'));
|
return callback(err || new Error('[[error:no-notification]]'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ pagination.create = function(currentPage, pageCount, queryObj) {
|
|||||||
prev: {page: 1, active: currentPage > 1},
|
prev: {page: 1, active: currentPage > 1},
|
||||||
next: {page: 1, active: currentPage < pageCount},
|
next: {page: 1, active: currentPage < pageCount},
|
||||||
rel: [],
|
rel: [],
|
||||||
pages: []
|
pages: [],
|
||||||
|
currentPage: 1,
|
||||||
|
pageCount: 1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pageCount = parseInt(pageCount, 10);
|
pageCount = parseInt(pageCount, 10);
|
||||||
@@ -44,7 +46,7 @@ pagination.create = function(currentPage, pageCount, queryObj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = {rel: [], pages: pages};
|
var data = {rel: [], pages: pages, currentPage: currentPage, pageCount: pageCount};
|
||||||
queryObj.page = previous;
|
queryObj.page = previous;
|
||||||
data.prev = {page: previous, active: currentPage > 1, qs: qs.stringify(queryObj)};
|
data.prev = {page: previous, active: currentPage > 1, qs: qs.stringify(queryObj)};
|
||||||
queryObj.page = next;
|
queryObj.page = next;
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ var async = require('async'),
|
|||||||
|
|
||||||
module.exports = function(Posts) {
|
module.exports = function(Posts) {
|
||||||
|
|
||||||
Posts.flag = function(post, uid, callback) {
|
Posts.flag = function(post, uid, reason, callback) {
|
||||||
|
if (!parseInt(uid, 10) || !reason) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
async.parallel({
|
async.parallel({
|
||||||
hasFlagged: async.apply(hasFlagged, post.pid, uid),
|
hasFlagged: async.apply(hasFlagged, post.pid, uid),
|
||||||
exists: async.apply(Posts.exists, post.pid)
|
exists: async.apply(Posts.exists, post.pid)
|
||||||
@@ -36,6 +39,9 @@ module.exports = function(Posts) {
|
|||||||
function(next) {
|
function(next) {
|
||||||
db.sortedSetAdd('pid:' + post.pid + ':flag:uids', now, uid, next);
|
db.sortedSetAdd('pid:' + post.pid + ':flag:uids', now, uid, next);
|
||||||
},
|
},
|
||||||
|
function(next) {
|
||||||
|
db.sortedSetAdd('pid:' + post.pid + ':flag:uid:reason', 0, uid + ':' + reason, next);
|
||||||
|
},
|
||||||
function(next) {
|
function(next) {
|
||||||
if (parseInt(post.uid, 10)) {
|
if (parseInt(post.uid, 10)) {
|
||||||
db.sortedSetAdd('uid:' + post.uid + ':flag:pids', now, post.pid, next);
|
db.sortedSetAdd('uid:' + post.uid + ':flag:pids', now, post.pid, next);
|
||||||
@@ -50,7 +56,7 @@ module.exports = function(Posts) {
|
|||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
], function(err, results) {
|
], function(err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -80,25 +86,74 @@ module.exports = function(Posts) {
|
|||||||
},
|
},
|
||||||
function(next) {
|
function(next) {
|
||||||
db.delete('pid:' + pid + ':flag:uids', next);
|
db.delete('pid:' + pid + ':flag:uids', next);
|
||||||
|
},
|
||||||
|
function(next) {
|
||||||
|
db.delete('pid:' + pid + ':flag:uid:reason', next);
|
||||||
}
|
}
|
||||||
], function(err, results) {
|
], function(err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Posts.dismissAllFlags = function(callback) {
|
Posts.dismissAllFlags = function(callback) {
|
||||||
db.delete('posts:flagged', callback);
|
db.getSortedSetRange('posts:flagged', 0, -1, function(err, pids) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
async.eachLimit(pids, 50, Posts.dismissFlag, callback);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Posts.getFlags = function(set, uid, start, stop, callback) {
|
Posts.getFlags = function(set, uid, start, stop, callback) {
|
||||||
db.getSortedSetRevRange(set, start, stop, function(err, pids) {
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
db.getSortedSetRevRange(set, start, stop, next);
|
||||||
|
},
|
||||||
|
function (pids, next) {
|
||||||
|
getFlaggedPostsWithReasons(pids, uid, next);
|
||||||
|
}
|
||||||
|
], callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
function getFlaggedPostsWithReasons(pids, uid, callback) {
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
async.parallel({
|
||||||
|
uidsReasons: function(next) {
|
||||||
|
async.map(pids, function(pid, next) {
|
||||||
|
db.getSortedSetRange('pid:' + pid + ':flag:uid:reason', 0, -1, next);
|
||||||
|
}, next);
|
||||||
|
},
|
||||||
|
posts: function(next) {
|
||||||
|
Posts.getPostSummaryByPids(pids, uid, {stripTags: false, extraFields: ['flags']}, next);
|
||||||
|
}
|
||||||
|
}, next);
|
||||||
|
},
|
||||||
|
function (results, next) {
|
||||||
|
async.map(results.uidsReasons, function(uidReasons, next) {
|
||||||
|
async.map(uidReasons, function(uidReason, next) {
|
||||||
|
var uid = uidReason.split(':')[0];
|
||||||
|
var reason = uidReason.substr(uidReason.indexOf(':') + 1);
|
||||||
|
user.getUserFields(uid, ['username', 'userslug', 'picture'], function(err, userData) {
|
||||||
|
next(err, {user: userData, reason: reason});
|
||||||
|
});
|
||||||
|
}, next);
|
||||||
|
}, function(err, reasons) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
Posts.getPostSummaryByPids(pids, uid, {stripTags: false, extraFields: ['flags']}, callback);
|
results.posts.forEach(function(post, index) {
|
||||||
|
if (post) {
|
||||||
|
post.flagReasons = reasons[index];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
next(null, results.posts);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
], callback);
|
||||||
|
}
|
||||||
|
|
||||||
Posts.getUserFlags = function(byUsername, sortBy, callerUID, start, stop, callback) {
|
Posts.getUserFlags = function(byUsername, sortBy, callerUID, start, stop, callback) {
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
@@ -112,7 +167,7 @@ module.exports = function(Posts) {
|
|||||||
db.getSortedSetRevRange('uid:' + uid + ':flag:pids', 0, -1, next);
|
db.getSortedSetRevRange('uid:' + uid + ':flag:pids', 0, -1, next);
|
||||||
},
|
},
|
||||||
function(pids, next) {
|
function(pids, next) {
|
||||||
Posts.getPostSummaryByPids(pids, callerUID, {stripTags: false, extraFields: ['flags']}, next);
|
getFlaggedPostsWithReasons(pids, callerUID, next);
|
||||||
},
|
},
|
||||||
function(posts, next) {
|
function(posts, next) {
|
||||||
if (sortBy === 'count') {
|
if (sortBy === 'count') {
|
||||||
@@ -120,6 +175,7 @@ module.exports = function(Posts) {
|
|||||||
return b.flags - a.flags;
|
return b.flags - a.flags;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
next(null, posts.slice(start, stop));
|
next(null, posts.slice(start, stop));
|
||||||
}
|
}
|
||||||
], callback);
|
], callback);
|
||||||
|
|||||||
@@ -179,7 +179,8 @@ module.exports = function(privileges) {
|
|||||||
'topics:create': results['topics:create'][0] || isAdminOrMod,
|
'topics:create': results['topics:create'][0] || isAdminOrMod,
|
||||||
editable: isAdminOrMod,
|
editable: isAdminOrMod,
|
||||||
view_deleted: isAdminOrMod,
|
view_deleted: isAdminOrMod,
|
||||||
read: results.read[0] || isAdminOrMod
|
read: results.read[0] || isAdminOrMod,
|
||||||
|
isAdminOrMod: isAdminOrMod
|
||||||
}, callback);
|
}, callback);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,8 +17,11 @@ module.exports = function (app, middleware, controllers) {
|
|||||||
setupPageRoute(app, '/user/:userslug/favourites', middleware, accountMiddlewares, controllers.accounts.posts.getFavourites);
|
setupPageRoute(app, '/user/:userslug/favourites', middleware, accountMiddlewares, controllers.accounts.posts.getFavourites);
|
||||||
setupPageRoute(app, '/user/:userslug/watched', middleware, accountMiddlewares, controllers.accounts.posts.getWatchedTopics);
|
setupPageRoute(app, '/user/:userslug/watched', middleware, accountMiddlewares, controllers.accounts.posts.getWatchedTopics);
|
||||||
setupPageRoute(app, '/user/:userslug/edit', middleware, accountMiddlewares, controllers.accounts.edit.get);
|
setupPageRoute(app, '/user/:userslug/edit', middleware, accountMiddlewares, controllers.accounts.edit.get);
|
||||||
|
setupPageRoute(app, '/user/:userslug/edit/username', middleware, accountMiddlewares, controllers.accounts.edit.username);
|
||||||
|
setupPageRoute(app, '/user/:userslug/edit/email', middleware, accountMiddlewares, controllers.accounts.edit.email);
|
||||||
|
setupPageRoute(app, '/user/:userslug/edit/password', middleware, accountMiddlewares, controllers.accounts.edit.password);
|
||||||
setupPageRoute(app, '/user/:userslug/settings', middleware, accountMiddlewares, controllers.accounts.settings.get);
|
setupPageRoute(app, '/user/:userslug/settings', middleware, accountMiddlewares, controllers.accounts.settings.get);
|
||||||
|
|
||||||
setupPageRoute(app, '/notifications', middleware, [middleware.authenticate], controllers.accounts.notifications.get);
|
setupPageRoute(app, '/notifications', middleware, [middleware.authenticate], controllers.accounts.notifications.get);
|
||||||
setupPageRoute(app, '/chats/:userslug?', middleware, [middleware.redirectToLoginIfGuest], controllers.accounts.chats.get);
|
setupPageRoute(app, '/chats/:userslug?', middleware, [middleware.authenticate], controllers.accounts.chats.get);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ function addRoutes(router, middleware, controllers) {
|
|||||||
router.get('/advanced/post-cache', middlewares, controllers.admin.postCache.get);
|
router.get('/advanced/post-cache', middlewares, controllers.admin.postCache.get);
|
||||||
|
|
||||||
router.get('/development/logger', middlewares, controllers.admin.logger.get);
|
router.get('/development/logger', middlewares, controllers.admin.logger.get);
|
||||||
|
router.get('/development/info', middlewares, controllers.admin.info.get);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function(app, middleware, controllers) {
|
module.exports = function(app, middleware, controllers) {
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
var express = require('express'),
|
var express = require('express'),
|
||||||
|
|
||||||
posts = require('../posts'),
|
|
||||||
categories = require('../categories'),
|
|
||||||
uploadsController = require('../controllers/uploads');
|
uploadsController = require('../controllers/uploads');
|
||||||
|
|
||||||
module.exports = function(app, middleware, controllers) {
|
module.exports = function(app, middleware, controllers) {
|
||||||
@@ -22,6 +20,7 @@ module.exports = function(app, middleware, controllers) {
|
|||||||
router.get('/categories/:cid/moderators', controllers.api.getModerators);
|
router.get('/categories/:cid/moderators', controllers.api.getModerators);
|
||||||
router.get('/recent/posts/:term?', controllers.api.getRecentPosts);
|
router.get('/recent/posts/:term?', controllers.api.getRecentPosts);
|
||||||
router.get('/unread/total', middleware.authenticate, controllers.unread.unreadTotal);
|
router.get('/unread/total', middleware.authenticate, controllers.unread.unreadTotal);
|
||||||
|
router.get('/topic/teaser/:topic_id', controllers.topics.teaser);
|
||||||
|
|
||||||
var multipart = require('connect-multiparty');
|
var multipart = require('connect-multiparty');
|
||||||
var multipartMiddleware = multipart();
|
var multipartMiddleware = multipart();
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ var nconf = require('nconf'),
|
|||||||
path = require('path'),
|
path = require('path'),
|
||||||
winston = require('winston'),
|
winston = require('winston'),
|
||||||
controllers = require('../controllers'),
|
controllers = require('../controllers'),
|
||||||
meta = require('../meta'),
|
|
||||||
plugins = require('../plugins'),
|
plugins = require('../plugins'),
|
||||||
express = require('express'),
|
express = require('express'),
|
||||||
|
|
||||||
@@ -30,14 +29,12 @@ function mainRoutes(app, middleware, controllers) {
|
|||||||
setupPageRoute(app, '/compose', middleware, [middleware.authenticate], controllers.compose);
|
setupPageRoute(app, '/compose', middleware, [middleware.authenticate], controllers.compose);
|
||||||
setupPageRoute(app, '/confirm/:code', middleware, [], controllers.confirmEmail);
|
setupPageRoute(app, '/confirm/:code', middleware, [], controllers.confirmEmail);
|
||||||
setupPageRoute(app, '/outgoing', middleware, [], controllers.outgoing);
|
setupPageRoute(app, '/outgoing', middleware, [], controllers.outgoing);
|
||||||
setupPageRoute(app, '/search/:term?', middleware, [middleware.guestSearchingAllowed], controllers.search.search);
|
setupPageRoute(app, '/search/:term?', middleware, [], controllers.search.search);
|
||||||
setupPageRoute(app, '/reset/:code?', middleware, [], controllers.reset);
|
setupPageRoute(app, '/reset/:code?', middleware, [], controllers.reset);
|
||||||
setupPageRoute(app, '/tos', middleware, [], controllers.termsOfUse);
|
setupPageRoute(app, '/tos', middleware, [], controllers.termsOfUse);
|
||||||
}
|
}
|
||||||
|
|
||||||
function topicRoutes(app, middleware, controllers) {
|
function topicRoutes(app, middleware, controllers) {
|
||||||
app.get('/api/topic/teaser/:topic_id', controllers.topics.teaser);
|
|
||||||
|
|
||||||
setupPageRoute(app, '/topic/:topic_id/:slug/:post_index?', middleware, [], controllers.topics.get);
|
setupPageRoute(app, '/topic/:topic_id/:slug/:post_index?', middleware, [], controllers.topics.get);
|
||||||
setupPageRoute(app, '/topic/:topic_id/:slug?', middleware, [], controllers.topics.get);
|
setupPageRoute(app, '/topic/:topic_id/:slug?', middleware, [], controllers.topics.get);
|
||||||
}
|
}
|
||||||
@@ -120,15 +117,7 @@ module.exports = function(app, middleware) {
|
|||||||
require('./debug')(app, middleware, controllers);
|
require('./debug')(app, middleware, controllers);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use(function(req, res, next) {
|
app.use(middleware.privateUploads);
|
||||||
if (req.user || parseInt(meta.config.privateUploads, 10) !== 1) {
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
if (req.path.startsWith('/uploads/files')) {
|
|
||||||
return res.status(403).json('not-allowed');
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use(relativePath, express.static(path.join(__dirname, '../../', 'public'), {
|
app.use(relativePath, express.static(path.join(__dirname, '../../', 'public'), {
|
||||||
maxAge: app.enabled('cache') ? 5184000000 : 0
|
maxAge: app.enabled('cache') ? 5184000000 : 0
|
||||||
@@ -144,7 +133,11 @@ module.exports = function(app, middleware) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function handle404(app, middleware) {
|
function handle404(app, middleware) {
|
||||||
app.use(function(req, res, next) {
|
var relativePath = nconf.get('relative_path');
|
||||||
|
var isLanguage = new RegExp('^' + relativePath + '/language/[\\w]{2,}/.*.json'),
|
||||||
|
isClientScript = new RegExp('^' + relativePath + '\\/src\\/.+\\.js');
|
||||||
|
|
||||||
|
app.use(function(req, res) {
|
||||||
if (plugins.hasListeners('action:meta.override404')) {
|
if (plugins.hasListeners('action:meta.override404')) {
|
||||||
return plugins.fireHook('action:meta.override404', {
|
return plugins.fireHook('action:meta.override404', {
|
||||||
req: req,
|
req: req,
|
||||||
@@ -153,14 +146,14 @@ function handle404(app, middleware) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var relativePath = nconf.get('relative_path');
|
|
||||||
var isLanguage = new RegExp('^' + relativePath + '/language/[\\w]{2,}/.*.json'),
|
|
||||||
isClientScript = new RegExp('^' + relativePath + '\\/src\\/.+\\.js');
|
|
||||||
|
|
||||||
if (isClientScript.test(req.url)) {
|
if (isClientScript.test(req.url)) {
|
||||||
res.type('text/javascript').status(200).send('');
|
res.type('text/javascript').status(200).send('');
|
||||||
} else if (isLanguage.test(req.url)) {
|
} else if (isLanguage.test(req.url)) {
|
||||||
res.status(200).json({});
|
res.status(200).json({});
|
||||||
|
} else if (req.path.startsWith(relativePath + '/uploads')) {
|
||||||
|
res.status(404).send('');
|
||||||
|
} else if (req.path === '/favicon.ico') {
|
||||||
|
res.status(404).send('');
|
||||||
} else if (req.accepts('html')) {
|
} else if (req.accepts('html')) {
|
||||||
if (process.env.NODE_ENV === 'development') {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
winston.warn('Route requested but not found: ' + req.url);
|
winston.warn('Route requested but not found: ' + req.url);
|
||||||
@@ -182,7 +175,7 @@ function handle404(app, middleware) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleErrors(app, middleware) {
|
function handleErrors(app, middleware) {
|
||||||
app.use(function(err, req, res, next) {
|
app.use(function(err, req, res) {
|
||||||
if (err.code === 'EBADCSRFTOKEN') {
|
if (err.code === 'EBADCSRFTOKEN') {
|
||||||
winston.error(req.path + '\n', err.message);
|
winston.error(req.path + '\n', err.message);
|
||||||
return res.sendStatus(403);
|
return res.sendStatus(403);
|
||||||
|
|||||||
@@ -22,15 +22,13 @@ search.search = function(data, callback) {
|
|||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
result.search_query = validator.escape(query);
|
data.search_query = validator.escape(query);
|
||||||
if (searchIn === 'titles' || searchIn === 'titlesposts') {
|
if (searchIn === 'titles' || searchIn === 'titlesposts') {
|
||||||
searchIn = 'posts';
|
searchIn = 'posts';
|
||||||
}
|
}
|
||||||
result[searchIn] = data.matches;
|
|
||||||
result.matchCount = data.matchCount;
|
data.time = (process.elapsedTimeSince(start) / 1000).toFixed(2);
|
||||||
result.pageCount = data.pageCount;
|
callback(null, data);
|
||||||
result.time = (process.elapsedTimeSince(start) / 1000).toFixed(2);
|
|
||||||
callback(null, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var start = process.hrtime();
|
var start = process.hrtime();
|
||||||
@@ -38,18 +36,12 @@ search.search = function(data, callback) {
|
|||||||
var query = data.query;
|
var query = data.query;
|
||||||
var searchIn = data.searchIn || 'titlesposts';
|
var searchIn = data.searchIn || 'titlesposts';
|
||||||
|
|
||||||
var result = {
|
|
||||||
posts: [],
|
|
||||||
users: [],
|
|
||||||
tags: []
|
|
||||||
};
|
|
||||||
|
|
||||||
if (searchIn === 'posts' || searchIn === 'titles' || searchIn === 'titlesposts') {
|
if (searchIn === 'posts' || searchIn === 'titles' || searchIn === 'titlesposts') {
|
||||||
searchInContent(data, done);
|
searchInContent(data, done);
|
||||||
} else if (searchIn === 'users') {
|
} else if (searchIn === 'users') {
|
||||||
searchInUsers(data, done);
|
user.search(data, done);
|
||||||
} else if (searchIn === 'tags') {
|
} else if (searchIn === 'tags') {
|
||||||
searchInTags(query, done);
|
topics.searchAndLoadTags(data, done);
|
||||||
} else {
|
} else {
|
||||||
callback(new Error('[[error:unknown-search-filter]]'));
|
callback(new Error('[[error:unknown-search-filter]]'));
|
||||||
}
|
}
|
||||||
@@ -91,7 +83,7 @@ function searchInContent(data, callback) {
|
|||||||
|
|
||||||
var matchCount = 0;
|
var matchCount = 0;
|
||||||
if (!results || (!results.pids.length && !results.tids.length)) {
|
if (!results || (!results.pids.length && !results.tids.length)) {
|
||||||
return callback(null, {matches: [], matchCount: matchCount, pageCount: 1});
|
return callback(null, {posts: [], matchCount: matchCount, pageCount: 1});
|
||||||
}
|
}
|
||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
@@ -118,7 +110,7 @@ function searchInContent(data, callback) {
|
|||||||
posts.getPostSummaryByPids(pids, data.uid, {}, next);
|
posts.getPostSummaryByPids(pids, data.uid, {}, next);
|
||||||
},
|
},
|
||||||
function(posts, next) {
|
function(posts, next) {
|
||||||
next(null, {matches: posts, matchCount: matchCount, pageCount: Math.max(1, Math.ceil(parseInt(matchCount, 10) / 10))});
|
next(null, {posts: posts, matchCount: matchCount, pageCount: Math.max(1, Math.ceil(parseInt(matchCount, 10) / 10))});
|
||||||
}
|
}
|
||||||
], callback);
|
], callback);
|
||||||
});
|
});
|
||||||
@@ -315,16 +307,12 @@ function sortPosts(posts, data) {
|
|||||||
}
|
}
|
||||||
data.sortBy = data.sortBy || 'timestamp';
|
data.sortBy = data.sortBy || 'timestamp';
|
||||||
data.sortDirection = data.sortDirection || 'desc';
|
data.sortDirection = data.sortDirection || 'desc';
|
||||||
|
var direction = data.sortDirection === 'desc' ? 1 : -1;
|
||||||
|
|
||||||
if (data.sortBy === 'timestamp') {
|
if (data.sortBy === 'timestamp') {
|
||||||
if (data.sortDirection === 'desc') {
|
|
||||||
posts.sort(function(p1, p2) {
|
posts.sort(function(p1, p2) {
|
||||||
return p2.timestamp - p1.timestamp;
|
return direction * (p2.timestamp - p1.timestamp);
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
posts.sort(function(p1, p2) {
|
|
||||||
return p1.timestamp - p2.timestamp;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -336,21 +324,13 @@ function sortPosts(posts, data) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var value = firstPost[fields[0]][fields[1]];
|
var isNumeric = utils.isNumber(firstPost[fields[0]][fields[1]]);
|
||||||
var isNumeric = utils.isNumber(value);
|
|
||||||
|
|
||||||
if (isNumeric) {
|
if (isNumeric) {
|
||||||
if (data.sortDirection === 'desc') {
|
|
||||||
posts.sort(function(p1, p2) {
|
posts.sort(function(p1, p2) {
|
||||||
return p2[fields[0]][fields[1]] - p1[fields[0]][fields[1]];
|
return direction * (p2[fields[0]][fields[1]] - p1[fields[0]][fields[1]]);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
posts.sort(function(p1, p2) {
|
|
||||||
return p1[fields[0]][fields[1]] - p2[fields[0]][fields[1]];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var direction = data.sortDirection === 'desc' ? 1 : -1;
|
|
||||||
posts.sort(function(p1, p2) {
|
posts.sort(function(p1, p2) {
|
||||||
if (p1[fields[0]][fields[1]] > p2[fields[0]][fields[1]]) {
|
if (p1[fields[0]][fields[1]] > p2[fields[0]][fields[1]]) {
|
||||||
return direction;
|
return direction;
|
||||||
@@ -435,25 +415,6 @@ function getSearchUids(data, callback) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchInUsers(data, callback) {
|
|
||||||
user.search(data, function(err, results) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
callback(null, {matches: results.users, matchCount: results.matchCount, pageCount: results.pageCount});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function searchInTags(query, callback) {
|
|
||||||
topics.searchAndLoadTags({query: query}, function(err, tags) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(null, {matches: tags, matchCount: tags.length, pageCount: 1});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
search.searchQuery = function(index, content, cids, uids, callback) {
|
search.searchQuery = function(index, content, cids, uids, callback) {
|
||||||
plugins.fireHook('filter:search.query', {
|
plugins.fireHook('filter:search.query', {
|
||||||
index: index,
|
index: index,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var async = require('async');
|
||||||
var groups = require('../../groups'),
|
var groups = require('../../groups'),
|
||||||
Groups = {};
|
Groups = {};
|
||||||
|
|
||||||
@@ -20,7 +21,17 @@ Groups.join = function(socket, data, callback) {
|
|||||||
return callback(new Error('[[error:invalid-data]]'));
|
return callback(new Error('[[error:invalid-data]]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
groups.join(data.groupName, data.uid, callback);
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
groups.isMember(data.uid, data.groupName, next);
|
||||||
|
},
|
||||||
|
function (isMember, next) {
|
||||||
|
if (isMember) {
|
||||||
|
return next(new Error('[[error:group-already-member]]'));
|
||||||
|
}
|
||||||
|
groups.join(data.groupName, data.uid, next);
|
||||||
|
}
|
||||||
|
], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
Groups.leave = function(socket, data, callback) {
|
Groups.leave = function(socket, data, callback) {
|
||||||
@@ -32,7 +43,17 @@ Groups.leave = function(socket, data, callback) {
|
|||||||
return callback(new Error('[[error:cant-remove-self-as-admin]]'));
|
return callback(new Error('[[error:cant-remove-self-as-admin]]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
groups.leave(data.groupName, data.uid, callback);
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
groups.isMember(data.uid, data.groupName, next);
|
||||||
|
},
|
||||||
|
function (isMember, next) {
|
||||||
|
if (!isMember) {
|
||||||
|
return next(new Error('[[error:group-not-member]]'));
|
||||||
|
}
|
||||||
|
groups.leave(data.groupName, data.uid, next);
|
||||||
|
}
|
||||||
|
], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
Groups.update = function(socket, data, callback) {
|
Groups.update = function(socket, data, callback) {
|
||||||
|
|||||||
@@ -15,7 +15,25 @@ SocketCategories.getRecentReplies = function(socket, cid, callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
SocketCategories.get = function(socket, data, callback) {
|
SocketCategories.get = function(socket, data, callback) {
|
||||||
categories.getCategoriesByPrivilege('categories:cid', socket.uid, 'find', callback);
|
async.parallel({
|
||||||
|
isAdmin: async.apply(user.isAdministrator, socket.uid),
|
||||||
|
categories: function(next) {
|
||||||
|
async.waterfall([
|
||||||
|
async.apply(db.getSortedSetRange, 'categories:cid', 0, -1),
|
||||||
|
async.apply(categories.getCategoriesData),
|
||||||
|
], next);
|
||||||
|
}
|
||||||
|
}, function(err, results) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
results.categories = results.categories.filter(function(category) {
|
||||||
|
return category && (!category.disabled || results.isAdmin);
|
||||||
|
});
|
||||||
|
|
||||||
|
callback(null, results.categories);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
SocketCategories.getWatchedCategories = function(socket, data, callback) {
|
SocketCategories.getWatchedCategories = function(socket, data, callback) {
|
||||||
|
|||||||
@@ -62,8 +62,11 @@ SocketGroups.leave = function(socket, data, callback) {
|
|||||||
|
|
||||||
function isOwner(next) {
|
function isOwner(next) {
|
||||||
return function (socket, data, callback) {
|
return function (socket, data, callback) {
|
||||||
groups.ownership.isOwner(socket.uid, data.groupName, function(err, isOwner) {
|
async.parallel({
|
||||||
if (err || !isOwner) {
|
isAdmin: async.apply(user.isAdmin, socket.uid),
|
||||||
|
isOwner: async.apply(groups.ownership.isOwner, socket.uid, data.groupName)
|
||||||
|
}, function(err, results) {
|
||||||
|
if (err || (!isOwner && !results.isAdmin)) {
|
||||||
return callback(err || new Error('[[error:no-privileges]]'));
|
return callback(err || new Error('[[error:no-privileges]]'));
|
||||||
}
|
}
|
||||||
next(socket, data, callback);
|
next(socket, data, callback);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
var async = require('async');
|
var async = require('async');
|
||||||
var winston = require('winston');
|
var winston = require('winston');
|
||||||
var nconf = require('nconf');
|
var nconf = require('nconf');
|
||||||
|
var validator = require('validator');
|
||||||
|
|
||||||
var websockets = require('./index');
|
var websockets = require('./index');
|
||||||
var user = require('../user');
|
var user = require('../user');
|
||||||
@@ -86,14 +87,14 @@ SocketHelpers.sendNotificationToTopicOwner = function(tid, fromuid, notification
|
|||||||
|
|
||||||
async.parallel({
|
async.parallel({
|
||||||
username: async.apply(user.getUserField, fromuid, 'username'),
|
username: async.apply(user.getUserField, fromuid, 'username'),
|
||||||
topicData: async.apply(topics.getTopicFields, tid, ['uid', 'slug']),
|
topicData: async.apply(topics.getTopicFields, tid, ['uid', 'slug', 'title']),
|
||||||
}, function(err, results) {
|
}, function(err, results) {
|
||||||
if (err || fromuid === parseInt(results.topicData.uid, 10)) {
|
if (err || fromuid === parseInt(results.topicData.uid, 10)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
notifications.create({
|
notifications.create({
|
||||||
bodyShort: '[[' + notification + ', ' + results.username + ']]',
|
bodyShort: '[[' + notification + ', ' + results.username + ', ' + results.topicData.title + ']]',
|
||||||
path: nconf.get('relative_path') + '/topic/' + results.topicData.slug,
|
path: nconf.get('relative_path') + '/topic/' + results.topicData.slug,
|
||||||
nid: 'tid:' + tid + ':uid:' + fromuid,
|
nid: 'tid:' + tid + ':uid:' + fromuid,
|
||||||
from: fromuid
|
from: fromuid
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
var SocketIO = require('socket.io'),
|
var SocketIO = require('socket.io'),
|
||||||
socketioWildcard = require('socketio-wildcard')(),
|
socketioWildcard = require('socketio-wildcard')(),
|
||||||
async = require('async'),
|
async = require('async'),
|
||||||
fs = require('fs'),
|
|
||||||
nconf = require('nconf'),
|
nconf = require('nconf'),
|
||||||
cookieParser = require('cookie-parser')(nconf.get('secret')),
|
cookieParser = require('cookie-parser')(nconf.get('secret')),
|
||||||
winston = require('winston'),
|
winston = require('winston'),
|
||||||
|
|||||||
@@ -1,15 +1,10 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var nconf = require('nconf'),
|
var validator = require('validator'),
|
||||||
winston = require('winston'),
|
|
||||||
validator = require('validator'),
|
|
||||||
|
|
||||||
db = require('../database'),
|
|
||||||
meta = require('../meta'),
|
meta = require('../meta'),
|
||||||
user = require('../user'),
|
user = require('../user'),
|
||||||
topics = require('../topics'),
|
topics = require('../topics'),
|
||||||
logger = require('../logger'),
|
|
||||||
plugins = require('../plugins'),
|
|
||||||
emitter = require('../emitter'),
|
emitter = require('../emitter'),
|
||||||
rooms = require('./rooms'),
|
rooms = require('./rooms'),
|
||||||
|
|
||||||
@@ -52,13 +47,7 @@ SocketMeta.rooms.enter = function(socket, data, callback) {
|
|||||||
return callback(new Error('[[error:not-allowed]]'));
|
return callback(new Error('[[error:not-allowed]]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (socket.currentRoom) {
|
leaveCurrentRoom(socket);
|
||||||
rooms.leave(socket, socket.currentRoom);
|
|
||||||
if (socket.currentRoom.indexOf('topic') !== -1) {
|
|
||||||
websockets.in(socket.currentRoom).emit('event:user_leave', socket.uid);
|
|
||||||
}
|
|
||||||
socket.currentRoom = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.enter) {
|
if (data.enter) {
|
||||||
rooms.enter(socket, data.enter);
|
rooms.enter(socket, data.enter);
|
||||||
@@ -75,6 +64,24 @@ SocketMeta.rooms.enter = function(socket, data, callback) {
|
|||||||
callback();
|
callback();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SocketMeta.rooms.leaveCurrent = function(socket, data, callback) {
|
||||||
|
if (!socket.uid || !socket.currentRoom) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
leaveCurrentRoom(socket);
|
||||||
|
callback();
|
||||||
|
};
|
||||||
|
|
||||||
|
function leaveCurrentRoom(socket) {
|
||||||
|
if (socket.currentRoom) {
|
||||||
|
rooms.leave(socket, socket.currentRoom);
|
||||||
|
if (socket.currentRoom.indexOf('topic') !== -1) {
|
||||||
|
websockets.in(socket.currentRoom).emit('event:user_leave', socket.uid);
|
||||||
|
}
|
||||||
|
socket.currentRoom = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SocketMeta.rooms.getAll = function(socket, data, callback) {
|
SocketMeta.rooms.getAll = function(socket, data, callback) {
|
||||||
var roomClients = rooms.roomClients();
|
var roomClients = rooms.roomClients();
|
||||||
var socketData = {
|
var socketData = {
|
||||||
|
|||||||
@@ -147,4 +147,11 @@ SocketModules.sounds.getMapping = function(socket, data, callback) {
|
|||||||
meta.sounds.getMapping(callback);
|
meta.sounds.getMapping(callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SocketModules.sounds.getData = function(socket, data, callback) {
|
||||||
|
async.parallel({
|
||||||
|
mapping: async.apply(meta.sounds.getMapping),
|
||||||
|
files: async.apply(meta.sounds.getFiles)
|
||||||
|
}, callback);
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = SocketModules;
|
module.exports = SocketModules;
|
||||||
|
|||||||
@@ -12,6 +12,23 @@ SocketNotifs.get = function(socket, data, callback) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SocketNotifs.loadMore = function(socket, data, callback) {
|
||||||
|
if (!data || !parseInt(data.after, 10)) {
|
||||||
|
return callback(new Error('[[error:invalid-data]]'));
|
||||||
|
}
|
||||||
|
if (!socket.uid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var start = parseInt(data.after, 10);
|
||||||
|
var stop = start + 20;
|
||||||
|
user.notifications.getAll(socket.uid, start, stop, function(err, notifications) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
callback(null, {notifications: notifications, nextStart: stop});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
SocketNotifs.getCount = function(socket, data, callback) {
|
SocketNotifs.getCount = function(socket, data, callback) {
|
||||||
user.notifications.getUnreadCount(socket.uid, callback);
|
user.notifications.getUnreadCount(socket.uid, callback);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,17 +13,21 @@ var meta = require('../../meta');
|
|||||||
|
|
||||||
module.exports = function(SocketPosts) {
|
module.exports = function(SocketPosts) {
|
||||||
|
|
||||||
SocketPosts.flag = function(socket, pid, callback) {
|
SocketPosts.flag = function(socket, data, callback) {
|
||||||
if (!socket.uid) {
|
if (!socket.uid) {
|
||||||
return callback(new Error('[[error:not-logged-in]]'));
|
return callback(new Error('[[error:not-logged-in]]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!data || !data.pid || !data.reason) {
|
||||||
|
return callback(new Error('[[error:invalid-data]]'));
|
||||||
|
}
|
||||||
|
|
||||||
var flaggingUser = {},
|
var flaggingUser = {},
|
||||||
post;
|
post;
|
||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
posts.getPostFields(pid, ['pid', 'tid', 'uid', 'content', 'deleted'], next);
|
posts.getPostFields(data.pid, ['pid', 'tid', 'uid', 'content', 'deleted'], next);
|
||||||
},
|
},
|
||||||
function (postData, next) {
|
function (postData, next) {
|
||||||
if (parseInt(postData.deleted, 10) === 1) {
|
if (parseInt(postData.deleted, 10) === 1) {
|
||||||
@@ -55,7 +59,7 @@ module.exports = function(SocketPosts) {
|
|||||||
flaggingUser = user.userData;
|
flaggingUser = user.userData;
|
||||||
flaggingUser.uid = socket.uid;
|
flaggingUser.uid = socket.uid;
|
||||||
|
|
||||||
posts.flag(post, socket.uid, next);
|
posts.flag(post, socket.uid, data.reason, next);
|
||||||
},
|
},
|
||||||
function (next) {
|
function (next) {
|
||||||
async.parallel({
|
async.parallel({
|
||||||
@@ -74,8 +78,8 @@ module.exports = function(SocketPosts) {
|
|||||||
notifications.create({
|
notifications.create({
|
||||||
bodyShort: '[[notifications:user_flagged_post_in, ' + flaggingUser.username + ', ' + post.topic.title + ']]',
|
bodyShort: '[[notifications:user_flagged_post_in, ' + flaggingUser.username + ', ' + post.topic.title + ']]',
|
||||||
bodyLong: post.content,
|
bodyLong: post.content,
|
||||||
pid: pid,
|
pid: data.pid,
|
||||||
nid: 'post_flag:' + pid + ':uid:' + socket.uid,
|
nid: 'post_flag:' + data.pid + ':uid:' + socket.uid,
|
||||||
from: socket.uid
|
from: socket.uid
|
||||||
}, function(err, notification) {
|
}, function(err, notification) {
|
||||||
if (err || !notification) {
|
if (err || !notification) {
|
||||||
|
|||||||
@@ -116,19 +116,6 @@ SocketUser.reset.commit = function(socket, data, callback) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
SocketUser.isAdminOrSelf = function(socket, uid, callback) {
|
|
||||||
if (socket.uid === parseInt(uid, 10)) {
|
|
||||||
return callback();
|
|
||||||
}
|
|
||||||
user.isAdministrator(socket.uid, function(err, isAdmin) {
|
|
||||||
if (err || !isAdmin) {
|
|
||||||
return callback(err || new Error('[[error:no-privileges]]'));
|
|
||||||
}
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
SocketUser.follow = function(socket, data, callback) {
|
SocketUser.follow = function(socket, data, callback) {
|
||||||
if (!socket.uid || !data) {
|
if (!socket.uid || !data) {
|
||||||
return;
|
return;
|
||||||
@@ -182,7 +169,7 @@ SocketUser.saveSettings = function(socket, data, callback) {
|
|||||||
return callback(new Error('[[error:invalid-data]]'));
|
return callback(new Error('[[error:invalid-data]]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
SocketUser.isAdminOrSelf(socket, data.uid, function(err) {
|
user.isAdminOrSelf(socket.uid, data.uid, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
@@ -220,6 +207,17 @@ SocketUser.getUnreadChatCount = function(socket, data, callback) {
|
|||||||
messaging.getUnreadCount(socket.uid, callback);
|
messaging.getUnreadCount(socket.uid, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SocketUser.getUnreadCounts = function(socket, data, callback) {
|
||||||
|
if (!socket.uid) {
|
||||||
|
return callback(null, {});
|
||||||
|
}
|
||||||
|
async.parallel({
|
||||||
|
unreadTopicCount: async.apply(topics.getTotalUnread, socket.uid),
|
||||||
|
unreadChatCount: async.apply(messaging.getUnreadCount, socket.uid),
|
||||||
|
unreadNotificationCount: async.apply(user.notifications.getUnreadCount, socket.uid)
|
||||||
|
}, callback);
|
||||||
|
};
|
||||||
|
|
||||||
SocketUser.loadMore = function(socket, data, callback) {
|
SocketUser.loadMore = function(socket, data, callback) {
|
||||||
if (!data || !data.set || parseInt(data.after, 10) < 0) {
|
if (!data || !data.set || parseInt(data.after, 10) < 0) {
|
||||||
return callback(new Error('[[error:invalid-data]]'));
|
return callback(new Error('[[error:invalid-data]]'));
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ module.exports = function(SocketUser) {
|
|||||||
} else if (type === 'uploaded') {
|
} else if (type === 'uploaded') {
|
||||||
type = 'uploadedpicture';
|
type = 'uploadedpicture';
|
||||||
} else {
|
} else {
|
||||||
return callback(new Error('[[error:invalid-image-type, ' + ['default', 'uploadedpicture'].join(', ') + ']]'));
|
return callback(new Error('[[error:invalid-image-type, ' + ['default', 'uploadedpicture'].join(', ') + ']]'));
|
||||||
}
|
}
|
||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
SocketUser.isAdminOrSelf(socket, data.uid, next);
|
user.isAdminOrSelf(socket.uid, data.uid, next);
|
||||||
},
|
},
|
||||||
function (next) {
|
function (next) {
|
||||||
if (!type) {
|
if (!type) {
|
||||||
@@ -47,7 +47,7 @@ module.exports = function(SocketUser) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SocketUser.isAdminOrSelf(socket, data.uid, function(err) {
|
user.isAdminOrSelf(socket.uid, data.uid, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ module.exports = function(SocketUser) {
|
|||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function (next) {
|
function (next) {
|
||||||
SocketUser.isAdminOrSelf(socket, data.uid, next);
|
user.isAdminOrSelf(socket.uid, data.uid, next);
|
||||||
},
|
},
|
||||||
function (next) {
|
function (next) {
|
||||||
user.getUserField(data.uid, 'uploadedpicture', next);
|
user.getUserField(data.uid, 'uploadedpicture', next);
|
||||||
|
|||||||
@@ -8,6 +8,44 @@ var events = require('../../events');
|
|||||||
|
|
||||||
module.exports = function(SocketUser) {
|
module.exports = function(SocketUser) {
|
||||||
|
|
||||||
|
SocketUser.changeUsernameEmail = function(socket, data, callback) {
|
||||||
|
if (!data || !data.uid || !socket.uid) {
|
||||||
|
return callback(new Error('[[error:invalid-data]]'));
|
||||||
|
}
|
||||||
|
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
isAdminOrSelfAndPasswordMatch(socket.uid, data, next);
|
||||||
|
},
|
||||||
|
function (next) {
|
||||||
|
SocketUser.updateProfile(socket, data, next);
|
||||||
|
}
|
||||||
|
], callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
function isAdminOrSelfAndPasswordMatch(uid, data, callback) {
|
||||||
|
async.parallel({
|
||||||
|
isAdmin: async.apply(user.isAdministrator, uid),
|
||||||
|
hasPassword: async.apply(user.hasPassword, data.uid),
|
||||||
|
passwordMatch: async.apply(user.isPasswordCorrect, data.uid, data.password)
|
||||||
|
}, function(err, results) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
var self = parseInt(uid, 10) === parseInt(data.uid, 10);
|
||||||
|
|
||||||
|
if (!results.isAdmin && !self) {
|
||||||
|
return callback(new Error('[[error:no-privileges]]'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self && results.hasPassword && !results.passwordMatch) {
|
||||||
|
return callback(new Error('[[error:invalid-password]]'));
|
||||||
|
}
|
||||||
|
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
SocketUser.changePassword = function(socket, data, callback) {
|
SocketUser.changePassword = function(socket, data, callback) {
|
||||||
if (!data || !data.uid || data.newPassword.length < meta.config.minimumPasswordLength) {
|
if (!data || !data.uid || data.newPassword.length < meta.config.minimumPasswordLength) {
|
||||||
return callback(new Error('[[error:invalid-data]]'));
|
return callback(new Error('[[error:invalid-data]]'));
|
||||||
@@ -31,7 +69,6 @@ module.exports = function(SocketUser) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
SocketUser.updateProfile = function(socket, data, callback) {
|
SocketUser.updateProfile = function(socket, data, callback) {
|
||||||
if (!socket.uid) {
|
if (!socket.uid) {
|
||||||
return callback('[[error:invalid-uid]]');
|
return callback('[[error:invalid-uid]]');
|
||||||
@@ -55,7 +92,7 @@ module.exports = function(SocketUser) {
|
|||||||
if (parseInt(meta.config['username:disableEdit'], 10) === 1) {
|
if (parseInt(meta.config['username:disableEdit'], 10) === 1) {
|
||||||
data.username = oldUserData.username;
|
data.username = oldUserData.username;
|
||||||
}
|
}
|
||||||
SocketUser.isAdminOrSelf(socket, data.uid, next);
|
user.isAdminOrSelf(socket.uid, data.uid, next);
|
||||||
},
|
},
|
||||||
function (next) {
|
function (next) {
|
||||||
user.updateProfile(data.uid, data, next);
|
user.updateProfile(data.uid, data, next);
|
||||||
|
|||||||
@@ -101,6 +101,9 @@ module.exports = function(Topics) {
|
|||||||
check(data.tags, meta.config.minimumTagsPerTopic, meta.config.maximumTagsPerTopic, 'not-enough-tags', 'too-many-tags', next);
|
check(data.tags, meta.config.minimumTagsPerTopic, meta.config.maximumTagsPerTopic, 'not-enough-tags', 'too-many-tags', next);
|
||||||
},
|
},
|
||||||
function(next) {
|
function(next) {
|
||||||
|
if (data.content) {
|
||||||
|
data.content = data.content.rtrim();
|
||||||
|
}
|
||||||
check(data.content, meta.config.minimumPostLength, meta.config.maximumPostLength, 'content-too-short', 'content-too-long', next);
|
check(data.content, meta.config.minimumPostLength, meta.config.maximumPostLength, 'content-too-short', 'content-too-long', next);
|
||||||
},
|
},
|
||||||
function(next) {
|
function(next) {
|
||||||
@@ -228,7 +231,7 @@ module.exports = function(Topics) {
|
|||||||
function(filteredData, next) {
|
function(filteredData, next) {
|
||||||
content = filteredData.content || data.content;
|
content = filteredData.content || data.content;
|
||||||
if (content) {
|
if (content) {
|
||||||
content = content.trim();
|
content = content.rtrim();
|
||||||
}
|
}
|
||||||
|
|
||||||
check(content, meta.config.minimumPostLength, meta.config.maximumPostLength, 'content-too-short', 'content-too-long', next);
|
check(content, meta.config.minimumPostLength, meta.config.maximumPostLength, 'content-too-short', 'content-too-long', next);
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var async = require('async'),
|
var async = require('async'),
|
||||||
winston = require('winston'),
|
|
||||||
db = require('../database'),
|
db = require('../database'),
|
||||||
meta = require('../meta'),
|
meta = require('../meta'),
|
||||||
_ = require('underscore'),
|
_ = require('underscore'),
|
||||||
plugins = require('../plugins'),
|
plugins = require('../plugins');
|
||||||
utils = require('../../public/src/utils');
|
|
||||||
|
|
||||||
module.exports = function(Topics) {
|
module.exports = function(Topics) {
|
||||||
|
|
||||||
@@ -248,7 +248,7 @@ module.exports = function(Topics) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Topics.searchTags = function(data, callback) {
|
Topics.searchTags = function(data, callback) {
|
||||||
if (!data) {
|
if (!data || !data.query) {
|
||||||
return callback(null, []);
|
return callback(null, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,9 +256,7 @@ module.exports = function(Topics) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
return callback(null, []);
|
return callback(null, []);
|
||||||
}
|
}
|
||||||
if (data.query === '') {
|
|
||||||
return callback(null, tags);
|
|
||||||
}
|
|
||||||
data.query = data.query.toLowerCase();
|
data.query = data.query.toLowerCase();
|
||||||
|
|
||||||
var matches = [];
|
var matches = [];
|
||||||
@@ -279,8 +277,14 @@ module.exports = function(Topics) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Topics.searchAndLoadTags = function(data, callback) {
|
Topics.searchAndLoadTags = function(data, callback) {
|
||||||
|
var searchResult = {
|
||||||
|
tags: [],
|
||||||
|
matchCount: 0,
|
||||||
|
pageCount: 1
|
||||||
|
};
|
||||||
|
|
||||||
if (!data.query || !data.query.length) {
|
if (!data.query || !data.query.length) {
|
||||||
return callback(null, []);
|
return callback(null, searchResult);
|
||||||
}
|
}
|
||||||
Topics.searchTags(data, function(err, tags) {
|
Topics.searchTags(data, function(err, tags) {
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -307,8 +311,10 @@ module.exports = function(Topics) {
|
|||||||
results.tagData.sort(function(a, b) {
|
results.tagData.sort(function(a, b) {
|
||||||
return b.score - a.score;
|
return b.score - a.score;
|
||||||
});
|
});
|
||||||
|
searchResult.tags = results.tagData;
|
||||||
callback(null, results.tagData);
|
searchResult.matchCount = results.tagData.length;
|
||||||
|
searchResult.pageCount = 1;
|
||||||
|
callback(null, searchResult);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ module.exports = function(Topics) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
require('../socket.io').in('uid_' + uid).emit('event:unread.updateCount', null, count);
|
require('../socket.io').in('uid_' + uid).emit('event:unread.updateCount', count);
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
18
src/user.js
18
src/user.js
@@ -3,14 +3,11 @@
|
|||||||
var async = require('async'),
|
var async = require('async'),
|
||||||
nconf = require('nconf'),
|
nconf = require('nconf'),
|
||||||
gravatar = require('gravatar'),
|
gravatar = require('gravatar'),
|
||||||
validator = require('validator'),
|
|
||||||
|
|
||||||
plugins = require('./plugins'),
|
plugins = require('./plugins'),
|
||||||
db = require('./database'),
|
db = require('./database'),
|
||||||
meta = require('./meta'),
|
meta = require('./meta'),
|
||||||
topics = require('./topics'),
|
topics = require('./topics'),
|
||||||
groups = require('./groups'),
|
|
||||||
Password = require('./password'),
|
|
||||||
privileges = require('./privileges'),
|
privileges = require('./privileges'),
|
||||||
utils = require('../public/src/utils');
|
utils = require('../public/src/utils');
|
||||||
|
|
||||||
@@ -37,6 +34,7 @@ var async = require('async'),
|
|||||||
require('./user/approval')(User);
|
require('./user/approval')(User);
|
||||||
require('./user/invite')(User);
|
require('./user/invite')(User);
|
||||||
require('./user/icon')(User);
|
require('./user/icon')(User);
|
||||||
|
require('./user/password')(User);
|
||||||
|
|
||||||
User.updateLastOnlineTime = function(uid, callback) {
|
User.updateLastOnlineTime = function(uid, callback) {
|
||||||
callback = callback || function() {};
|
callback = callback || function() {};
|
||||||
@@ -158,7 +156,7 @@ var async = require('async'),
|
|||||||
User.getUidByUserslug(userslug, function(err, exists) {
|
User.getUidByUserslug(userslug, function(err, exists) {
|
||||||
callback(err, !! exists);
|
callback(err, !! exists);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
User.getUidByUsername = function(username, callback) {
|
User.getUidByUsername = function(username, callback) {
|
||||||
if (!username) {
|
if (!username) {
|
||||||
@@ -224,6 +222,18 @@ var async = require('async'),
|
|||||||
privileges.users.isAdministrator(uid, callback);
|
privileges.users.isAdministrator(uid, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
User.isAdminOrSelf = function(callerUid, uid, callback) {
|
||||||
|
if (parseInt(callerUid, 10) === parseInt(uid, 10)) {
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
User.isAdministrator(callerUid, function(err, isAdmin) {
|
||||||
|
if (err || !isAdmin) {
|
||||||
|
return callback(err || new Error('[[error:no-privileges]]'));
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
}(exports));
|
}(exports));
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ var async = require('async'),
|
|||||||
db = require('../database'),
|
db = require('../database'),
|
||||||
posts = require('../posts'),
|
posts = require('../posts'),
|
||||||
topics = require('../topics'),
|
topics = require('../topics'),
|
||||||
|
favourites = require('../favourites'),
|
||||||
groups = require('../groups'),
|
groups = require('../groups'),
|
||||||
plugins = require('../plugins'),
|
plugins = require('../plugins'),
|
||||||
batch = require('../batch');
|
batch = require('../batch');
|
||||||
@@ -21,12 +22,35 @@ module.exports = function(User) {
|
|||||||
function(next) {
|
function(next) {
|
||||||
deleteTopics(uid, next);
|
deleteTopics(uid, next);
|
||||||
},
|
},
|
||||||
|
function(next) {
|
||||||
|
deleteVotes(uid, next);
|
||||||
|
},
|
||||||
function(next) {
|
function(next) {
|
||||||
User.deleteAccount(uid, next);
|
User.deleteAccount(uid, next);
|
||||||
}
|
}
|
||||||
], callback);
|
], callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function deleteVotes(uid, callback) {
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
async.parallel({
|
||||||
|
upvotedPids: async.apply(db.getSortedSetRange, 'uid:' + uid + ':upvote', 0, -1),
|
||||||
|
downvotedPids: async.apply(db.getSortedSetRange, 'uid:' + uid + ':downvote', 0, -1)
|
||||||
|
}, next);
|
||||||
|
},
|
||||||
|
function (pids, next) {
|
||||||
|
pids = pids.upvotedPids.concat(pids.downvotedPids).filter(function(pid, index, array) {
|
||||||
|
return pid && array.indexOf(pid) === index;
|
||||||
|
});
|
||||||
|
|
||||||
|
async.eachLimit(pids, 50, function(pid, next) {
|
||||||
|
favourites.unvote(pid, uid, next);
|
||||||
|
}, next);
|
||||||
|
}
|
||||||
|
], callback);
|
||||||
|
}
|
||||||
|
|
||||||
function deletePosts(uid, callback) {
|
function deletePosts(uid, callback) {
|
||||||
deleteSortedSetElements('uid:' + uid + ':posts', posts.purge, callback);
|
deleteSortedSetElements('uid:' + uid + ':posts', posts.purge, callback);
|
||||||
}
|
}
|
||||||
@@ -125,20 +149,20 @@ module.exports = function(User) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function deleteUserIps(uid, callback) {
|
function deleteUserIps(uid, callback) {
|
||||||
db.getSortedSetRange('uid:' + uid + ':ip', 0, -1, function(err, ips) {
|
async.waterfall([
|
||||||
if (err) {
|
function (next) {
|
||||||
return callback(err);
|
db.getSortedSetRange('uid:' + uid + ':ip', 0, -1, next);
|
||||||
}
|
},
|
||||||
|
function (ips, next) {
|
||||||
async.each(ips, function(ip, next) {
|
var keys = ips.map(function(ip) {
|
||||||
db.sortedSetRemove('ip:' + ip + ':uid', uid, next);
|
return 'ip:' + ip + ':uid';
|
||||||
}, function(err) {
|
|
||||||
if (err) {
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
db.delete('uid:' + uid + ':ip', callback);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
db.sortedSetsRemove(keys, uid, next);
|
||||||
|
},
|
||||||
|
function (next) {
|
||||||
|
db.delete('uid:' + uid + ':ip', next);
|
||||||
|
}
|
||||||
|
], callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteUserFromFollowers(uid, callback) {
|
function deleteUserFromFollowers(uid, callback) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ var async = require('async'),
|
|||||||
if (!parseInt(uid, 10)) {
|
if (!parseInt(uid, 10)) {
|
||||||
return callback(null , {read: [], unread: []});
|
return callback(null , {read: [], unread: []});
|
||||||
}
|
}
|
||||||
getNotifications(uid, 10, function(err, notifications) {
|
getNotifications(uid, 0, 9, function(err, notifications) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
@@ -38,8 +38,8 @@ var async = require('async'),
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
UserNotifications.getAll = function(uid, count, callback) {
|
UserNotifications.getAll = function(uid, start, stop, callback) {
|
||||||
getNotifications(uid, count, function(err, notifs) {
|
getNotifications(uid, start, stop, function(err, notifs) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
@@ -52,13 +52,13 @@ var async = require('async'),
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function getNotifications(uid, count, callback) {
|
function getNotifications(uid, start, stop, callback) {
|
||||||
async.parallel({
|
async.parallel({
|
||||||
unread: function(next) {
|
unread: function(next) {
|
||||||
getNotificationsFromSet('uid:' + uid + ':notifications:unread', false, uid, 0, count - 1, next);
|
getNotificationsFromSet('uid:' + uid + ':notifications:unread', false, uid, start, stop, next);
|
||||||
},
|
},
|
||||||
read: function(next) {
|
read: function(next) {
|
||||||
getNotificationsFromSet('uid:' + uid + ':notifications:read', true, uid, 0, count - 1, next);
|
getNotificationsFromSet('uid:' + uid + ':notifications:read', true, uid, start, stop, next);
|
||||||
}
|
}
|
||||||
}, callback);
|
}, callback);
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user