mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-12-16 21:40:23 +01:00
Compare commits
92 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4d4c3cc92 | ||
|
|
3a12ba177a | ||
|
|
28e1538fdb | ||
|
|
eed66c099b | ||
|
|
ece2edf579 | ||
|
|
1961f01cab | ||
|
|
4a214b6ef0 | ||
|
|
dda429ab5d | ||
|
|
15feaafd68 | ||
|
|
14e7907e06 | ||
|
|
b4b483b35a | ||
|
|
79c9bdba7f | ||
|
|
a6837a7869 | ||
|
|
0a485a7ff6 | ||
|
|
bca1602474 | ||
|
|
96ee0a2017 | ||
|
|
25550e18d0 | ||
|
|
154d0160bc | ||
|
|
aefa56221b | ||
|
|
dd40cbc139 | ||
|
|
23db2e5c9e | ||
|
|
eff1b174c0 | ||
|
|
545069b069 | ||
|
|
f767535ce5 | ||
|
|
aeebd069e2 | ||
|
|
d2aa2a9a29 | ||
|
|
d7eb30ccbd | ||
|
|
9bc12f28b4 | ||
|
|
4d11fba20a | ||
|
|
cb6f587f24 | ||
|
|
c647793512 | ||
|
|
caa057ff4d | ||
|
|
43152bdaf9 | ||
|
|
4cdb7ff32b | ||
|
|
7cbb01a78a | ||
|
|
555eddff83 | ||
|
|
a3cab53b73 | ||
|
|
454d5827fd | ||
|
|
186c426691 | ||
|
|
5e1e1ecf6f | ||
|
|
2d3d0f688a | ||
|
|
7975844e4d | ||
|
|
f2b138510e | ||
|
|
1c95ef4060 | ||
|
|
b43e12a42a | ||
|
|
3f793ae902 | ||
|
|
ac56f3a30a | ||
|
|
e2ffac74bc | ||
|
|
1c08ca54c5 | ||
|
|
f1547a7b1f | ||
|
|
746fa93c80 | ||
|
|
5ab1758d28 | ||
|
|
2e4e1df3d9 | ||
|
|
eded61d66e | ||
|
|
d9360da9a5 | ||
|
|
2b7a1b7515 | ||
|
|
1e66116e1d | ||
|
|
a95582b382 | ||
|
|
7860cfdec3 | ||
|
|
30bbea9c74 | ||
|
|
481105d6be | ||
|
|
f939a632a6 | ||
|
|
c05f56d28c | ||
|
|
b844251587 | ||
|
|
b9bd907a6b | ||
|
|
17d86a2a35 | ||
|
|
c70c67394a | ||
|
|
92d3559146 | ||
|
|
0e9a3c3a9f | ||
|
|
41263f0332 | ||
|
|
3747427538 | ||
|
|
b65554ca15 | ||
|
|
00cb15d3c8 | ||
|
|
6690f49c4e | ||
|
|
ff805a704d | ||
|
|
f83be710a0 | ||
|
|
3933549659 | ||
|
|
4993b74c23 | ||
|
|
76e7a98c88 | ||
|
|
999e98e43d | ||
|
|
74af205426 | ||
|
|
9ad82f4907 | ||
|
|
2e6b37e018 | ||
|
|
67070e335e | ||
|
|
22536e694c | ||
|
|
929282a2f7 | ||
|
|
b0092b68c6 | ||
|
|
91446378bd | ||
|
|
dceec0ce46 | ||
|
|
1856e394f3 | ||
|
|
8dc7a0dbbf | ||
|
|
6e17ff7981 |
@@ -1,16 +1,15 @@
|
|||||||
Please support NodeBB development! Check out our IndieGoGo campaign and like, share, and follow us :)
|
Please support NodeBB development! Check out our IndieGoGo campaign and like, share, and follow us :)
|
||||||
[NodeBB Homepage](http://www.nodebb.org/ "NodeBB") # [IndieGoGo campaign](https://www.indiegogo.com/projects/nodebb-the-discussion-platform-of-the-future/ "IndieGoGo") # [Follow on Twitter](http://www.twitter.com/NodeBB/ "NodeBB Twitter") # [Like us on Facebook](http://www.facebook.com/NodeBB/ "NodeBB Facebook")
|
[NodeBB Homepage](http://www.nodebb.org/ "NodeBB") # [Follow on Twitter](http://www.twitter.com/NodeBB/ "NodeBB Twitter") # [Like us on Facebook](http://www.facebook.com/NodeBB/ "NodeBB Facebook")
|
||||||
|
|
||||||
# NodeBB
|
# NodeBB
|
||||||
**NodeBB** is a robust Node.js driven forum built on a redis database. It is powered by web sockets, and is compatible down to IE8.
|
**NodeBB** is a robust Node.js driven forum built on a redis database. It is powered by web sockets, and is compatible down to IE8.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## How can I follow along/contribute?
|
## How can I follow along/contribute?
|
||||||
|
|
||||||
* Our [Indiegogo campaign](https://www.indiegogo.com/projects/nodebb-the-discussion-platform-of-the-future/) is accepting contributions until August 17th, 2013
|
|
||||||
* Our feature roadmap is hosted on the project wiki's [Version History / Roadmap](https://github.com/designcreateplay/NodeBB/wiki/Version-History-%26-Roadmap)
|
* Our feature roadmap is hosted on the project wiki's [Version History / Roadmap](https://github.com/designcreateplay/NodeBB/wiki/Version-History-%26-Roadmap)
|
||||||
* If you are a developer, feel free to check out the source and submit pull requests.
|
* If you are a developer, feel free to check out the source and submit pull requests.
|
||||||
* If you are a designer, NodeBB needs themes! NodeBB will accept any LESS or CSS file and use it in place of the default Twitter Bootstrap theme. Consider extending Bootstrap themes by extending the base bootstrap LESS file.
|
* If you are a designer, NodeBB needs themes! NodeBB will accept any LESS or CSS file and use it in place of the default Twitter Bootstrap theme. Consider extending Bootstrap themes by extending the base bootstrap LESS file.
|
||||||
|
|||||||
84
app.js
84
app.js
@@ -16,45 +16,64 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Configuration setup
|
||||||
|
nconf = require('nconf');
|
||||||
|
nconf.argv().file({ file: __dirname + '/config.json'});
|
||||||
|
|
||||||
var fs = require('fs'),
|
var fs = require('fs'),
|
||||||
nconf = require('nconf'),
|
winston = require('winston'),
|
||||||
pkg = require('./package.json'),
|
pkg = require('./package.json'),
|
||||||
url = require('url');
|
url = require('url'),
|
||||||
|
meta = require('./src/meta.js');
|
||||||
|
|
||||||
// Runtime environment
|
// Runtime environment
|
||||||
global.env = process.env.NODE_ENV || 'production',
|
global.env = process.env.NODE_ENV || 'production',
|
||||||
|
|
||||||
// Configuration setup
|
|
||||||
nconf.argv().file({ file: __dirname + '/config.json'});
|
|
||||||
|
winston.remove(winston.transports.Console);
|
||||||
|
winston.add(winston.transports.Console, {
|
||||||
|
colorize:true
|
||||||
|
});
|
||||||
|
|
||||||
|
winston.add(winston.transports.File, {
|
||||||
|
filename:'error.log',
|
||||||
|
level:'error'
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: remove once https://github.com/flatiron/winston/issues/280 is fixed
|
||||||
|
winston.err = function(err) {
|
||||||
|
winston.error(err.stack);
|
||||||
|
};
|
||||||
|
|
||||||
// Log GNU copyright info along with server info
|
// Log GNU copyright info along with server info
|
||||||
console.log('Info: NodeBB v' + pkg.version + ' Copyright (C) 2013 DesignCreatePlay Inc.');
|
winston.info('NodeBB v' + pkg.version + ' Copyright (C) 2013 DesignCreatePlay Inc.');
|
||||||
console.log('Info: This program comes with ABSOLUTELY NO WARRANTY.');
|
winston.info('This program comes with ABSOLUTELY NO WARRANTY.');
|
||||||
console.log('Info: This is free software, and you are welcome to redistribute it under certain conditions.');
|
winston.info('This is free software, and you are welcome to redistribute it under certain conditions.');
|
||||||
console.log('Info: ===');
|
winston.info('===');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(nconf.get('upgrade')) {
|
if(nconf.get('upgrade')) {
|
||||||
require('./src/upgrade').upgrade();
|
meta.configs.init(function() {
|
||||||
|
require('./src/upgrade').upgrade();
|
||||||
|
});
|
||||||
} else if (!nconf.get('setup') && nconf.get('base_url')) {
|
} else if (!nconf.get('setup') && nconf.get('base_url')) {
|
||||||
nconf.set('url', nconf.get('base_url') + (nconf.get('use_port') ? ':' + nconf.get('port') : '') + nconf.get('relative_path') + '/');
|
nconf.set('url', nconf.get('base_url') + (nconf.get('use_port') ? ':' + nconf.get('port') : '') + nconf.get('relative_path') + '/');
|
||||||
nconf.set('upload_url', nconf.get('url') + 'uploads/');
|
nconf.set('upload_url', nconf.get('url') + 'uploads/');
|
||||||
global.nconf = nconf;
|
|
||||||
|
|
||||||
console.log('Info: Initializing NodeBB v' + pkg.version + ', on port ' + nconf.get('port') + ', using Redis store at ' + nconf.get('redis:host') + ':' + nconf.get('redis:port') + '.');
|
winston.info('Initializing NodeBB v' + pkg.version + ', on port ' + nconf.get('port') + ', using Redis store at ' + nconf.get('redis:host') + ':' + nconf.get('redis:port') + '.');
|
||||||
console.log('Info: Base Configuration OK.');
|
winston.info('Base Configuration OK.');
|
||||||
|
|
||||||
// TODO: Replace this with nconf-redis
|
meta.configs.init(function() {
|
||||||
var meta = require('./src/meta.js');
|
// Initial setup for Redis & Reds
|
||||||
global.config = {};
|
var reds = require('reds');
|
||||||
meta.config.get(function(config) {
|
RDB = require('./src/redis.js');
|
||||||
for(c in config) {
|
reds.createClient = function() {
|
||||||
if (config.hasOwnProperty(c)) {
|
return reds.client || (reds.client = RDB);
|
||||||
global.config[c] = config[c];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var categories = require('./src/categories.js'),
|
var categories = require('./src/categories.js'),
|
||||||
RDB = require('./src/redis.js'),
|
|
||||||
templates = require('./public/src/templates.js'),
|
templates = require('./public/src/templates.js'),
|
||||||
webserver = require('./src/webserver.js'),
|
webserver = require('./src/webserver.js'),
|
||||||
websockets = require('./src/websockets.js'),
|
websockets = require('./src/websockets.js'),
|
||||||
@@ -74,7 +93,7 @@ if(nconf.get('upgrade')) {
|
|||||||
templates.init([
|
templates.init([
|
||||||
'header', 'footer', 'logout', 'outgoing', 'admin/header', 'admin/footer', 'admin/index',
|
'header', 'footer', 'logout', 'outgoing', 'admin/header', 'admin/footer', 'admin/index',
|
||||||
'emails/reset', 'emails/reset_plaintext', 'emails/email_confirm', 'emails/email_confirm_plaintext',
|
'emails/reset', 'emails/reset_plaintext', 'emails/email_confirm', 'emails/email_confirm_plaintext',
|
||||||
'emails/header', 'emails/footer', 'install/header', 'install/footer', 'install/redis',
|
'emails/header', 'emails/footer',
|
||||||
|
|
||||||
'noscript/header', 'noscript/home', 'noscript/category', 'noscript/topic'
|
'noscript/header', 'noscript/home', 'noscript/category', 'noscript/topic'
|
||||||
]);
|
]);
|
||||||
@@ -83,10 +102,10 @@ if(nconf.get('upgrade')) {
|
|||||||
|
|
||||||
//setup scripts to be moved outside of the app in future.
|
//setup scripts to be moved outside of the app in future.
|
||||||
function setup_categories() {
|
function setup_categories() {
|
||||||
console.log('Info: Checking categories...');
|
winston.info('Checking categories...');
|
||||||
categories.getAllCategories(function(data) {
|
categories.getAllCategories(function(data) {
|
||||||
if (data.categories.length === 0) {
|
if (data.categories.length === 0) {
|
||||||
console.log('Info: Setting up default categories...');
|
winston.info('Setting up default categories...');
|
||||||
|
|
||||||
fs.readFile(config.ROOT_DIRECTORY + '/install/data/categories.json', function(err, default_categories) {
|
fs.readFile(config.ROOT_DIRECTORY + '/install/data/categories.json', function(err, default_categories) {
|
||||||
default_categories = JSON.parse(default_categories);
|
default_categories = JSON.parse(default_categories);
|
||||||
@@ -96,27 +115,26 @@ if(nconf.get('upgrade')) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
console.log('Info: Hardcoding uid 1 as an admin');
|
winston.info('Hardcoding uid 1 as an admin');
|
||||||
var user = require('./src/user.js');
|
var user = require('./src/user.js');
|
||||||
user.makeAdministrator(1);
|
user.makeAdministrator(1);
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
console.log('Info: Categories OK. Found ' + data.categories.length + ' categories.');
|
winston.info('Categories OK. Found ' + data.categories.length + ' categories.');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setup_categories();
|
setup_categories();
|
||||||
}(global.configuration));
|
}(global.configuration));
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// New install, ask setup questions
|
// New install, ask setup questions
|
||||||
if (nconf.get('setup')) console.log('Info: NodeBB Setup Triggered via Command Line');
|
if (nconf.get('setup')) winston.info('NodeBB Setup Triggered via Command Line');
|
||||||
else console.log('Info: Configuration not found, starting NodeBB setup');
|
else winston.info('Configuration not found, starting NodeBB setup');
|
||||||
|
|
||||||
var install = require('./src/install');
|
var install = require('./src/install');
|
||||||
|
|
||||||
@@ -128,7 +146,7 @@ if(nconf.get('upgrade')) {
|
|||||||
|
|
||||||
install.setup(function(err) {
|
install.setup(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log('Error: There was a problem completing NodeBB setup: ', err.message);
|
winston.error('There was a problem completing NodeBB setup: ', err.message);
|
||||||
} else {
|
} else {
|
||||||
if (!nconf.get('setup')) {
|
if (!nconf.get('setup')) {
|
||||||
process.stdout.write(
|
process.stdout.write(
|
||||||
@@ -136,7 +154,7 @@ if(nconf.get('upgrade')) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
process.exit();
|
process.exit();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "nodebb",
|
"name": "nodebb",
|
||||||
"license": "GPLv3 or later",
|
"license": "GPLv3 or later",
|
||||||
"description": "NodeBB Forum",
|
"description": "NodeBB Forum",
|
||||||
"version": "0.0.5",
|
"version": "0.0.6",
|
||||||
"homepage": "http://www.nodebb.org",
|
"homepage": "http://www.nodebb.org",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -33,7 +33,9 @@
|
|||||||
"sitemap": "~0.6.0",
|
"sitemap": "~0.6.0",
|
||||||
"cheerio": "~0.12.0",
|
"cheerio": "~0.12.0",
|
||||||
"request": "~2.25.0",
|
"request": "~2.25.0",
|
||||||
"reds": "~0.2.4"
|
"reds": "~0.2.4",
|
||||||
|
"winston": "~0.7.2",
|
||||||
|
"nodebb-plugin-mentions": "~0.1.0"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/designcreateplay/NodeBB/issues"
|
"url": "https://github.com/designcreateplay/NodeBB/issues"
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
@import "mixins";
|
@import "mixins";
|
||||||
|
|
||||||
|
html {
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
/*background: #fdfdfd;*/ // port to default theme when it is implemented.
|
/*background: #fdfdfd;*/ // port to default theme when it is implemented.
|
||||||
-webkit-transition: margin-bottom 250ms ease;
|
-webkit-transition: margin-bottom 250ms ease;
|
||||||
@@ -38,7 +42,7 @@ button, a {
|
|||||||
vertical-align: 17%;
|
vertical-align: 17%;
|
||||||
}
|
}
|
||||||
.nav .badge {
|
.nav .badge {
|
||||||
vertical-align: 10%;
|
vertical-align: 2%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#alert_window {
|
#alert_window {
|
||||||
@@ -197,6 +201,12 @@ footer.footer {
|
|||||||
font-weight:bold;
|
font-weight:bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.account-block {
|
||||||
|
div {
|
||||||
|
padding-bottom:10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.account-picture-block{
|
.account-picture-block{
|
||||||
display:inline-block;
|
display:inline-block;
|
||||||
vertical-align:top;
|
vertical-align:top;
|
||||||
@@ -213,7 +223,6 @@ footer.footer {
|
|||||||
|
|
||||||
.user-profile-picture {
|
.user-profile-picture {
|
||||||
width:128px;
|
width:128px;
|
||||||
margin-bottom:10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-picture-label {
|
.user-picture-label {
|
||||||
@@ -235,6 +244,7 @@ footer.footer {
|
|||||||
color: #333;
|
color: #333;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
overflow:hidden;
|
||||||
p {
|
p {
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
@@ -435,14 +445,33 @@ body .navbar .nodebb-inline-block {
|
|||||||
padding-bottom:20px;
|
padding-bottom:20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.dropdown-toggle {
|
.dropdown-toggle {
|
||||||
i {
|
i {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|
||||||
|
@-webkit-keyframes glow
|
||||||
|
{
|
||||||
|
from {text-shadow: 0 0 5px #aaf, 0 0 5px #aaf, 0 0 5px #aaf;}
|
||||||
|
50% {text-shadow: 0 0 10px #aaf, 0 0 10px #aaf, 0 0 10px #aaf;}
|
||||||
|
to {text-shadow: 0 0 5px #aaf, 0 0 5px #aaf, 0 0 5px #aaf;}
|
||||||
|
}
|
||||||
|
@keyframes glow
|
||||||
|
{
|
||||||
|
from {text-shadow: 0 0 5px #aaf, 0 0 5px #aaf, 0 0 5px #aaf;}
|
||||||
|
50% {text-shadow: 0 0 10px #aaf, 0 0 10px #aaf, 0 0 10px #aaf;}
|
||||||
|
to {text-shadow: 0 0 5px #aaf, 0 0 5px #aaf, 0 0 5px #aaf;}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
color: #558;
|
color: #558;
|
||||||
|
|
||||||
text-shadow: 0 0 1em #aaf, 0 0 1em #aaf, 0 0 1em #aaf;
|
text-shadow: 0 0 1em #aaf, 0 0 1em #aaf, 0 0 1em #aaf;
|
||||||
|
-webkit-animation:glow 1.5s infinite linear;
|
||||||
|
animation:glow 1.5s infinite linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,16 +552,23 @@ body .navbar .nodebb-inline-block {
|
|||||||
visibility: visible;
|
visibility: visible;
|
||||||
|
|
||||||
.btn-toolbar {
|
.btn-toolbar {
|
||||||
width: 90%;
|
&.formatting-bar {
|
||||||
margin: 0 auto;
|
width: 90%;
|
||||||
|
margin: 0 auto 8px auto;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
color: white;
|
color: white;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.action-bar {
|
||||||
|
width: 90%;
|
||||||
|
margin: 8px auto 0 auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
@@ -543,7 +579,8 @@ body .navbar .nodebb-inline-block {
|
|||||||
-webkit-border-radius: 0px;
|
-webkit-border-radius: 0px;
|
||||||
-moz-border-radius: 0px;
|
-moz-border-radius: 0px;
|
||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
margin: 1% 1% 2% 1%;
|
margin: 5px auto 10px auto;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
@@ -552,41 +589,43 @@ body .navbar .nodebb-inline-block {
|
|||||||
padding: 0.5em;
|
padding: 0.5em;
|
||||||
display: block;
|
display: block;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
margin: 0.5em auto;
|
margin: 0em auto;
|
||||||
resize: none;
|
resize: none;
|
||||||
color: white;
|
color: white;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#imagedrop {
|
.imagedrop {
|
||||||
text-align:center;
|
text-align: center;
|
||||||
color:white;
|
color: white;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height:230px;
|
height: 214px;
|
||||||
line-height:230px;
|
line-height: 214px;
|
||||||
font-size:20px;
|
font-size: 20px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#imagelist {
|
.imagelist {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 5px;
|
bottom: 50px;
|
||||||
left: 0px;
|
left: 5%;
|
||||||
padding-left:2em;
|
|
||||||
|
div {
|
||||||
div {
|
margin-right:5px;
|
||||||
margin-right:5px;
|
}
|
||||||
}
|
|
||||||
span {
|
span {
|
||||||
line-height:20px;
|
line-height:20px;
|
||||||
float:left;
|
float:left;
|
||||||
}
|
}
|
||||||
button {
|
|
||||||
padding-left:5px;
|
button {
|
||||||
}
|
padding-left:5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -827,7 +866,7 @@ body .navbar .nodebb-inline-block {
|
|||||||
.form-search {
|
.form-search {
|
||||||
float: left;
|
float: left;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
margin-bottom:0px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-result-post {
|
.search-result-post {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.profile-block, .post-block {
|
.profile-block, .post-block {
|
||||||
|
position:relative;
|
||||||
border: 1px solid rgba(0, 0, 0, 0.06);
|
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
@@ -98,12 +99,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
&.deleted {
|
&.deleted {
|
||||||
-moz-opacity: 0.30;
|
-moz-opacity: 0.30;
|
||||||
opacity: 0.30;
|
opacity: 0.30;
|
||||||
}
|
}
|
||||||
/*http://stackoverflow.com/questions/11037517/bootstrap-making-responsive-changes-to-layout*/
|
/*http://stackoverflow.com/questions/11037517/bootstrap-making-responsive-changes-to-layout*/
|
||||||
@media (max-width: 979px) {
|
@media (max-width: 979px) {
|
||||||
|
|
||||||
|
|
||||||
.span12-tablet {
|
.span12-tablet {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
margin-left:0px;
|
margin-left:0px;
|
||||||
@@ -111,14 +116,42 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 979px) {
|
||||||
|
.speech-bubble:after
|
||||||
|
{
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 9px;
|
||||||
|
left: -7px;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 7px 7px 7px 0;
|
||||||
|
border-color: transparent #FFFFFF;
|
||||||
|
display: block;
|
||||||
|
width: 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.speech-bubble:before
|
||||||
|
{
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 9px;
|
||||||
|
left: -8px;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 7px 7px 7px 0;
|
||||||
|
border-color: transparent rgba(0, 0, 0, 0.125);
|
||||||
|
display: block;
|
||||||
|
width: 0;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.main-post {
|
.main-post {
|
||||||
h3 {
|
h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
.topic-title {
|
.topic-title {
|
||||||
width: auto;
|
width: auto;
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow:ellipsis;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ var ajaxify = {};
|
|||||||
|
|
||||||
|
|
||||||
(function($) {
|
(function($) {
|
||||||
|
|
||||||
var location = document.location || window.location,
|
var location = document.location || window.location,
|
||||||
rootUrl = location.protocol + '//' + (location.hostname || location.host) + (location.port ? ':' + location.port : ''),
|
rootUrl = location.protocol + '//' + (location.hostname || location.host) + (location.port ? ':' + location.port : ''),
|
||||||
content = null;
|
content = null;
|
||||||
@@ -26,6 +26,7 @@ var ajaxify = {};
|
|||||||
};
|
};
|
||||||
|
|
||||||
ajaxify.go = function(url, callback, template, quiet) {
|
ajaxify.go = function(url, callback, template, quiet) {
|
||||||
|
$(window).off('scroll');
|
||||||
// leave room and join global
|
// leave room and join global
|
||||||
app.enter_room('global');
|
app.enter_room('global');
|
||||||
|
|
||||||
@@ -38,14 +39,14 @@ var ajaxify = {};
|
|||||||
}
|
}
|
||||||
|
|
||||||
var tpl_url = templates.get_custom_map(url.split('?')[0]);
|
var tpl_url = templates.get_custom_map(url.split('?')[0]);
|
||||||
|
|
||||||
if (tpl_url == false && !templates[url]) {
|
if (tpl_url == false && !templates[url]) {
|
||||||
if(url === '' || url === '/') {
|
if(url === '' || url === '/') {
|
||||||
tpl_url = 'home';
|
tpl_url = 'home';
|
||||||
} else {
|
} else {
|
||||||
tpl_url = url.split('/')[0].split('?')[0];
|
tpl_url = url.split('/')[0].split('?')[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (templates[url]) {
|
} else if (templates[url]) {
|
||||||
tpl_url = url;
|
tpl_url = url;
|
||||||
}
|
}
|
||||||
@@ -66,9 +67,9 @@ var ajaxify = {};
|
|||||||
if (callback) {
|
if (callback) {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.process_page();
|
app.process_page();
|
||||||
|
|
||||||
jQuery('#content, #footer').stop(true, true).fadeIn(200, function() {
|
jQuery('#content, #footer').stop(true, true).fadeIn(200, function() {
|
||||||
if(window.location.hash)
|
if(window.location.hash)
|
||||||
hash = window.location.hash;
|
hash = window.location.hash;
|
||||||
@@ -76,11 +77,9 @@ var ajaxify = {};
|
|||||||
app.scrollToPost(hash.substr(1));
|
app.scrollToPost(hash.substr(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
}, url, template);
|
utils.refreshTitle(url);
|
||||||
|
|
||||||
socket.emit('api:meta.buildTitle', url, function(title) {
|
}, url, template);
|
||||||
document.title = title;
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -95,12 +94,15 @@ var ajaxify = {};
|
|||||||
|
|
||||||
// Enhancing all anchors to ajaxify...
|
// Enhancing all anchors to ajaxify...
|
||||||
$(document.body).on('click', 'a', function(e) {
|
$(document.body).on('click', 'a', function(e) {
|
||||||
if (this.href == window.location.href + "#") return;
|
|
||||||
if(this.href.slice(-1) === "#") return;
|
function hrefEmpty(href) {
|
||||||
|
return href == 'javascript:;' || href == window.location.href + "#" || href.slice(-1) === "#";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hrefEmpty(this.href)) return;
|
||||||
|
|
||||||
var url = this.href.replace(rootUrl +'/', '');
|
var url = this.href.replace(rootUrl +'/', '');
|
||||||
|
|
||||||
if (this.target !== '') return;
|
if (this.target !== '') return;
|
||||||
|
|
||||||
if (!e.ctrlKey && e.which === 1) {
|
if (!e.ctrlKey && e.which === 1) {
|
||||||
@@ -127,7 +129,7 @@ var ajaxify = {};
|
|||||||
|
|
||||||
script.type = "text/javascript";
|
script.type = "text/javascript";
|
||||||
try {
|
try {
|
||||||
script.appendChild(document.createTextNode(data));
|
script.appendChild(document.createTextNode(data));
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
script.text = data;
|
script.text = data;
|
||||||
}
|
}
|
||||||
@@ -163,5 +165,5 @@ var ajaxify = {};
|
|||||||
evalScript(scripts[i]);
|
evalScript(scripts[i]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}(jQuery));
|
}(jQuery));
|
||||||
@@ -8,18 +8,18 @@ var socket,
|
|||||||
var showWelcomeMessage = false;
|
var showWelcomeMessage = false;
|
||||||
|
|
||||||
function loadConfig() {
|
function loadConfig() {
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: RELATIVE_PATH + '/api/config',
|
url: RELATIVE_PATH + '/api/config',
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
API_URL = data.api_url;
|
API_URL = data.api_url;
|
||||||
|
|
||||||
config = data;
|
config = data;
|
||||||
socket = io.connect(config.socket.address + (config.socket.port ? ':' + config.socket.port : ''));
|
socket = io.connect(config.socket.address + (config.socket.port ? ':' + config.socket.port : ''));
|
||||||
|
|
||||||
var reconnecting = false;
|
var reconnecting = false;
|
||||||
var reconnectTries = 0;
|
var reconnectTries = 0;
|
||||||
|
|
||||||
socket.on('event:connect', function(data) {
|
socket.on('event:connect', function(data) {
|
||||||
console.log('connected to nodebb socket: ', data);
|
console.log('connected to nodebb socket: ', data);
|
||||||
app.username = data.username;
|
app.username = data.username;
|
||||||
@@ -29,11 +29,7 @@ var socket,
|
|||||||
socket.on('event:alert', function(data) {
|
socket.on('event:alert', function(data) {
|
||||||
app.alert(data);
|
app.alert(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('event:consolelog', function(data) {
|
|
||||||
console.log(data);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on('connect', function(data){
|
socket.on('connect', function(data){
|
||||||
if(reconnecting) {
|
if(reconnecting) {
|
||||||
setTimeout(function(){
|
setTimeout(function(){
|
||||||
@@ -50,28 +46,28 @@ var socket,
|
|||||||
socket.emit('api:updateHeader', { fields: ['username', 'picture', 'userslug'] });
|
socket.emit('api:updateHeader', { fields: ['username', 'picture', 'userslug'] });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('reconnecting', function(data) {
|
socket.on('reconnecting', function(data) {
|
||||||
function showDisconnectModal() {
|
function showDisconnectModal() {
|
||||||
$('#disconnect-modal').modal({
|
$('#disconnect-modal').modal({
|
||||||
backdrop:'static',
|
backdrop:'static',
|
||||||
show:true
|
show:true
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#reload-button').on('click',function(){
|
$('#reload-button').on('click',function(){
|
||||||
$('#disconnect-modal').modal('hide');
|
$('#disconnect-modal').modal('hide');
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
reconnecting = true;
|
reconnecting = true;
|
||||||
reconnectTries++;
|
reconnectTries++;
|
||||||
|
|
||||||
if(reconnectTries > 4) {
|
if(reconnectTries > 4) {
|
||||||
showDisconnectModal();
|
showDisconnectModal();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.alert({
|
app.alert({
|
||||||
alert_id: 'connection_alert',
|
alert_id: 'connection_alert',
|
||||||
title: 'Reconnecting',
|
title: 'Reconnecting',
|
||||||
@@ -80,15 +76,15 @@ var socket,
|
|||||||
timeout: 5000
|
timeout: 5000
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:user.get_online_users', function(users) {
|
socket.on('api:user.get_online_users', function(users) {
|
||||||
jQuery('.username-field').each(function() {
|
jQuery('.username-field').each(function() {
|
||||||
if (this.processed === true)
|
if (this.processed === true)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var el = jQuery(this),
|
var el = jQuery(this),
|
||||||
uid = el.parents('li').attr('data-uid');
|
uid = el.parents('li').attr('data-uid');
|
||||||
|
|
||||||
if (uid && jQuery.inArray(uid, users) !== -1) {
|
if (uid && jQuery.inArray(uid, users) !== -1) {
|
||||||
el.find('i').remove();
|
el.find('i').remove();
|
||||||
el.prepend('<i class="icon-circle"></i>');
|
el.prepend('<i class="icon-circle"></i>');
|
||||||
@@ -96,19 +92,19 @@ var socket,
|
|||||||
el.find('i').remove();
|
el.find('i').remove();
|
||||||
el.prepend('<i class="icon-circle-blank"></i>');
|
el.prepend('<i class="icon-circle-blank"></i>');
|
||||||
}
|
}
|
||||||
|
|
||||||
el.processed = true;
|
el.processed = true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.enter_room('global');
|
app.enter_room('global');
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
async: false
|
async: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// takes a string like 1000 and returns 1,000
|
// takes a string like 1000 and returns 1,000
|
||||||
app.addCommas = function(text) {
|
app.addCommas = function(text) {
|
||||||
return text.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
|
return text.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
|
||||||
@@ -125,14 +121,14 @@ var socket,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// use unique alert_id to have multiple alerts visible at a time, use the same alert_id to fade out the current instance
|
// use unique alert_id to have multiple alerts visible at a time, use the same alert_id to fade out the current instance
|
||||||
// type : error, success, info, warning/notify
|
// type : error, success, info, warning/notify
|
||||||
// title = bolded title text
|
// title = bolded title text
|
||||||
// message = alert message content
|
// message = alert message content
|
||||||
// timeout default = permanent
|
// timeout default = permanent
|
||||||
// location : alert_window (default) or content
|
// location : alert_window (default) or content
|
||||||
app.alert = function(params) {
|
app.alert = function(params) {
|
||||||
var alert_id = 'alert_button_' + ((params.alert_id) ? params.alert_id : new Date().getTime());
|
var alert_id = 'alert_button_' + ((params.alert_id) ? params.alert_id : new Date().getTime());
|
||||||
|
|
||||||
var alert = $('#'+alert_id);
|
var alert = $('#'+alert_id);
|
||||||
|
|
||||||
@@ -142,7 +138,7 @@ var socket,
|
|||||||
$(this).remove();
|
$(this).remove();
|
||||||
});
|
});
|
||||||
}, timeout);
|
}, timeout);
|
||||||
|
|
||||||
$(div).attr('timeoutId', timeoutId);
|
$(div).attr('timeoutId', timeoutId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +146,7 @@ var socket,
|
|||||||
alert.find('strong').html(params.title);
|
alert.find('strong').html(params.title);
|
||||||
alert.find('p').html(params.message);
|
alert.find('p').html(params.message);
|
||||||
alert.attr('class', "alert toaster-alert " + ((params.type=='warning') ? '' : "alert-" + params.type));
|
alert.attr('class', "alert toaster-alert " + ((params.type=='warning') ? '' : "alert-" + params.type));
|
||||||
|
|
||||||
clearTimeout(alert.attr('timeoutId'));
|
clearTimeout(alert.attr('timeoutId'));
|
||||||
startTimeout(alert, params.timeout);
|
startTimeout(alert, params.timeout);
|
||||||
}
|
}
|
||||||
@@ -164,7 +160,7 @@ var socket,
|
|||||||
strong.innerHTML = params.title;
|
strong.innerHTML = params.title;
|
||||||
|
|
||||||
div.className = "alert toaster-alert " + ((params.type=='warning') ? '' : "alert-" + params.type);
|
div.className = "alert toaster-alert " + ((params.type=='warning') ? '' : "alert-" + params.type);
|
||||||
|
|
||||||
div.setAttribute('id', alert_id);
|
div.setAttribute('id', alert_id);
|
||||||
div.appendChild(button);
|
div.appendChild(button);
|
||||||
div.appendChild(strong);
|
div.appendChild(strong);
|
||||||
@@ -176,7 +172,7 @@ var socket,
|
|||||||
div.parentNode.removeChild(div);
|
div.parentNode.removeChild(div);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.location == null)
|
if (params.location == null)
|
||||||
params.location = 'alert_window';
|
params.location = 'alert_window';
|
||||||
|
|
||||||
jQuery('#'+params.location).prepend(jQuery(div).fadeIn('100'));
|
jQuery('#'+params.location).prepend(jQuery(div).fadeIn('100'));
|
||||||
@@ -220,18 +216,17 @@ var socket,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
app.current_room = null;
|
app.current_room = null;
|
||||||
app.enter_room = function(room) {
|
app.enter_room = function(room) {
|
||||||
|
|
||||||
if(socket) {
|
if(socket) {
|
||||||
if (app.current_room === room)
|
if (app.current_room === room)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
socket.emit('event:enter_room', {
|
socket.emit('event:enter_room', {
|
||||||
'enter': room,
|
'enter': room,
|
||||||
'leave': app.current_room
|
'leave': app.current_room
|
||||||
});
|
});
|
||||||
|
|
||||||
app.current_room = room;
|
app.current_room = room;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -242,7 +237,7 @@ var socket,
|
|||||||
jQuery('.post-row').each(function() {
|
jQuery('.post-row').each(function() {
|
||||||
uids.push(this.getAttribute('data-uid'));
|
uids.push(this.getAttribute('data-uid'));
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.emit('api:user.get_online_users', uids);
|
socket.emit('api:user.get_online_users', uids);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,7 +253,7 @@ var socket,
|
|||||||
var url = window.location.href,
|
var url = window.location.href,
|
||||||
parts = url.split('/'),
|
parts = url.split('/'),
|
||||||
active = parts[parts.length-1];
|
active = parts[parts.length-1];
|
||||||
|
|
||||||
jQuery('#main-nav li').removeClass('active');
|
jQuery('#main-nav li').removeClass('active');
|
||||||
if(active) {
|
if(active) {
|
||||||
jQuery('#main-nav li a').each(function() {
|
jQuery('#main-nav li a').each(function() {
|
||||||
@@ -273,7 +268,7 @@ var socket,
|
|||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
window.scrollTo(0, 1); // rehide address bar on mobile after page load completes.
|
window.scrollTo(0, 1); // rehide address bar on mobile after page load completes.
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +281,7 @@ var socket,
|
|||||||
timeout: 5000
|
timeout: 5000
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(showWelcomeMessage) {
|
if(showWelcomeMessage) {
|
||||||
showWelcomeMessage = false;
|
showWelcomeMessage = false;
|
||||||
if(document.readyState !== 'complete') {
|
if(document.readyState !== 'complete') {
|
||||||
@@ -330,36 +325,54 @@ var socket,
|
|||||||
if(app.infiniteLoaderActive)
|
if(app.infiniteLoaderActive)
|
||||||
return;
|
return;
|
||||||
app.infiniteLoaderActive = true;
|
app.infiniteLoaderActive = true;
|
||||||
socket.emit('api:topic.loadMore', {
|
socket.emit('api:topic.loadMore', {
|
||||||
tid: tid,
|
tid: tid,
|
||||||
after: document.querySelectorAll('#post-container li[data-pid]').length
|
after: document.querySelectorAll('#post-container li[data-pid]').length
|
||||||
}, function(data) {
|
}, function(data) {
|
||||||
app.infiniteLoaderActive = false;
|
app.infiniteLoaderActive = false;
|
||||||
if(data.posts.length) {
|
if(data.posts.length) {
|
||||||
app.createNewPosts(data);
|
app.createNewPosts(data);
|
||||||
if(callback)
|
|
||||||
callback();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(callback)
|
||||||
|
callback(data.posts);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
app.scrollToPost = function(pid) {
|
app.scrollToPost = function(pid) {
|
||||||
|
|
||||||
if(!pid)
|
if(!pid)
|
||||||
return;
|
return;
|
||||||
var container = $(document.body),
|
|
||||||
scrollTo = $('#post_anchor_' + pid);
|
|
||||||
|
|
||||||
if(!scrollTo.length) {
|
var container = $(document.body),
|
||||||
var tid = $('#post-container').attr('data-tid');
|
scrollTo = $('#post_anchor_' + pid),
|
||||||
app.loadMorePosts(tid, function() {
|
tid = $('#post-container').attr('data-tid');
|
||||||
app.scrollToPost(pid);
|
|
||||||
|
function animateScroll() {
|
||||||
|
$('body,html').animate({
|
||||||
|
scrollTop: scrollTo.offset().top - container.offset().top + container.scrollTop() - $('#header-menu').height()
|
||||||
});
|
});
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
container.animate({
|
if(!scrollTo.length && tid) {
|
||||||
scrollTop: scrollTo.offset().top - container.offset().top + container.scrollTop() - $('#header-menu').height()
|
|
||||||
});
|
var intervalID = setInterval(function() {
|
||||||
|
app.loadMorePosts(tid, function(posts) {
|
||||||
|
scrollTo = $('#post_anchor_' + pid);
|
||||||
|
|
||||||
|
if(tid && scrollTo.length) {
|
||||||
|
animateScroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!posts.length || scrollTo.length)
|
||||||
|
clearInterval(intervalID);
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
} else if(tid) {
|
||||||
|
animateScroll();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jQuery('document').ready(function() {
|
jQuery('document').ready(function() {
|
||||||
@@ -428,6 +441,6 @@ var socket,
|
|||||||
el.off('mousemove');
|
el.off('mousemove');
|
||||||
onTouchEnd();
|
onTouchEnd();
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
|
|||||||
@@ -5,11 +5,7 @@
|
|||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
var rep = $('#reputation');
|
app.addCommasToNumbers();
|
||||||
rep.html(app.addCommas(rep.html()));
|
|
||||||
|
|
||||||
var postcount = $('#postcount');
|
|
||||||
postcount.html(app.addCommas(postcount.html()));
|
|
||||||
|
|
||||||
var followBtn = $('#follow-btn');
|
var followBtn = $('#follow-btn');
|
||||||
var unfollowBtn = $('#unfollow-btn');
|
var unfollowBtn = $('#unfollow-btn');
|
||||||
|
|||||||
@@ -2,19 +2,35 @@
|
|||||||
var yourid = templates.get('yourid'),
|
var yourid = templates.get('yourid'),
|
||||||
theirid = templates.get('theirid');
|
theirid = templates.get('theirid');
|
||||||
|
|
||||||
|
|
||||||
|
function createMenu() {
|
||||||
|
var userslug = $('.account-username-box').attr('data-userslug');
|
||||||
|
var links = $('<div class="account-sub-links inline-block pull-right">\
|
||||||
|
<span id="settingsLink" class="pull-right"><a href="/users/' + userslug + '/settings">settings</a></span>\
|
||||||
|
<span id="favouritesLink" class="pull-right"><a href="/users/' + userslug + '/favourites">favourites</a></span>\
|
||||||
|
<span class="pull-right"><a href="/users/' + userslug + '/followers">followers</a></span>\
|
||||||
|
<span class="pull-right"><a href="/users/' + userslug + '/following">following</a></span>\
|
||||||
|
<span id="editLink" class="pull-right"><a href="/users/' + userslug + '/edit">edit</a></span>\
|
||||||
|
</div>');
|
||||||
|
|
||||||
|
$('.account-username-box').append(links);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
createMenu();
|
||||||
|
|
||||||
var editLink = $('#editLink');
|
var editLink = $('#editLink');
|
||||||
var settingsLink = $('#settingsLink');
|
var settingsLink = $('#settingsLink');
|
||||||
|
var favouritesLink = $('#favouritesLink');
|
||||||
|
|
||||||
if(yourid === "0") {
|
if(yourid === "0" || yourid !== theirid) {
|
||||||
editLink.hide();
|
|
||||||
settingsLink.hide();
|
|
||||||
}
|
|
||||||
else if(yourid !== theirid) {
|
|
||||||
editLink.hide();
|
editLink.hide();
|
||||||
settingsLink.hide();
|
settingsLink.hide();
|
||||||
|
favouritesLink.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}());
|
}());
|
||||||
@@ -8,6 +8,11 @@
|
|||||||
return (parent.attr('data-admin') !== "0");
|
return (parent.attr('data-admin') !== "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isUserBanned(element) {
|
||||||
|
var parent = $(element).parents('.users-box');
|
||||||
|
return (parent.attr('data-banned') !== "" && parent.attr('data-banned') !== "0");
|
||||||
|
}
|
||||||
|
|
||||||
function getUID(element) {
|
function getUID(element) {
|
||||||
var parent = $(element).parents('.users-box');
|
var parent = $(element).parents('.users-box');
|
||||||
return parent.attr('data-uid');
|
return parent.attr('data-uid');
|
||||||
@@ -34,6 +39,20 @@
|
|||||||
deleteBtn.show();
|
deleteBtn.show();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jQuery('.ban-btn').each(function(index, element) {
|
||||||
|
var banBtn = $(element);
|
||||||
|
var isAdmin = isUserAdmin(banBtn);
|
||||||
|
var isBanned = isUserBanned(banBtn);
|
||||||
|
|
||||||
|
if(isAdmin)
|
||||||
|
banBtn.addClass('disabled');
|
||||||
|
else if(isBanned)
|
||||||
|
banBtn.addClass('btn-warning');
|
||||||
|
else
|
||||||
|
banBtn.removeClass('btn-warning');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
jQuery('.admin-btn').on('click', function() {
|
jQuery('.admin-btn').on('click', function() {
|
||||||
var adminBtn = $(this);
|
var adminBtn = $(this);
|
||||||
var isAdmin = isUserAdmin(adminBtn);
|
var isAdmin = isUserAdmin(adminBtn);
|
||||||
@@ -74,6 +93,30 @@
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jQuery('.ban-btn').on('click', function() {
|
||||||
|
var banBtn = $(this);
|
||||||
|
var isAdmin = isUserAdmin(banBtn);
|
||||||
|
var isBanned = isUserBanned(banBtn);
|
||||||
|
var parent = banBtn.parents('.users-box');
|
||||||
|
var uid = getUID(banBtn);
|
||||||
|
|
||||||
|
if(!isAdmin) {
|
||||||
|
if(isBanned) {
|
||||||
|
socket.emit('api:admin.user.unbanUser', uid);
|
||||||
|
banBtn.removeClass('btn-warning');
|
||||||
|
parent.attr('data-banned', 0);
|
||||||
|
} else {
|
||||||
|
bootbox.confirm('Do you really want to ban "' + parent.attr('data-username') +'"?', function(confirm) {
|
||||||
|
socket.emit('api:admin.user.banUser', uid);
|
||||||
|
banBtn.addClass('btn-warning');
|
||||||
|
parent.attr('data-banned', 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -171,9 +214,9 @@
|
|||||||
$('#load-more-users-btn').on('click', loadMoreUsers);
|
$('#load-more-users-btn').on('click', loadMoreUsers);
|
||||||
|
|
||||||
$(window).off('scroll').on('scroll', function() {
|
$(window).off('scroll').on('scroll', function() {
|
||||||
var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
|
var bottom = ($(document).height() - $(window).height()) * 0.9;
|
||||||
|
|
||||||
if (document.body.scrollTop > bottom && !loadingMoreUsers) {
|
if ($(window).scrollTop() > bottom && !loadingMoreUsers) {
|
||||||
loadMoreUsers();
|
loadMoreUsers();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
facebook_url = templates.get('facebook-share-url'),
|
facebook_url = templates.get('facebook-share-url'),
|
||||||
google_url = templates.get('google-share-url'),
|
google_url = templates.get('google-share-url'),
|
||||||
loadingMoreTopics = false;
|
loadingMoreTopics = false;
|
||||||
|
|
||||||
app.enter_room(room);
|
app.enter_room(room);
|
||||||
|
|
||||||
twitterEl.addEventListener('click', function() {
|
twitterEl.addEventListener('click', function() {
|
||||||
@@ -36,7 +36,6 @@
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
function onNewTopic(data) {
|
function onNewTopic(data) {
|
||||||
|
|
||||||
var html = templates.prepare(templates['category'].blocks['topics']).parse({ topics: [data] }),
|
var html = templates.prepare(templates['category'].blocks['topics']).parse({ topics: [data] }),
|
||||||
topic = document.createElement('div'),
|
topic = document.createElement('div'),
|
||||||
container = document.getElementById('topics-container'),
|
container = document.getElementById('topics-container'),
|
||||||
@@ -49,7 +48,7 @@
|
|||||||
|
|
||||||
topic.innerHTML = html;
|
topic.innerHTML = html;
|
||||||
topic = topic.querySelector('a');
|
topic = topic.querySelector('a');
|
||||||
|
|
||||||
if (numTopics > 0) {
|
if (numTopics > 0) {
|
||||||
for(x=0;x<numTopics;x++) {
|
for(x=0;x<numTopics;x++) {
|
||||||
if (topics[x].querySelector('.icon-pushpin')) continue;
|
if (topics[x].querySelector('.icon-pushpin')) continue;
|
||||||
@@ -61,6 +60,8 @@
|
|||||||
container.insertBefore(topic, null);
|
container.insertBefore(topic, null);
|
||||||
$(topic).hide().fadeIn('slow');
|
$(topic).hide().fadeIn('slow');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
socket.emit('api:categories.getRecentReplies', cid);
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.on('event:new_topic', onNewTopic);
|
socket.on('event:new_topic', onNewTopic);
|
||||||
@@ -74,7 +75,7 @@
|
|||||||
var recent_replies = document.getElementById('category_recent_replies');
|
var recent_replies = document.getElementById('category_recent_replies');
|
||||||
|
|
||||||
recent_replies.innerHTML = '';
|
recent_replies.innerHTML = '';
|
||||||
|
|
||||||
var frag = document.createDocumentFragment(),
|
var frag = document.createDocumentFragment(),
|
||||||
li = document.createElement('li');
|
li = document.createElement('li');
|
||||||
for (var i=0,numPosts=posts.length; i<numPosts; i++) {
|
for (var i=0,numPosts=posts.length; i<numPosts; i++) {
|
||||||
@@ -94,7 +95,7 @@
|
|||||||
recent_replies.appendChild(frag);
|
recent_replies.appendChild(frag);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function onTopicsLoaded(topics) {
|
function onTopicsLoaded(topics) {
|
||||||
|
|
||||||
var html = templates.prepare(templates['category'].blocks['topics']).parse({ topics: topics }),
|
var html = templates.prepare(templates['category'].blocks['topics']).parse({ topics: topics }),
|
||||||
@@ -105,14 +106,14 @@
|
|||||||
|
|
||||||
container.append(html);
|
container.append(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function loadMoreTopics(cid) {
|
function loadMoreTopics(cid) {
|
||||||
loadingMoreTopics = true;
|
loadingMoreTopics = true;
|
||||||
socket.emit('api:category.loadMore', {
|
socket.emit('api:category.loadMore', {
|
||||||
cid: cid,
|
cid: cid,
|
||||||
after: $('#topics-container').children().length
|
after: $('#topics-container').children().length
|
||||||
}, function(data) {
|
}, function(data) {
|
||||||
if(data.topics.length) {
|
if(data.topics.length) {
|
||||||
onTopicsLoaded(data.topics);
|
onTopicsLoaded(data.topics);
|
||||||
@@ -122,9 +123,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$(window).off('scroll').on('scroll', function(ev) {
|
$(window).off('scroll').on('scroll', function(ev) {
|
||||||
var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
|
var bottom = ($(document).height() - $(window).height()) * 0.9;
|
||||||
|
|
||||||
if (document.body.scrollTop > bottom && !loadingMoreTopics) {
|
if ($(window).scrollTop() > bottom && !loadingMoreTopics) {
|
||||||
loadMoreTopics(cid);
|
loadMoreTopics(cid);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
11
public/src/forum/favourites.js
Normal file
11
public/src/forum/favourites.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
(function() {
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
|
||||||
|
$('.user-favourite-posts .topic-row').on('click', function() {
|
||||||
|
ajaxify.go($(this).attr('topic-url'));
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}());
|
||||||
@@ -10,13 +10,7 @@
|
|||||||
$('#no-followers-notice').show();
|
$('#no-followers-notice').show();
|
||||||
}
|
}
|
||||||
|
|
||||||
$('.reputation').each(function(index, element) {
|
app.addCommasToNumbers();
|
||||||
$(element).html(app.addCommas($(element).html()));
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.postcount').each(function(index, element) {
|
|
||||||
$(element).html(app.addCommas($(element).html()));
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -32,14 +32,7 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$('.reputation').each(function(index, element) {
|
app.addCommasToNumbers();
|
||||||
$(element).html(app.addCommas($(element).html()));
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.postcount').each(function(index, element) {
|
|
||||||
$(element).html(app.addCommas($(element).html()));
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
user_label = document.getElementById('user_label'),
|
user_label = document.getElementById('user_label'),
|
||||||
active_record = document.getElementById('active_record'),
|
active_record = document.getElementById('active_record'),
|
||||||
right_menu = document.getElementById('right-menu');
|
right_menu = document.getElementById('right-menu');
|
||||||
|
|
||||||
socket.emit('user.count', {});
|
socket.emit('user.count', {});
|
||||||
socket.on('user.count', function(data) {
|
socket.on('user.count', function(data) {
|
||||||
num_users.innerHTML = "We currently have <b>" + data.count + "</b> registered users.";
|
num_users.innerHTML = "We currently have <b>" + data.count + "</b> registered users.";
|
||||||
@@ -28,24 +28,28 @@
|
|||||||
|
|
||||||
socket.emit('api:user.active.get');
|
socket.emit('api:user.active.get');
|
||||||
socket.on('api:user.active.get', function(data) {
|
socket.on('api:user.active.get', function(data) {
|
||||||
|
|
||||||
var plural_users = parseInt(data.users) !== 1,
|
var plural_users = parseInt(data.users) !== 1,
|
||||||
plural_anon = parseInt(data.anon) !== 1;
|
plural_anon = parseInt(data.anon) !== 1;
|
||||||
|
|
||||||
active_users.innerHTML = 'There ' + (plural_users ? 'are' : 'is') + ' <strong>' + data.users + '</strong> user' + (plural_users ? 's' : '') + ' and <strong>' + data.anon + '</strong> guest' + (plural_anon ? 's' : '') + ' online';
|
active_users.innerHTML = 'There ' + (plural_users ? 'are' : 'is') + ' <strong>' + data.users + '</strong> user' + (plural_users ? 's' : '') + ' and <strong>' + data.anon + '</strong> guest' + (plural_anon ? 's' : '') + ' online';
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.emit('api:user.active.get_record');
|
socket.emit('api:user.active.get_record');
|
||||||
socket.on('api:user.active.get_record', function(data) {
|
socket.on('api:user.active.get_record', function(data) {
|
||||||
active_record.innerHTML = "most users ever online was <strong>" + data.record + "</strong> on <strong>" + (new Date(parseInt(data.timestamp,10))).toUTCString() + "</strong>";
|
active_record.innerHTML = "most users ever online was <strong>" + data.record + "</strong> on <strong>" + (new Date(parseInt(data.timestamp,10))).toUTCString() + "</strong>";
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.emit('api:updateHeader', { fields: ['username', 'picture', 'userslug'] });
|
socket.emit('api:updateHeader', { fields: ['username', 'picture', 'userslug'] });
|
||||||
|
|
||||||
socket.on('api:updateHeader', function(data) {
|
socket.on('api:updateHeader', function(data) {
|
||||||
|
|
||||||
var rightMenu = $('#right-menu');
|
var rightMenu = $('#right-menu'),
|
||||||
if (data.uid > 0) {
|
isLoggedIn = data.uid > 0;
|
||||||
|
|
||||||
|
if (isLoggedIn) {
|
||||||
|
jQuery('.nodebb-loggedin').show();
|
||||||
|
jQuery('.nodebb-loggedout').hide();
|
||||||
|
|
||||||
var userLabel = rightMenu.find('#user_label');
|
var userLabel = rightMenu.find('#user_label');
|
||||||
if(userLabel.length) {
|
if(userLabel.length) {
|
||||||
@@ -55,8 +59,7 @@
|
|||||||
userLabel.find('img').attr('src',data['picture']);
|
userLabel.find('img').attr('src',data['picture']);
|
||||||
if(data['username'])
|
if(data['username'])
|
||||||
userLabel.find('span').html(data['username']);
|
userLabel.find('span').html(data['username']);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
var userli = $('<li> \
|
var userli = $('<li> \
|
||||||
<a id="user_label" href="/users/'+data['userslug']+'"> \
|
<a id="user_label" href="/users/'+data['userslug']+'"> \
|
||||||
<img src="'+data['picture']+'"/> \
|
<img src="'+data['picture']+'"/> \
|
||||||
@@ -69,6 +72,9 @@
|
|||||||
rightMenu.append(logoutli);
|
rightMenu.append(logoutli);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
jQuery('.nodebb-loggedin').hide();
|
||||||
|
jQuery('.nodebb-loggedout').show();
|
||||||
|
|
||||||
rightMenu.html('');
|
rightMenu.html('');
|
||||||
|
|
||||||
var registerEl = document.createElement('li'),
|
var registerEl = document.createElement('li'),
|
||||||
@@ -90,10 +96,39 @@
|
|||||||
notifTrigger.addEventListener('click', function(e) {
|
notifTrigger.addEventListener('click', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (notifContainer.className.indexOf('open') === -1) {
|
if (notifContainer.className.indexOf('open') === -1) {
|
||||||
socket.emit('api:notifications.get');
|
socket.emit('api:notifications.get', null, function(data) {
|
||||||
socket.emit('api:notifications.mark_all_read', null, function() {
|
var notifFrag = document.createDocumentFragment(),
|
||||||
notifIcon.className = 'icon-circle-blank';
|
notifEl = document.createElement('li'),
|
||||||
utils.refreshTitle();
|
numRead = data.read.length,
|
||||||
|
numUnread = data.unread.length,
|
||||||
|
x;
|
||||||
|
notifList.innerHTML = '';
|
||||||
|
if ((data.read.length + data.unread.length) > 0) {
|
||||||
|
for(x=0;x<numUnread;x++) {
|
||||||
|
notifEl.setAttribute('data-nid', data.unread[x].nid);
|
||||||
|
notifEl.className = 'unread';
|
||||||
|
notifEl.innerHTML = '<a href="' + data.unread[x].path + '"><span class="pull-right">' + utils.relativeTime(data.unread[x].datetime, true) + '</span>' + data.unread[x].text + '</a>';
|
||||||
|
notifFrag.appendChild(notifEl.cloneNode(true));
|
||||||
|
}
|
||||||
|
for(x=0;x<numRead;x++) {
|
||||||
|
notifEl.setAttribute('data-nid', data.read[x].nid);
|
||||||
|
notifEl.className = '';
|
||||||
|
notifEl.innerHTML = '<a href="' + data.read[x].path + '"><span class="pull-right">' + utils.relativeTime(data.read[x].datetime, true) + '</span>' + data.read[x].text + '</a>';
|
||||||
|
notifFrag.appendChild(notifEl.cloneNode(true));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
notifEl.innerHTML = '<a>You have no notifications</a>';
|
||||||
|
notifFrag.appendChild(notifEl);
|
||||||
|
}
|
||||||
|
notifList.appendChild(notifFrag);
|
||||||
|
|
||||||
|
if (data.unread.length > 0) notifIcon.className = 'icon-circle active';
|
||||||
|
else notifIcon.className = 'icon-circle-blank';
|
||||||
|
|
||||||
|
socket.emit('api:notifications.mark_all_read', null, function() {
|
||||||
|
notifIcon.className = 'icon-circle-blank';
|
||||||
|
utils.refreshTitle();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -109,37 +144,15 @@
|
|||||||
if (nid > 0) socket.emit('api:notifications.mark_read', nid);
|
if (nid > 0) socket.emit('api:notifications.mark_read', nid);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
socket.on('api:notifications.get', function(data) {
|
|
||||||
var notifFrag = document.createDocumentFragment(),
|
|
||||||
notifEl = document.createElement('li'),
|
|
||||||
numRead = data.read.length,
|
|
||||||
numUnread = data.unread.length,
|
|
||||||
x;
|
|
||||||
notifList.innerHTML = '';
|
|
||||||
if ((data.read.length + data.unread.length) > 0) {
|
|
||||||
for(x=0;x<numUnread;x++) {
|
|
||||||
notifEl.setAttribute('data-nid', data.unread[x].nid);
|
|
||||||
notifEl.className = 'unread';
|
|
||||||
notifEl.innerHTML = '<a href="' + data.unread[x].path + '"><span class="pull-right">' + utils.relativeTime(data.unread[x].datetime, true) + '</span>' + data.unread[x].text + '</a>';
|
|
||||||
notifFrag.appendChild(notifEl.cloneNode(true));
|
|
||||||
}
|
|
||||||
for(x=0;x<numRead;x++) {
|
|
||||||
notifEl.setAttribute('data-nid', data.read[x].nid);
|
|
||||||
notifEl.className = '';
|
|
||||||
notifEl.innerHTML = '<a href="' + data.read[x].path + '"><span class="pull-right">' + utils.relativeTime(data.read[x].datetime, true) + '</span>' + data.read[x].text + '</a>';
|
|
||||||
notifFrag.appendChild(notifEl.cloneNode(true));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
notifEl.innerHTML = '<a>You have no notifications</a>';
|
|
||||||
notifFrag.appendChild(notifEl);
|
|
||||||
}
|
|
||||||
notifList.appendChild(notifFrag);
|
|
||||||
|
|
||||||
if (data.unread.length > 0) notifIcon.className = 'icon-circle active';
|
|
||||||
else notifIcon.className = 'icon-circle-blank';
|
|
||||||
});
|
|
||||||
socket.on('event:new_notification', function() {
|
socket.on('event:new_notification', function() {
|
||||||
document.querySelector('.notifications a i').className = 'icon-circle active';
|
document.querySelector('.notifications a i').className = 'icon-circle active';
|
||||||
|
app.alert({
|
||||||
|
alert_id: 'new_notif',
|
||||||
|
title: 'New notification',
|
||||||
|
message: 'You have unread notifications.',
|
||||||
|
type: 'notify',
|
||||||
|
timeout: 2000
|
||||||
|
});
|
||||||
utils.refreshTitle();
|
utils.refreshTitle();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -148,12 +161,12 @@
|
|||||||
var username = data.username;
|
var username = data.username;
|
||||||
var fromuid = data.fromuid;
|
var fromuid = data.fromuid;
|
||||||
var message = data.message;
|
var message = data.message;
|
||||||
|
|
||||||
require(['chat'], function(chat) {
|
require(['chat'], function(chat) {
|
||||||
var chatModal = chat.createModalIfDoesntExist(username, fromuid);
|
var chatModal = chat.createModalIfDoesntExist(username, fromuid);
|
||||||
chatModal.show();
|
chatModal.show();
|
||||||
chat.bringModalToTop(chatModal);
|
chat.bringModalToTop(chatModal);
|
||||||
|
|
||||||
chat.appendChatMessage(chatModal, message);
|
chat.appendChatMessage(chatModal, message);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,26 +12,29 @@
|
|||||||
if (target) {
|
if (target) {
|
||||||
document.location.href = target.getAttribute('data-url');
|
document.location.href = target.getAttribute('data-url');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#login').on('click', function() {
|
$('#login').on('click', function() {
|
||||||
|
|
||||||
var loginData = {
|
var loginData = {
|
||||||
'username': $('#username').val(),
|
'username': $('#username').val(),
|
||||||
'password': $('#password').val(),
|
'password': $('#password').val(),
|
||||||
'_csrf': $('#csrf-token').val()
|
'_csrf': $('#csrf-token').val()
|
||||||
};
|
};
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
url: RELATIVE_PATH + '/login',
|
url: RELATIVE_PATH + '/login',
|
||||||
data: loginData,
|
data: loginData,
|
||||||
success: function(data, textStatus, jqXHR) {
|
success: function(data, textStatus, jqXHR) {
|
||||||
$('#login-error-notify').hide();
|
if(!data.success) {
|
||||||
window.location.replace(RELATIVE_PATH + "/?loggedin");
|
$('#login-error-notify').html(data.message).show();
|
||||||
|
} else {
|
||||||
|
$('#login-error-notify').hide();
|
||||||
|
window.location.replace(RELATIVE_PATH + "/?loggedin");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
error : function(data, textStatus, jqXHR) {
|
error : function(data, textStatus, jqXHR) {
|
||||||
$('#login-error-notify').show().delay(1000).fadeOut(250);
|
$('#login-error-notify').show();
|
||||||
},
|
},
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
async: true,
|
async: true,
|
||||||
@@ -40,5 +43,6 @@
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.querySelector('#content input').focus();
|
||||||
}());
|
}());
|
||||||
|
|||||||
@@ -69,9 +69,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$(window).off('scroll').on('scroll', function() {
|
$(window).off('scroll').on('scroll', function() {
|
||||||
var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
|
var bottom = ($(document).height() - $(window).height()) * 0.9;
|
||||||
|
|
||||||
if (document.body.scrollTop > bottom && !loadingMoreTopics) {
|
if ($(window).scrollTop() > bottom && !loadingMoreTopics) {
|
||||||
loadMoreTopics();
|
loadMoreTopics();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
pinned: templates.get('pinned')
|
pinned: templates.get('pinned')
|
||||||
},
|
},
|
||||||
topic_name = templates.get('topic_name');
|
topic_name = templates.get('topic_name');
|
||||||
|
|
||||||
|
|
||||||
jQuery('document').ready(function() {
|
jQuery('document').ready(function() {
|
||||||
|
|
||||||
app.addCommasToNumbers();
|
app.addCommasToNumbers();
|
||||||
|
|
||||||
var room = 'topic_' + tid,
|
var room = 'topic_' + tid,
|
||||||
adminTools = document.getElementById('thread-tools');
|
adminTools = document.getElementById('thread-tools');
|
||||||
|
|
||||||
@@ -26,17 +26,12 @@
|
|||||||
if (thread_state.pinned === '1') set_pinned_state(true);
|
if (thread_state.pinned === '1') set_pinned_state(true);
|
||||||
|
|
||||||
if (expose_tools === '1') {
|
if (expose_tools === '1') {
|
||||||
var deleteThreadEl = document.getElementById('delete_thread'),
|
var moveThreadModal = $('#move_thread_modal');
|
||||||
lockThreadEl = document.getElementById('lock_thread'),
|
|
||||||
pinThreadEl = document.getElementById('pin_thread'),
|
|
||||||
moveThreadEl = document.getElementById('move_thread'),
|
|
||||||
moveThreadModal = $('#move_thread_modal');
|
|
||||||
|
|
||||||
adminTools.style.visibility = 'inherit';
|
adminTools.style.visibility = 'inherit';
|
||||||
|
|
||||||
// Add events to the thread tools
|
// Add events to the thread tools
|
||||||
deleteThreadEl.addEventListener('click', function(e) {
|
$('#delete_thread').on('click', function(e) {
|
||||||
e.preventDefault();
|
|
||||||
if (thread_state.deleted !== '1') {
|
if (thread_state.deleted !== '1') {
|
||||||
bootbox.confirm('Are you sure you want to delete this thread?', function(confirm) {
|
bootbox.confirm('Are you sure you want to delete this thread?', function(confirm) {
|
||||||
if (confirm) socket.emit('api:topic.delete', { tid: tid });
|
if (confirm) socket.emit('api:topic.delete', { tid: tid });
|
||||||
@@ -46,30 +41,31 @@
|
|||||||
if (confirm) socket.emit('api:topic.restore', { tid: tid });
|
if (confirm) socket.emit('api:topic.restore', { tid: tid });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, false);
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
lockThreadEl.addEventListener('click', function(e) {
|
$('#lock_thread').on('click', function(e) {
|
||||||
e.preventDefault();
|
|
||||||
if (thread_state.locked !== '1') {
|
if (thread_state.locked !== '1') {
|
||||||
socket.emit('api:topic.lock', { tid: tid });
|
socket.emit('api:topic.lock', { tid: tid });
|
||||||
} else {
|
} else {
|
||||||
socket.emit('api:topic.unlock', { tid: tid });
|
socket.emit('api:topic.unlock', { tid: tid });
|
||||||
}
|
}
|
||||||
}, false);
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
pinThreadEl.addEventListener('click', function(e) {
|
$('#pin_thread').on('click', function(e) {
|
||||||
e.preventDefault();
|
|
||||||
if (thread_state.pinned !== '1') {
|
if (thread_state.pinned !== '1') {
|
||||||
socket.emit('api:topic.pin', { tid: tid });
|
socket.emit('api:topic.pin', { tid: tid });
|
||||||
} else {
|
} else {
|
||||||
socket.emit('api:topic.unpin', { tid: tid });
|
socket.emit('api:topic.unpin', { tid: tid });
|
||||||
}
|
}
|
||||||
}, false);
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
moveThreadEl.addEventListener('click', function(e) {
|
$('#move_thread').on('click', function(e) {
|
||||||
e.preventDefault();
|
|
||||||
moveThreadModal.modal('show');
|
moveThreadModal.modal('show');
|
||||||
}, false);
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
moveThreadModal.on('shown', function() {
|
moveThreadModal.on('shown', function() {
|
||||||
var loadingEl = document.getElementById('categories-loading');
|
var loadingEl = document.getElementById('categories-loading');
|
||||||
@@ -195,16 +191,18 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.emit('api:topic.followCheck', tid);
|
socket.emit('api:topic.followCheck', tid);
|
||||||
followEl[0].addEventListener('click', function() {
|
if(followEl[0]) {
|
||||||
socket.emit('api:topic.follow', tid);
|
followEl[0].addEventListener('click', function() {
|
||||||
}, false);
|
socket.emit('api:topic.follow', tid);
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
|
||||||
// Infinite scrolling of posts
|
|
||||||
$(window).off('scroll').on('scroll', function() {
|
$(window).off('scroll').on('scroll', function() {
|
||||||
var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
|
var bottom = ($(document).height() - $(window).height()) * 0.9;
|
||||||
|
|
||||||
if (document.body.scrollTop > bottom && !app.infiniteLoaderActive && $('#post-container').children().length) {
|
if ($(window).scrollTop() > bottom && !app.infiniteLoaderActive && $('#post-container').children().length) {
|
||||||
app.loadMorePosts(tid);
|
app.loadMorePosts(tid);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -254,11 +252,9 @@
|
|||||||
|
|
||||||
var element = $(this).find('i');
|
var element = $(this).find('i');
|
||||||
if(element.attr('class') == 'icon-star-empty') {
|
if(element.attr('class') == 'icon-star-empty') {
|
||||||
element.attr('class', 'icon-star');
|
|
||||||
socket.emit('api:posts.favourite', {pid: pid, room_id: app.current_room});
|
socket.emit('api:posts.favourite', {pid: pid, room_id: app.current_room});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
element.attr('class', 'icon-star-empty');
|
|
||||||
socket.emit('api:posts.unfavourite', {pid: pid, room_id: app.current_room});
|
socket.emit('api:posts.unfavourite', {pid: pid, room_id: app.current_room});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -284,19 +280,21 @@
|
|||||||
socket.emit('api:posts.delete', { pid: pid }) :
|
socket.emit('api:posts.delete', { pid: pid }) :
|
||||||
socket.emit('api:posts.restore', { pid: pid });
|
socket.emit('api:posts.restore', { pid: pid });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.post-container').delegate('.chat', 'click', function(e) {
|
$('.post-container').delegate('.chat', 'click', function(e) {
|
||||||
|
|
||||||
var username = $(this).parents('li').attr('data-username');
|
var username = $(this).parents('li').attr('data-username');
|
||||||
var touid = $(this).parents('li').attr('data-uid');
|
var touid = $(this).parents('li').attr('data-uid');
|
||||||
|
|
||||||
require(['chat'], function(chat){
|
if(username === app.username || !app.username)
|
||||||
|
return;
|
||||||
|
|
||||||
|
require(['chat'], function(chat) {
|
||||||
var chatModal = chat.createModalIfDoesntExist(username, touid);
|
var chatModal = chat.createModalIfDoesntExist(username, touid);
|
||||||
chatModal.show();
|
chatModal.show();
|
||||||
chat.bringModalToTop(chatModal);
|
chat.bringModalToTop(chatModal);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
ajaxify.register_events([
|
ajaxify.register_events([
|
||||||
@@ -372,7 +370,7 @@
|
|||||||
var editedPostEl = document.getElementById('content_' + data.pid);
|
var editedPostEl = document.getElementById('content_' + data.pid);
|
||||||
|
|
||||||
var editedPostTitle = $('#topic_title_'+data.pid);
|
var editedPostTitle = $('#topic_title_'+data.pid);
|
||||||
|
|
||||||
if(editedPostTitle.length > 0) {
|
if(editedPostTitle.length > 0) {
|
||||||
editedPostTitle.fadeOut(250, function() {
|
editedPostTitle.fadeOut(250, function() {
|
||||||
editedPostTitle.html(data.title);
|
editedPostTitle.html(data.title);
|
||||||
@@ -387,9 +385,22 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:posts.favourite', function(data) {
|
socket.on('api:posts.favourite', function(data) {
|
||||||
if (data.status !== 'ok' && data.pid) {
|
if (data.status === 'ok' && data.pid) {
|
||||||
var favEl = document.querySelector('.post_rep_' + data.pid).nextSibling;
|
var favEl = document.querySelector('.post_rep_' + data.pid).nextSibling;
|
||||||
if (favEl) favEl.className = 'icon-star-empty';
|
if (favEl) {
|
||||||
|
favEl.className = 'icon-star';
|
||||||
|
$(favEl).parent().addClass('btn-warning');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('api:posts.unfavourite', function(data) {
|
||||||
|
if (data.status === 'ok' && data.pid) {
|
||||||
|
var favEl = document.querySelector('.post_rep_' + data.pid).nextSibling;
|
||||||
|
if (favEl) {
|
||||||
|
favEl.className = 'icon-star-empty';
|
||||||
|
$(favEl).parent().removeClass('btn-warning');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -582,7 +593,7 @@
|
|||||||
var postEl = $(document.querySelector('#post-container li[data-pid="' + pid + '"]')),
|
var postEl = $(document.querySelector('#post-container li[data-pid="' + pid + '"]')),
|
||||||
editEl = postEl.find('.edit'),
|
editEl = postEl.find('.edit'),
|
||||||
deleteEl = postEl.find('.delete');
|
deleteEl = postEl.find('.delete');
|
||||||
|
|
||||||
if (state) {
|
if (state) {
|
||||||
editEl.removeClass('none');
|
editEl.removeClass('none');
|
||||||
deleteEl.removeClass('none');
|
deleteEl.removeClass('none');
|
||||||
|
|||||||
@@ -56,6 +56,10 @@
|
|||||||
$('#topics-container').empty();
|
$('#topics-container').empty();
|
||||||
$('#category-no-topics').removeClass('hidden');
|
$('#category-no-topics').removeClass('hidden');
|
||||||
app.alertSuccess('All topics marked as read!');
|
app.alertSuccess('All topics marked as read!');
|
||||||
|
$('#numUnreadBadge')
|
||||||
|
.removeClass('badge-important')
|
||||||
|
.addClass('badge-inverse')
|
||||||
|
.html('0');
|
||||||
} else {
|
} else {
|
||||||
app.alertError('There was an error marking topics read!');
|
app.alertError('There was an error marking topics read!');
|
||||||
}
|
}
|
||||||
@@ -78,21 +82,24 @@
|
|||||||
if(data.topics && data.topics.length) {
|
if(data.topics && data.topics.length) {
|
||||||
onTopicsLoaded(data.topics);
|
onTopicsLoaded(data.topics);
|
||||||
$('#topics-container').attr('data-next-start', data.nextStart);
|
$('#topics-container').attr('data-next-start', data.nextStart);
|
||||||
|
} else {
|
||||||
|
$('#load-more-btn').hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadingMoreTopics = false;
|
loadingMoreTopics = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(window).off('scroll').on('scroll', function() {
|
$(window).off('scroll').on('scroll', function() {
|
||||||
var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
|
var bottom = ($(document).height() - $(window).height()) * 0.9;
|
||||||
|
|
||||||
if (document.body.scrollTop > bottom && !loadingMoreTopics) {
|
if ($(window).scrollTop() > bottom && !loadingMoreTopics) {
|
||||||
loadMoreTopics();
|
loadMoreTopics();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if($("body").height() <= $(window).height() && $('#topics-container').children().length)
|
if($("body").height() <= $(window).height() && $('#topics-container').children().length >= 20)
|
||||||
$('#load-more-btn').show();
|
$('#load-more-btn').show();
|
||||||
|
|
||||||
$('#load-more-btn').on('click', function() {
|
$('#load-more-btn').on('click', function() {
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
parts = url.split('/'),
|
parts = url.split('/'),
|
||||||
active = parts[parts.length-1];
|
active = parts[parts.length-1];
|
||||||
|
|
||||||
|
app.addCommasToNumbers();
|
||||||
|
|
||||||
jQuery('.nav-pills li').removeClass('active');
|
jQuery('.nav-pills li').removeClass('active');
|
||||||
jQuery('.nav-pills li a').each(function() {
|
jQuery('.nav-pills li a').each(function() {
|
||||||
if (this.getAttribute('href').match(active)) {
|
if (this.getAttribute('href').match(active)) {
|
||||||
@@ -67,13 +69,7 @@
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.reputation').each(function(index, element) {
|
|
||||||
$(element).html(app.addCommas($(element).html()));
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.postcount').each(function(index, element) {
|
|
||||||
$(element).html(app.addCommas($(element).html()));
|
|
||||||
});
|
|
||||||
|
|
||||||
function onUsersLoaded(users) {
|
function onUsersLoaded(users) {
|
||||||
var html = templates.prepare(templates['users'].blocks['users']).parse({ users: users });
|
var html = templates.prepare(templates['users'].blocks['users']).parse({ users: users });
|
||||||
@@ -109,9 +105,9 @@
|
|||||||
$('#load-more-users-btn').on('click', loadMoreUsers);
|
$('#load-more-users-btn').on('click', loadMoreUsers);
|
||||||
|
|
||||||
$(window).off('scroll').on('scroll', function() {
|
$(window).off('scroll').on('scroll', function() {
|
||||||
var bottom = (document.body.offsetHeight - $(window).height()) * 0.9;
|
var bottom = ($(document).height() - $(window).height()) * 0.9;
|
||||||
|
|
||||||
if (document.body.scrollTop > bottom && !loadingMoreUsers) {
|
if ($(window).scrollTop() > bottom && !loadingMoreUsers) {
|
||||||
loadMoreUsers();
|
loadMoreUsers();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
define(['taskbar'], function(taskbar) {
|
define(['taskbar'], function(taskbar) {
|
||||||
|
|
||||||
var module = {};
|
var module = {};
|
||||||
|
|
||||||
|
|
||||||
module.bringModalToTop = function(chatModal) {
|
module.bringModalToTop = function(chatModal) {
|
||||||
var topZ = 0;
|
var topZ = 0;
|
||||||
$('.modal').each(function() {
|
$('.modal').each(function() {
|
||||||
@@ -11,7 +10,7 @@ define(['taskbar'], function(taskbar) {
|
|||||||
topZ = thisZ;
|
topZ = thisZ;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
chatModal.css('zIndex', topZ+1);
|
chatModal.css('zIndex', topZ + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.createModalIfDoesntExist = function(username, touid) {
|
module.createModalIfDoesntExist = function(username, touid) {
|
||||||
@@ -39,7 +38,9 @@ define(['taskbar'], function(taskbar) {
|
|||||||
module.bringModalToTop(chatModal);
|
module.bringModalToTop(chatModal);
|
||||||
});
|
});
|
||||||
|
|
||||||
addSendHandler(chatModal, touid);
|
addSendHandler(chatModal, touid);
|
||||||
|
|
||||||
|
getChatMessages(chatModal, touid);
|
||||||
}
|
}
|
||||||
|
|
||||||
taskbar.push('chat', chatModal.attr('UUID'), {title:'chat with '+username});
|
taskbar.push('chat', chatModal.attr('UUID'), {title:'chat with '+username});
|
||||||
@@ -58,6 +59,14 @@ define(['taskbar'], function(taskbar) {
|
|||||||
taskbar.minimize('chat', uuid);
|
taskbar.minimize('chat', uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getChatMessages(chatModal, touid) {
|
||||||
|
socket.emit('getChatMessages', {touid:touid}, function(messages) {
|
||||||
|
for(var i = 0; i<messages.length; ++i) {
|
||||||
|
module.appendChatMessage(chatModal, messages[i].content);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function addSendHandler(chatModal, touid) {
|
function addSendHandler(chatModal, touid) {
|
||||||
chatModal.find('#chat-message-input').off('keypress');
|
chatModal.find('#chat-message-input').off('keypress');
|
||||||
chatModal.find('#chat-message-input').on('keypress', function(e) {
|
chatModal.find('#chat-message-input').on('keypress', function(e) {
|
||||||
|
|||||||
@@ -7,12 +7,29 @@ define(['taskbar'], function(taskbar) {
|
|||||||
postContainer: undefined,
|
postContainer: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function createImageLabel(img, postImages) {
|
||||||
|
var imageLabel = $('<div class="label"><span>'+ img.name +'</span></div>');
|
||||||
|
var closeButton = $('<button class="close">×</button>');
|
||||||
|
|
||||||
|
closeButton.on('click', function(e) {
|
||||||
|
|
||||||
|
imageLabel.remove();
|
||||||
|
var index = postImages.indexOf(img);
|
||||||
|
if(index !== -1) {
|
||||||
|
postImages.splice(index, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
imageLabel.append(closeButton);
|
||||||
|
return imageLabel;
|
||||||
|
}
|
||||||
|
|
||||||
function loadFile(file) {
|
function loadFile(file) {
|
||||||
var reader = new FileReader();
|
var reader = new FileReader(),
|
||||||
var dropDiv = $('#imagedrop');
|
dropDiv = $('.post-window .imagedrop'),
|
||||||
var imagelist = $('#imagelist');
|
imagelist = $('.post-window .imagelist'),
|
||||||
var uuid = dropDiv.parents('[data-uuid]').attr('data-uuid');
|
uuid = dropDiv.parents('[data-uuid]').attr('data-uuid'),
|
||||||
var posts = composer.posts[uuid];
|
posts = composer.posts[uuid];
|
||||||
|
|
||||||
$(reader).on('loadend', function(e) {
|
$(reader).on('loadend', function(e) {
|
||||||
var bin = this.result;
|
var bin = this.result;
|
||||||
@@ -25,19 +42,9 @@ define(['taskbar'], function(taskbar) {
|
|||||||
|
|
||||||
posts.images.push(img);
|
posts.images.push(img);
|
||||||
|
|
||||||
var imageLabel = $('<div class="label"><span>'+ file.name +'</span></div>');
|
var imageLabel = createImageLabel(img, posts.images);
|
||||||
var closeButton = $('<button class="close">×</button>');
|
|
||||||
closeButton.on('click', function(e) {
|
|
||||||
|
|
||||||
imageLabel.remove();
|
|
||||||
var index = posts.images.indexOf(img);
|
|
||||||
if(index !== -1) {
|
|
||||||
posts.images.splice(index, 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
imageLabel.append(closeButton);
|
imagelist.append(imageLabel);
|
||||||
imagelist.append(imageLabel);
|
|
||||||
dropDiv.hide();
|
dropDiv.hide();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -46,12 +53,29 @@ define(['taskbar'], function(taskbar) {
|
|||||||
|
|
||||||
function initializeFileReader() {
|
function initializeFileReader() {
|
||||||
jQuery.event.props.push( "dataTransfer" );
|
jQuery.event.props.push( "dataTransfer" );
|
||||||
|
|
||||||
if(window.FileReader) {
|
var draggingDocument = false;
|
||||||
var drop = $('#imagedrop');
|
|
||||||
|
|
||||||
$(composer.postContainer).on('dragenter dragover', function() {
|
if(window.FileReader) {
|
||||||
drop.show();
|
var drop = $('.post-window .imagedrop'),
|
||||||
|
textarea = $('.post-window textarea');
|
||||||
|
|
||||||
|
$(document).on('dragstart', function(e) {
|
||||||
|
draggingDocument = true;
|
||||||
|
}).on('dragend', function(e) {
|
||||||
|
draggingDocument = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
textarea.on('dragenter', function(e) {
|
||||||
|
if(draggingDocument)
|
||||||
|
return;
|
||||||
|
drop.css('top', textarea.position().top + 'px');
|
||||||
|
drop.show();
|
||||||
|
|
||||||
|
drop.on('dragleave', function(ev) {
|
||||||
|
drop.hide();
|
||||||
|
drop.off('dragleave');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function cancel(e) {
|
function cancel(e) {
|
||||||
@@ -61,22 +85,22 @@ define(['taskbar'], function(taskbar) {
|
|||||||
|
|
||||||
drop.on('dragover', cancel);
|
drop.on('dragover', cancel);
|
||||||
drop.on('dragenter', cancel);
|
drop.on('dragenter', cancel);
|
||||||
|
|
||||||
drop.on('drop', function(e) {
|
drop.on('drop', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var uuid = drop.parents('[data-uuid]').attr('data-uuid');
|
var uuid = drop.parents('[data-uuid]').attr('data-uuid'),
|
||||||
var posts = composer.posts[uuid];
|
posts = composer.posts[uuid],
|
||||||
|
dt = e.dataTransfer,
|
||||||
var dt = e.dataTransfer;
|
files = dt.files;
|
||||||
var files = dt.files;
|
|
||||||
|
|
||||||
for (var i=0; i<files.length; i++) {
|
for (var i=0; i<files.length; i++) {
|
||||||
loadFile(files[i]);
|
loadFile(files[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!files.length)
|
||||||
|
drop.hide();
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,21 +112,19 @@ define(['taskbar'], function(taskbar) {
|
|||||||
composer.postContainer.className = 'post-window row-fluid';
|
composer.postContainer.className = 'post-window row-fluid';
|
||||||
composer.postContainer.innerHTML = '<div class="span5">' +
|
composer.postContainer.innerHTML = '<div class="span5">' +
|
||||||
'<input type="text" tabIndex="1" placeholder="Enter your topic title here..." />' +
|
'<input type="text" tabIndex="1" placeholder="Enter your topic title here..." />' +
|
||||||
'<div class="btn-toolbar">' +
|
'<div class="btn-toolbar formatting-bar">' +
|
||||||
'<div class="btn-group formatting-bar">' +
|
'<div class="btn-group">' +
|
||||||
'<span class="btn btn-link" tabindex="-1"><i class="icon-bold"></i></span>' +
|
'<span class="btn btn-link" tabindex="-1"><i class="icon-bold"></i></span>' +
|
||||||
'<span class="btn btn-link" tabindex="-1"><i class="icon-italic"></i></span>' +
|
'<span class="btn btn-link" tabindex="-1"><i class="icon-italic"></i></span>' +
|
||||||
'<span class="btn btn-link" tabindex="-1"><i class="icon-list"></i></span>' +
|
'<span class="btn btn-link" tabindex="-1"><i class="icon-list"></i></span>' +
|
||||||
'<span class="btn btn-link" tabindex="-1"><i class="icon-link"></i></span>' +
|
'<span class="btn btn-link" tabindex="-1"><i class="icon-link"></i></span>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'<div style="position:relative;">'+
|
'<textarea tabIndex="2"></textarea>' +
|
||||||
'<div id="imagedrop" class=""><div>Drag and Drop Images Here</div></div>'+
|
'<div class="imagelist"></div>'+
|
||||||
'<textarea tabIndex="2"></textarea>' +
|
'<div class="imagedrop"><div>Drag and Drop Images Here</div></div>'+
|
||||||
'<div id="imagelist"></div>'+
|
'<div class="btn-toolbar action-bar">' +
|
||||||
'</div>'+
|
'<div class="btn-group" style="float: right; margin-right: -8px">' +
|
||||||
'<div class="btn-toolbar">' +
|
|
||||||
'<div class="btn-group action-bar" style="float: right; margin-right: -8px">' +
|
|
||||||
'<button data-action="minimize" class="btn hidden-phone" tabIndex="4"><i class="icon-download-alt"></i> Minimize</button>' +
|
'<button data-action="minimize" class="btn hidden-phone" tabIndex="4"><i class="icon-download-alt"></i> Minimize</button>' +
|
||||||
'<button class="btn" data-action="discard" tabIndex="5"><i class="icon-remove"></i> Discard</button>' +
|
'<button class="btn" data-action="discard" tabIndex="5"><i class="icon-remove"></i> Discard</button>' +
|
||||||
'<button data-action="post" class="btn" tabIndex="3"><i class="icon-ok"></i> Submit</button>' +
|
'<button data-action="post" class="btn" tabIndex="3"><i class="icon-ok"></i> Submit</button>' +
|
||||||
@@ -112,7 +134,8 @@ define(['taskbar'], function(taskbar) {
|
|||||||
|
|
||||||
document.body.insertBefore(composer.postContainer, taskbar);
|
document.body.insertBefore(composer.postContainer, taskbar);
|
||||||
|
|
||||||
initializeFileReader();
|
if(config.imgurClientIDSet)
|
||||||
|
initializeFileReader();
|
||||||
|
|
||||||
socket.on('api:composer.push', function(threadData) {
|
socket.on('api:composer.push', function(threadData) {
|
||||||
if (!threadData.error) {
|
if (!threadData.error) {
|
||||||
@@ -152,12 +175,14 @@ define(['taskbar'], function(taskbar) {
|
|||||||
|
|
||||||
// Post Window events
|
// Post Window events
|
||||||
var jPostContainer = $(composer.postContainer),
|
var jPostContainer = $(composer.postContainer),
|
||||||
postContentEl = composer.postContainer.querySelector('textarea')
|
postContentEl = composer.postContainer.querySelector('textarea');
|
||||||
|
|
||||||
jPostContainer.on('change', 'input, textarea', function() {
|
jPostContainer.on('change', 'input, textarea', function() {
|
||||||
var uuid = $(this).parents('.post-window')[0].getAttribute('data-uuid');
|
var uuid = $(this).parents('.post-window')[0].getAttribute('data-uuid');
|
||||||
if (this.nodeName === 'INPUT') composer.posts[uuid].title = this.value;
|
if (this.nodeName === 'INPUT') composer.posts[uuid].title = this.value;
|
||||||
else if (this.nodeName === 'TEXTAREA') composer.posts[uuid].body = this.value;
|
else if (this.nodeName === 'TEXTAREA') composer.posts[uuid].body = this.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
jPostContainer.on('click', '.action-bar button', function() {
|
jPostContainer.on('click', '.action-bar button', function() {
|
||||||
var action = this.getAttribute('data-action'),
|
var action = this.getAttribute('data-action'),
|
||||||
uuid = $(this).parents('.post-window').attr('data-uuid');
|
uuid = $(this).parents('.post-window').attr('data-uuid');
|
||||||
@@ -167,6 +192,7 @@ define(['taskbar'], function(taskbar) {
|
|||||||
case 'discard': composer.discard(uuid); break;
|
case 'discard': composer.discard(uuid); break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
jPostContainer.on('click', '.formatting-bar span', function() {
|
jPostContainer.on('click', '.formatting-bar span', function() {
|
||||||
var iconClass = this.querySelector('i').className,
|
var iconClass = this.querySelector('i').className,
|
||||||
cursorEnd = postContentEl.value.length,
|
cursorEnd = postContentEl.value.length,
|
||||||
@@ -239,15 +265,22 @@ define(['taskbar'], function(taskbar) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createPostImages(images) {
|
||||||
|
var imagelist = $(composer.postContainer).find('.imagelist');
|
||||||
|
imagelist.empty();
|
||||||
|
|
||||||
|
if(images && images.length) {
|
||||||
|
for(var i=0; i<images.length; ++i) {
|
||||||
|
var imageLabel = createImageLabel(images[i], images);
|
||||||
|
imagelist.append(imageLabel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
composer.load = function(post_uuid) {
|
composer.load = function(post_uuid) {
|
||||||
var post_data = composer.posts[post_uuid],
|
var post_data = composer.posts[post_uuid],
|
||||||
titleEl = composer.postContainer.querySelector('input'),
|
titleEl = composer.postContainer.querySelector('input'),
|
||||||
bodyEl = composer.postContainer.querySelector('textarea'),
|
bodyEl = composer.postContainer.querySelector('textarea');
|
||||||
dropDiv = $(composer.postContainer).find('#imagedrop'),
|
|
||||||
imagelist = $(composer.postContainer).find('#imagelist');
|
|
||||||
|
|
||||||
dropDiv.hide();
|
|
||||||
imagelist.empty();
|
|
||||||
|
|
||||||
composer.reposition(post_uuid);
|
composer.reposition(post_uuid);
|
||||||
composer.active = post_uuid;
|
composer.active = post_uuid;
|
||||||
@@ -264,7 +297,9 @@ define(['taskbar'], function(taskbar) {
|
|||||||
titleEl.value = post_data.title;
|
titleEl.value = post_data.title;
|
||||||
titleEl.readOnly = false;
|
titleEl.readOnly = false;
|
||||||
}
|
}
|
||||||
bodyEl.value = post_data.body
|
bodyEl.value = post_data.body;
|
||||||
|
|
||||||
|
createPostImages(post_data.images);
|
||||||
|
|
||||||
// Direct user focus to the correct element
|
// Direct user focus to the correct element
|
||||||
if ((parseInt(post_data.tid) || parseInt(post_data.pid)) > 0) {
|
if ((parseInt(post_data.tid) || parseInt(post_data.pid)) > 0) {
|
||||||
@@ -292,7 +327,7 @@ define(['taskbar'], function(taskbar) {
|
|||||||
|
|
||||||
composer.post = function(post_uuid) {
|
composer.post = function(post_uuid) {
|
||||||
// Check title and post length
|
// Check title and post length
|
||||||
var postData = composer.posts[post_uuid],
|
var postData = composer.posts[post_uuid],
|
||||||
titleEl = composer.postContainer.querySelector('input'),
|
titleEl = composer.postContainer.querySelector('input'),
|
||||||
bodyEl = composer.postContainer.querySelector('textarea');
|
bodyEl = composer.postContainer.querySelector('textarea');
|
||||||
|
|
||||||
@@ -347,7 +382,8 @@ define(['taskbar'], function(taskbar) {
|
|||||||
|
|
||||||
composer.discard = function(post_uuid) {
|
composer.discard = function(post_uuid) {
|
||||||
if (composer.posts[post_uuid]) {
|
if (composer.posts[post_uuid]) {
|
||||||
$(composer.postContainer).find('#imagedrop').html('');
|
$(composer.postContainer).find('.imagedrop').hide();
|
||||||
|
$(composer.postContainer).find('.imagelist').empty();
|
||||||
delete composer.posts[post_uuid];
|
delete composer.posts[post_uuid];
|
||||||
composer.minimize();
|
composer.minimize();
|
||||||
taskbar.discard('composer', post_uuid);
|
taskbar.discard('composer', post_uuid);
|
||||||
|
|||||||
@@ -181,7 +181,7 @@
|
|||||||
if (!templates[tpl_url] || !template_data) return;
|
if (!templates[tpl_url] || !template_data) return;
|
||||||
|
|
||||||
if(typeof global !== "undefined")
|
if(typeof global !== "undefined")
|
||||||
template_data['relative_path'] = global.nconf.get('relative_path');
|
template_data['relative_path'] = nconf.get('relative_path');
|
||||||
else
|
else
|
||||||
template_data['relative_path'] = RELATIVE_PATH;
|
template_data['relative_path'] = RELATIVE_PATH;
|
||||||
|
|
||||||
|
|||||||
@@ -126,13 +126,38 @@
|
|||||||
return tags;
|
return tags;
|
||||||
},
|
},
|
||||||
|
|
||||||
refreshTitle: function() {
|
refreshTitle: function(url) {
|
||||||
var a = document.createElement('a');
|
if (!url) {
|
||||||
|
var a = document.createElement('a');
|
||||||
|
a.href = document.location;
|
||||||
|
url = a.pathname.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
a.href = document.location;
|
socket.emit('api:meta.buildTitle', url, function(title, numNotifications) {
|
||||||
socket.emit('api:meta.buildTitle', a.pathname.slice(1), function(title) {
|
document.title = (numNotifications > 0 ? '(' + numNotifications + ') ' : '') + title;
|
||||||
document.title = title;
|
if (numNotifications > 0) document.querySelector('.notifications a i').className = 'icon-circle active';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jQuery.getJSON(RELATIVE_PATH + '/api/unread/total', function(data) {
|
||||||
|
var badge = jQuery('#numUnreadBadge');
|
||||||
|
badge.html(data.count > 20 ? '20+' : data.count);
|
||||||
|
|
||||||
|
if (data.count > 0) {
|
||||||
|
badge
|
||||||
|
.removeClass('badge-inverse')
|
||||||
|
.addClass('badge-important')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
badge
|
||||||
|
.removeClass('badge-important')
|
||||||
|
.addClass('badge-inverse')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
isRelativeUrl: function(url) {
|
||||||
|
var firstChar = url.slice(0, 1);
|
||||||
|
return (firstChar === '.' || firstChar === '/');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,55 +1,48 @@
|
|||||||
|
|
||||||
<div class="well">
|
<div class="well">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="account-username-box" data-userslug="{userslug}">
|
||||||
<div class="account-username-box">
|
|
||||||
<span class="account-username">
|
<span class="account-username">
|
||||||
<a href="/users/{userslug}">{username}</a>
|
<a href="/users/{userslug}">{username}</a>
|
||||||
</span>
|
</span>
|
||||||
<div class="account-sub-links inline-block pull-right">
|
|
||||||
<span id="settingsLink" class="pull-right"><a href="/users/{userslug}/settings">settings</a></span>
|
|
||||||
<span class="pull-right"><a href="/users/{userslug}/followers">followers</a></span>
|
|
||||||
<span class="pull-right"><a href="/users/{userslug}/following">following</a></span>
|
|
||||||
<span id="editLink" class="pull-right"><a href="/users/{userslug}/edit">edit</a></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
<div class="span2" style="text-align: center; margin-bottom:20px;">
|
<div class="span2 account-block" style="text-align: center; margin-bottom:20px;">
|
||||||
<div class="account-picture-block">
|
<div class="account-picture-block">
|
||||||
<img src="{picture}" class="user-profile-picture img-polaroid"/>
|
<img src="{picture}" class="user-profile-picture img-polaroid"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="account-online-status">
|
<div class="account-online-status">
|
||||||
<span><i class="icon-circle-blank"></i> <span>offline</span></span>
|
<span><i class="icon-circle-blank"></i> <span>offline</span></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="{show_banned}">
|
||||||
|
<span class="label label-important">banned</span>
|
||||||
|
</div>
|
||||||
<div id="user-actions">
|
<div id="user-actions">
|
||||||
<a id="follow-btn" href="#" class="btn hide">Follow</a>
|
<a id="follow-btn" href="#" class="btn hide">Follow</a>
|
||||||
<a id="unfollow-btn" href="#" class="btn hide">Unfollow</a>
|
<a id="unfollow-btn" href="#" class="btn hide">Unfollow</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="span4">
|
<div class="span4">
|
||||||
<h4>profile</h4>
|
|
||||||
<div class="inline-block">
|
<div class="inline-block">
|
||||||
<div class="account-bio-block">
|
<div class="account-bio-block">
|
||||||
<span class="account-bio-label">email</span><i class="icon-eye-close {emailClass}" title="Email hidden"></i>
|
<span class="account-bio-label">email</span><i class="icon-eye-close {emailClass}" title="Email hidden"></i>
|
||||||
<span>{email}</span>
|
<span>{email}</span>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<span class="account-bio-label">full name</span>
|
<span class="account-bio-label">full name</span>
|
||||||
<span>{fullname}</span>
|
<span>{fullname}</span>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<span class="account-bio-label">website</span>
|
<span class="account-bio-label">website</span>
|
||||||
<span><a href="{website}">{website}</a></span>
|
<span><a href="{website}">{website}</a></span>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<span class="account-bio-label">location</span>
|
<span class="account-bio-label">location</span>
|
||||||
<span>{location}</span>
|
<span>{location}</span>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<span class="account-bio-label">age</span>
|
<span class="account-bio-label">age</span>
|
||||||
<span>{age}</span>
|
<span>{age}</span>
|
||||||
<br/>
|
<br/>
|
||||||
@@ -58,22 +51,26 @@
|
|||||||
<span>{joindate}</span>
|
<span>{joindate}</span>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
|
<span class="account-bio-label">profile views</span>
|
||||||
|
<span class="formatted-number">{profileviews}</span>
|
||||||
|
<br/>
|
||||||
|
|
||||||
<span class="account-bio-label">reputation</span>
|
<span class="account-bio-label">reputation</span>
|
||||||
<span id='reputation'>{reputation}</span>
|
<span class="formatted-number">{reputation}</span>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<span class="account-bio-label">posts</span>
|
<span class="account-bio-label">posts</span>
|
||||||
<span id='postcount'>{postcount}</span>
|
<span class="formatted-number">{postcount}</span>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<span class="account-bio-label">followers</span>
|
<span class="account-bio-label">followers</span>
|
||||||
<span>{followerCount}</span>
|
<span class="formatted-number">{followerCount}</span>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<span class="account-bio-label">following</span>
|
<span class="account-bio-label">following</span>
|
||||||
<span>{followingCount}</span>
|
<span class="formatted-number">{followingCount}</span>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
<span class="account-bio-label">signature</span>
|
<span class="account-bio-label">signature</span>
|
||||||
<div class="post-signature">
|
<div class="post-signature">
|
||||||
@@ -82,14 +79,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="span6 user-recent-posts">
|
<div class="span6 user-recent-posts">
|
||||||
<h4>recent posts </h4>
|
|
||||||
<!-- BEGIN posts -->
|
<!-- BEGIN posts -->
|
||||||
<div class="topic-row img-polaroid clearfix" topic-url="topic/{posts.tid}/#{posts.pid}">
|
<div class="topic-row img-polaroid clearfix" topic-url="topic/{posts.tid}/#{posts.pid}">
|
||||||
<span>{posts.content}</span>
|
<span>{posts.content}</span>
|
||||||
<span class="pull-right">{posts.relativeTime} ago</span>
|
<span class="pull-right">{posts.relativeTime} ago</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- END posts -->
|
<!-- END posts -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -60,17 +60,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="account-username-box">
|
<div class="account-username-box" data-userslug="{userslug}">
|
||||||
<span class="account-username">
|
<span class="account-username">
|
||||||
<a href="/users/{userslug}">{username}</a> <i class="icon-chevron-right"></i>
|
<a href="/users/{userslug}">{username}</a> <i class="icon-chevron-right"></i>
|
||||||
<a href="/users/{userslug}/edit">edit</a>
|
<a href="/users/{userslug}/edit">edit</a>
|
||||||
</span>
|
</span>
|
||||||
<div class="account-sub-links inline-block pull-right">
|
|
||||||
<span id="settingsLink" class="pull-right"><a href="/users/{userslug}/settings">settings</a></span>
|
|
||||||
<span class="pull-right"><a href="/users/{userslug}/followers">followers</a></span>
|
|
||||||
<span class="pull-right"><a href="/users/{userslug}/following">following</a></span>
|
|
||||||
<span id="editLink" class="pull-right"><a href="/users/{userslug}/edit">edit</a></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
@@ -171,4 +165,5 @@
|
|||||||
<input type="hidden" template-variable="gravatarpicture" value="{gravatarpicture}" />
|
<input type="hidden" template-variable="gravatarpicture" value="{gravatarpicture}" />
|
||||||
<input type="hidden" template-variable="uploadedpicture" value="{uploadedpicture}" />
|
<input type="hidden" template-variable="uploadedpicture" value="{uploadedpicture}" />
|
||||||
|
|
||||||
|
<script type="text/javascript" src="{relative_path}/src/forum/accountheader.js"></script>
|
||||||
<script type="text/javascript" src="{relative_path}/src/forum/accountedit.js"></script>
|
<script type="text/javascript" src="{relative_path}/src/forum/accountedit.js"></script>
|
||||||
|
|||||||
@@ -1,17 +1,11 @@
|
|||||||
|
|
||||||
<div class="well">
|
<div class="well">
|
||||||
|
|
||||||
<div class="account-username-box">
|
<div class="account-username-box" data-userslug="{userslug}">
|
||||||
<span class="account-username">
|
<span class="account-username">
|
||||||
<a href="/users/{userslug}">{username}</a> <i class="icon-chevron-right"></i>
|
<a href="/users/{userslug}">{username}</a> <i class="icon-chevron-right"></i>
|
||||||
<a href="/users/{userslug}/settings">settings</a>
|
<a href="/users/{userslug}/settings">settings</a>
|
||||||
</span>
|
</span>
|
||||||
<div class="account-sub-links inline-block pull-right">
|
|
||||||
<span id="settingsLink" class="pull-right"><a href="/users/{userslug}/settings">settings</a></span>
|
|
||||||
<span class="pull-right"><a href="/users/{userslug}/followers">followers</a></span>
|
|
||||||
<span class="pull-right"><a href="/users/{userslug}/following">following</a></span>
|
|
||||||
<span id="editLink" class="pull-right"><a href="/users/{userslug}/edit">edit</a></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row-fluid">
|
<div class="row-fluid">
|
||||||
@@ -31,4 +25,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="{relative_path}/src/forum/accountheader.js"></script>
|
||||||
<script type="text/javascript" src="{relative_path}/src/forum/accountsettings.js"></script>
|
<script type="text/javascript" src="{relative_path}/src/forum/accountsettings.js"></script>
|
||||||
@@ -27,6 +27,8 @@
|
|||||||
</script>
|
</script>
|
||||||
<link rel="stylesheet" type="text/css" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css">
|
<link rel="stylesheet" type="text/css" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css">
|
||||||
<script type="text/javascript" src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
|
<script type="text/javascript" src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
|
||||||
|
<script src="{relative_path}/src/utils.js"></script>
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="{relative_path}/css/style.css" />
|
<link rel="stylesheet" type="text/css" href="{relative_path}/css/style.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="{relative_path}/css/admin.css" />
|
<link rel="stylesheet" type="text/css" href="{relative_path}/css/admin.css" />
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
<input type="text" placeholder="Your Community Name" data-field="title" />
|
<input type="text" placeholder="Your Community Name" data-field="title" />
|
||||||
<label>Site Description</label>
|
<label>Site Description</label>
|
||||||
<input type="text" class="input-xxlarge" placeholder="A short description about your community" data-field="description" />
|
<input type="text" class="input-xxlarge" placeholder="A short description about your community" data-field="description" />
|
||||||
|
<label>Imgur Client ID</label>
|
||||||
|
<input type="text" class="input-xxlarge" placeholder="Imgur ClientID for image uploads" data-field="imgurClientID" />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
<ul id="users-container" class="users">
|
<ul id="users-container" class="users">
|
||||||
<!-- BEGIN users -->
|
<!-- BEGIN users -->
|
||||||
<div class="users-box" data-uid="{users.uid}" data-admin="{users.administrator}" data-username="{users.username}">
|
<div class="users-box" data-uid="{users.uid}" data-admin="{users.administrator}" data-username="{users.username}" data-banned="{users.banned}">
|
||||||
<a href="/users/{users.userslug}">
|
<a href="/users/{users.userslug}">
|
||||||
<img src="{users.picture}" class="img-polaroid"/>
|
<img src="{users.picture}" class="img-polaroid"/>
|
||||||
</a>
|
</a>
|
||||||
@@ -37,6 +37,9 @@
|
|||||||
<div>
|
<div>
|
||||||
<a href="#" class="btn delete-btn btn-danger">Delete</a>
|
<a href="#" class="btn delete-btn btn-danger">Delete</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="#" class="btn ban-btn">Ban</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- END users -->
|
<!-- END users -->
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -10,13 +10,8 @@
|
|||||||
<div id="category_active_users"></div>
|
<div id="category_active_users"></div>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="alert alert-warning hide {no_topics_message}" id="category-no-topics">
|
|
||||||
<strong>There are no topics in this category.</strong><br />
|
|
||||||
Why don't you try posting one?
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<button id="new_post" class="btn btn-primary btn-large {show_topic_button}">New Topic</button>
|
<button id="new_post" class="btn btn-primary btn-large {show_topic_button}">New Topic</button>
|
||||||
|
|
||||||
<div class="inline-block pull-right">
|
<div class="inline-block pull-right">
|
||||||
@@ -27,7 +22,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="{show_sidebar}" />
|
<hr/>
|
||||||
|
|
||||||
|
<div class="alert alert-warning hide {no_topics_message}" id="category-no-topics">
|
||||||
|
<strong>There are no topics in this category.</strong><br />
|
||||||
|
Why don't you try posting one?
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="category row">
|
<div class="category row">
|
||||||
<div class="{topic_row_size}">
|
<div class="{topic_row_size}">
|
||||||
|
|||||||
@@ -25,13 +25,17 @@
|
|||||||
"users[^]*following": "following",
|
"users[^]*following": "following",
|
||||||
"users[^]*followers": "followers",
|
"users[^]*followers": "followers",
|
||||||
"users[^]*settings": "accountsettings",
|
"users[^]*settings": "accountsettings",
|
||||||
|
"users[^]*favourites": "favourites",
|
||||||
"users/[^]*": "account",
|
"users/[^]*": "account",
|
||||||
|
|
||||||
"recent": "recent",
|
"recent": "recent",
|
||||||
"unread": "unread",
|
"unread": "unread",
|
||||||
"popular": "category",
|
"popular": "category",
|
||||||
"active": "category",
|
"active": "category",
|
||||||
"search": "search"
|
"search": "search",
|
||||||
|
"reset/[^]*": "reset_code",
|
||||||
|
"reset": "reset"
|
||||||
|
|
||||||
},
|
},
|
||||||
"force_refresh": {
|
"force_refresh": {
|
||||||
"logout": true
|
"logout": true
|
||||||
|
|||||||
34
public/templates/favourites.tpl
Normal file
34
public/templates/favourites.tpl
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
<div class="well">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="account-username-box" data-userslug="{userslug}">
|
||||||
|
<span class="account-username">
|
||||||
|
<a href="/users/{userslug}">{username}</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="no-favourites-notice" class="alert alert-warning {show_nofavourites}">You don't have any favourites, favourite some posts to see them here!</div>
|
||||||
|
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="span12 user-favourite-posts">
|
||||||
|
<!-- BEGIN posts -->
|
||||||
|
<div class="topic-row img-polaroid clearfix" topic-url="topic/{posts.tid}/#{posts.pid}">
|
||||||
|
<span><strong>{posts.username}</strong> : </span>
|
||||||
|
<span>{posts.content}</span>
|
||||||
|
<div>
|
||||||
|
<span class="pull-right">{posts.relativeTime} ago</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
<!-- END posts -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript" src="{relative_path}/src/forum/accountheader.js"></script>
|
||||||
|
<script type="text/javascript" src="{relative_path}/src/forum/favourites.js"></script>
|
||||||
@@ -1,17 +1,11 @@
|
|||||||
|
|
||||||
<div class="well">
|
<div class="well">
|
||||||
|
|
||||||
<div class="account-username-box">
|
<div class="account-username-box" data-userslug="{userslug}">
|
||||||
<span class="account-username">
|
<span class="account-username">
|
||||||
<a href="/users/{userslug}">{username}</a> <i class="icon-chevron-right"></i>
|
<a href="/users/{userslug}">{username}</a> <i class="icon-chevron-right"></i>
|
||||||
<a href="/users/{userslug}/followers">followers</a>
|
<a href="/users/{userslug}/followers">followers</a>
|
||||||
</span>
|
</span>
|
||||||
<div class="account-sub-links inline-block pull-right">
|
|
||||||
<span id="settingsLink" class="pull-right"><a href="/users/{userslug}/settings">settings</a></span>
|
|
||||||
<span class="pull-right"><a href="/users/{userslug}/followers">followers</a></span>
|
|
||||||
<span class="pull-right"><a href="/users/{userslug}/following">following</a></span>
|
|
||||||
<span id="editLink" class="pull-right"><a href="/users/{userslug}/edit">edit</a></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -24,15 +18,14 @@
|
|||||||
<a href="/users/{followers.userslug}">{followers.username}</a>
|
<a href="/users/{followers.userslug}">{followers.username}</a>
|
||||||
<br/>
|
<br/>
|
||||||
<div title="reputation">
|
<div title="reputation">
|
||||||
<span class='reputation'>{followers.reputation}</span>
|
<span class='formatted-number'>{followers.reputation}</span>
|
||||||
<i class='icon-star'></i>
|
<i class='icon-star'></i>
|
||||||
</div>
|
</div>
|
||||||
<div title="post count">
|
<div title="post count">
|
||||||
<span class='postcount'>{followers.postcount}</span>
|
<span class='formatted-number'>{followers.postcount}</span>
|
||||||
<i class='icon-pencil'></i>
|
<i class='icon-pencil'></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- END followers -->
|
<!-- END followers -->
|
||||||
</div>
|
</div>
|
||||||
<div id="no-followers-notice" class="alert alert-warning hide">This user doesn't have any followers :(</div>
|
<div id="no-followers-notice" class="alert alert-warning hide">This user doesn't have any followers :(</div>
|
||||||
|
|||||||
@@ -1,19 +1,11 @@
|
|||||||
|
|
||||||
<div class="well">
|
<div class="well">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="account-username-box" data-userslug="{userslug}">
|
||||||
<div class="account-username-box">
|
|
||||||
<span class="account-username">
|
<span class="account-username">
|
||||||
<a href="/users/{userslug}">{username}</a> <i class="icon-chevron-right"></i>
|
<a href="/users/{userslug}">{username}</a> <i class="icon-chevron-right"></i>
|
||||||
<a href="/users/{userslug}/following">following</a>
|
<a href="/users/{userslug}/following">following</a>
|
||||||
</span>
|
</span>
|
||||||
<div class="account-sub-links inline-block pull-right">
|
|
||||||
<span id="settingsLink" class="pull-right"><a href="/users/{userslug}/settings">settings</a></span>
|
|
||||||
<span class="pull-right"><a href="/users/{userslug}/followers">followers</a></span>
|
|
||||||
<span class="pull-right"><a href="/users/{userslug}/following">following</a></span>
|
|
||||||
<span id="editLink" class="pull-right"><a href="/users/{userslug}/edit">edit</a></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@@ -26,11 +18,11 @@
|
|||||||
<a href="/users/{following.userslug}">{following.username}</a>
|
<a href="/users/{following.userslug}">{following.username}</a>
|
||||||
<br/>
|
<br/>
|
||||||
<div title="reputation">
|
<div title="reputation">
|
||||||
<span class='reputation'>{following.reputation}</span>
|
<span class='formatted-number'>{following.reputation}</span>
|
||||||
<i class='icon-star'></i>
|
<i class='icon-star'></i>
|
||||||
</div>
|
</div>
|
||||||
<div title="post count">
|
<div title="post count">
|
||||||
<span class='postcount'>{following.postcount}</span>
|
<span class='formatted-number'>{following.postcount}</span>
|
||||||
<i class='icon-pencil'></i>
|
<i class='icon-pencil'></i>
|
||||||
</div>
|
</div>
|
||||||
<a id="unfollow-btn" href="#" class="btn unfollow-btn" followingUid="{following.uid}" data-username="{following.username}">Unfollow</a>
|
<a id="unfollow-btn" href="#" class="btn unfollow-btn" followingUid="{following.uid}" data-username="{following.username}">Unfollow</a>
|
||||||
|
|||||||
@@ -48,8 +48,8 @@
|
|||||||
<li>
|
<li>
|
||||||
<a href="/recent">Recent</a>
|
<a href="/recent">Recent</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li class="nodebb-loggedin">
|
||||||
<a href="/unread">Unread</a>
|
<a href="/unread"><span id="numUnreadBadge" class="badge badge-inverse">0</span> Unread</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/users">Users</a>
|
<a href="/users">Users</a>
|
||||||
@@ -62,11 +62,12 @@
|
|||||||
<li><a href="#"><i class="icon-refresh icon-spin"></i> Loading Notifications</a></li>
|
<li><a href="#"><i class="icon-refresh icon-spin"></i> Loading Notifications</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<form id="search-form"
|
<li>
|
||||||
class="form-search form-inline" action="" method="GET">
|
<form id="search-form" class="form-search form-inline" action="" method="GET">
|
||||||
<input type="text" name="query" class="input-medium search-query">
|
<input type="text" name="query" class="input-medium search-query">
|
||||||
<button type="submit" class="btn hide">Search</button>
|
<button type="submit" class="btn hide">Search</button>
|
||||||
</form>
|
</form>
|
||||||
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -110,7 +110,6 @@
|
|||||||
contentEl.addEventListener('click', function(e) {
|
contentEl.addEventListener('click', function(e) {
|
||||||
if (e.target.hasAttribute('data-path')) {
|
if (e.target.hasAttribute('data-path')) {
|
||||||
var href = 'install/' + e.target.getAttribute('data-path');
|
var href = 'install/' + e.target.getAttribute('data-path');
|
||||||
console.log(href);
|
|
||||||
if (!e.target.disabled) ajaxify.go(href);
|
if (!e.target.disabled) ajaxify.go(href);
|
||||||
}
|
}
|
||||||
}, false);
|
}, false);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<button class="btn btn-primary" id="login" type="submit">Login</button> <a href="/reset">Forgot Password?</a>
|
<button class="btn btn-primary" id="login" type="submit">Login</button> <a href="/reset">Forgot Password?</a>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<span id="login-error-notify" class="label label-important hide">Invalid username/password</span><br/>
|
<div id="login-error-notify" class="alert alert-danger hide">Invalid username/password</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="well span6 {alternate_logins:display}">
|
<div class="well span6 {alternate_logins:display}">
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
<button id="ids_{main_posts.pid}_{main_posts.uid}" class="btn delete {main_posts.display_moderator_tools}" type="button" title="Delete"><i class="icon-trash"></i></button>
|
<button id="ids_{main_posts.pid}_{main_posts.uid}" class="btn delete {main_posts.display_moderator_tools}" type="button" title="Delete"><i class="icon-trash"></i></button>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button class="btn follow" type="button" title="Be notified of new replies in this topic"><i class="icon-eye-open"></i></button>
|
<button class="btn follow" type="button" title="Be notified of new replies in this topic"><i class="icon-eye-open"></i></button>
|
||||||
<button id="favs_{main_posts.pid}_{main_posts.uid}" class="favourite btn" type="button">
|
<button id="favs_{main_posts.pid}_{main_posts.uid}" class="favourite btn {main_posts.fav_button_class}" type="button">
|
||||||
<span>Favourite</span>
|
<span>Favourite</span>
|
||||||
<span class="post_rep_{main_posts.pid}">{main_posts.post_rep} </span><i class="{main_posts.fav_star_class}"></i>
|
<span class="post_rep_{main_posts.pid}">{main_posts.post_rep} </span><i class="{main_posts.fav_star_class}"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -89,9 +89,10 @@
|
|||||||
<i class="icon-star"></i><span class="user_rep_{posts.uid} formatted-number">{posts.user_rep}</span>
|
<i class="icon-star"></i><span class="user_rep_{posts.uid} formatted-number">{posts.user_rep}</span>
|
||||||
<div id="ids_{posts.pid}_{posts.uid}" class="chat hidden-phone" title="Chat"><i class="icon-comment"></i></div>
|
<div id="ids_{posts.pid}_{posts.uid}" class="chat hidden-phone" title="Chat"><i class="icon-comment"></i></div>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="label label-important {posts.show_banned}">banned</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="span11 span12-tablet">
|
<div class="span11 span12-tablet">
|
||||||
<div class="post-block">
|
<div class="post-block speech-bubble">
|
||||||
<div id="content_{posts.pid}" class="post-content">{posts.content}</div>
|
<div id="content_{posts.pid}" class="post-content">{posts.content}</div>
|
||||||
<div id="images_{posts.pid}" class="post-images">
|
<div id="images_{posts.pid}" class="post-images">
|
||||||
<!-- BEGIN uploadedImages -->
|
<!-- BEGIN uploadedImages -->
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<button id="mark-allread-btn" class="btn {show_markallread_button}">Mark All Read</button>
|
<button id="mark-allread-btn" class="btn {show_markallread_button}">Mark All As Read</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="category row">
|
<div class="category row">
|
||||||
|
|||||||
@@ -24,11 +24,11 @@
|
|||||||
<a href="/users/{users.userslug}">{users.username}</a>
|
<a href="/users/{users.userslug}">{users.username}</a>
|
||||||
<br/>
|
<br/>
|
||||||
<div title="reputation">
|
<div title="reputation">
|
||||||
<span class='reputation'>{users.reputation}</span>
|
<span class='formatted-number'>{users.reputation}</span>
|
||||||
<i class='icon-star'></i>
|
<i class='icon-star'></i>
|
||||||
</div>
|
</div>
|
||||||
<div title="post count">
|
<div title="post count">
|
||||||
<span class='postcount'>{users.postcount}</span>
|
<span class='formatted-number'>{users.postcount}</span>
|
||||||
<i class='icon-pencil'></i>
|
<i class='icon-pencil'></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ var RDB = require('./../redis.js'),
|
|||||||
|
|
||||||
UserAdmin.deleteUser = function(uid, theirid, socket) {
|
UserAdmin.deleteUser = function(uid, theirid, socket) {
|
||||||
user.isAdministrator(uid, function(amIAdmin) {
|
user.isAdministrator(uid, function(amIAdmin) {
|
||||||
user.isAdministrator(theirid, function(areTheyAdmin){
|
user.isAdministrator(theirid, function(areTheyAdmin) {
|
||||||
if(amIAdmin && !areTheyAdmin) {
|
if(amIAdmin && !areTheyAdmin) {
|
||||||
user.delete(theirid, function(data) {
|
user.delete(theirid, function(data) {
|
||||||
|
|
||||||
@@ -58,8 +58,39 @@ var RDB = require('./../redis.js'),
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
UserAdmin.banUser = function(uid, theirid, socket) {
|
||||||
|
user.isAdministrator(uid, function(amIAdmin) {
|
||||||
|
user.isAdministrator(theirid, function(areTheyAdmin) {
|
||||||
|
if(amIAdmin && !areTheyAdmin) {
|
||||||
|
user.ban(theirid, function(err, result) {
|
||||||
|
|
||||||
|
socket.emit('event:alert', {
|
||||||
|
title: 'User Banned',
|
||||||
|
message: 'This user is banned!',
|
||||||
|
type: 'success',
|
||||||
|
timeout: 2000
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
UserAdmin.unbanUser = function(uid, theirid, socket) {
|
||||||
|
user.isAdministrator(uid, function(amIAdmin) {
|
||||||
|
if(amIAdmin) {
|
||||||
|
user.unban(theirid, function(err, result) {
|
||||||
|
socket.emit('event:alert', {
|
||||||
|
title: 'User Unbanned',
|
||||||
|
message: 'This user is unbanned!',
|
||||||
|
type: 'success',
|
||||||
|
timeout: 2000
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,13 @@ var RDB = require('./redis.js'),
|
|||||||
utils = require('./../public/src/utils.js'),
|
utils = require('./../public/src/utils.js'),
|
||||||
user = require('./user.js'),
|
user = require('./user.js'),
|
||||||
async = require('async'),
|
async = require('async'),
|
||||||
topics = require('./topics.js');
|
topics = require('./topics.js'),
|
||||||
|
winston = require('winston');
|
||||||
|
|
||||||
(function(Categories) {
|
(function(Categories) {
|
||||||
|
|
||||||
Categories.getCategoryById = function(category_id, current_user, callback) {
|
Categories.getCategoryById = function(category_id, current_user, callback) {
|
||||||
|
|
||||||
Categories.getCategoryData(category_id, function(err, categoryData) {
|
Categories.getCategoryData(category_id, function(err, categoryData) {
|
||||||
if (err) return callback(err);
|
if (err) return callback(err);
|
||||||
|
|
||||||
@@ -38,9 +39,9 @@ var RDB = require('./redis.js'),
|
|||||||
'category_id': category_id,
|
'category_id': category_id,
|
||||||
'active_users': [],
|
'active_users': [],
|
||||||
'topics' : [],
|
'topics' : [],
|
||||||
'twitter-intent-url': 'https://twitter.com/intent/tweet?url=' + encodeURIComponent(global.nconf.get('url') + 'category/' + category_slug) + '&text=' + encodeURIComponent(category_name),
|
'twitter-intent-url': 'https://twitter.com/intent/tweet?url=' + encodeURIComponent(nconf.get('url') + 'category/' + category_slug) + '&text=' + encodeURIComponent(category_name),
|
||||||
'facebook-share-url': 'https://www.facebook.com/sharer/sharer.php?u=' + encodeURIComponent(global.nconf.get('url') + 'category/' + category_slug),
|
'facebook-share-url': 'https://www.facebook.com/sharer/sharer.php?u=' + encodeURIComponent(nconf.get('url') + 'category/' + category_slug),
|
||||||
'google-share-url': 'https://plus.google.com/share?url=' + encodeURIComponent(global.nconf.get('url') + 'category/' + category_slug)
|
'google-share-url': 'https://plus.google.com/share?url=' + encodeURIComponent(nconf.get('url') + 'category/' + category_slug)
|
||||||
};
|
};
|
||||||
|
|
||||||
function getTopics(next) {
|
function getTopics(next) {
|
||||||
@@ -48,7 +49,7 @@ var RDB = require('./redis.js'),
|
|||||||
next(null, topicsData);
|
next(null, topicsData);
|
||||||
}, category_id);
|
}, category_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getModerators(next) {
|
function getModerators(next) {
|
||||||
Categories.getModerators(category_id, next);
|
Categories.getModerators(category_id, next);
|
||||||
}
|
}
|
||||||
@@ -65,7 +66,6 @@ var RDB = require('./redis.js'),
|
|||||||
categoryData.moderators = moderators;
|
categoryData.moderators = moderators;
|
||||||
categoryData.show_sidebar = 'hidden';
|
categoryData.show_sidebar = 'hidden';
|
||||||
categoryData.no_topics_message = 'show';
|
categoryData.no_topics_message = 'show';
|
||||||
|
|
||||||
callback(null, categoryData);
|
callback(null, categoryData);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -156,22 +156,22 @@ var RDB = require('./redis.js'),
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
callback(allread);
|
callback(allread);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Categories.markAsRead = function(cid, uid) {
|
Categories.markAsRead = function(cid, uid) {
|
||||||
RDB.sadd('cid:' + cid + ':read_by_uid', uid);
|
RDB.sadd('cid:' + cid + ':read_by_uid', uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
Categories.hasReadCategories = function(cids, uid, callback) {
|
Categories.hasReadCategories = function(cids, uid, callback) {
|
||||||
var batch = RDB.multi();
|
var batch = RDB.multi();
|
||||||
|
|
||||||
for (var i=0, ii=cids.length; i<ii; i++) {
|
for (var i=0, ii=cids.length; i<ii; i++) {
|
||||||
batch.sismember('cid:' + cids[i] + ':read_by_uid', uid);
|
batch.sismember('cid:' + cids[i] + ':read_by_uid', uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
batch.exec(function(err, hasRead) {
|
batch.exec(function(err, hasRead) {
|
||||||
callback(hasRead);
|
callback(hasRead);
|
||||||
});
|
});
|
||||||
@@ -180,15 +180,16 @@ var RDB = require('./redis.js'),
|
|||||||
Categories.hasReadCategory = function(cid, uid, callback) {
|
Categories.hasReadCategory = function(cid, uid, callback) {
|
||||||
RDB.sismember('cid:' + cid + ':read_by_uid', uid, function(err, hasRead) {
|
RDB.sismember('cid:' + cid + ':read_by_uid', uid, function(err, hasRead) {
|
||||||
RDB.handle(err);
|
RDB.handle(err);
|
||||||
|
|
||||||
callback(hasRead);
|
callback(hasRead);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Categories.getRecentReplies = function(cid, count, callback) {
|
Categories.getRecentReplies = function(cid, count, callback) {
|
||||||
RDB.zrevrange('categories:recent_posts:cid:' + cid, 0, (count<10)?10:count, function(err, pids) {
|
RDB.zrevrange('categories:recent_posts:cid:' + cid, 0, (count<10)?10:count, function(err, pids) {
|
||||||
|
|
||||||
if(err) {
|
if(err) {
|
||||||
console.log(err);
|
winston.err(err);
|
||||||
callback([]);
|
callback([]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -198,11 +199,11 @@ var RDB = require('./redis.js'),
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
posts.getPostSummaryByPids(pids, function(posts) {
|
posts.getPostSummaryByPids(pids, function(err, postData) {
|
||||||
if(posts.length > count) {
|
if(postData.length > count) {
|
||||||
posts = posts.slice(0, count);
|
postData = postData.slice(0, count);
|
||||||
}
|
}
|
||||||
callback(posts);
|
callback(postData);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -213,8 +214,8 @@ var RDB = require('./redis.js'),
|
|||||||
|
|
||||||
function movePost(pid, callback) {
|
function movePost(pid, callback) {
|
||||||
posts.getPostField(pid, 'timestamp', function(timestamp) {
|
posts.getPostField(pid, 'timestamp', function(timestamp) {
|
||||||
RDB.zrem('categories:recent_posts:cid:' + oldCid, pid);
|
RDB.zrem('categories:recent_posts:cid:' + oldCid, pid);
|
||||||
RDB.zadd('categories:recent_posts:cid:' + cid, timestamp, pid);
|
RDB.zadd('categories:recent_posts:cid:' + cid, timestamp, pid);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,12 +223,12 @@ var RDB = require('./redis.js'),
|
|||||||
if(!err) {
|
if(!err) {
|
||||||
callback(null, 1)
|
callback(null, 1)
|
||||||
} else {
|
} else {
|
||||||
console.log(err);
|
winston.err(err);
|
||||||
callback(err, null);
|
callback(err, null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log(err);
|
winston.err(err);
|
||||||
callback(err, null);
|
callback(err, null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -239,20 +240,20 @@ var RDB = require('./redis.js'),
|
|||||||
else callback(new Error('No category found!'));
|
else callback(new Error('No category found!'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Categories.getCategoryField = function(cid, field, callback) {
|
Categories.getCategoryField = function(cid, field, callback) {
|
||||||
RDB.hget('category:' + cid, field, callback);
|
RDB.hget('category:' + cid, field, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
Categories.getCategoryFields = function(cid, fields, callback) {
|
Categories.getCategoryFields = function(cid, fields, callback) {
|
||||||
RDB.hmgetObject('category:' + cid, fields, function(err, data) {
|
RDB.hmgetObject('category:' + cid, fields, function(err, data) {
|
||||||
if(err === null)
|
if(err === null)
|
||||||
callback(data);
|
callback(data);
|
||||||
else
|
else
|
||||||
console.log(err);
|
winston.err(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Categories.setCategoryField = function(cid, field, value) {
|
Categories.setCategoryField = function(cid, field, value) {
|
||||||
RDB.hset('category:' + cid, field, value);
|
RDB.hset('category:' + cid, field, value);
|
||||||
}
|
}
|
||||||
@@ -266,37 +267,37 @@ var RDB = require('./redis.js'),
|
|||||||
callback({'categories' : []});
|
callback({'categories' : []});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var categories = [];
|
var categories = [];
|
||||||
|
|
||||||
function getCategory(cid, callback) {
|
function getCategory(cid, callback) {
|
||||||
Categories.getCategoryData(cid, function(err, categoryData) {
|
Categories.getCategoryData(cid, function(err, categoryData) {
|
||||||
|
|
||||||
if(err) {
|
if(err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Categories.hasReadCategory(cid, current_user, function(hasRead) {
|
Categories.hasReadCategory(cid, current_user, function(hasRead) {
|
||||||
categoryData['badgeclass'] = (parseInt(categoryData.topic_count,10) === 0 || (hasRead && current_user != 0)) ? '' : 'badge-important';
|
categoryData['badgeclass'] = (parseInt(categoryData.topic_count, 10) === 0 || (hasRead && current_user != 0)) ? '' : 'badge-important';
|
||||||
|
|
||||||
categories.push(categoryData);
|
categories.push(categoryData);
|
||||||
callback(null);
|
callback(null);
|
||||||
}) ;
|
}) ;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async.eachSeries(cids, getCategory, function(err) {
|
async.eachSeries(cids, getCategory, function(err) {
|
||||||
if(err) {
|
if(err) {
|
||||||
console.log(err);
|
winston.err(err);
|
||||||
callback(null);
|
callback(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
callback({'categories': categories});
|
callback({'categories': categories});
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}(exports));
|
}(exports));
|
||||||
|
|
||||||
|
|||||||
@@ -13,33 +13,31 @@ var RDB = require('./redis.js'),
|
|||||||
type: 'error',
|
type: 'error',
|
||||||
timeout: 5000
|
timeout: 5000
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.emit('api:posts.favourite', {
|
|
||||||
status: 'error',
|
|
||||||
pid: pid
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
posts.getPostField(pid, 'uid', function(uid_of_poster) {
|
posts.getPostFields(pid, ['uid', 'timestamp'], function(postData) {
|
||||||
|
|
||||||
Favourites.hasFavourited(pid, uid, function(hasFavourited) {
|
Favourites.hasFavourited(pid, uid, function(hasFavourited) {
|
||||||
if (hasFavourited == false) {
|
if (hasFavourited == false) {
|
||||||
RDB.sadd('pid:' + pid + ':users_favourited', uid);
|
RDB.sadd('pid:' + pid + ':users_favourited', uid);
|
||||||
|
RDB.zadd('uid:' + uid + ':favourites', postData.timestamp, pid);
|
||||||
|
|
||||||
RDB.hincrby('post:' + pid, 'reputation', 1);
|
RDB.hincrby('post:' + pid, 'reputation', 1);
|
||||||
|
|
||||||
if (uid !== uid_of_poster) {
|
if (uid !== postData.uid) {
|
||||||
user.incrementUserFieldBy(uid_of_poster, 'reputation', 1, function(err, newreputation) {
|
user.incrementUserFieldBy(postData.uid, 'reputation', 1, function(err, newreputation) {
|
||||||
RDB.zadd('users:reputation', newreputation, uid_of_poster);
|
RDB.zadd('users:reputation', newreputation, postData.uid);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (room_id) {
|
if (room_id) {
|
||||||
io.sockets.in(room_id).emit('event:rep_up', {uid: uid !== uid_of_poster ? uid_of_poster : 0, pid: pid});
|
io.sockets.in(room_id).emit('event:rep_up', {uid: uid !== postData.uid ? postData.uid : 0, pid: pid});
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.emit('api:posts.favourite', {
|
socket.emit('api:posts.favourite', {
|
||||||
status: 'ok'
|
status: 'ok',
|
||||||
|
pid: pid
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -62,10 +60,12 @@ var RDB = require('./redis.js'),
|
|||||||
|
|
||||||
Favourites.hasFavourited(pid, uid, function(hasFavourited) {
|
Favourites.hasFavourited(pid, uid, function(hasFavourited) {
|
||||||
if (hasFavourited == true) {
|
if (hasFavourited == true) {
|
||||||
|
|
||||||
RDB.srem('pid:' + pid + ':users_favourited', uid);
|
RDB.srem('pid:' + pid + ':users_favourited', uid);
|
||||||
|
RDB.zrem('uid:' + uid + ':favourites', pid);
|
||||||
|
|
||||||
RDB.hincrby('post:' + pid, 'reputation', -1);
|
RDB.hincrby('post:' + pid, 'reputation', -1);
|
||||||
|
|
||||||
if (uid !== uid_of_poster) {
|
if (uid !== uid_of_poster) {
|
||||||
user.incrementUserFieldBy(uid_of_poster, 'reputation', -1, function(err, newreputation) {
|
user.incrementUserFieldBy(uid_of_poster, 'reputation', -1, function(err, newreputation) {
|
||||||
RDB.zadd('users:reputation', newreputation, uid_of_poster);
|
RDB.zadd('users:reputation', newreputation, uid_of_poster);
|
||||||
@@ -75,6 +75,11 @@ var RDB = require('./redis.js'),
|
|||||||
if (room_id) {
|
if (room_id) {
|
||||||
io.sockets.in(room_id).emit('event:rep_down', {uid: uid !== uid_of_poster ? uid_of_poster : 0, pid: pid});
|
io.sockets.in(room_id).emit('event:rep_down', {uid: uid !== uid_of_poster ? uid_of_poster : 0, pid: pid});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
socket.emit('api:posts.unfavourite', {
|
||||||
|
status: 'ok',
|
||||||
|
pid: pid
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -83,7 +88,7 @@ var RDB = require('./redis.js'),
|
|||||||
Favourites.hasFavourited = function(pid, uid, callback) {
|
Favourites.hasFavourited = function(pid, uid, callback) {
|
||||||
RDB.sismember('pid:' + pid + ':users_favourited', uid, function(err, hasFavourited) {
|
RDB.sismember('pid:' + pid + ':users_favourited', uid, function(err, hasFavourited) {
|
||||||
RDB.handle(err);
|
RDB.handle(err);
|
||||||
|
|
||||||
callback(hasFavourited);
|
callback(hasFavourited);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -95,10 +100,10 @@ var RDB = require('./redis.js'),
|
|||||||
for (var i=0, ii=pids.length; i<ii; i++) {
|
for (var i=0, ii=pids.length; i<ii; i++) {
|
||||||
(function(post_id) {
|
(function(post_id) {
|
||||||
Favourites.hasFavourited(post_id, uid, function(hasFavourited) {
|
Favourites.hasFavourited(post_id, uid, function(hasFavourited) {
|
||||||
|
|
||||||
data[post_id] = hasFavourited;
|
data[post_id] = hasFavourited;
|
||||||
loaded ++;
|
loaded ++;
|
||||||
if (loaded === pids.length)
|
if (loaded === pids.length)
|
||||||
callback(data);
|
callback(data);
|
||||||
});
|
});
|
||||||
}(pids[i]));
|
}(pids[i]));
|
||||||
|
|||||||
@@ -4,12 +4,13 @@
|
|||||||
posts = require('./posts.js'),
|
posts = require('./posts.js'),
|
||||||
topics = require('./topics.js'),
|
topics = require('./topics.js'),
|
||||||
fs = require('fs'),
|
fs = require('fs'),
|
||||||
rss = require('node-rss');
|
rss = require('node-rss'),
|
||||||
|
winston = require('winston');
|
||||||
|
|
||||||
function saveFeed(location, feed) {
|
function saveFeed(location, feed) {
|
||||||
fs.writeFile(location, rss.getFeedXML(feed), function (err) {
|
fs.writeFile(location, rss.getFeedXML(feed), function (err) {
|
||||||
if(err) {
|
if(err) {
|
||||||
console.log(err);
|
winston.err(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -32,7 +33,7 @@
|
|||||||
var cache_time_in_seconds = 60;
|
var cache_time_in_seconds = 60;
|
||||||
|
|
||||||
topics.getTopicWithPosts(tid, 0, function(err, topicData) {
|
topics.getTopicWithPosts(tid, 0, function(err, topicData) {
|
||||||
if (err) console.log('Error: Problem saving topic RSS feed', err);
|
if (err) winston.error('Problem saving topic RSS feed', err.stack);
|
||||||
|
|
||||||
var location = '/topic/' + topicData.slug,
|
var location = '/topic/' + topicData.slug,
|
||||||
xml_url = '/topic/' + tid + '.rss';
|
xml_url = '/topic/' + tid + '.rss';
|
||||||
@@ -69,7 +70,7 @@
|
|||||||
Feed.updateCategory = function(cid) {
|
Feed.updateCategory = function(cid) {
|
||||||
categories.getCategoryById(cid, 0, function(err, categoryData) {
|
categories.getCategoryById(cid, 0, function(err, categoryData) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log('Error: Could not update RSS feed for category ' + cid);
|
winston.error('Could not update RSS feed for category ' + cid, err.stack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ var request = require('request');
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var post = request.post(options, function(err, req, body){
|
var post = request.post(options, function(err, req, body) {
|
||||||
try{
|
try{
|
||||||
callback(err, JSON.parse(body));
|
callback(err, JSON.parse(body));
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
|
|||||||
@@ -79,16 +79,16 @@ var async = require('async'),
|
|||||||
port: config.port
|
port: config.port
|
||||||
},
|
},
|
||||||
api_url: protocol + '//' + host + (config.use_port ? ':' + config.port : '') + relative_path + '/api/',
|
api_url: protocol + '//' + host + (config.use_port ? ':' + config.port : '') + relative_path + '/api/',
|
||||||
relative_path: relative_path
|
relative_path: relative_path
|
||||||
};
|
};
|
||||||
|
|
||||||
server_conf.base_url = protocol + '//' + host;
|
server_conf.base_url = protocol + '//' + host;
|
||||||
server_conf.relative_path = relative_path;
|
server_conf.relative_path = relative_path;
|
||||||
server_conf.imgurClientID = '';
|
|
||||||
|
meta.configs.set('postDelay', 10000);
|
||||||
meta.config.set('postDelay', 10000);
|
meta.configs.set('minimumPostLength', 8);
|
||||||
meta.config.set('minimumPostLength', 8);
|
meta.configs.set('minimumTitleLength', 3);
|
||||||
meta.config.set('minimumTitleLength', 3);
|
meta.configs.set('imgurClientID', '');
|
||||||
|
|
||||||
install.save(server_conf, client_conf, callback);
|
install.save(server_conf, client_conf, callback);
|
||||||
});
|
});
|
||||||
|
|||||||
23
src/login.js
23
src/login.js
@@ -2,7 +2,8 @@
|
|||||||
var user = require('./user.js'),
|
var user = require('./user.js'),
|
||||||
bcrypt = require('bcrypt'),
|
bcrypt = require('bcrypt'),
|
||||||
RDB = require('./redis.js'),
|
RDB = require('./redis.js'),
|
||||||
path = require('path');
|
path = require('path'),
|
||||||
|
winston = require('winston');
|
||||||
|
|
||||||
(function(Login){
|
(function(Login){
|
||||||
|
|
||||||
@@ -23,18 +24,28 @@ var user = require('./user.js'),
|
|||||||
message: 'invalid-user'
|
message: 'invalid-user'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
user.getUserField(uid, 'password', function(user_password) {
|
user.getUserFields(uid, ['password', 'banned'], function(err, userData) {
|
||||||
bcrypt.compare(password, user_password, function(err, res) {
|
if(err)
|
||||||
|
return next(err);
|
||||||
|
|
||||||
|
if(userData.banned && userData.banned === '1') {
|
||||||
|
return next({
|
||||||
|
status: "error",
|
||||||
|
message: "user-banned"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bcrypt.compare(password, userData.password, function(err, res) {
|
||||||
if(err) {
|
if(err) {
|
||||||
console.log(err);
|
winston.err(err);
|
||||||
next({
|
next({
|
||||||
status: "error",
|
status: "error",
|
||||||
message: 'bcrypt compare error'
|
message: 'bcrypt compare error'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
next({
|
next({
|
||||||
status: "ok",
|
status: "ok",
|
||||||
|
|||||||
76
src/messaging.js
Normal file
76
src/messaging.js
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
|
||||||
|
var RDB = require('./redis'),
|
||||||
|
async = require('async');
|
||||||
|
|
||||||
|
|
||||||
|
(function(Messaging) {
|
||||||
|
|
||||||
|
function sortUids(fromuid, touid) {
|
||||||
|
var uids = [fromuid, touid];
|
||||||
|
uids.sort();
|
||||||
|
return uids;
|
||||||
|
}
|
||||||
|
|
||||||
|
Messaging.addMessage = function(fromuid, touid, content, callback) {
|
||||||
|
var uids = sortUids(fromuid, touid);
|
||||||
|
|
||||||
|
RDB.incr('global:next_message_id', function(err, mid) {
|
||||||
|
if(err)
|
||||||
|
return callback(err, null);
|
||||||
|
|
||||||
|
var message = {
|
||||||
|
content: content,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
fromuid: fromuid,
|
||||||
|
touid: touid
|
||||||
|
};
|
||||||
|
|
||||||
|
RDB.hmset('message:' + mid, message);
|
||||||
|
RDB.rpush('messages:' + uids[0] + ':' + uids[1], mid);
|
||||||
|
|
||||||
|
callback(null, message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Messaging.getMessages = function(fromuid, touid, callback) {
|
||||||
|
var uids = sortUids(fromuid, touid);
|
||||||
|
|
||||||
|
RDB.lrange('messages:' + uids[0] + ':' + uids[1], 0, -1, function(err, mids) {
|
||||||
|
if(err)
|
||||||
|
return callback(err, null);
|
||||||
|
|
||||||
|
if(!mids || !mids.length) {
|
||||||
|
return callback(null, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
user.getUserField(touid, 'username', function(err, tousername) {
|
||||||
|
|
||||||
|
var messages = [];
|
||||||
|
|
||||||
|
function getMessage(mid, next) {
|
||||||
|
RDB.hgetall('message:' + mid, function(err, message) {
|
||||||
|
if(err)
|
||||||
|
return next(err);
|
||||||
|
|
||||||
|
if(message.fromuid === fromuid)
|
||||||
|
message.content = 'You : ' + message.content;
|
||||||
|
else
|
||||||
|
message.content = tousername + ' : ' + message.content;
|
||||||
|
|
||||||
|
messages.push(message);
|
||||||
|
next(null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async.eachSeries(mids, getMessage, function(err) {
|
||||||
|
if(err)
|
||||||
|
return callback(err, null);
|
||||||
|
|
||||||
|
callback(null, messages);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}(exports));
|
||||||
26
src/meta.js
26
src/meta.js
@@ -5,7 +5,14 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
fs = require('fs');
|
fs = require('fs');
|
||||||
|
|
||||||
(function(Meta) {
|
(function(Meta) {
|
||||||
Meta.config = {
|
|
||||||
|
Meta.configs = {
|
||||||
|
init: function(callback) {
|
||||||
|
Meta.configs.get(function(config) {
|
||||||
|
Meta.config = config;
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
},
|
||||||
get: function(callback) {
|
get: function(callback) {
|
||||||
RDB.hgetall('config', function(err, config) {
|
RDB.hgetall('config', function(err, config) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
@@ -48,9 +55,9 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
if (exists) {
|
if (exists) {
|
||||||
fs.readFile(themeConfPath, function(err, conf) {
|
fs.readFile(themeConfPath, function(err, conf) {
|
||||||
conf = JSON.parse(conf);
|
conf = JSON.parse(conf);
|
||||||
conf.src = global.nconf.get('url') + 'themes/' + themeDir + '/' + conf.src;
|
conf.src = nconf.get('url') + 'themes/' + themeDir + '/' + conf.src;
|
||||||
if (conf.screenshot) conf.screenshot = global.nconf.get('url') + 'themes/' + themeDir + '/' + conf.screenshot;
|
if (conf.screenshot) conf.screenshot = nconf.get('url') + 'themes/' + themeDir + '/' + conf.screenshot;
|
||||||
else conf.screenshot = global.nconf.get('url') + 'images/themes/default.png';
|
else conf.screenshot = nconf.get('url') + 'images/themes/default.png';
|
||||||
themeArr.push(conf);
|
themeArr.push(conf);
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
@@ -80,10 +87,10 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
}, function(err, values) {
|
}, function(err, values) {
|
||||||
var title;
|
var title;
|
||||||
|
|
||||||
if (err) title = global.config.title || 'NodeBB';
|
if (err) title = Meta.config.title || 'NodeBB';
|
||||||
else title = (values.notifCount > 0 ? '(' + values.notifCount + ') ' : '') + (values.title ? values.title + ' | ' : '') + (global.config.title || 'NodeBB');
|
else title = (values.title ? values.title + ' | ' : '') + (Meta.config.title || 'NodeBB');
|
||||||
|
|
||||||
callback(null, title);
|
callback(null, title, values.notifCount);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
parseFragment: function(urlFragment, callback) {
|
parseFragment: function(urlFragment, callback) {
|
||||||
@@ -110,4 +117,7 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
} else callback(null);
|
} else callback(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(exports));
|
|
||||||
|
|
||||||
|
}(exports));
|
||||||
|
|
||||||
|
|||||||
114
src/plugins.js
114
src/plugins.js
@@ -2,12 +2,13 @@ var fs = require('fs'),
|
|||||||
path = require('path'),
|
path = require('path'),
|
||||||
RDB = require('./redis.js'),
|
RDB = require('./redis.js'),
|
||||||
async = require('async'),
|
async = require('async'),
|
||||||
|
winston = require('winston'),
|
||||||
plugins = {
|
plugins = {
|
||||||
libraries: [],
|
libraries: [],
|
||||||
loadedHooks: {},
|
loadedHooks: {},
|
||||||
init: function() {
|
init: function() {
|
||||||
if (this.initialized) return;
|
if (this.initialized) return;
|
||||||
if (global.env === 'development') console.log('Info: [plugins] Initializing plugins system');
|
if (global.env === 'development') winston.info('[plugins] Initializing plugins system');
|
||||||
|
|
||||||
var _self = this;
|
var _self = this;
|
||||||
|
|
||||||
@@ -19,40 +20,44 @@ var fs = require('fs'),
|
|||||||
function(plugins, next) {
|
function(plugins, next) {
|
||||||
async.each(plugins, function(plugin) {
|
async.each(plugins, function(plugin) {
|
||||||
// TODO: Update this check to also check node_modules
|
// TODO: Update this check to also check node_modules
|
||||||
var pluginPath = path.join(__dirname, '../plugins/', plugin);
|
var pluginPath = path.join(__dirname, '../plugins/', plugin),
|
||||||
fs.exists(pluginPath, function(exists) {
|
modulePath = path.join(__dirname, '../node_modules/', plugin);
|
||||||
if (exists) {
|
if (fs.existsSync(pluginPath)) _self.loadPlugin(pluginPath, next);
|
||||||
fs.readFile(path.join(pluginPath, 'plugin.json'), function(err, data) {
|
else if (fs.existsSync(modulePath)) _self.loadPlugin(modulePath, next);
|
||||||
if (err) return next(err);
|
else {
|
||||||
|
if (global.env === 'development') winston.info('[plugins] Plugin \'' + plugin + '\' not found');
|
||||||
var pluginData = JSON.parse(data);
|
next(); // Ignore this plugin silently
|
||||||
_self.libraries[pluginData.id] = require(path.join(pluginPath, pluginData.library));
|
}
|
||||||
if (pluginData.hooks) {
|
|
||||||
for(var x=0,numHooks=pluginData.hooks.length;x<numHooks;x++) {
|
|
||||||
_self.registerHook(pluginData.id, pluginData.hooks[x]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (global.env === 'development') console.log('Info: [plugins] Loaded plugin: ' + pluginData.id);
|
|
||||||
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (global.env === 'development') console.log('Info: [plugins] Plugin \'' + plugin + '\' not found');
|
|
||||||
next(); // Ignore this plugin silently
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}, next);
|
}, next);
|
||||||
}
|
}
|
||||||
], function(err) {
|
], function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (global.env === 'development') console.log('Info: [plugins] NodeBB encountered a problem while loading plugins', err.message);
|
if (global.env === 'development') winston.info('[plugins] NodeBB encountered a problem while loading plugins', err.message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global.env === 'development') console.log('Info: [plugins] Plugins OK');
|
if (global.env === 'development') winston.info('[plugins] Plugins OK');
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
initialized: false,
|
initialized: false,
|
||||||
|
loadPlugin: function(pluginPath, callback) {
|
||||||
|
var _self = this;
|
||||||
|
|
||||||
|
fs.readFile(path.join(pluginPath, 'plugin.json'), function(err, data) {
|
||||||
|
if (err) return callback(err);
|
||||||
|
|
||||||
|
var pluginData = JSON.parse(data);
|
||||||
|
_self.libraries[pluginData.id] = require(path.join(pluginPath, pluginData.library));
|
||||||
|
if (pluginData.hooks) {
|
||||||
|
for(var x=0,numHooks=pluginData.hooks.length;x<numHooks;x++) {
|
||||||
|
_self.registerHook(pluginData.id, pluginData.hooks[x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (global.env === 'development') winston.info('[plugins] Loaded plugin: ' + pluginData.id);
|
||||||
|
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
},
|
||||||
registerHook: function(id, data) {
|
registerHook: function(id, data) {
|
||||||
/*
|
/*
|
||||||
`data` is an object consisting of (* is required):
|
`data` is an object consisting of (* is required):
|
||||||
@@ -65,8 +70,8 @@ var fs = require('fs'),
|
|||||||
|
|
||||||
if (data.hook && data.method) {
|
if (data.hook && data.method) {
|
||||||
_self.loadedHooks[data.hook] = _self.loadedHooks[data.hook] || [];
|
_self.loadedHooks[data.hook] = _self.loadedHooks[data.hook] || [];
|
||||||
_self.loadedHooks[data.hook].push([id, data.method]);
|
_self.loadedHooks[data.hook].push([id, data.method, !!data.callbacked]);
|
||||||
if (global.env === 'development') console.log('Info: [plugins] Hook registered: ' + data.hook + ' will call ' + id);
|
if (global.env === 'development') winston.info('[plugins] Hook registered: ' + data.hook + ' will call ' + id);
|
||||||
} else return;
|
} else return;
|
||||||
},
|
},
|
||||||
fireHook: function(hook, args, callback) {
|
fireHook: function(hook, args, callback) {
|
||||||
@@ -75,7 +80,7 @@ var fs = require('fs'),
|
|||||||
hookList = this.loadedHooks[hook];
|
hookList = this.loadedHooks[hook];
|
||||||
|
|
||||||
if (hookList && Array.isArray(hookList)) {
|
if (hookList && Array.isArray(hookList)) {
|
||||||
if (global.env === 'development') console.log('Info: [plugins] Firing hook: \'' + hook + '\'');
|
if (global.env === 'development') winston.info('[plugins] Firing hook: \'' + hook + '\'');
|
||||||
var hookType = hook.split(':')[0];
|
var hookType = hook.split(':')[0];
|
||||||
switch(hookType) {
|
switch(hookType) {
|
||||||
case 'filter':
|
case 'filter':
|
||||||
@@ -83,7 +88,7 @@ var fs = require('fs'),
|
|||||||
var returnVal = (Array.isArray(args) ? args[0] : args);
|
var returnVal = (Array.isArray(args) ? args[0] : args);
|
||||||
|
|
||||||
async.each(hookList, function(hookObj, next) {
|
async.each(hookList, function(hookObj, next) {
|
||||||
if (hookObj.callbacked) {
|
if (hookObj[2]) {
|
||||||
_self.libraries[hookObj[0]][hookObj[1]](returnVal, function(err, afterVal) {
|
_self.libraries[hookObj[0]][hookObj[1]](returnVal, function(err, afterVal) {
|
||||||
returnVal = afterVal;
|
returnVal = afterVal;
|
||||||
next(err);
|
next(err);
|
||||||
@@ -94,7 +99,9 @@ var fs = require('fs'),
|
|||||||
}
|
}
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (global.env === 'development') console.log('Info: [plugins] Problem executing hook: ' + hook);
|
if (global.env === 'development') {
|
||||||
|
winston.info('[plugins] Problem executing hook: ' + hook);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(returnVal);
|
callback(returnVal);
|
||||||
@@ -109,7 +116,7 @@ var fs = require('fs'),
|
|||||||
) {
|
) {
|
||||||
_self.libraries[hookObj[0]][hookObj[1]].apply(_self.libraries[hookObj[0]], args);
|
_self.libraries[hookObj[0]][hookObj[1]].apply(_self.libraries[hookObj[0]], args);
|
||||||
} else {
|
} else {
|
||||||
if (global.env === 'development') console.log('Info: [plugins] Expected method \'' + hookObj[1] + '\' in plugin \'' + hookObj[0] + '\' not found, skipping.');
|
if (global.env === 'development') winston.info('[plugins] Expected method \'' + hookObj[1] + '\' in plugin \'' + hookObj[0] + '\' not found, skipping.');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@@ -129,13 +136,13 @@ var fs = require('fs'),
|
|||||||
toggleActive: function(id, callback) {
|
toggleActive: function(id, callback) {
|
||||||
this.isActive(id, function(err, active) {
|
this.isActive(id, function(err, active) {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (global.env === 'development') console.log('Info: [plugins] Could not toggle active state on plugin \'' + id + '\'');
|
if (global.env === 'development') winston.info('[plugins] Could not toggle active state on plugin \'' + id + '\'');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RDB[(active ? 'srem' : 'sadd')]('plugins:active', id, function(err, success) {
|
RDB[(active ? 'srem' : 'sadd')]('plugins:active', id, function(err, success) {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (global.env === 'development') console.log('Info: [plugins] Could not toggle active state on plugin \'' + id + '\'');
|
if (global.env === 'development') winston.info('[plugins] Could not toggle active state on plugin \'' + id + '\'');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,26 +156,49 @@ var fs = require('fs'),
|
|||||||
showInstalled: function(callback) {
|
showInstalled: function(callback) {
|
||||||
// TODO: Also check /node_modules
|
// TODO: Also check /node_modules
|
||||||
var _self = this;
|
var _self = this;
|
||||||
moduleBasePath = path.join(__dirname, '../plugins');
|
localPluginPath = path.join(__dirname, '../plugins'),
|
||||||
|
npmPluginPath = path.join(__dirname, '../node_modules');
|
||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function(next) {
|
function(next) {
|
||||||
fs.readdir(moduleBasePath, next);
|
async.parallel([
|
||||||
|
function(next) {
|
||||||
|
fs.readdir(localPluginPath, next);
|
||||||
|
},
|
||||||
|
function(next) {
|
||||||
|
fs.readdir(npmPluginPath, next);
|
||||||
|
}
|
||||||
|
], function(err, dirs) {
|
||||||
|
if (err) return next(err);
|
||||||
|
|
||||||
|
dirs[0] = dirs[0].map(function(file) {
|
||||||
|
return path.join(localPluginPath, file);
|
||||||
|
}).filter(function(file) {
|
||||||
|
var stats = fs.statSync(file);
|
||||||
|
if (stats.isDirectory()) return true;
|
||||||
|
else return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
dirs[1] = dirs[1].map(function(file) {
|
||||||
|
return path.join(npmPluginPath, file);
|
||||||
|
}).filter(function(file) {
|
||||||
|
var stats = fs.statSync(file);
|
||||||
|
if (stats.isDirectory() && file.substr(npmPluginPath.length+1, 14) === 'nodebb-plugin-') return true;
|
||||||
|
else return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
next(err, dirs[0].concat(dirs[1]));
|
||||||
|
});
|
||||||
},
|
},
|
||||||
function(files, next) {
|
function(files, next) {
|
||||||
var plugins = [];
|
var plugins = [];
|
||||||
|
|
||||||
async.each(files, function(file, next) {
|
async.each(files, function(file, next) {
|
||||||
var modulePath = path.join(moduleBasePath, file),
|
var configPath;
|
||||||
configPath;
|
|
||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function(next) {
|
function(next) {
|
||||||
fs.stat(path.join(moduleBasePath, file), next);
|
fs.readFile(path.join(file, 'plugin.json'), next);
|
||||||
},
|
|
||||||
function(stats, next) {
|
|
||||||
if (stats.isDirectory()) fs.readFile(path.join(modulePath, 'plugin.json'), next);
|
|
||||||
else next(new Error('not-a-directory'));
|
|
||||||
},
|
},
|
||||||
function(configJSON, next) {
|
function(configJSON, next) {
|
||||||
var config = JSON.parse(configJSON);
|
var config = JSON.parse(configJSON);
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ var RDB = require('./redis.js'),
|
|||||||
threadTools = require('./threadTools.js'),
|
threadTools = require('./threadTools.js'),
|
||||||
user = require('./user.js'),
|
user = require('./user.js'),
|
||||||
async = require('async'),
|
async = require('async'),
|
||||||
|
|
||||||
utils = require('../public/src/utils'),
|
utils = require('../public/src/utils'),
|
||||||
plugins = require('./plugins'),
|
plugins = require('./plugins'),
|
||||||
reds = require('reds'),
|
reds = require('reds'),
|
||||||
postSearch = reds.createSearch('nodebbpostsearch'),
|
postSearch = reds.createSearch('nodebbpostsearch'),
|
||||||
topicSearch = reds.createSearch('nodebbtopicsearch');
|
topicSearch = reds.createSearch('nodebbtopicsearch'),
|
||||||
|
winston = require('winston'),
|
||||||
|
meta = require('./meta.js');
|
||||||
|
|
||||||
(function(PostTools) {
|
(function(PostTools) {
|
||||||
PostTools.isMain = function(pid, tid, callback) {
|
PostTools.isMain = function(pid, tid, callback) {
|
||||||
@@ -20,8 +22,8 @@ var RDB = require('./redis.js'),
|
|||||||
}
|
}
|
||||||
|
|
||||||
PostTools.privileges = function(pid, uid, callback) {
|
PostTools.privileges = function(pid, uid, callback) {
|
||||||
//todo: break early if one condition is true
|
//todo: break early if one condition is true
|
||||||
|
|
||||||
function getThreadPrivileges(next) {
|
function getThreadPrivileges(next) {
|
||||||
posts.getPostField(pid, 'tid', function(tid) {
|
posts.getPostField(pid, 'tid', function(tid) {
|
||||||
threadTools.privileges(tid, uid, function(privileges) {
|
threadTools.privileges(tid, uid, function(privileges) {
|
||||||
@@ -39,8 +41,9 @@ var RDB = require('./redis.js'),
|
|||||||
}
|
}
|
||||||
|
|
||||||
function hasEnoughRep(next) {
|
function hasEnoughRep(next) {
|
||||||
user.getUserField(uid, 'reputation', function(reputation) {
|
user.getUserField(uid, 'reputation', function(err, reputation) {
|
||||||
next(null, reputation >= global.config['privileges:manage_content']);
|
if (err) return next(null, false);
|
||||||
|
next(null, reputation >= meta.config['privileges:manage_content']);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +97,7 @@ var RDB = require('./redis.js'),
|
|||||||
PostTools.delete = function(uid, pid) {
|
PostTools.delete = function(uid, pid) {
|
||||||
var success = function() {
|
var success = function() {
|
||||||
posts.setPostField(pid, 'deleted', 1);
|
posts.setPostField(pid, 'deleted', 1);
|
||||||
|
|
||||||
postSearch.remove(pid);
|
postSearch.remove(pid);
|
||||||
|
|
||||||
posts.getPostFields(pid, ['tid', 'uid'], function(postData) {
|
posts.getPostFields(pid, ['tid', 'uid'], function(postData) {
|
||||||
@@ -102,7 +105,7 @@ var RDB = require('./redis.js'),
|
|||||||
user.decrementUserFieldBy(postData.uid, 'postcount', 1, function(err, postcount) {
|
user.decrementUserFieldBy(postData.uid, 'postcount', 1, function(err, postcount) {
|
||||||
RDB.zadd('users:postcount', postcount, postData.uid);
|
RDB.zadd('users:postcount', postcount, postData.uid);
|
||||||
});
|
});
|
||||||
|
|
||||||
io.sockets.in('topic_' + postData.tid).emit('event:post_deleted', {
|
io.sockets.in('topic_' + postData.tid).emit('event:post_deleted', {
|
||||||
pid: pid
|
pid: pid
|
||||||
});
|
});
|
||||||
@@ -111,12 +114,12 @@ var RDB = require('./redis.js'),
|
|||||||
threadTools.get_latest_undeleted_pid(postData.tid, function(err, pid) {
|
threadTools.get_latest_undeleted_pid(postData.tid, function(err, pid) {
|
||||||
if (err && err.message === 'no-undeleted-pids-found') {
|
if (err && err.message === 'no-undeleted-pids-found') {
|
||||||
threadTools.delete(postData.tid, -1, function(err) {
|
threadTools.delete(postData.tid, -1, function(err) {
|
||||||
if (err) console.log('Error: Could not delete topic (tid: ' + postData.tid + ')');
|
if (err) winston.error('Could not delete topic (tid: ' + postData.tid + ')', err.stack);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
posts.getPostField(pid, 'timestamp', function(timestamp) {
|
posts.getPostField(pid, 'timestamp', function(timestamp) {
|
||||||
topics.updateTimestamp(postData.tid, timestamp);
|
topics.updateTimestamp(postData.tid, timestamp);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -140,11 +143,11 @@ var RDB = require('./redis.js'),
|
|||||||
io.sockets.in('topic_' + postData.tid).emit('event:post_restored', {
|
io.sockets.in('topic_' + postData.tid).emit('event:post_restored', {
|
||||||
pid: pid
|
pid: pid
|
||||||
});
|
});
|
||||||
|
|
||||||
threadTools.get_latest_undeleted_pid(postData.tid, function(err, pid) {
|
threadTools.get_latest_undeleted_pid(postData.tid, function(err, pid) {
|
||||||
posts.getPostField(pid, 'timestamp', function(timestamp) {
|
posts.getPostField(pid, 'timestamp', function(timestamp) {
|
||||||
topics.updateTimestamp(postData.tid, timestamp);
|
topics.updateTimestamp(postData.tid, timestamp);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
postSearch.index(postData.content, pid);
|
postSearch.index(postData.content, pid);
|
||||||
@@ -168,18 +171,18 @@ var RDB = require('./redis.js'),
|
|||||||
|
|
||||||
if (md && md.length > 0) {
|
if (md && md.length > 0) {
|
||||||
var parsedContentDOM = cheerio.load(marked(md));
|
var parsedContentDOM = cheerio.load(marked(md));
|
||||||
var domain = global.nconf.get('url');
|
var domain = nconf.get('url');
|
||||||
|
|
||||||
parsedContentDOM('a').each(function() {
|
parsedContentDOM('a').each(function() {
|
||||||
this.attr('rel', 'nofollow');
|
this.attr('rel', 'nofollow');
|
||||||
var href = this.attr('href');
|
var href = this.attr('href');
|
||||||
|
|
||||||
if (href && !href.match(domain)) {
|
if (href && !href.match(domain) && !utils.isRelativeUrl(href)) {
|
||||||
this.attr('href', domain + 'outgoing?url=' + encodeURIComponent(href));
|
this.attr('href', domain + 'outgoing?url=' + encodeURIComponent(href));
|
||||||
if (!isSignature) this.append(' <i class="icon-external-link"></i>');
|
if (!isSignature) this.append(' <i class="icon-external-link"></i>');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
html = parsedContentDOM.html();
|
html = parsedContentDOM.html();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
210
src/posts.js
210
src/posts.js
@@ -10,18 +10,20 @@ var RDB = require('./redis.js'),
|
|||||||
async = require('async'),
|
async = require('async'),
|
||||||
plugins = require('./plugins'),
|
plugins = require('./plugins'),
|
||||||
reds = require('reds'),
|
reds = require('reds'),
|
||||||
|
postSearch = reds.createSearch('nodebbpostsearch'),
|
||||||
nconf = require('nconf'),
|
nconf = require('nconf'),
|
||||||
postSearch = reds.createSearch('nodebbpostsearch');
|
meta = require('./meta.js'),
|
||||||
|
winston = require('winston');
|
||||||
|
|
||||||
(function(Posts) {
|
(function(Posts) {
|
||||||
|
|
||||||
Posts.getPostsByTid = function(tid, start, end, callback) {
|
Posts.getPostsByTid = function(tid, start, end, callback) {
|
||||||
RDB.lrange('tid:' + tid + ':posts', start, end, function(err, pids) {
|
RDB.lrange('tid:' + tid + ':posts', start, end, function(err, pids) {
|
||||||
|
|
||||||
RDB.handle(err);
|
RDB.handle(err);
|
||||||
|
|
||||||
if (pids.length) {
|
if (pids.length) {
|
||||||
Posts.getPostsByPids(pids, function(posts) {
|
Posts.getPostsByPids(pids, function(err, posts) {
|
||||||
callback(posts);
|
callback(posts);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -29,21 +31,26 @@ var RDB = require('./redis.js'),
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Posts.addUserInfoToPost = function(post, callback) {
|
Posts.addUserInfoToPost = function(post, callback) {
|
||||||
user.getUserFields(post.uid, ['username', 'userslug', 'reputation', 'postcount', 'picture', 'signature'], function(userData) {
|
user.getUserFields(post.uid, ['username', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned'], function(err, userData) {
|
||||||
|
if(err)
|
||||||
|
return callback();
|
||||||
|
|
||||||
post.username = userData.username || 'anonymous';
|
post.username = userData.username || 'anonymous';
|
||||||
post.userslug = userData.userslug || '';
|
post.userslug = userData.userslug || '';
|
||||||
post.user_rep = userData.reputation || 0;
|
post.user_rep = userData.reputation || 0;
|
||||||
post.user_postcount = userData.postcount || 0;
|
post.user_postcount = userData.postcount || 0;
|
||||||
post.picture = userData.picture || require('gravatar').url('', {}, https=global.nconf.get('https'));
|
post.user_banned = userData.banned || '0';
|
||||||
|
post.picture = userData.picture || require('gravatar').url('', {}, https=nconf.get('https'));
|
||||||
post.signature = postTools.markdownToHTML(userData.signature, true);
|
post.signature = postTools.markdownToHTML(userData.signature, true);
|
||||||
|
|
||||||
if(post.editor !== '') {
|
if(post.editor !== '') {
|
||||||
user.getUserFields(post.editor, ['username', 'userslug'], function(editorData) {
|
user.getUserFields(post.editor, ['username', 'userslug'], function(err, editorData) {
|
||||||
|
if(err)
|
||||||
|
return callback();
|
||||||
post.editorname = editorData.username;
|
post.editorname = editorData.username;
|
||||||
post.editorslug = editorData.userslug;
|
post.editorslug = editorData.userslug;
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -53,9 +60,9 @@ var RDB = require('./redis.js'),
|
|||||||
}
|
}
|
||||||
|
|
||||||
Posts.getPostSummaryByPids = function(pids, callback) {
|
Posts.getPostSummaryByPids = function(pids, callback) {
|
||||||
|
|
||||||
var returnData = [];
|
var posts = [];
|
||||||
|
|
||||||
function getPostSummary(pid, callback) {
|
function getPostSummary(pid, callback) {
|
||||||
Posts.getPostFields(pid, ['pid', 'tid', 'content', 'uid', 'timestamp', 'deleted'], function(postData) {
|
Posts.getPostFields(pid, ['pid', 'tid', 'content', 'uid', 'timestamp', 'deleted'], function(postData) {
|
||||||
if(postData.deleted === '1') {
|
if(postData.deleted === '1') {
|
||||||
@@ -63,33 +70,46 @@ var RDB = require('./redis.js'),
|
|||||||
}
|
}
|
||||||
|
|
||||||
Posts.addUserInfoToPost(postData, function() {
|
Posts.addUserInfoToPost(postData, function() {
|
||||||
topics.getTopicField(postData.tid, 'slug', function(err, topicSlug) {
|
topics.getTopicFields(postData.tid, ['slug', 'deleted'], function(err, topicData) {
|
||||||
|
if(err)
|
||||||
|
return callback(err);
|
||||||
|
|
||||||
|
if(topicData.deleted === '1')
|
||||||
|
return callback(null);
|
||||||
|
|
||||||
if(postData.content)
|
if(postData.content)
|
||||||
postData.content = utils.strip_tags(postTools.markdownToHTML(postData.content));
|
postData.content = utils.strip_tags(postTools.markdownToHTML(postData.content));
|
||||||
|
|
||||||
postData.topicSlug = topicSlug;
|
postData.relativeTime = utils.relativeTime(postData.timestamp);
|
||||||
returnData.push(postData);
|
postData.topicSlug = topicData.slug;
|
||||||
|
posts.push(postData);
|
||||||
callback(null);
|
callback(null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async.eachSeries(pids, getPostSummary, function(err) {
|
async.eachSeries(pids, getPostSummary, function(err) {
|
||||||
if(!err) {
|
if(!err) {
|
||||||
callback(returnData);
|
callback(null, posts);
|
||||||
} else {
|
} else {
|
||||||
console.log(err);
|
callback(err, null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Posts.filterBannedPosts = function(posts) {
|
||||||
|
return posts.filter(function(post) {
|
||||||
|
return post.user_banned === '0';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Posts.getPostData = function(pid, callback) {
|
Posts.getPostData = function(pid, callback) {
|
||||||
RDB.hgetall('post:' + pid, function(err, data) {
|
RDB.hgetall('post:' + pid, function(err, data) {
|
||||||
if(err === null) {
|
if(err === null) {
|
||||||
callback(data);
|
plugins.fireHook('filter:post.get', data, function(data) {
|
||||||
|
callback(data);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
console.log(err);
|
console.log(err);
|
||||||
@@ -104,7 +124,7 @@ var RDB = require('./redis.js'),
|
|||||||
else {
|
else {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Posts.getPostField = function(pid, field, callback) {
|
Posts.getPostField = function(pid, field, callback) {
|
||||||
@@ -122,20 +142,25 @@ var RDB = require('./redis.js'),
|
|||||||
|
|
||||||
|
|
||||||
Posts.getPostsByPids = function(pids, callback) {
|
Posts.getPostsByPids = function(pids, callback) {
|
||||||
var posts = [];
|
var posts = [];
|
||||||
|
|
||||||
function iterator(pid, callback) {
|
function iterator(pid, callback) {
|
||||||
Posts.getPostData(pid, function(postData) {
|
Posts.getPostData(pid, function(postData) {
|
||||||
if(postData) {
|
if(postData) {
|
||||||
postData.relativeTime = utils.relativeTime(postData.timestamp);
|
postData.relativeTime = utils.relativeTime(postData.timestamp);
|
||||||
postData.post_rep = postData.reputation;
|
postData.post_rep = postData.reputation;
|
||||||
postData['edited-class'] = postData.editor !== '' ? '' : 'none';
|
postData['edited-class'] = postData.editor !== '' ? '' : 'none';
|
||||||
postData['relativeEditTime'] = postData.edited !== '0' ? utils.relativeTime(postData.edited) : '';
|
postData['relativeEditTime'] = postData.edited !== '0' ? utils.relativeTime(postData.edited) : '';
|
||||||
|
|
||||||
postData.content = postTools.markdownToHTML(postData.content);
|
postData.content = postTools.markdownToHTML(postData.content);
|
||||||
|
|
||||||
if(postData.uploadedImages) {
|
if(postData.uploadedImages) {
|
||||||
postData.uploadedImages = JSON.parse(postData.uploadedImages);
|
try {
|
||||||
|
postData.uploadedImages = JSON.parse(postData.uploadedImages);
|
||||||
|
} catch(err) {
|
||||||
|
postData.uploadedImages = [];
|
||||||
|
winston.err(err);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
postData.uploadedImages = [];
|
postData.uploadedImages = [];
|
||||||
}
|
}
|
||||||
@@ -147,9 +172,9 @@ var RDB = require('./redis.js'),
|
|||||||
|
|
||||||
async.eachSeries(pids, iterator, function(err) {
|
async.eachSeries(pids, iterator, function(err) {
|
||||||
if(!err) {
|
if(!err) {
|
||||||
callback(posts);
|
callback(null, posts);
|
||||||
} else {
|
} else {
|
||||||
callback([]);
|
callback(err, null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -173,15 +198,15 @@ var RDB = require('./redis.js'),
|
|||||||
type: 'error',
|
type: 'error',
|
||||||
timeout: 2000,
|
timeout: 2000,
|
||||||
title: 'Content too short',
|
title: 'Content too short',
|
||||||
message: "Please enter a longer post. At least " + config.minimumPostLength + " characters.",
|
message: "Please enter a longer post. At least " + meta.config.minimumPostLength + " characters.",
|
||||||
alert_id: 'post_error'
|
alert_id: 'post_error'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Posts.emitTooManyPostsAlert = function(socket) {
|
Posts.emitTooManyPostsAlert = function(socket) {
|
||||||
socket.emit('event:alert', {
|
socket.emit('event:alert', {
|
||||||
title: 'Too many posts!',
|
title: 'Too many posts!',
|
||||||
message: 'You can only post every '+ config.postDelay/1000 + ' seconds.',
|
message: 'You can only post every '+ meta.config.postDelay/1000 + ' seconds.',
|
||||||
type: 'error',
|
type: 'error',
|
||||||
timeout: 2000
|
timeout: 2000
|
||||||
});
|
});
|
||||||
@@ -192,49 +217,36 @@ var RDB = require('./redis.js'),
|
|||||||
content = content.trim();
|
content = content.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!content || content.length < config.minimumPostLength) {
|
if (!content || content.length < meta.config.minimumPostLength) {
|
||||||
callback(new Error('content-too-short'), null);
|
callback(new Error('content-too-short'), null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.getUserField(uid, 'lastposttime', function(lastposttime) {
|
user.getUserField(uid, 'lastposttime', function(lastposttime) {
|
||||||
if(Date.now() - lastposttime < config.postDelay) {
|
if(Date.now() - lastposttime < meta.config.postDelay) {
|
||||||
callback(new Error('too-many-posts'), null);
|
callback(new Error('too-many-posts'), null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Posts.create(uid, tid, content, images, function(postData) {
|
Posts.create(uid, tid, content, images, function(postData) {
|
||||||
if (postData) {
|
if (postData) {
|
||||||
topics.addPostToTopic(tid, postData.pid);
|
|
||||||
|
|
||||||
topics.markUnRead(tid);
|
topics.markUnRead(tid);
|
||||||
|
|
||||||
Posts.get_cid_by_pid(postData.pid, function(cid) {
|
Posts.get_cid_by_pid(postData.pid, function(cid) {
|
||||||
RDB.del('cid:' + cid + ':read_by_uid', function(err, data) {
|
RDB.del('cid:' + cid + ':read_by_uid', function(err, data) {
|
||||||
topics.markAsRead(tid, uid);
|
topics.markAsRead(tid, uid);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
threadTools.notify_followers(tid, uid);
|
threadTools.notify_followers(tid, uid);
|
||||||
|
|
||||||
postData.content = postTools.markdownToHTML(postData.content);
|
Posts.addUserInfoToPost(postData, function() {
|
||||||
postData.post_rep = 0;
|
var socketData = { posts: [postData] };
|
||||||
postData.relativeTime = utils.relativeTime(postData.timestamp)
|
|
||||||
postData.fav_star_class = 'icon-star-empty';
|
|
||||||
postData['edited-class'] = 'none';
|
|
||||||
postData.uploadedImages = JSON.parse(postData.uploadedImages);
|
|
||||||
|
|
||||||
var socketData = {
|
|
||||||
'posts' : [
|
|
||||||
postData
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
posts.addUserInfoToPost(socketData['posts'][0], function() {
|
|
||||||
io.sockets.in('topic_' + tid).emit('event:new_post', socketData);
|
io.sockets.in('topic_' + tid).emit('event:new_post', socketData);
|
||||||
io.sockets.in('recent_posts').emit('event:new_post', socketData);
|
io.sockets.in('recent_posts').emit('event:new_post', socketData);
|
||||||
});
|
});
|
||||||
|
|
||||||
callback(null, 'Reply successful');
|
callback(null, 'Reply successful');
|
||||||
} else {
|
} else {
|
||||||
callback(new Error('reply-error'), null);
|
callback(new Error('reply-error'), null);
|
||||||
@@ -242,19 +254,19 @@ var RDB = require('./redis.js'),
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Posts.create = function(uid, tid, content, images, callback) {
|
Posts.create = function(uid, tid, content, images, callback) {
|
||||||
if (uid === null) {
|
if (uid === null) {
|
||||||
callback(null);
|
callback(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
topics.isLocked(tid, function(locked) {
|
topics.isLocked(tid, function(locked) {
|
||||||
if (!locked || locked === '0') {
|
if (!locked || locked === '0') {
|
||||||
RDB.incr('global:next_post_id', function(err, pid) {
|
RDB.incr('global:next_post_id', function(err, pid) {
|
||||||
RDB.handle(err);
|
RDB.handle(err);
|
||||||
|
|
||||||
plugins.fireHook('filter:save_post_content', content, function(content) {
|
plugins.fireHook('filter:post.save', content, function(content) {
|
||||||
var timestamp = Date.now(),
|
var timestamp = Date.now(),
|
||||||
postData = {
|
postData = {
|
||||||
'pid': pid,
|
'pid': pid,
|
||||||
@@ -266,16 +278,24 @@ var RDB = require('./redis.js'),
|
|||||||
'editor': '',
|
'editor': '',
|
||||||
'edited': 0,
|
'edited': 0,
|
||||||
'deleted': 0,
|
'deleted': 0,
|
||||||
'uploadedImages': ''
|
'uploadedImages': '[]',
|
||||||
|
'fav_button_class': '',
|
||||||
|
'fav_star_class': 'icon-star-empty',
|
||||||
|
'show_banned': 'hide',
|
||||||
|
'relativeTime': '0 seconds',
|
||||||
|
'post_rep': '0',
|
||||||
|
'edited-class': 'none',
|
||||||
|
'relativeEditTime': ''
|
||||||
};
|
};
|
||||||
|
|
||||||
RDB.hmset('post:' + pid, postData);
|
RDB.hmset('post:' + pid, postData);
|
||||||
|
|
||||||
|
topics.addPostToTopic(tid, pid);
|
||||||
topics.increasePostCount(tid);
|
topics.increasePostCount(tid);
|
||||||
topics.updateTimestamp(tid, timestamp);
|
topics.updateTimestamp(tid, timestamp);
|
||||||
|
|
||||||
RDB.incr('totalpostcount');
|
RDB.incr('totalpostcount');
|
||||||
|
|
||||||
topics.getTopicField(tid, 'cid', function(err, cid) {
|
topics.getTopicField(tid, 'cid', function(err, cid) {
|
||||||
RDB.handle(err);
|
RDB.handle(err);
|
||||||
|
|
||||||
@@ -292,22 +312,36 @@ var RDB = require('./redis.js'),
|
|||||||
|
|
||||||
RDB.sadd('cid:' + cid + ':active_users', uid);
|
RDB.sadd('cid:' + cid + ':active_users', uid);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
user.onNewPostMade(uid, tid, pid, timestamp);
|
|
||||||
|
|
||||||
uploadPostImages(postData, images, function(err, uploadedImages) {
|
user.onNewPostMade(uid, tid, pid, timestamp);
|
||||||
if(err) {
|
|
||||||
console.log('Uploading images failed!');
|
async.parallel({
|
||||||
} else {
|
uploadedImages: function(next) {
|
||||||
postData.uploadedImages = JSON.stringify(uploadedImages);
|
uploadPostImages(postData, images, function(err, uploadedImages) {
|
||||||
Posts.setPostField(pid, 'uploadedImages', postData.uploadedImages);
|
if(err) {
|
||||||
|
winston.error('Uploading images failed!', err.stack);
|
||||||
|
next(null, []);
|
||||||
|
} else {
|
||||||
|
next(null, uploadedImages);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
content: function(next) {
|
||||||
|
plugins.fireHook('filter:post.get', postData, function(postData) {
|
||||||
|
postData.content = postTools.markdownToHTML(postData.content, false);
|
||||||
|
next(null, postData.content);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
}, function(err, results) {
|
||||||
|
postData.uploadedImages = results.uploadedImages;
|
||||||
|
Posts.setPostField(pid, 'uploadedImages', JSON.stringify(postData.uploadedImages));
|
||||||
|
postData.content = results.content;
|
||||||
callback(postData);
|
callback(postData);
|
||||||
});
|
});
|
||||||
|
|
||||||
plugins.fireHook('action:save_post_content', [pid, content]);
|
plugins.fireHook('action:post.save', [postData]);
|
||||||
|
|
||||||
postSearch.index(content, pid);
|
postSearch.index(content, pid);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -319,9 +353,9 @@ var RDB = require('./redis.js'),
|
|||||||
|
|
||||||
function uploadPostImages(postData, images, callback) {
|
function uploadPostImages(postData, images, callback) {
|
||||||
var imgur = require('./imgur');
|
var imgur = require('./imgur');
|
||||||
imgur.setClientID(global.nconf.get('imgurClientID'));
|
imgur.setClientID(meta.config.imgurClientID);
|
||||||
|
|
||||||
var uploadedImages = [];
|
var uploadedImages = [];
|
||||||
|
|
||||||
function uploadImage(image, callback) {
|
function uploadImage(image, callback) {
|
||||||
imgur.upload(image.data, 'base64', function(err, data) {
|
imgur.upload(image.data, 'base64', function(err, data) {
|
||||||
@@ -333,10 +367,11 @@ var RDB = require('./redis.js'),
|
|||||||
uploadedImages.push(img);
|
uploadedImages.push(img);
|
||||||
callback(null);
|
callback(null);
|
||||||
} else {
|
} else {
|
||||||
|
winston.error('Can\'t upload image, did you set imgurClientID?');
|
||||||
callback(data);
|
callback(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!images) {
|
if(!images) {
|
||||||
@@ -352,20 +387,20 @@ var RDB = require('./redis.js'),
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Posts.getPostsByUid = function(uid, start, end, callback) {
|
Posts.getPostsByUid = function(uid, start, end, callback) {
|
||||||
|
|
||||||
user.getPostIds(uid, start, end, function(pids) {
|
user.getPostIds(uid, start, end, function(pids) {
|
||||||
|
|
||||||
if(pids && pids.length) {
|
if(pids && pids.length) {
|
||||||
|
|
||||||
Posts.getPostsByPids(pids, function(posts) {
|
Posts.getPostsByPids(pids, function(err, posts) {
|
||||||
callback(posts);
|
callback(posts);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
callback([]);
|
callback([]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Posts.getTopicPostStats = function(socket) {
|
Posts.getTopicPostStats = function(socket) {
|
||||||
@@ -373,11 +408,11 @@ var RDB = require('./redis.js'),
|
|||||||
if(err === null) {
|
if(err === null) {
|
||||||
var stats = {
|
var stats = {
|
||||||
topics: data[0]?data[0]:0,
|
topics: data[0]?data[0]:0,
|
||||||
posts: data[1]?data[1]:0
|
posts: data[1]?data[1]:0
|
||||||
};
|
};
|
||||||
|
|
||||||
socket.emit('post.stats', stats);
|
socket.emit('post.stats', stats);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
console.log(err);
|
console.log(err);
|
||||||
});
|
});
|
||||||
@@ -407,4 +442,19 @@ var RDB = require('./redis.js'),
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Posts.getFavourites = function(uid, callback) {
|
||||||
|
RDB.zrevrange('uid:' + uid + ':favourites', 0, -1, function(err, pids) {
|
||||||
|
if(err)
|
||||||
|
return callback(err, null);
|
||||||
|
|
||||||
|
Posts.getPostSummaryByPids(pids, function(err, posts) {
|
||||||
|
if(err)
|
||||||
|
return callback(err, null);
|
||||||
|
|
||||||
|
callback(null, posts);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}(exports));
|
}(exports));
|
||||||
18
src/redis.js
18
src/redis.js
@@ -1,8 +1,9 @@
|
|||||||
(function(RedisDB) {
|
(function(RedisDB) {
|
||||||
var redis = require('redis'),
|
var redis = require('redis'),
|
||||||
nconf = require('nconf'),
|
nconf = require('nconf'),
|
||||||
utils = require('./../public/src/utils.js');
|
utils = require('./../public/src/utils.js'),
|
||||||
|
winston = require('winston');
|
||||||
|
|
||||||
RedisDB.exports = redis.createClient(nconf.get('redis:port'), nconf.get('redis:host'));
|
RedisDB.exports = redis.createClient(nconf.get('redis:port'), nconf.get('redis:host'));
|
||||||
|
|
||||||
if(nconf.get('redis:password')) {
|
if(nconf.get('redis:password')) {
|
||||||
@@ -11,14 +12,9 @@
|
|||||||
|
|
||||||
RedisDB.exports.handle = function(error) {
|
RedisDB.exports.handle = function(error) {
|
||||||
if (error !== null) {
|
if (error !== null) {
|
||||||
|
winston.err(error);
|
||||||
if (global.env !== 'production') {
|
if (global.env !== 'production') {
|
||||||
console.log("################# ERROR LOG ####################");
|
|
||||||
console.log(error);
|
|
||||||
console.log(arguments.callee.name);
|
|
||||||
console.log("################# ERROR LOG ####################");
|
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
} else {
|
|
||||||
console.log(error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,7 +40,7 @@
|
|||||||
RedisDB.exports.hmget(key, fields, function(err, data) {
|
RedisDB.exports.hmget(key, fields, function(err, data) {
|
||||||
if(err === null) {
|
if(err === null) {
|
||||||
var returnData = {};
|
var returnData = {};
|
||||||
|
|
||||||
for(var i=0, ii=fields.length; i<ii; ++i) {
|
for(var i=0, ii=fields.length; i<ii; ++i) {
|
||||||
returnData[fields[i]] = data[i];
|
returnData[fields[i]] = data[i];
|
||||||
}
|
}
|
||||||
@@ -55,8 +51,8 @@
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
callback(err, null);
|
callback(err, null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ var user = require('./../user.js'),
|
|||||||
RDB = require('./../redis.js'),
|
RDB = require('./../redis.js'),
|
||||||
pkg = require('./../../package.json'),
|
pkg = require('./../../package.json'),
|
||||||
categories = require('./../categories.js'),
|
categories = require('./../categories.js'),
|
||||||
plugins = require('../plugins');
|
plugins = require('../plugins'),
|
||||||
|
winston = require('winston');
|
||||||
|
|
||||||
(function(Admin) {
|
(function(Admin) {
|
||||||
Admin.isAdmin = function(req, res, next) {
|
Admin.isAdmin = function(req, res, next) {
|
||||||
@@ -17,7 +18,7 @@ var user = require('./../user.js'),
|
|||||||
Admin.build_header = function(res) {
|
Admin.build_header = function(res) {
|
||||||
return templates['admin/header'].parse({
|
return templates['admin/header'].parse({
|
||||||
csrf:res.locals.csrf_token,
|
csrf:res.locals.csrf_token,
|
||||||
relative_path: global.nconf.get('relative_path')
|
relative_path: nconf.get('relative_path')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +143,7 @@ var user = require('./../user.js'),
|
|||||||
finalData[key] = jsonObject[key];
|
finalData[key] = jsonObject[key];
|
||||||
}
|
}
|
||||||
} catch(err){
|
} catch(err){
|
||||||
console.log('invalid redis status', i, data[i], err);
|
winston.warn('can\'t parse redis status variable, ignoring', i, data[i], err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ var user = require('./../user.js'),
|
|||||||
utils = require('./../../public/src/utils.js'),
|
utils = require('./../../public/src/utils.js'),
|
||||||
pkg = require('../../package.json'),
|
pkg = require('../../package.json'),
|
||||||
meta = require('./../meta.js');
|
meta = require('./../meta.js');
|
||||||
|
|
||||||
|
|
||||||
(function(Api) {
|
(function(Api) {
|
||||||
Api.create_routes = function(app) {
|
Api.create_routes = function(app) {
|
||||||
@@ -16,18 +16,16 @@ var user = require('./../user.js'),
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/config', function(req, res, next) {
|
app.get('/api/config', function(req, res, next) {
|
||||||
meta.config.getFields(['postDelay', 'minimumTitleLength', 'minimumPostLength'], function(err, metaConfig) {
|
var config = require('../../public/config.json');
|
||||||
if(err) return next();
|
|
||||||
var clientConfig = require('../../public/config.json');
|
|
||||||
|
|
||||||
for (var attrname in metaConfig) {
|
|
||||||
clientConfig[attrname] = metaConfig[attrname];
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json(200, clientConfig);
|
config['postDelay'] = meta.config['postDelay'];
|
||||||
})
|
config['minimumTitleLength'] = meta.config['minimumTitleLength'];
|
||||||
|
config['minimumPostLength'] = meta.config['minimumPostLength'];
|
||||||
|
config['imgurClientIDSet'] = !!meta.config['imgurClientID'];
|
||||||
|
|
||||||
|
res.json(200, config);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/home', function(req, res) {
|
app.get('/api/home', function(req, res) {
|
||||||
var uid = (req.user) ? req.user.uid : 0;
|
var uid = (req.user) ? req.user.uid : 0;
|
||||||
categories.getAllCategories(function(data) {
|
categories.getAllCategories(function(data) {
|
||||||
@@ -45,8 +43,8 @@ var user = require('./../user.js'),
|
|||||||
}
|
}
|
||||||
|
|
||||||
require('async').each(data.categories, iterator, function(err) {
|
require('async').each(data.categories, iterator, function(err) {
|
||||||
data.motd_class = (config.show_motd === '1' || config.show_motd === undefined) ? '' : 'none';
|
data.motd_class = (meta.config.show_motd === '1' || meta.config.show_motd === undefined) ? '' : 'none';
|
||||||
data.motd = marked(config.motd || "# NodeBB v" + pkg.version + "\nWelcome to NodeBB, the discussion platform of the future.\n\n<a target=\"_blank\" href=\"http://www.nodebb.org\" class=\"btn btn-large\"><i class=\"icon-comment\"></i> Get NodeBB</a> <a target=\"_blank\" href=\"https://github.com/designcreateplay/NodeBB\" class=\"btn btn-large\"><i class=\"icon-github-alt\"></i> Fork us on Github</a> <a target=\"_blank\" href=\"https://twitter.com/dcplabs\" class=\"btn btn-large\"><i class=\"icon-twitter\"></i> @dcplabs</a>");
|
data.motd = marked(meta.config.motd || "# NodeBB <span class='hidden-phone'>v " + pkg.version + "</span>\nWelcome to NodeBB, the discussion platform of the future.\n\n<a target=\"_blank\" href=\"http://www.nodebb.org\" class=\"btn btn-large\"><i class=\"icon-comment\"></i><span class='hidden-phone'> Get NodeBB</span></a> <a target=\"_blank\" href=\"https://github.com/designcreateplay/NodeBB\" class=\"btn btn-large\"><i class=\"icon-github-alt\"></i><span class='hidden-phone'> Fork us on Github</span></a> <a target=\"_blank\" href=\"https://twitter.com/dcplabs\" class=\"btn btn-large\"><i class=\"icon-twitter\"></i><span class='hidden-phone'> @dcplabs</span></a>");
|
||||||
res.json(data);
|
res.json(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -62,7 +60,7 @@ var user = require('./../user.js'),
|
|||||||
data = {
|
data = {
|
||||||
'login_window:spansize': 'span12',
|
'login_window:spansize': 'span12',
|
||||||
'alternate_logins:display': 'none'
|
'alternate_logins:display': 'none'
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
data = {
|
data = {
|
||||||
'login_window:spansize': 'span6',
|
'login_window:spansize': 'span6',
|
||||||
@@ -77,7 +75,7 @@ var user = require('./../user.js'),
|
|||||||
|
|
||||||
res.json(data);
|
res.json(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/register', function(req, res) {
|
app.get('/api/register', function(req, res) {
|
||||||
var data = {},
|
var data = {},
|
||||||
login_strategies = auth.get_login_strategies(),
|
login_strategies = auth.get_login_strategies(),
|
||||||
@@ -87,7 +85,7 @@ var user = require('./../user.js'),
|
|||||||
data = {
|
data = {
|
||||||
'register_window:spansize': 'span12',
|
'register_window:spansize': 'span12',
|
||||||
'alternate_logins:display': 'none'
|
'alternate_logins:display': 'none'
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
data = {
|
data = {
|
||||||
'register_window:spansize': 'span6',
|
'register_window:spansize': 'span6',
|
||||||
@@ -102,22 +100,25 @@ var user = require('./../user.js'),
|
|||||||
|
|
||||||
res.json(data);
|
res.json(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/topic/:id/:slug?', function(req, res) {
|
app.get('/api/topic/:id/:slug?', function(req, res, next) {
|
||||||
var uid = (req.user) ? req.user.uid : 0;
|
var uid = (req.user) ? req.user.uid : 0;
|
||||||
topics.getTopicWithPosts(req.params.id, uid, function(err, data) {
|
topics.getTopicWithPosts(req.params.id, uid, function(err, data) {
|
||||||
|
if(data.deleted === '1' && data.expose_tools === 0) {
|
||||||
|
return res.json(404, {});
|
||||||
|
}
|
||||||
res.json(data);
|
res.json(data);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/category/:id/:slug?', function(req, res, next) {
|
app.get('/api/category/:id/:slug?', function(req, res, next) {
|
||||||
var uid = (req.user) ? req.user.uid : 0;
|
var uid = (req.user) ? req.user.uid : 0;
|
||||||
categories.getCategoryById(req.params.id, uid, function(err, data) {
|
categories.getCategoryById(req.params.id, uid, function(err, data) {
|
||||||
if (!err)
|
if (!err)
|
||||||
res.json(data);
|
res.json(data);
|
||||||
else
|
else
|
||||||
next();
|
next();
|
||||||
}, req.params.id, uid);
|
}, req.params.id, uid);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/recent', function(req, res) {
|
app.get('/api/recent', function(req, res) {
|
||||||
@@ -134,6 +135,13 @@ var user = require('./../user.js'),
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get('/api/unread/total', function(req, res) {
|
||||||
|
var uid = (req.user) ? req.user.uid : 0;
|
||||||
|
topics.getTotalUnread(uid, function(data) {
|
||||||
|
res.json(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
app.get('/api/confirm/:id', function(req, res) {
|
app.get('/api/confirm/:id', function(req, res) {
|
||||||
user.email.confirm(req.params.id, function(data) {
|
user.email.confirm(req.params.id, function(data) {
|
||||||
if (data.status === 'ok') {
|
if (data.status === 'ok') {
|
||||||
@@ -158,13 +166,13 @@ var user = require('./../user.js'),
|
|||||||
if (url) {
|
if (url) {
|
||||||
res.json({
|
res.json({
|
||||||
url: url,
|
url: url,
|
||||||
home: global.nconf.get('url')
|
home: nconf.get('url')
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.status(404);
|
res.status(404);
|
||||||
res.redirect(global.nconf.get('relative_path') + '/404');
|
res.redirect(nconf.get('relative_path') + '/404');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/search', function(req, res) {
|
app.get('/api/search', function(req, res) {
|
||||||
return res.json({
|
return res.json({
|
||||||
@@ -191,7 +199,9 @@ var user = require('./../user.js'),
|
|||||||
if(err)
|
if(err)
|
||||||
return callback(err, null);
|
return callback(err, null);
|
||||||
|
|
||||||
posts.getPostSummaryByPids(pids, function(posts) {
|
posts.getPostSummaryByPids(pids, function(err, posts) {
|
||||||
|
if(err)
|
||||||
|
return callback(err, null);
|
||||||
callback(null, posts);
|
callback(null, posts);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@@ -201,7 +211,7 @@ var user = require('./../user.js'),
|
|||||||
search(topicSearch, function(err, tids) {
|
search(topicSearch, function(err, tids) {
|
||||||
if(err)
|
if(err)
|
||||||
return callback(err, null);
|
return callback(err, null);
|
||||||
console.log(tids);
|
|
||||||
topics.getTopicsByTids(tids, 0, function(topics) {
|
topics.getTopicsByTids(tids, 0, function(topics) {
|
||||||
callback(null, topics);
|
callback(null, topics);
|
||||||
}, 0);
|
}, 0);
|
||||||
@@ -209,7 +219,7 @@ var user = require('./../user.js'),
|
|||||||
}
|
}
|
||||||
|
|
||||||
async.parallel([searchPosts, searchTopics], function(err, results) {
|
async.parallel([searchPosts, searchTopics], function(err, results) {
|
||||||
if (err)
|
if (err)
|
||||||
return next();
|
return next();
|
||||||
var noresults = !results[0].length && !results[1].length;
|
var noresults = !results[0].length && !results[1].length;
|
||||||
return res.json({
|
return res.json({
|
||||||
@@ -220,11 +230,19 @@ var user = require('./../user.js'),
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get('/api/reset', function(req, res) {
|
||||||
|
res.json({});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/api/reset/:code', function(req, res) {
|
||||||
|
res.json({ reset_code: req.params.code });
|
||||||
|
});
|
||||||
|
|
||||||
app.get('/api/404', function(req, res) {
|
app.get('/api/404', function(req, res) {
|
||||||
res.json({});
|
res.json({});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/403', function(req, res) {
|
app.get('/api/403', function(req, res) {
|
||||||
res.json({});
|
res.json({});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,7 +6,9 @@
|
|||||||
passportFacebook = require('passport-facebook').Strategy,
|
passportFacebook = require('passport-facebook').Strategy,
|
||||||
login_strategies = [],
|
login_strategies = [],
|
||||||
nconf = require('nconf'),
|
nconf = require('nconf'),
|
||||||
users = require('../user'),
|
meta = require('../meta'),
|
||||||
|
user = require('../user'),
|
||||||
|
winston = require('winston'),
|
||||||
login_module = require('./../login.js');
|
login_module = require('./../login.js');
|
||||||
|
|
||||||
passport.use(new passportLocal(function(user, password, next) {
|
passport.use(new passportLocal(function(user, password, next) {
|
||||||
@@ -16,10 +18,10 @@
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (global.config['social:twitter:key'] && global.config['social:twitter:secret']) {
|
if (meta.config['social:twitter:key'] && meta.config['social:twitter:secret']) {
|
||||||
passport.use(new passportTwitter({
|
passport.use(new passportTwitter({
|
||||||
consumerKey: global.config['social:twitter:key'],
|
consumerKey: meta.config['social:twitter:key'],
|
||||||
consumerSecret: global.config['social:twitter:secret'],
|
consumerSecret: meta.config['social:twitter:secret'],
|
||||||
callbackURL: nconf.get('url') + 'auth/twitter/callback'
|
callbackURL: nconf.get('url') + 'auth/twitter/callback'
|
||||||
}, function(token, tokenSecret, profile, done) {
|
}, function(token, tokenSecret, profile, done) {
|
||||||
login_module.loginViaTwitter(profile.id, profile.username, profile.photos, function(err, user) {
|
login_module.loginViaTwitter(profile.id, profile.username, profile.photos, function(err, user) {
|
||||||
@@ -31,10 +33,10 @@
|
|||||||
login_strategies.push('twitter');
|
login_strategies.push('twitter');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global.config['social:google:id'] && global.config['social:google:secret']) {
|
if (meta.config['social:google:id'] && meta.config['social:google:secret']) {
|
||||||
passport.use(new passportGoogle({
|
passport.use(new passportGoogle({
|
||||||
clientID: global.config['social:google:id'],
|
clientID: meta.config['social:google:id'],
|
||||||
clientSecret: global.config['social:google:secret'],
|
clientSecret: meta.config['social:google:secret'],
|
||||||
callbackURL: nconf.get('url') + 'auth/google/callback'
|
callbackURL: nconf.get('url') + 'auth/google/callback'
|
||||||
}, function(accessToken, refreshToken, profile, done) {
|
}, function(accessToken, refreshToken, profile, done) {
|
||||||
login_module.loginViaGoogle(profile.id, profile.displayName, profile.emails[0].value, function(err, user) {
|
login_module.loginViaGoogle(profile.id, profile.displayName, profile.emails[0].value, function(err, user) {
|
||||||
@@ -46,10 +48,10 @@
|
|||||||
login_strategies.push('google');
|
login_strategies.push('google');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global.config['social:facebook:app_id'] && global.config['social:facebook:secret']) {
|
if (meta.config['social:facebook:app_id'] && meta.config['social:facebook:secret']) {
|
||||||
passport.use(new passportFacebook({
|
passport.use(new passportFacebook({
|
||||||
clientID: global.config['social:facebook:app_id'],
|
clientID: meta.config['social:facebook:app_id'],
|
||||||
clientSecret: global.config['social:facebook:secret'],
|
clientSecret: meta.config['social:facebook:secret'],
|
||||||
callbackURL: nconf.get('url') + 'auth/facebook/callback'
|
callbackURL: nconf.get('url') + 'auth/facebook/callback'
|
||||||
}, function(accessToken, refreshToken, profile, done) {
|
}, function(accessToken, refreshToken, profile, done) {
|
||||||
login_module.loginViaFacebook(profile.id, profile.displayName, profile.emails[0].value, function(err, user) {
|
login_module.loginViaFacebook(profile.id, profile.displayName, profile.emails[0].value, function(err, user) {
|
||||||
@@ -75,7 +77,7 @@
|
|||||||
app.use(passport.initialize());
|
app.use(passport.initialize());
|
||||||
app.use(passport.session());
|
app.use(passport.session());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Auth.get_login_strategies = function() {
|
Auth.get_login_strategies = function() {
|
||||||
return login_strategies;
|
return login_strategies;
|
||||||
@@ -85,7 +87,7 @@
|
|||||||
|
|
||||||
app.get('/logout', function(req, res) {
|
app.get('/logout', function(req, res) {
|
||||||
if (req.user && req.user.uid > 0) {
|
if (req.user && req.user.uid > 0) {
|
||||||
console.log('info: [Auth] Session ' + req.sessionID + ' logout (uid: ' + req.user.uid + ')');
|
winston.info('[Auth] Session ' + req.sessionID + ' logout (uid: ' + req.user.uid + ')');
|
||||||
login_module.logout(req.sessionID, function(logout) {
|
login_module.logout(req.sessionID, function(logout) {
|
||||||
req.logout();
|
req.logout();
|
||||||
app.build_header({ req: req, res: res }, function(err, header) {
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
@@ -126,33 +128,43 @@
|
|||||||
|
|
||||||
app.get('/reset/:code', function(req, res) {
|
app.get('/reset/:code', function(req, res) {
|
||||||
app.build_header({ req: req, res: res }, function(err, header) {
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
res.send(header + templates['reset_code'].parse({ reset_code: req.params.code }) + templates['footer']);
|
res.send(header + app.create_route('reset/'+req.params.code) + templates['footer']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/reset', function(req, res) {
|
app.get('/reset', function(req, res) {
|
||||||
app.build_header({ req: req, res: res }, function(err, header) {
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
console.log(header);
|
res.send(header + app.create_route('reset') + templates['footer']);
|
||||||
res.send(header + templates['reset'] + templates['footer']);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.post('/login', function(req, res, next) {
|
||||||
app.post('/login', passport.authenticate('local'), function(req, res) {
|
passport.authenticate('local', function(err, user, info) {
|
||||||
res.json({success:1});
|
if(err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
if (!user) {
|
||||||
|
return res.send({ success : false, message : info.message });
|
||||||
|
}
|
||||||
|
req.login({
|
||||||
|
uid: user.uid
|
||||||
|
}, function() {
|
||||||
|
res.send({ success : true, message : 'authentication succeeded' });
|
||||||
|
});
|
||||||
|
})(req, res, next);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/register', function(req, res) {
|
|
||||||
users.create(req.body.username, req.body.password, req.body.email, function(err, uid) {
|
|
||||||
|
|
||||||
if (err === null && uid > 0) {
|
app.post('/register', function(req, res) {
|
||||||
|
user.create(req.body.username, req.body.password, req.body.email, function(err, uid) {
|
||||||
|
|
||||||
|
if (err === null && uid) {
|
||||||
req.login({
|
req.login({
|
||||||
uid: uid
|
uid: uid
|
||||||
}, function() {
|
}, function() {
|
||||||
res.redirect(global.nconf.get('relative_path') + '/');
|
res.redirect(nconf.get('relative_path') + '/');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.redirect(global.nconf.get('relative_path') + '/register');
|
res.redirect(nconf.get('relative_path') + '/register');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,16 +4,17 @@ var user = require('./../user.js'),
|
|||||||
fs = require('fs'),
|
fs = require('fs'),
|
||||||
utils = require('./../../public/src/utils.js'),
|
utils = require('./../../public/src/utils.js'),
|
||||||
path = require('path'),
|
path = require('path'),
|
||||||
marked = require('marked');
|
marked = require('marked'),
|
||||||
|
winston = require('winston');
|
||||||
|
|
||||||
(function(User) {
|
(function(User) {
|
||||||
User.create_routes = function(app) {
|
User.create_routes = function(app) {
|
||||||
|
|
||||||
app.get('/uid/:uid', function(req, res) {
|
app.get('/uid/:uid', function(req, res) {
|
||||||
|
|
||||||
if(!req.params.uid)
|
if(!req.params.uid)
|
||||||
return res.redirect('/404');
|
return res.redirect('/404');
|
||||||
|
|
||||||
user.getUserData(req.params.uid, function(data) {
|
user.getUserData(req.params.uid, function(data) {
|
||||||
if(data) {
|
if(data) {
|
||||||
res.send(data);
|
res.send(data);
|
||||||
@@ -21,7 +22,7 @@ var user = require('./../user.js'),
|
|||||||
res.json(404, {error:"User doesn't exist!"});
|
res.json(404, {error:"User doesn't exist!"});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/users', function(req, res) {
|
app.get('/users', function(req, res) {
|
||||||
@@ -29,25 +30,25 @@ var user = require('./../user.js'),
|
|||||||
res.send(header + app.create_route("users", "users") + templates['footer']);
|
res.send(header + app.create_route("users", "users") + templates['footer']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/users-latest', function(req, res) {
|
app.get('/users-latest', function(req, res) {
|
||||||
app.build_header({ req: req, res: res }, function(err, header) {
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
res.send(header + app.create_route("users-latest", "users") + templates['footer']);
|
res.send(header + app.create_route("users-latest", "users") + templates['footer']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/users-sort-posts', function(req, res) {
|
app.get('/users-sort-posts', function(req, res) {
|
||||||
app.build_header({ req: req, res: res }, function(err, header) {
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
res.send(header + app.create_route("users-sort-posts", "users") + templates['footer']);
|
res.send(header + app.create_route("users-sort-posts", "users") + templates['footer']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/users-sort-reputation', function(req, res) {
|
app.get('/users-sort-reputation', function(req, res) {
|
||||||
app.build_header({ req: req, res: res }, function(err, header) {
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
res.send(header + app.create_route("users-sort-reputation", "users") + templates['footer']);
|
res.send(header + app.create_route("users-sort-reputation", "users") + templates['footer']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/users-search', function(req, res) {
|
app.get('/users-search', function(req, res) {
|
||||||
app.build_header({ req: req, res: res }, function(err, header) {
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
res.send(header + app.create_route("users-search", "users") + templates['footer']);
|
res.send(header + app.create_route("users-search", "users") + templates['footer']);
|
||||||
@@ -63,23 +64,22 @@ var user = require('./../user.js'),
|
|||||||
|
|
||||||
user.get_uid_by_userslug(req.params.userslug, function(uid) {
|
user.get_uid_by_userslug(req.params.userslug, function(uid) {
|
||||||
if(!uid) {
|
if(!uid) {
|
||||||
next();
|
return next();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.build_header({ req: req, res: res }, function(err, header) {
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
res.send(header + app.create_route('users/'+req.params.userslug, 'account') + templates['footer']);
|
res.send(header + app.create_route('users/' + req.params.userslug, 'account') + templates['footer']);
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/users/:userslug/edit', function(req, res) {
|
app.get('/users/:userslug/edit', function(req, res) {
|
||||||
|
|
||||||
if(!req.user)
|
if(!req.user)
|
||||||
return res.redirect('/403');
|
return res.redirect('/403');
|
||||||
|
|
||||||
user.getUserField(req.user.uid, 'userslug', function(userslug) {
|
user.getUserField(req.user.uid, 'userslug', function(err, userslug) {
|
||||||
|
|
||||||
if(req.params.userslug && userslug === req.params.userslug) {
|
if(req.params.userslug && userslug === req.params.userslug) {
|
||||||
app.build_header({ req: req, res: res }, function(err, header) {
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
res.send(header + app.create_route('users/'+req.params.userslug+'/edit','accountedit') + templates['footer']);
|
res.send(header + app.create_route('users/'+req.params.userslug+'/edit','accountedit') + templates['footer']);
|
||||||
@@ -87,46 +87,46 @@ var user = require('./../user.js'),
|
|||||||
} else {
|
} else {
|
||||||
return res.redirect('/404');
|
return res.redirect('/404');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/users/:userslug/settings', function(req, res) {
|
app.get('/users/:userslug/settings', function(req, res) {
|
||||||
|
|
||||||
if(!req.user)
|
if(!req.user)
|
||||||
return res.redirect('/403');
|
return res.redirect('/403');
|
||||||
|
|
||||||
user.getUserField(req.user.uid, 'userslug', function(userslug) {
|
user.getUserField(req.user.uid, 'userslug', function(err, userslug) {
|
||||||
if(req.params.userslug && userslug === req.params.userslug) {
|
if(req.params.userslug && userslug === req.params.userslug) {
|
||||||
app.build_header({ req: req, res: res }, function(err, header) {
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
res.send(header + app.create_route('users/'+req.params.userslug+'/settings','accountsettings') + templates['footer']);
|
res.send(header + app.create_route('users/'+req.params.userslug+'/settings','accountsettings') + templates['footer']);
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
return res.redirect('/404');
|
return res.redirect('/404');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/users/uploadpicture', function(req, res) {
|
app.post('/users/uploadpicture', function(req, res) {
|
||||||
if(!req.user)
|
if(!req.user)
|
||||||
return res.redirect('/403');
|
return res.redirect('/403');
|
||||||
|
|
||||||
if(req.files.userPhoto.size > 262144) {
|
if(req.files.userPhoto.size > 262144) {
|
||||||
res.send({
|
res.send({
|
||||||
error: 'Images must be smaller than 256kb!'
|
error: 'Images must be smaller than 256kb!'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var allowedTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'];
|
var allowedTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'];
|
||||||
|
|
||||||
if(allowedTypes.indexOf(req.files.userPhoto.type) === -1) {
|
if(allowedTypes.indexOf(req.files.userPhoto.type) === -1) {
|
||||||
res.send({
|
res.send({
|
||||||
error: 'Allowed image types are png, jpg and gif!'
|
error: 'Allowed image types are png, jpg and gif!'
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.getUserField(req.user.uid, 'uploadedpicture', function(oldpicture) {
|
user.getUserField(req.user.uid, 'uploadedpicture', function(err, oldpicture) {
|
||||||
if(!oldpicture) {
|
if(!oldpicture) {
|
||||||
uploadUserPicture(req.user.uid, path.extname(req.files.userPhoto.name), req.files.userPhoto.path, res);
|
uploadUserPicture(req.user.uid, path.extname(req.files.userPhoto.name), req.files.userPhoto.path, res);
|
||||||
return;
|
return;
|
||||||
@@ -135,15 +135,15 @@ var user = require('./../user.js'),
|
|||||||
var absolutePath = path.join(global.configuration['ROOT_DIRECTORY'], global.nconf.get('upload_path'), path.basename(oldpicture));
|
var absolutePath = path.join(global.configuration['ROOT_DIRECTORY'], global.nconf.get('upload_path'), path.basename(oldpicture));
|
||||||
|
|
||||||
fs.unlink(absolutePath, function(err) {
|
fs.unlink(absolutePath, function(err) {
|
||||||
if(err) {
|
if(err) {
|
||||||
console.error('[%d] %s', Date.now(), + err);
|
winston.error('[%d] %s', Date.now(), + err);
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadUserPicture(req.user.uid, path.extname(req.files.userPhoto.name), req.files.userPhoto.path, res);
|
uploadUserPicture(req.user.uid, path.extname(req.files.userPhoto.name), req.files.userPhoto.path, res);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function uploadUserPicture(uid, extension, tempPath, res) {
|
function uploadUserPicture(uid, extension, tempPath, res) {
|
||||||
if(!extension) {
|
if(!extension) {
|
||||||
res.send({
|
res.send({
|
||||||
@@ -154,10 +154,9 @@ var user = require('./../user.js'),
|
|||||||
|
|
||||||
var filename = uid + '-profileimg' + extension;
|
var filename = uid + '-profileimg' + extension;
|
||||||
var uploadPath = path.join(global.configuration['ROOT_DIRECTORY'], global.nconf.get('upload_path'), filename);
|
var uploadPath = path.join(global.configuration['ROOT_DIRECTORY'], global.nconf.get('upload_path'), filename);
|
||||||
|
|
||||||
// @todo move to proper logging code - this should only be temporary
|
winston.info('Attempting upload to: '+ uploadPath);
|
||||||
console.log('Info: Attempting upload to: '+ uploadPath);
|
|
||||||
|
|
||||||
var is = fs.createReadStream(tempPath);
|
var is = fs.createReadStream(tempPath);
|
||||||
var os = fs.createWriteStream(uploadPath);
|
var os = fs.createWriteStream(uploadPath);
|
||||||
|
|
||||||
@@ -176,11 +175,7 @@ var user = require('./../user.js'),
|
|||||||
height: 128
|
height: 128
|
||||||
}, function(err, stdout, stderr){
|
}, function(err, stdout, stderr){
|
||||||
if (err) {
|
if (err) {
|
||||||
// @todo: better logging method; for now, send to stderr.
|
winston.err(err.message, err.stack);
|
||||||
// ideally, this should be happening in another process
|
|
||||||
// to avoid poisoning the main process on error or allowing a significant problem
|
|
||||||
// to crash the main process
|
|
||||||
console.error('[%d] %s', Date.now(), + err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json({ path: imageUrl });
|
res.json({ path: imageUrl });
|
||||||
@@ -189,7 +184,7 @@ var user = require('./../user.js'),
|
|||||||
});
|
});
|
||||||
|
|
||||||
os.on('error', function(err) {
|
os.on('error', function(err) {
|
||||||
console.error('[%d] %s', Date.now(), + err);
|
winston.error('[%d] %s', Date.now(), + err);
|
||||||
});
|
});
|
||||||
|
|
||||||
is.pipe(os);
|
is.pipe(os);
|
||||||
@@ -199,24 +194,24 @@ var user = require('./../user.js'),
|
|||||||
|
|
||||||
if(!req.user)
|
if(!req.user)
|
||||||
return res.redirect('/403');
|
return res.redirect('/403');
|
||||||
|
|
||||||
user.get_uid_by_userslug(req.params.userslug, function(uid) {
|
user.get_uid_by_userslug(req.params.userslug, function(uid) {
|
||||||
if(!uid) {
|
if(!uid) {
|
||||||
res.redirect('/404');
|
res.redirect('/404');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.build_header({ req: req, res: res }, function(err, header) {
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
res.send(header + app.create_route('users/'+req.params.userslug+'/following','following') + templates['footer']);
|
res.send(header + app.create_route('users/'+req.params.userslug+'/following','following') + templates['footer']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/users/:userslug/followers', function(req, res) {
|
app.get('/users/:userslug/followers', function(req, res) {
|
||||||
|
|
||||||
if(!req.user)
|
if(!req.user)
|
||||||
return res.redirect('/403');
|
return res.redirect('/403');
|
||||||
|
|
||||||
user.get_uid_by_userslug(req.params.userslug, function(uid) {
|
user.get_uid_by_userslug(req.params.userslug, function(uid) {
|
||||||
if(!uid) {
|
if(!uid) {
|
||||||
res.redirect('/404');
|
res.redirect('/404');
|
||||||
@@ -228,6 +223,22 @@ var user = require('./../user.js'),
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get('/users/:userslug/favourites', function(req, res) {
|
||||||
|
|
||||||
|
if(!req.user)
|
||||||
|
return res.redirect('/403');
|
||||||
|
|
||||||
|
user.get_uid_by_userslug(req.params.userslug, function(uid) {
|
||||||
|
if(!uid) {
|
||||||
|
res.redirect('/404');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
|
res.send(header + app.create_route('users/'+req.params.userslug+'/favourites','favourites') + templates['footer']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
app.get('/api/users/:userslug/following', function(req, res) {
|
app.get('/api/users/:userslug/following', function(req, res) {
|
||||||
var callerUID = req.user ? req.user.uid : 0;
|
var callerUID = req.user ? req.user.uid : 0;
|
||||||
|
|
||||||
@@ -238,7 +249,7 @@ var user = require('./../user.js'),
|
|||||||
userData.followingCount = followingData.length;
|
userData.followingCount = followingData.length;
|
||||||
res.json(userData);
|
res.json(userData);
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
res.json(404, { error: 'User not found!' }) ;
|
res.json(404, { error: 'User not found!' }) ;
|
||||||
}
|
}
|
||||||
@@ -247,7 +258,7 @@ var user = require('./../user.js'),
|
|||||||
|
|
||||||
app.get('/api/users/:userslug/followers', function(req, res) {
|
app.get('/api/users/:userslug/followers', function(req, res) {
|
||||||
var callerUID = req.user ? req.user.uid : 0;
|
var callerUID = req.user ? req.user.uid : 0;
|
||||||
|
|
||||||
getUserDataByUserSlug(req.params.userslug, callerUID, function(userData) {
|
getUserDataByUserSlug(req.params.userslug, callerUID, function(userData) {
|
||||||
if(userData) {
|
if(userData) {
|
||||||
user.getFollowers(userData.uid, function(followersData) {
|
user.getFollowers(userData.uid, function(followersData) {
|
||||||
@@ -257,7 +268,7 @@ var user = require('./../user.js'),
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.json(404, { error: 'User not found!' }) ;
|
res.json(404, { error: 'User not found!' }) ;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -269,7 +280,7 @@ var user = require('./../user.js'),
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/users/:userslug/settings', function(req, res) {
|
app.get('/api/users/:userslug/settings', function(req, res, next) {
|
||||||
var callerUID = req.user ? req.user.uid : 0;
|
var callerUID = req.user ? req.user.uid : 0;
|
||||||
|
|
||||||
user.get_uid_by_userslug(req.params.userslug, function(uid) {
|
user.get_uid_by_userslug(req.params.userslug, function(uid) {
|
||||||
@@ -277,12 +288,15 @@ var user = require('./../user.js'),
|
|||||||
res.json(404, { error: 'User not found!' }) ;
|
res.json(404, { error: 'User not found!' }) ;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(uid !== callerUID || callerUID === "0") {
|
if(uid !== callerUID || callerUID === "0") {
|
||||||
res.json(403, { error: 'Not allowed!' });
|
res.json(403, { error: 'Not allowed!' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
user.getUserFields(uid, ['username','userslug','showemail'], function(userData) {
|
user.getUserFields(uid, ['username','userslug','showemail'], function(err, userData) {
|
||||||
|
if(err)
|
||||||
|
return next(err);
|
||||||
|
|
||||||
if(userData) {
|
if(userData) {
|
||||||
if(userData.showemail && userData.showemail === "1")
|
if(userData.showemail && userData.showemail === "1")
|
||||||
userData.showemail = "checked";
|
userData.showemail = "checked";
|
||||||
@@ -291,9 +305,42 @@ var user = require('./../user.js'),
|
|||||||
res.json(userData);
|
res.json(userData);
|
||||||
} else {
|
} else {
|
||||||
res.json(404, { error: 'User not found!' }) ;
|
res.json(404, { error: 'User not found!' }) ;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/api/users/:userslug/favourites', function(req, res, next) {
|
||||||
|
var callerUID = req.user ? req.user.uid : 0;
|
||||||
|
|
||||||
|
user.get_uid_by_userslug(req.params.userslug, function(uid) {
|
||||||
|
if(!uid) {
|
||||||
|
res.json(404, { error: 'User not found!' }) ;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(uid !== callerUID || callerUID === "0") {
|
||||||
|
res.json(403, { error: 'Not allowed!' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
user.getUserFields(uid, ['username','userslug'], function(err, userData) {
|
||||||
|
if(err)
|
||||||
|
return next(err);
|
||||||
|
|
||||||
|
if(userData) {
|
||||||
|
posts.getFavourites(uid, function(err, posts) {
|
||||||
|
if(err)
|
||||||
|
return next(err);
|
||||||
|
userData.posts = posts;
|
||||||
|
userData.show_nofavourites = posts.length?'hide':'show';
|
||||||
|
res.json(userData);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.json(404, { error: 'User not found!' }) ;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/users/:userslug', function(req, res) {
|
app.get('/api/users/:userslug', function(req, res) {
|
||||||
@@ -307,13 +354,17 @@ var user = require('./../user.js'),
|
|||||||
userData.posts = posts.filter(function(p) {return p.deleted !== "1";});
|
userData.posts = posts.filter(function(p) {return p.deleted !== "1";});
|
||||||
userData.isFollowing = isFollowing;
|
userData.isFollowing = isFollowing;
|
||||||
userData.signature = postTools.markdownToHTML(userData.signature, true);
|
userData.signature = postTools.markdownToHTML(userData.signature, true);
|
||||||
|
if(!userData.profileviews)
|
||||||
|
userData.profileviews = 1;
|
||||||
|
if(callerUID !== userData.uid)
|
||||||
|
user.incrementUserFieldBy(userData.uid, 'profileviews', 1);
|
||||||
res.json(userData);
|
res.json(userData);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
res.json(404, { error: 'User not found!' }) ;
|
res.json(404, { error: 'User not found!' }) ;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/users', getUsersSortedByJoinDate);
|
app.get('/api/users', getUsersSortedByJoinDate);
|
||||||
@@ -321,17 +372,17 @@ var user = require('./../user.js'),
|
|||||||
app.get('/api/users-sort-reputation', getUsersSortedByReputation);
|
app.get('/api/users-sort-reputation', getUsersSortedByReputation);
|
||||||
app.get('/api/users-latest', getUsersSortedByJoinDate);
|
app.get('/api/users-latest', getUsersSortedByJoinDate);
|
||||||
app.get('/api/users-search', getUsersForSearch);
|
app.get('/api/users-search', getUsersForSearch);
|
||||||
|
|
||||||
|
|
||||||
function getUsersSortedByJoinDate(req, res) {
|
function getUsersSortedByJoinDate(req, res) {
|
||||||
user.getUsers('users:joindate', 0, 49, function(err, data) {
|
user.getUsers('users:joindate', 0, 49, function(err, data) {
|
||||||
res.json({ search_display: 'none',loadmore_display:'block', users:data });
|
res.json({ search_display: 'none', loadmore_display:'block', users:data });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUsersSortedByPosts(req, res) {
|
function getUsersSortedByPosts(req, res) {
|
||||||
user.getUsers('users:postcount', 0, 49, function(err, data) {
|
user.getUsers('users:postcount', 0, 49, function(err, data) {
|
||||||
res.json({ search_display: 'none',loadmore_display:'block', users:data });
|
res.json({ search_display: 'none', loadmore_display:'block', users:data });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,19 +391,19 @@ var user = require('./../user.js'),
|
|||||||
res.json({ search_display: 'none', loadmore_display:'block', users:data });
|
res.json({ search_display: 'none', loadmore_display:'block', users:data });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUsersForSearch(req, res) {
|
function getUsersForSearch(req, res) {
|
||||||
res.json({ search_display: 'block', loadmore_display:'none', users: [] });
|
res.json({ search_display: 'block', loadmore_display:'none', users: [] });
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUserDataByUserSlug(userslug, callerUID, callback) {
|
function getUserDataByUserSlug(userslug, callerUID, callback) {
|
||||||
user.get_uid_by_userslug(userslug, function(uid) {
|
user.get_uid_by_userslug(userslug, function(uid) {
|
||||||
|
|
||||||
if(uid === null) {
|
if(uid === null) {
|
||||||
callback(null);
|
callback(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.getUserData(uid, function(data) {
|
user.getUserData(uid, function(data) {
|
||||||
if(data) {
|
if(data) {
|
||||||
data.joindate = utils.relativeTime(data.joindate);
|
data.joindate = utils.relativeTime(data.joindate);
|
||||||
@@ -362,19 +413,20 @@ var user = require('./../user.js'),
|
|||||||
} else {
|
} else {
|
||||||
data.age = new Date().getFullYear() - new Date(data.birthday).getFullYear();
|
data.age = new Date().getFullYear() - new Date(data.birthday).getFullYear();
|
||||||
}
|
}
|
||||||
|
|
||||||
function canSeeEmail() {
|
function canSeeEmail() {
|
||||||
return callerUID === uid || (data.email && (data.showemail && data.showemail === "1"));
|
return callerUID === uid || (data.email && (data.showemail && data.showemail === "1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!canSeeEmail())
|
if(!canSeeEmail())
|
||||||
data.email = "";
|
data.email = "";
|
||||||
|
|
||||||
if(callerUID === uid && (!data.showemail || data.showemail === "0"))
|
if(callerUID === uid && (!data.showemail || data.showemail === "0"))
|
||||||
data.emailClass = "";
|
data.emailClass = "";
|
||||||
else
|
else
|
||||||
data.emailClass = "hide";
|
data.emailClass = "hide";
|
||||||
|
|
||||||
|
data.show_banned = data.banned === '1'?'':'hide';
|
||||||
|
|
||||||
data.uid = uid;
|
data.uid = uid;
|
||||||
data.yourid = callerUID;
|
data.yourid = callerUID;
|
||||||
@@ -391,7 +443,7 @@ var user = require('./../user.js'),
|
|||||||
callback(null);
|
callback(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ var path = require('path'),
|
|||||||
async.parallel([sitemap.getStaticUrls, sitemap.getDynamicUrls], function(err, urls) {
|
async.parallel([sitemap.getStaticUrls, sitemap.getDynamicUrls], function(err, urls) {
|
||||||
var urls = urls[0].concat(urls[1]),
|
var urls = urls[0].concat(urls[1]),
|
||||||
map = sm.createSitemap({
|
map = sm.createSitemap({
|
||||||
hostname: global.nconf.get('url'),
|
hostname: nconf.get('url'),
|
||||||
cacheTime: 600000,
|
cacheTime: 600000,
|
||||||
urls: urls
|
urls: urls
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ var RDB = require('./redis.js'),
|
|||||||
notifications = require('./notifications.js'),
|
notifications = require('./notifications.js'),
|
||||||
posts = require('./posts'),
|
posts = require('./posts'),
|
||||||
reds = require('reds'),
|
reds = require('reds'),
|
||||||
topicSearch = reds.createSearch('nodebbtopicsearch');
|
topicSearch = reds.createSearch('nodebbtopicsearch'),
|
||||||
|
winston = require('winston'),
|
||||||
|
meta = require('./meta');
|
||||||
|
|
||||||
(function(ThreadTools) {
|
(function(ThreadTools) {
|
||||||
|
|
||||||
@@ -16,10 +18,10 @@ var RDB = require('./redis.js'),
|
|||||||
callback(!!ismember || false);
|
callback(!!ismember || false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadTools.privileges = function(tid, uid, callback) {
|
ThreadTools.privileges = function(tid, uid, callback) {
|
||||||
//todo: break early if one condition is true
|
//todo: break early if one condition is true
|
||||||
|
|
||||||
function getCategoryPrivileges(next) {
|
function getCategoryPrivileges(next) {
|
||||||
topics.getTopicField(tid, 'cid', function(err, cid) {
|
topics.getTopicField(tid, 'cid', function(err, cid) {
|
||||||
categories.privileges(cid, uid, function(privileges) {
|
categories.privileges(cid, uid, function(privileges) {
|
||||||
@@ -29,11 +31,12 @@ var RDB = require('./redis.js'),
|
|||||||
}
|
}
|
||||||
|
|
||||||
function hasEnoughRep(next) {
|
function hasEnoughRep(next) {
|
||||||
user.getUserField(uid, 'reputation', function(reputation) {
|
user.getUserField(uid, 'reputation', function(err, reputation) {
|
||||||
next(null, reputation >= global.config['privileges:manage_topic']);
|
if (err) return next(null, false);
|
||||||
|
next(null, reputation >= meta.config['privileges:manage_topic']);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async.parallel([getCategoryPrivileges, hasEnoughRep], function(err, results) {
|
async.parallel([getCategoryPrivileges, hasEnoughRep], function(err, results) {
|
||||||
callback({
|
callback({
|
||||||
@@ -86,8 +89,8 @@ var RDB = require('./redis.js'),
|
|||||||
ThreadTools.delete = function(tid, uid, callback) {
|
ThreadTools.delete = function(tid, uid, callback) {
|
||||||
ThreadTools.privileges(tid, uid, function(privileges) {
|
ThreadTools.privileges(tid, uid, function(privileges) {
|
||||||
if (privileges.editable || uid === -1) {
|
if (privileges.editable || uid === -1) {
|
||||||
|
|
||||||
topics.setTopicField(tid, 'deleted', 1);
|
topics.delete(tid);
|
||||||
ThreadTools.lock(tid, uid);
|
ThreadTools.lock(tid, uid);
|
||||||
|
|
||||||
topicSearch.remove(tid);
|
topicSearch.remove(tid);
|
||||||
@@ -106,15 +109,15 @@ var RDB = require('./redis.js'),
|
|||||||
ThreadTools.privileges(tid, uid, function(privileges) {
|
ThreadTools.privileges(tid, uid, function(privileges) {
|
||||||
if (privileges.editable) {
|
if (privileges.editable) {
|
||||||
|
|
||||||
topics.setTopicField(tid, 'deleted', 0);
|
topics.restore(tid);
|
||||||
ThreadTools.unlock(tid, uid);
|
ThreadTools.unlock(tid, uid);
|
||||||
|
|
||||||
if (socket) {
|
io.sockets.in('topic_' + tid).emit('event:topic_restored', {
|
||||||
io.sockets.in('topic_' + tid).emit('event:topic_restored', {
|
tid: tid,
|
||||||
tid: tid,
|
status: 'ok'
|
||||||
status: 'ok'
|
});
|
||||||
});
|
|
||||||
|
|
||||||
|
if (socket) {
|
||||||
socket.emit('api:topic.restore', {
|
socket.emit('api:topic.restore', {
|
||||||
status: 'ok',
|
status: 'ok',
|
||||||
tid: tid
|
tid: tid
|
||||||
@@ -131,12 +134,12 @@ var RDB = require('./redis.js'),
|
|||||||
ThreadTools.pin = function(tid, uid, socket) {
|
ThreadTools.pin = function(tid, uid, socket) {
|
||||||
ThreadTools.privileges(tid, uid, function(privileges) {
|
ThreadTools.privileges(tid, uid, function(privileges) {
|
||||||
if (privileges.editable) {
|
if (privileges.editable) {
|
||||||
|
|
||||||
topics.setTopicField(tid, 'pinned', 1);
|
topics.setTopicField(tid, 'pinned', 1);
|
||||||
topics.getTopicField(tid, 'cid', function(err, cid) {
|
topics.getTopicField(tid, 'cid', function(err, cid) {
|
||||||
RDB.zadd('categories:' + cid + ':tid', Math.pow(2,53), tid);
|
RDB.zadd('categories:' + cid + ':tid', Math.pow(2,53), tid);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (socket) {
|
if (socket) {
|
||||||
io.sockets.in('topic_' + tid).emit('event:topic_pinned', {
|
io.sockets.in('topic_' + tid).emit('event:topic_pinned', {
|
||||||
tid: tid,
|
tid: tid,
|
||||||
@@ -155,9 +158,9 @@ var RDB = require('./redis.js'),
|
|||||||
ThreadTools.unpin = function(tid, uid, socket) {
|
ThreadTools.unpin = function(tid, uid, socket) {
|
||||||
ThreadTools.privileges(tid, uid, function(privileges) {
|
ThreadTools.privileges(tid, uid, function(privileges) {
|
||||||
if (privileges.editable) {
|
if (privileges.editable) {
|
||||||
|
|
||||||
topics.setTopicField(tid, 'pinned', 0);
|
topics.setTopicField(tid, 'pinned', 0);
|
||||||
topics.getTopicFields(tid, ['cid', 'lastposttime'], function(topicData) {
|
topics.getTopicFields(tid, ['cid', 'lastposttime'], function(err, topicData) {
|
||||||
RDB.zadd('categories:' + topicData.cid + ':tid', topicData.lastposttime, tid);
|
RDB.zadd('categories:' + topicData.cid + ':tid', topicData.lastposttime, tid);
|
||||||
});
|
});
|
||||||
if (socket) {
|
if (socket) {
|
||||||
@@ -176,23 +179,23 @@ var RDB = require('./redis.js'),
|
|||||||
}
|
}
|
||||||
|
|
||||||
ThreadTools.move = function(tid, cid, socket) {
|
ThreadTools.move = function(tid, cid, socket) {
|
||||||
|
|
||||||
topics.getTopicFields(tid, ['cid', 'lastposttime'], function(topicData) {
|
topics.getTopicFields(tid, ['cid', 'lastposttime'], function(err, topicData) {
|
||||||
var oldCid = topicData.cid;
|
var oldCid = topicData.cid;
|
||||||
var multi = RDB.multi();
|
var multi = RDB.multi();
|
||||||
|
|
||||||
multi.zrem('categories:' + oldCid + ':tid', tid);
|
multi.zrem('categories:' + oldCid + ':tid', tid);
|
||||||
multi.zadd('categories:' + cid + ':tid', topicData.lastposttime, tid);
|
multi.zadd('categories:' + cid + ':tid', topicData.lastposttime, tid);
|
||||||
|
|
||||||
multi.exec(function(err, result) {
|
multi.exec(function(err, result) {
|
||||||
|
|
||||||
if (!err && result === 1) {
|
if (!err && result[0] === 1 && result[1] === 1) {
|
||||||
|
|
||||||
topics.setTopicField(tid, 'cid', cid);
|
topics.setTopicField(tid, 'cid', cid);
|
||||||
|
|
||||||
categories.moveRecentReplies(tid, oldCid, cid, function(err, data) {
|
categories.moveRecentReplies(tid, oldCid, cid, function(err, data) {
|
||||||
if(err) {
|
if(err) {
|
||||||
console.log(err);
|
winston.err(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -257,7 +260,7 @@ var RDB = require('./redis.js'),
|
|||||||
ThreadTools.notify_followers = function(tid, exceptUid) {
|
ThreadTools.notify_followers = function(tid, exceptUid) {
|
||||||
async.parallel([
|
async.parallel([
|
||||||
function(next) {
|
function(next) {
|
||||||
|
|
||||||
topics.getTopicField(tid, 'title', function(err, title) {
|
topics.getTopicField(tid, 'title', function(err, title) {
|
||||||
topics.getTeaser(tid, function(err, teaser) {
|
topics.getTeaser(tid, function(err, teaser) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
@@ -267,8 +270,8 @@ var RDB = require('./redis.js'),
|
|||||||
} else next(err);
|
} else next(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
function(next) {
|
function(next) {
|
||||||
ThreadTools.get_followers(tid, function(err, followers) {
|
ThreadTools.get_followers(tid, function(err, followers) {
|
||||||
@@ -289,16 +292,15 @@ var RDB = require('./redis.js'),
|
|||||||
var numPosts = posts.length;
|
var numPosts = posts.length;
|
||||||
if(!numPosts)
|
if(!numPosts)
|
||||||
return callback(new Error('no-undeleted-pids-found'));
|
return callback(new Error('no-undeleted-pids-found'));
|
||||||
|
|
||||||
while(numPosts--) {
|
while(numPosts--) {
|
||||||
if(posts[numPosts].deleted !== '1') {
|
if(posts[numPosts].deleted !== '1') {
|
||||||
callback(null, posts[numPosts].pid);
|
callback(null, posts[numPosts].pid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we got here, nothing was found...
|
|
||||||
callback(new Error('no-undeleted-pids-found'));
|
callback(new Error('no-undeleted-pids-found'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}(exports));
|
}(exports));
|
||||||
293
src/topics.js
293
src/topics.js
@@ -20,8 +20,6 @@ marked.setOptions({
|
|||||||
|
|
||||||
(function(Topics) {
|
(function(Topics) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Topics.getTopicData = function(tid, callback) {
|
Topics.getTopicData = function(tid, callback) {
|
||||||
RDB.hgetall('topic:' + tid, function(err, data) {
|
RDB.hgetall('topic:' + tid, function(err, data) {
|
||||||
if(err === null)
|
if(err === null)
|
||||||
@@ -33,8 +31,7 @@ marked.setOptions({
|
|||||||
|
|
||||||
Topics.getTopicDataWithUsername = function(tid, callback) {
|
Topics.getTopicDataWithUsername = function(tid, callback) {
|
||||||
Topics.getTopicData(tid, function(topic) {
|
Topics.getTopicData(tid, function(topic) {
|
||||||
user.getUserField(topic.uid, 'username', function(username) {
|
user.getUserField(topic.uid, 'username', function(err, username) {
|
||||||
|
|
||||||
topic.username = username;
|
topic.username = username;
|
||||||
callback(topic);
|
callback(topic);
|
||||||
});
|
});
|
||||||
@@ -45,15 +42,15 @@ marked.setOptions({
|
|||||||
posts.getPostsByTid(tid, start, end, function(postData) {
|
posts.getPostsByTid(tid, start, end, function(postData) {
|
||||||
if(Array.isArray(postData) && !postData.length)
|
if(Array.isArray(postData) && !postData.length)
|
||||||
return callback([]);
|
return callback([]);
|
||||||
|
|
||||||
function getFavouritesData(next) {
|
function getFavouritesData(next) {
|
||||||
var pids = [];
|
var pids = [];
|
||||||
for(var i=0; i<postData.length; ++i)
|
for(var i=0; i<postData.length; ++i)
|
||||||
pids.push(postData[i].pid);
|
pids.push(postData[i].pid);
|
||||||
|
|
||||||
favourites.getFavouritesByPostIDs(pids, current_user, function(fav_data) {
|
favourites.getFavouritesByPostIDs(pids, current_user, function(fav_data) {
|
||||||
next(null, fav_data);
|
next(null, fav_data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addUserInfoToPosts(next) {
|
function addUserInfoToPosts(next) {
|
||||||
@@ -63,26 +60,28 @@ marked.setOptions({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async.each(postData, iterator, function(err) {
|
async.each(postData, iterator, function(err) {
|
||||||
next(err, null);
|
next(err, null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPrivileges(next) {
|
function getPrivileges(next) {
|
||||||
threadTools.privileges(tid, current_user, function(privData) {
|
threadTools.privileges(tid, current_user, function(privData) {
|
||||||
next(null, privData);
|
next(null, privData);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async.parallel([getFavouritesData, addUserInfoToPosts, getPrivileges], function(err, results) {
|
async.parallel([getFavouritesData, addUserInfoToPosts, getPrivileges], function(err, results) {
|
||||||
var fav_data = results[0],
|
var fav_data = results[0],
|
||||||
privileges = results[2];
|
privileges = results[2];
|
||||||
|
|
||||||
for(var i=0; i<postData.length; ++i) {
|
for(var i=0; i<postData.length; ++i) {
|
||||||
|
postData[i].fav_button_class = fav_data[postData[i].pid]? 'btn-warning' : '';
|
||||||
postData[i].fav_star_class = fav_data[postData[i].pid] ? 'icon-star' : 'icon-star-empty';
|
postData[i].fav_star_class = fav_data[postData[i].pid] ? 'icon-star' : 'icon-star-empty';
|
||||||
postData[i]['display_moderator_tools'] = (postData[i].uid == current_user || privileges.editable) ? 'show' : 'none';
|
postData[i]['display_moderator_tools'] = (postData[i].uid == current_user || privileges.editable) ? 'show' : 'none';
|
||||||
|
postData[i].show_banned = postData[i].user_banned === '1'?'show':'hide';
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(postData);
|
callback(postData);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -99,9 +98,9 @@ marked.setOptions({
|
|||||||
var timestamp = Date.now();
|
var timestamp = Date.now();
|
||||||
|
|
||||||
var args = [ 'topics:recent', '+inf', timestamp - 86400000, 'WITHSCORES', 'LIMIT', start, end - start + 1];
|
var args = [ 'topics:recent', '+inf', timestamp - 86400000, 'WITHSCORES', 'LIMIT', start, end - start + 1];
|
||||||
|
|
||||||
RDB.zrevrangebyscore(args, function(err, tids) {
|
RDB.zrevrangebyscore(args, function(err, tids) {
|
||||||
|
|
||||||
var latestTopics = {
|
var latestTopics = {
|
||||||
'category_name' : 'Recent',
|
'category_name' : 'Recent',
|
||||||
'show_sidebar' : 'hidden',
|
'show_sidebar' : 'hidden',
|
||||||
@@ -124,7 +123,49 @@ marked.setOptions({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Topics.getTotalUnread = function(uid, callback) {
|
||||||
|
|
||||||
|
var unreadTids = [],
|
||||||
|
start = 0,
|
||||||
|
stop = 21,
|
||||||
|
done = false;
|
||||||
|
|
||||||
|
async.whilst(
|
||||||
|
function () { return unreadTids.length < 21 && !done; },
|
||||||
|
function (callback) {
|
||||||
|
RDB.zrevrange('topics:recent', start, stop, function(err, tids) {
|
||||||
|
|
||||||
|
if(err)
|
||||||
|
return callback(err);
|
||||||
|
|
||||||
|
if(tids && !tids.length) {
|
||||||
|
done = true;
|
||||||
|
return callback(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Topics.hasReadTopics(tids, uid, function(read) {
|
||||||
|
|
||||||
|
var newtids = tids.filter(function(tid, index, self) {
|
||||||
|
return read[index] === 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
unreadTids.push.apply(unreadTids, newtids);
|
||||||
|
|
||||||
|
start = stop + 1;
|
||||||
|
stop = start + 21;
|
||||||
|
callback(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function (err) {
|
||||||
|
callback({
|
||||||
|
count: unreadTids.length
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
Topics.getUnreadTopics = function(uid, start, stop, callback) {
|
Topics.getUnreadTopics = function(uid, start, stop, callback) {
|
||||||
|
|
||||||
var unreadTopics = {
|
var unreadTopics = {
|
||||||
@@ -137,65 +178,82 @@ marked.setOptions({
|
|||||||
'topics' : []
|
'topics' : []
|
||||||
};
|
};
|
||||||
|
|
||||||
RDB.zrevrange('topics:recent', start, stop, function (err, tids) {
|
function noUnreadTopics() {
|
||||||
|
unreadTopics.no_topics_message = 'show';
|
||||||
function noUnreadTopics() {
|
unreadTopics.show_markallread_button = 'hidden';
|
||||||
unreadTopics.no_topics_message = 'show';
|
callback(unreadTopics);
|
||||||
unreadTopics.show_markallread_button = 'hidden';
|
}
|
||||||
|
|
||||||
|
function sendUnreadTopics(topicIds) {
|
||||||
|
Topics.getTopicsByTids(topicIds, uid, function(topicData) {
|
||||||
|
unreadTopics.topics = topicData;
|
||||||
|
unreadTopics.nextStart = start + topicIds.length;
|
||||||
|
if(!topicData || topicData.length === 0)
|
||||||
|
unreadTopics.no_topics_message = 'show';
|
||||||
|
if(uid === 0 || topicData.length === 0)
|
||||||
|
unreadTopics.show_markallread_button = 'hidden';
|
||||||
callback(unreadTopics);
|
callback(unreadTopics);
|
||||||
}
|
});
|
||||||
|
}
|
||||||
function sendUnreadTopics(topicIds) {
|
|
||||||
Topics.getTopicsByTids(topicIds, uid, function(topicData) {
|
var unreadTids = [],
|
||||||
unreadTopics.topics = topicData;
|
done = false;
|
||||||
unreadTopics.nextStart = start + tids.length;
|
|
||||||
if(uid === 0)
|
async.whilst(
|
||||||
unreadTopics.show_markallread_button = 'hidden';
|
function () { return unreadTids.length < 20 && !done; },
|
||||||
callback(unreadTopics);
|
function (callback) {
|
||||||
});
|
RDB.zrevrange('topics:recent', start, stop, function(err, tids) {
|
||||||
}
|
if(err)
|
||||||
|
return callback(err);
|
||||||
if (!tids || !tids.length) {
|
|
||||||
noUnreadTopics();
|
if(tids && !tids.length) {
|
||||||
return;
|
done = true;
|
||||||
}
|
return callback(null);
|
||||||
|
|
||||||
if(uid === 0) {
|
|
||||||
sendUnreadTopics(tids);
|
|
||||||
} else {
|
|
||||||
|
|
||||||
Topics.hasReadTopics(tids, uid, function(read) {
|
|
||||||
|
|
||||||
var unreadTids = tids.filter(function(tid, index, self) {
|
|
||||||
return read[index] === 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!unreadTids || !unreadTids.length) {
|
|
||||||
noUnreadTopics();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(uid === 0) {
|
||||||
|
unreadTids.push.apply(unreadTids, tids);
|
||||||
|
callback(null);
|
||||||
|
} else {
|
||||||
|
Topics.hasReadTopics(tids, uid, function(read) {
|
||||||
|
|
||||||
|
var newtids = tids.filter(function(tid, index, self) {
|
||||||
|
return read[index] === 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
unreadTids.push.apply(unreadTids, newtids);
|
||||||
|
start = stop + 1;
|
||||||
|
stop = start + 19;
|
||||||
|
callback(null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function (err) {
|
||||||
|
if(err)
|
||||||
|
return callback([]);
|
||||||
|
if(unreadTids.length)
|
||||||
sendUnreadTopics(unreadTids);
|
sendUnreadTopics(unreadTids);
|
||||||
});
|
else
|
||||||
|
noUnreadTopics();
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Topics.getTopicsByTids = function(tids, current_user, callback, category_id) {
|
Topics.getTopicsByTids = function(tids, current_user, callback, category_id) {
|
||||||
|
|
||||||
var retrieved_topics = [];
|
var retrieved_topics = [];
|
||||||
|
|
||||||
if(!Array.isArray(tids) || tids.length === 0) {
|
if(!Array.isArray(tids) || tids.length === 0) {
|
||||||
callback(retrieved_topics);
|
callback(retrieved_topics);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTopicInfo(topicData, callback) {
|
function getTopicInfo(topicData, callback) {
|
||||||
|
|
||||||
function getUserName(next) {
|
function getUserInfo(next) {
|
||||||
user.getUserField(topicData.uid, 'username', function(username) {
|
user.getUserFields(topicData.uid, ['username'], next);
|
||||||
next(null, username);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasReadTopic(next) {
|
function hasReadTopic(next) {
|
||||||
@@ -217,17 +275,13 @@ marked.setOptions({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async.parallel([getUserName, hasReadTopic, getTeaserInfo, getPrivileges], function(err, results) {
|
async.parallel([getUserInfo, hasReadTopic, getTeaserInfo, getPrivileges], function(err, results) {
|
||||||
var username = results[0],
|
|
||||||
hasReadTopic = results[1],
|
|
||||||
teaserInfo = results[2],
|
|
||||||
privileges = results[3];
|
|
||||||
|
|
||||||
callback({
|
callback({
|
||||||
username: username,
|
username: results[0].username,
|
||||||
hasread: hasReadTopic,
|
userbanned: results[0].banned,
|
||||||
teaserInfo: teaserInfo,
|
hasread: results[1],
|
||||||
privileges: privileges
|
teaserInfo: results[2],
|
||||||
|
privileges: results[3]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -242,7 +296,7 @@ marked.setOptions({
|
|||||||
if(!topicData) {
|
if(!topicData) {
|
||||||
return callback(null);
|
return callback(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
getTopicInfo(topicData, function(topicInfo) {
|
getTopicInfo(topicData, function(topicInfo) {
|
||||||
|
|
||||||
topicData['pin-icon'] = topicData.pinned === '1' ? 'icon-pushpin' : 'none';
|
topicData['pin-icon'] = topicData.pinned === '1' ? 'icon-pushpin' : 'none';
|
||||||
@@ -260,12 +314,12 @@ marked.setOptions({
|
|||||||
|
|
||||||
if (isTopicVisible(topicData, topicInfo))
|
if (isTopicVisible(topicData, topicInfo))
|
||||||
retrieved_topics.push(topicData);
|
retrieved_topics.push(topicData);
|
||||||
|
|
||||||
callback(null);
|
callback(null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async.eachSeries(tids, loadTopic, function(err) {
|
async.eachSeries(tids, loadTopic, function(err) {
|
||||||
if(!err) {
|
if(!err) {
|
||||||
callback(retrieved_topics);
|
callback(retrieved_topics);
|
||||||
@@ -276,7 +330,7 @@ marked.setOptions({
|
|||||||
|
|
||||||
Topics.getTopicWithPosts = function(tid, current_user, callback) {
|
Topics.getTopicWithPosts = function(tid, current_user, callback) {
|
||||||
threadTools.exists(tid, function(exists) {
|
threadTools.exists(tid, function(exists) {
|
||||||
if (!exists)
|
if (!exists)
|
||||||
return callback(new Error('Topic tid \'' + tid + '\' not found'));
|
return callback(new Error('Topic tid \'' + tid + '\' not found'));
|
||||||
|
|
||||||
Topics.markAsRead(tid, current_user);
|
Topics.markAsRead(tid, current_user);
|
||||||
@@ -297,8 +351,8 @@ marked.setOptions({
|
|||||||
threadTools.privileges(tid, current_user, function(privData) {
|
threadTools.privileges(tid, current_user, function(privData) {
|
||||||
next(null, privData);
|
next(null, privData);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCategoryData(next) {
|
function getCategoryData(next) {
|
||||||
Topics.getCategoryData(tid, next);
|
Topics.getCategoryData(tid, next);
|
||||||
}
|
}
|
||||||
@@ -309,14 +363,14 @@ marked.setOptions({
|
|||||||
callback(err, null);
|
callback(err, null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var topicData = results[0],
|
var topicData = results[0],
|
||||||
topicPosts = results[1],
|
topicPosts = results[1],
|
||||||
privileges = results[2],
|
privileges = results[2],
|
||||||
categoryData = results[3];
|
categoryData = results[3];
|
||||||
|
|
||||||
var main_posts = topicPosts.splice(0, 1);
|
var main_posts = topicPosts.splice(0, 1);
|
||||||
|
|
||||||
callback(null, {
|
callback(null, {
|
||||||
'topic_name':topicData.title,
|
'topic_name':topicData.title,
|
||||||
'category_name':categoryData.name,
|
'category_name':categoryData.name,
|
||||||
@@ -364,7 +418,7 @@ marked.setOptions({
|
|||||||
if (err) {
|
if (err) {
|
||||||
throw new Error(err);
|
throw new Error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
var topicData = results[0],
|
var topicData = results[0],
|
||||||
hasRead = results[1],
|
hasRead = results[1],
|
||||||
teaser = results[2];
|
teaser = results[2];
|
||||||
@@ -375,7 +429,7 @@ marked.setOptions({
|
|||||||
topicData.teaser_username = teaser.username || '';
|
topicData.teaser_username = teaser.username || '';
|
||||||
topicData.teaser_timestamp = teaser.timestamp ? utils.relativeTime(teaser.timestamp) : '';
|
topicData.teaser_timestamp = teaser.timestamp ? utils.relativeTime(teaser.timestamp) : '';
|
||||||
topicData.teaser_userpicture = teaser.picture;
|
topicData.teaser_userpicture = teaser.picture;
|
||||||
|
|
||||||
callback(topicData);
|
callback(topicData);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -417,7 +471,7 @@ marked.setOptions({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Topics.markAllRead = function(uid, callback) {
|
Topics.markAllRead = function(uid, callback) {
|
||||||
RDB.smembers('topics:tid', function(err, tids) {
|
RDB.smembers('topics:tid', function(err, tids) {
|
||||||
if(err) {
|
if(err) {
|
||||||
@@ -425,13 +479,13 @@ marked.setOptions({
|
|||||||
callback(err, null);
|
callback(err, null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tids && tids.length) {
|
if(tids && tids.length) {
|
||||||
for(var i=0; i<tids.length; ++i) {
|
for(var i=0; i<tids.length; ++i) {
|
||||||
Topics.markAsRead(tids[i], uid);
|
Topics.markAsRead(tids[i], uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(null, true);
|
callback(null, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -445,15 +499,15 @@ marked.setOptions({
|
|||||||
}
|
}
|
||||||
|
|
||||||
Topics.markUnRead = function(tid) {
|
Topics.markUnRead = function(tid) {
|
||||||
RDB.del('tid:' + tid + ':read_by_uid');
|
RDB.del('tid:' + tid + ':read_by_uid');
|
||||||
}
|
}
|
||||||
|
|
||||||
Topics.markAsRead = function(tid, uid) {
|
Topics.markAsRead = function(tid, uid) {
|
||||||
|
|
||||||
RDB.sadd(schema.topics(tid).read_by_uid, uid);
|
RDB.sadd(schema.topics(tid).read_by_uid, uid);
|
||||||
|
|
||||||
Topics.getTopicField(tid, 'cid', function(err, cid) {
|
Topics.getTopicField(tid, 'cid', function(err, cid) {
|
||||||
|
|
||||||
categories.isTopicsRead(cid, uid, function(read) {
|
categories.isTopicsRead(cid, uid, function(read) {
|
||||||
if(read) {
|
if(read) {
|
||||||
categories.markAsRead(cid, uid);
|
categories.markAsRead(cid, uid);
|
||||||
@@ -466,9 +520,9 @@ marked.setOptions({
|
|||||||
var batch = RDB.multi();
|
var batch = RDB.multi();
|
||||||
|
|
||||||
for (var i=0, ii=tids.length; i<ii; i++) {
|
for (var i=0, ii=tids.length; i<ii; i++) {
|
||||||
batch.sismember(schema.topics(tids[i]).read_by_uid, uid);
|
batch.sismember(schema.topics(tids[i]).read_by_uid, uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
batch.exec(function(err, hasRead) {
|
batch.exec(function(err, hasRead) {
|
||||||
callback(hasRead);
|
callback(hasRead);
|
||||||
});
|
});
|
||||||
@@ -483,9 +537,9 @@ marked.setOptions({
|
|||||||
console.log(err);
|
console.log(err);
|
||||||
callback(false);
|
callback(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Topics.getTeasers = function(tids, callback) {
|
Topics.getTeasers = function(tids, callback) {
|
||||||
var teasers = [];
|
var teasers = [];
|
||||||
if (Array.isArray(tids)) {
|
if (Array.isArray(tids)) {
|
||||||
@@ -506,7 +560,10 @@ marked.setOptions({
|
|||||||
if (!err) {
|
if (!err) {
|
||||||
posts.getPostFields(pid, ['content', 'uid', 'timestamp'], function(postData) {
|
posts.getPostFields(pid, ['content', 'uid', 'timestamp'], function(postData) {
|
||||||
|
|
||||||
user.getUserFields(postData.uid, ['username', 'picture'], function(userData) {
|
user.getUserFields(postData.uid, ['username', 'picture'], function(err, userData) {
|
||||||
|
if(err)
|
||||||
|
return callback(err, null);
|
||||||
|
|
||||||
var stripped = postData.content,
|
var stripped = postData.content,
|
||||||
timestamp = postData.timestamp;
|
timestamp = postData.timestamp;
|
||||||
|
|
||||||
@@ -532,34 +589,34 @@ marked.setOptions({
|
|||||||
type: 'error',
|
type: 'error',
|
||||||
timeout: 2000,
|
timeout: 2000,
|
||||||
title: 'Title too short',
|
title: 'Title too short',
|
||||||
message: "Please enter a longer title. At least " + config.minimumTitleLength + " characters.",
|
message: "Please enter a longer title. At least " + meta.config.minimumTitleLength + " characters.",
|
||||||
alert_id: 'post_error'
|
alert_id: 'post_error'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Topics.post = function(uid, title, content, category_id, images, callback) {
|
Topics.post = function(uid, title, content, category_id, images, callback) {
|
||||||
if (!category_id)
|
if (!category_id)
|
||||||
throw new Error('Attempted to post without a category_id');
|
throw new Error('Attempted to post without a category_id');
|
||||||
|
|
||||||
if(content)
|
if(content)
|
||||||
content = content.trim();
|
content = content.trim();
|
||||||
if(title)
|
if(title)
|
||||||
title = title.trim();
|
title = title.trim();
|
||||||
|
|
||||||
if (uid === 0) {
|
if (uid === 0) {
|
||||||
callback(new Error('not-logged-in'), null);
|
callback(new Error('not-logged-in'), null);
|
||||||
return;
|
return;
|
||||||
} else if(!title || title.length < config.minimumTitleLength) {
|
} else if(!title || title.length < meta.config.minimumTitleLength) {
|
||||||
callback(new Error('title-too-short'), null);
|
callback(new Error('title-too-short'), null);
|
||||||
return;
|
return;
|
||||||
} else if (!content || content.length < config.miminumPostLength) {
|
} else if (!content || content.length < meta.config.miminumPostLength) {
|
||||||
callback(new Error('content-too-short'), null);
|
callback(new Error('content-too-short'), null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.getUserField(uid, 'lastposttime', function(lastposttime) {
|
|
||||||
|
|
||||||
if(Date.now() - lastposttime < config.postDelay) {
|
user.getUserField(uid, 'lastposttime', function(err, lastposttime) {
|
||||||
|
if (err) lastposttime = 0;
|
||||||
|
if(Date.now() - lastposttime < meta.config.postDelay) {
|
||||||
callback(new Error('too-many-posts'), null);
|
callback(new Error('too-many-posts'), null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -590,9 +647,9 @@ marked.setOptions({
|
|||||||
'postcount': 0,
|
'postcount': 0,
|
||||||
'locked': 0,
|
'locked': 0,
|
||||||
'deleted': 0,
|
'deleted': 0,
|
||||||
'pinned': 0
|
'pinned': 0
|
||||||
});
|
});
|
||||||
|
|
||||||
topicSearch.index(title, tid);
|
topicSearch.index(title, tid);
|
||||||
RDB.set('topicslug:' + slug + ':tid', tid);
|
RDB.set('topicslug:' + slug + ':tid', tid);
|
||||||
|
|
||||||
@@ -613,7 +670,6 @@ marked.setOptions({
|
|||||||
|
|
||||||
posts.create(uid, tid, content, images, function(postData) {
|
posts.create(uid, tid, content, images, function(postData) {
|
||||||
if (postData) {
|
if (postData) {
|
||||||
RDB.lpush(schema.topics(tid).posts, postData.pid);
|
|
||||||
|
|
||||||
// Auto-subscribe the post creator to the newly created topic
|
// Auto-subscribe the post creator to the newly created topic
|
||||||
threadTools.toggleFollow(tid, uid);
|
threadTools.toggleFollow(tid, uid);
|
||||||
@@ -634,16 +690,9 @@ marked.setOptions({
|
|||||||
Topics.getTopicField = function(tid, field, callback) {
|
Topics.getTopicField = function(tid, field, callback) {
|
||||||
RDB.hget('topic:' + tid, field, callback);
|
RDB.hget('topic:' + tid, field, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
Topics.getTopicFields = function(tid, fields, callback) {
|
Topics.getTopicFields = function(tid, fields, callback) {
|
||||||
RDB.hmgetObject('topic:' + tid, fields, function(err, data) {
|
RDB.hmgetObject('topic:' + tid, fields, callback);
|
||||||
if(err === null) {
|
|
||||||
callback(data);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Topics.setTopicField = function(tid, field, value) {
|
Topics.setTopicField = function(tid, field, value) {
|
||||||
@@ -661,10 +710,10 @@ marked.setOptions({
|
|||||||
}
|
}
|
||||||
|
|
||||||
Topics.updateTimestamp = function(tid, timestamp) {
|
Topics.updateTimestamp = function(tid, timestamp) {
|
||||||
RDB.zadd(schema.topics().recent, timestamp, tid);
|
RDB.zadd('topics:recent', timestamp, tid);
|
||||||
Topics.setTopicField(tid, 'lastposttime', timestamp);
|
Topics.setTopicField(tid, 'lastposttime', timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
Topics.addPostToTopic = function(tid, pid) {
|
Topics.addPostToTopic = function(tid, pid) {
|
||||||
RDB.rpush('tid:' + tid + ':posts', pid);
|
RDB.rpush('tid:' + tid + ':posts', pid);
|
||||||
}
|
}
|
||||||
@@ -673,6 +722,18 @@ marked.setOptions({
|
|||||||
RDB.lrange('tid:' + tid + ':posts', 0, -1, callback);
|
RDB.lrange('tid:' + tid + ':posts', 0, -1, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Topics.delete = function(tid) {
|
||||||
|
Topics.setTopicField(tid, 'deleted', 1);
|
||||||
|
RDB.zrem('topics:recent', tid);
|
||||||
|
}
|
||||||
|
|
||||||
|
Topics.restore = function(tid) {
|
||||||
|
Topics.setTopicField(tid, 'deleted', 0);
|
||||||
|
Topics.getTopicField(tid, 'lastposttime', function(err, lastposttime) {
|
||||||
|
RDB.zadd('topics:recent', lastposttime, tid);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Topics.reIndexTopic = function(tid, callback) {
|
Topics.reIndexTopic = function(tid, callback) {
|
||||||
Topics.getPids(tid, function(err, pids) {
|
Topics.getPids(tid, function(err, pids) {
|
||||||
if(err) {
|
if(err) {
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
var RDB = require('./redis.js'),
|
var RDB = require('./redis.js'),
|
||||||
async = require('async');
|
async = require('async'),
|
||||||
|
winston = require('winston'),
|
||||||
|
user = require('./user');
|
||||||
|
|
||||||
|
|
||||||
function upgradeCategory(cid, callback) {
|
function upgradeCategory(cid, callback) {
|
||||||
RDB.type('categories:'+ cid +':tid', function(err, type) {
|
RDB.type('categories:'+ cid +':tid', function(err, type) {
|
||||||
if (type === 'set') {
|
if (type === 'set') {
|
||||||
RDB.smembers('categories:' + cid + ':tid', function(err, tids) {
|
RDB.smembers('categories:' + cid + ':tid', function(err, tids) {
|
||||||
|
|
||||||
function moveTopic(tid, callback) {
|
function moveTopic(tid, callback) {
|
||||||
RDB.hget('topic:' + tid, 'timestamp', function(err, timestamp) {
|
RDB.hget('topic:' + tid, 'timestamp', function(err, timestamp) {
|
||||||
if(err)
|
if(err)
|
||||||
@@ -17,81 +18,83 @@ function upgradeCategory(cid, callback) {
|
|||||||
callback(null);
|
callback(null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async.each(tids, moveTopic, function(err) {
|
async.each(tids, moveTopic, function(err) {
|
||||||
if(!err) {
|
if(!err) {
|
||||||
console.log('renaming ' + cid);
|
|
||||||
RDB.rename('temp_categories:' + cid + ':tid', 'categories:' + cid + ':tid');
|
RDB.rename('temp_categories:' + cid + ':tid', 'categories:' + cid + ':tid');
|
||||||
callback(null);
|
callback(null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log('category already upgraded '+ cid);
|
winston.info('category already upgraded '+ cid);
|
||||||
callback(null);
|
callback(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function upgradeUser(uid, callback) {
|
function upgradeUser(uid, callback) {
|
||||||
RDB.hmgetObject('user:' + uid, ['joindate', 'postcount', 'reputation'], function(err, userData) {
|
user.getUserFields(uid, ['joindate', 'postcount', 'reputation'], function(err, userData) {
|
||||||
if(err)
|
if(err)
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
|
||||||
RDB.zadd('users:joindate', userData.joindate, uid);
|
RDB.zadd('users:joindate', userData.joindate, uid);
|
||||||
RDB.zadd('users:postcount', userData.postcount, uid);
|
RDB.zadd('users:postcount', userData.postcount, uid);
|
||||||
RDB.zadd('users:reputation', userData.reputation, uid);
|
RDB.zadd('users:reputation', userData.reputation, uid);
|
||||||
|
|
||||||
callback(null);
|
callback(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.upgrade = function() {
|
exports.upgrade = function() {
|
||||||
|
|
||||||
console.log('upgrading nodebb now');
|
winston.info('upgrading nodebb now');
|
||||||
|
|
||||||
var schema = [
|
var schema = [
|
||||||
function upgradeCategories(next) {
|
function upgradeCategories(next) {
|
||||||
console.log('upgrading categories');
|
winston.info('upgrading categories');
|
||||||
|
|
||||||
RDB.lrange('categories:cid', 0, -1, function(err, cids) {
|
RDB.lrange('categories:cid', 0, -1, function(err, cids) {
|
||||||
|
|
||||||
async.each(cids, upgradeCategory, function(err) {
|
async.each(cids, upgradeCategory, function(err) {
|
||||||
if(!err)
|
if(!err) {
|
||||||
next(null, 'upgraded categories');
|
winston.info('upgraded categories');
|
||||||
else
|
next(null, null);
|
||||||
|
} else {
|
||||||
next(err, null);
|
next(err, null);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
function upgradeUsers(next) {
|
function upgradeUsers(next) {
|
||||||
console.log('upgrading users');
|
winston.info('upgrading users');
|
||||||
|
|
||||||
RDB.lrange('userlist', 0, -1, function(err, uids) {
|
RDB.lrange('userlist', 0, -1, function(err, uids) {
|
||||||
|
|
||||||
async.each(uids, upgradeUser, function(err) {
|
async.each(uids, upgradeUser, function(err) {
|
||||||
if(!err)
|
if(!err) {
|
||||||
next(null, 'upgraded users');
|
winston.info('upgraded users')
|
||||||
else
|
next(null, null);
|
||||||
|
} else {
|
||||||
next(err, null);
|
next(err, null);
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
async.series(schema, function(err, results) {
|
async.series(schema, function(err, results) {
|
||||||
if(!err)
|
if(!err)
|
||||||
console.log('upgrade complete');
|
winston.info('upgrade complete');
|
||||||
else
|
else
|
||||||
console.log(err);
|
winston.err(err);
|
||||||
|
|
||||||
process.exit();
|
process.exit();
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
140
src/user.js
140
src/user.js
@@ -2,7 +2,8 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
RDB = require('./redis.js'),
|
RDB = require('./redis.js'),
|
||||||
crypto = require('crypto'),
|
crypto = require('crypto'),
|
||||||
emailjs = require('emailjs'),
|
emailjs = require('emailjs'),
|
||||||
emailjsServer = emailjs.server.connect(config.mailer),
|
meta = require('./meta.js'),
|
||||||
|
emailjsServer = emailjs.server.connect(meta.config.mailer),
|
||||||
bcrypt = require('bcrypt'),
|
bcrypt = require('bcrypt'),
|
||||||
marked = require('marked'),
|
marked = require('marked'),
|
||||||
notifications = require('./notifications.js'),
|
notifications = require('./notifications.js'),
|
||||||
@@ -41,14 +42,14 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
} else next();
|
} else next();
|
||||||
}
|
}
|
||||||
], function(err, results) {
|
], function(err, results) {
|
||||||
if (err) return callback(err, 0); // FIXME: Maintaining the 0 for backwards compatibility. Do we need this?
|
if (err) return callback(err, null);
|
||||||
|
|
||||||
RDB.incr('global:next_user_id', function(err, uid) {
|
RDB.incr('global:next_user_id', function(err, uid) {
|
||||||
RDB.handle(err);
|
RDB.handle(err);
|
||||||
|
|
||||||
var gravatar = User.createGravatarURLFromEmail(email);
|
var gravatar = User.createGravatarURLFromEmail(email);
|
||||||
var timestamp = Date.now();
|
var timestamp = Date.now();
|
||||||
|
|
||||||
RDB.hmset('user:'+uid, {
|
RDB.hmset('user:'+uid, {
|
||||||
'uid': uid,
|
'uid': uid,
|
||||||
'username' : username,
|
'username' : username,
|
||||||
@@ -63,13 +64,15 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
'picture': gravatar,
|
'picture': gravatar,
|
||||||
'gravatarpicture' : gravatar,
|
'gravatarpicture' : gravatar,
|
||||||
'uploadedpicture': '',
|
'uploadedpicture': '',
|
||||||
|
'profileviews': 0,
|
||||||
'reputation': 0,
|
'reputation': 0,
|
||||||
'postcount': 0,
|
'postcount': 0,
|
||||||
'lastposttime': 0,
|
'lastposttime': 0,
|
||||||
'administrator': (uid == 1) ? 1 : 0,
|
'administrator': (uid == 1) ? 1 : 0,
|
||||||
|
'banned': 0,
|
||||||
'showemail': 0
|
'showemail': 0
|
||||||
});
|
});
|
||||||
|
|
||||||
RDB.set('username:' + username + ':uid', uid);
|
RDB.set('username:' + username + ':uid', uid);
|
||||||
RDB.set('userslug:'+ userslug +':uid', uid);
|
RDB.set('userslug:'+ userslug +':uid', uid);
|
||||||
|
|
||||||
@@ -87,7 +90,7 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
RDB.zadd('users:joindate', timestamp, uid);
|
RDB.zadd('users:joindate', timestamp, uid);
|
||||||
RDB.zadd('users:postcount', 0, uid);
|
RDB.zadd('users:postcount', 0, uid);
|
||||||
RDB.zadd('users:reputation', 0, uid);
|
RDB.zadd('users:reputation', 0, uid);
|
||||||
|
|
||||||
io.sockets.emit('user.latest', {userslug: userslug, username: username});
|
io.sockets.emit('user.latest', {userslug: userslug, username: username});
|
||||||
|
|
||||||
if (password !== undefined) {
|
if (password !== undefined) {
|
||||||
@@ -100,7 +103,7 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
User.delete = function(uid, callback) {
|
User.delete = function(uid, callback) {
|
||||||
RDB.exists('user:'+uid, function(err, exists) {
|
RDB.exists('user:'+uid, function(err, exists) {
|
||||||
if(exists === 1) {
|
if(exists === 1) {
|
||||||
@@ -126,25 +129,21 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
User.ban = function(uid, callback) {
|
||||||
|
User.setUserField(uid, 'banned', 1, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
User.unban = function(uid, callback) {
|
||||||
|
User.setUserField(uid, 'banned', 0, callback);
|
||||||
|
}
|
||||||
|
|
||||||
User.getUserField = function(uid, field, callback) {
|
User.getUserField = function(uid, field, callback) {
|
||||||
RDB.hget('user:' + uid, field, function(err, data) {
|
RDB.hget('user:' + uid, field, callback);
|
||||||
if(err === null) {
|
|
||||||
callback(data);
|
|
||||||
} else {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
User.getUserFields = function(uid, fields, callback) {
|
User.getUserFields = function(uid, fields, callback) {
|
||||||
RDB.hmgetObject('user:' + uid, fields, function(err, data) {
|
RDB.hmgetObject('user:' + uid, fields, callback);
|
||||||
if(err === null) {
|
|
||||||
callback(data);
|
|
||||||
} else {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
User.getMultipleUserFields = function(uids, fields, callback) {
|
User.getMultipleUserFields = function(uids, fields, callback) {
|
||||||
@@ -160,7 +159,9 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
});
|
});
|
||||||
|
|
||||||
function iterator(uid, callback) {
|
function iterator(uid, callback) {
|
||||||
User.getUserFields(uid, fields, function(userData) {
|
User.getUserFields(uid, fields, function(err, userData) {
|
||||||
|
if(err)
|
||||||
|
return callback(err);
|
||||||
returnData.push(userData);
|
returnData.push(userData);
|
||||||
callback(null);
|
callback(null);
|
||||||
});
|
});
|
||||||
@@ -190,6 +191,12 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
User.filterBannedUsers = function(users) {
|
||||||
|
return users.filter(function(user) {
|
||||||
|
return (!user.banned || user.banned === '0');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
User.updateProfile = function(uid, data, callback) {
|
User.updateProfile = function(uid, data, callback) {
|
||||||
|
|
||||||
var fields = ['email', 'fullname', 'website', 'location', 'birthday', 'signature'];
|
var fields = ['email', 'fullname', 'website', 'location', 'birthday', 'signature'];
|
||||||
@@ -199,30 +206,30 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
if(data['signature'] !== undefined && data['signature'].length > 150) {
|
if(data['signature'] !== undefined && data['signature'].length > 150) {
|
||||||
next({error:'Signature can\'t be longer than 150 characters!'}, false);
|
next({error:'Signature can\'t be longer than 150 characters!'}, false);
|
||||||
} else {
|
} else {
|
||||||
next(null, true);
|
next(null, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isEmailAvailable(next) {
|
function isEmailAvailable(next) {
|
||||||
if(!data['email']) {
|
if(!data['email']) {
|
||||||
return next(null, true);
|
return next(null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
User.getUserField(uid, 'email', function(email) {
|
User.getUserField(uid, 'email', function(err, email) {
|
||||||
if(email !== data['email']) {
|
if(email !== data['email']) {
|
||||||
User.isEmailAvailable(data['email'], function(available) {
|
User.isEmailAvailable(data['email'], function(available) {
|
||||||
if(!available) {
|
if(!available) {
|
||||||
next({error:'Email not available!'}, false);
|
next({error:'Email not available!'}, false);
|
||||||
} else {
|
} else {
|
||||||
next(null, true);
|
next(null, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
next(null, true);
|
next(null, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async.series([isSignatureValid, isEmailAvailable], function(err, results) {
|
async.series([isSignatureValid, isEmailAvailable], function(err, results) {
|
||||||
if(err) {
|
if(err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
@@ -245,8 +252,11 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
if(field === 'email') {
|
if(field === 'email') {
|
||||||
var gravatarpicture = User.createGravatarURLFromEmail(data[field]);
|
var gravatarpicture = User.createGravatarURLFromEmail(data[field]);
|
||||||
User.setUserField(uid, 'gravatarpicture', gravatarpicture);
|
User.setUserField(uid, 'gravatarpicture', gravatarpicture);
|
||||||
User.getUserFields(uid, ['email', 'picture', 'uploadedpicture'], function(userData) {
|
User.getUserFields(uid, ['email', 'picture', 'uploadedpicture'], function(err, userData) {
|
||||||
RDB.del('email:' + userData['email'] + ':uid');
|
if(err)
|
||||||
|
return callback(err);
|
||||||
|
|
||||||
|
RDB.del('email:' + userData['email'] + ':uid');
|
||||||
RDB.set('email:' + data['email'] + ':uid', uid);
|
RDB.set('email:' + data['email'] + ':uid', uid);
|
||||||
User.setUserField(uid, field, data[field]);
|
User.setUserField(uid, field, data[field]);
|
||||||
if(userData.picture !== userData.uploadedpicture) {
|
if(userData.picture !== userData.uploadedpicture) {
|
||||||
@@ -259,9 +269,9 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
return;
|
return;
|
||||||
} else if(field === 'signature') {
|
} else if(field === 'signature') {
|
||||||
data[field] = utils.strip_tags(data[field]);
|
data[field] = utils.strip_tags(data[field]);
|
||||||
}
|
}
|
||||||
|
|
||||||
User.setUserField(uid, field, data[field]);
|
User.setUserField(uid, field, data[field]);
|
||||||
|
|
||||||
callback(null);
|
callback(null);
|
||||||
} else {
|
} else {
|
||||||
@@ -285,10 +295,10 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
User.changePassword = function(uid, data, callback) {
|
User.changePassword = function(uid, data, callback) {
|
||||||
if(!utils.isPasswordValid(data.newPassword)) {
|
if(!utils.isPasswordValid(data.newPassword)) {
|
||||||
callback({err:'Invalid password!'});
|
callback({err:'Invalid password!'});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
User.getUserField(uid, 'password', function(user_password) {
|
User.getUserField(uid, 'password', function(err, user_password) {
|
||||||
bcrypt.compare(data.currentPassword, user_password, function(err, res) {
|
bcrypt.compare(data.currentPassword, user_password, function(err, res) {
|
||||||
if(err) {
|
if(err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
@@ -309,8 +319,8 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
User.setUserField = function(uid, field, value) {
|
User.setUserField = function(uid, field, value, callback) {
|
||||||
RDB.hset('user:' + uid, field, value);
|
RDB.hset('user:' + uid, field, value, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
User.setUserFields = function(uid, data) {
|
User.setUserFields = function(uid, data) {
|
||||||
@@ -327,12 +337,12 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
|
|
||||||
User.getUsers = function(set, start, stop, callback) {
|
User.getUsers = function(set, start, stop, callback) {
|
||||||
var data = [];
|
var data = [];
|
||||||
|
|
||||||
RDB.zrevrange(set, start, stop, function(err, uids) {
|
RDB.zrevrange(set, start, stop, function(err, uids) {
|
||||||
if(err) {
|
if(err) {
|
||||||
return callback(err, null);
|
return callback(err, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function iterator(uid, callback) {
|
function iterator(uid, callback) {
|
||||||
User.getUserData(uid, function(userData) {
|
User.getUserData(uid, function(userData) {
|
||||||
if(userData) {
|
if(userData) {
|
||||||
@@ -341,11 +351,10 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
callback(null);
|
callback(null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async.eachSeries(uids, iterator, function(err) {
|
async.eachSeries(uids, iterator, function(err) {
|
||||||
callback(err, data);
|
callback(err, data);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,13 +364,13 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
default: 'identicon',
|
default: 'identicon',
|
||||||
rating: 'pg'
|
rating: 'pg'
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!email) {
|
if (!email) {
|
||||||
email = '';
|
email = '';
|
||||||
options.forcedefault = 'y';
|
options.forcedefault = 'y';
|
||||||
}
|
}
|
||||||
|
|
||||||
return require('gravatar').url(email, options, https=global.nconf.get('https'));
|
return require('gravatar').url(email, options, https=nconf.get('https'));
|
||||||
}
|
}
|
||||||
|
|
||||||
User.hashPassword = function(password, callback) {
|
User.hashPassword = function(password, callback) {
|
||||||
@@ -370,7 +379,7 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bcrypt.genSalt(config.bcrypt_rounds, function(err, salt) {
|
bcrypt.genSalt(nconf.get('bcrypt_rounds'), function(err, salt) {
|
||||||
bcrypt.hash(password, salt, function(err, hash) {
|
bcrypt.hash(password, salt, function(err, hash) {
|
||||||
callback(hash);
|
callback(hash);
|
||||||
});
|
});
|
||||||
@@ -406,7 +415,7 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
User.incrementUserFieldBy(uid, 'postcount', 1, function(err, newpostcount) {
|
User.incrementUserFieldBy(uid, 'postcount', 1, function(err, newpostcount) {
|
||||||
RDB.zadd('users:postcount', newpostcount, uid);
|
RDB.zadd('users:postcount', newpostcount, uid);
|
||||||
});
|
});
|
||||||
|
|
||||||
User.setUserField(uid, 'lastposttime', timestamp);
|
User.setUserField(uid, 'lastposttime', timestamp);
|
||||||
|
|
||||||
User.sendPostNotificationToFollowers(uid, tid, pid);
|
User.sendPostNotificationToFollowers(uid, tid, pid);
|
||||||
@@ -435,9 +444,9 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
}
|
}
|
||||||
|
|
||||||
User.sendConfirmationEmail = function (email) {
|
User.sendConfirmationEmail = function (email) {
|
||||||
if (global.config['email:host'] && global.config['email:port'] && global.config['email:from']) {
|
if (meta.config['email:host'] && meta.config['email:port'] && meta.config['email:from']) {
|
||||||
var confirm_code = utils.generateUUID(),
|
var confirm_code = utils.generateUUID(),
|
||||||
confirm_link = config.url + 'confirm/' + confirm_code,
|
confirm_link = nconf.get('url') + 'confirm/' + confirm_code,
|
||||||
confirm_email = global.templates['emails/header'] + global.templates['emails/email_confirm'].parse({'CONFIRM_LINK': confirm_link}) + global.templates['emails/footer'],
|
confirm_email = global.templates['emails/header'] + global.templates['emails/email_confirm'].parse({'CONFIRM_LINK': confirm_link}) + global.templates['emails/footer'],
|
||||||
confirm_email_plaintext = global.templates['emails/email_confirm_plaintext'].parse({ 'CONFIRM_LINK': confirm_link });
|
confirm_email_plaintext = global.templates['emails/email_confirm_plaintext'].parse({ 'CONFIRM_LINK': confirm_link });
|
||||||
|
|
||||||
@@ -451,10 +460,10 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
RDB.set(confirm_key, email);
|
RDB.set(confirm_key, email);
|
||||||
RDB.expire(confirm_key, expiry_time);
|
RDB.expire(confirm_key, expiry_time);
|
||||||
|
|
||||||
// Send intro email w/ confirm code
|
// Send intro email w/ confirm code
|
||||||
var message = emailjs.message.create({
|
var message = emailjs.message.create({
|
||||||
text: confirm_email_plaintext,
|
text: confirm_email_plaintext,
|
||||||
from: config.mailer.from,
|
from: meta.config.mailer.from,
|
||||||
to: email,
|
to: email,
|
||||||
subject: '[NodeBB] Registration Email Verification',
|
subject: '[NodeBB] Registration Email Verification',
|
||||||
attachment: [
|
attachment: [
|
||||||
@@ -562,19 +571,19 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
callback(null);
|
callback(null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async.eachSeries(uids, iterator, function(err) {
|
async.eachSeries(uids, iterator, function(err) {
|
||||||
callback(returnData);
|
callback(returnData);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
User.sendPostNotificationToFollowers = function(uid, tid, pid) {
|
User.sendPostNotificationToFollowers = function(uid, tid, pid) {
|
||||||
User.getUserField(uid, 'username', function(username) {
|
User.getUserField(uid, 'username', function(err, username) {
|
||||||
RDB.smembers('followers:' + uid, function(err, followers) {
|
RDB.smembers('followers:' + uid, function(err, followers) {
|
||||||
topics.getTopicField(tid, 'slug', function(err, slug) {
|
topics.getTopicField(tid, 'slug', function(err, slug) {
|
||||||
var message = username + ' made a new post';
|
var message = username + ' made a new post';
|
||||||
|
|
||||||
notifications.create(message, 5, global.nconf.get('url') + 'topic/' + slug + '#' + pid, 'notification_'+ Date.now(), function(nid) {
|
notifications.create(message, 5, nconf.get('url') + 'topic/' + slug + '#' + pid, 'notification_'+ Date.now(), function(nid) {
|
||||||
notifications.push(nid, followers);
|
notifications.push(nid, followers);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -610,8 +619,9 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
RDB.zrevrange('users:joindate', 0, 0, function(err, uid) {
|
RDB.zrevrange('users:joindate', 0, 0, function(err, uid) {
|
||||||
RDB.handle(err);
|
RDB.handle(err);
|
||||||
|
|
||||||
User.getUserFields(uid, ['username', 'userslug'], function(userData) {
|
User.getUserFields(uid, ['username', 'userslug'], function(err, userData) {
|
||||||
socket.emit('user.latest', {userslug: userData.userslug, username: userData.username});
|
if(!err && userData)
|
||||||
|
socket.emit('user.latest', {userslug: userData.userslug, username: userData.username});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -642,14 +652,14 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
}
|
}
|
||||||
|
|
||||||
function iterator(uid, callback) {
|
function iterator(uid, callback) {
|
||||||
User.getUserField(uid, 'username', function(username) {
|
User.getUserField(uid, 'username', function(err, username) {
|
||||||
usernames.push(username);
|
usernames.push(username);
|
||||||
callback(null);
|
callback(null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async.eachSeries(uids, iterator, function(err) {
|
async.eachSeries(uids, iterator, function(err) {
|
||||||
callback(usernames);
|
callback(usernames);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,14 +671,14 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
}
|
}
|
||||||
|
|
||||||
function iterator(uid, callback) {
|
function iterator(uid, callback) {
|
||||||
User.getUserField(uid, 'userslug', function(userslug) {
|
User.getUserField(uid, 'userslug', function(err, userslug) {
|
||||||
userslugs.push(userslug);
|
userslugs.push(userslug);
|
||||||
callback(null);
|
callback(null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async.eachSeries(uids, iterator, function(err) {
|
async.eachSeries(uids, iterator, function(err) {
|
||||||
callback(userslugs);
|
callback(userslugs);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -777,6 +787,7 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
|
|
||||||
User.reset = {
|
User.reset = {
|
||||||
validate: function(socket, code, callback) {
|
validate: function(socket, code, callback) {
|
||||||
|
|
||||||
if (typeof callback !== 'function') {
|
if (typeof callback !== 'function') {
|
||||||
callback = null;
|
callback = null;
|
||||||
}
|
}
|
||||||
@@ -826,13 +837,13 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
RDB.set('reset:' + reset_code + ':uid', uid);
|
RDB.set('reset:' + reset_code + ':uid', uid);
|
||||||
RDB.set('reset:' + reset_code + ':expiry', (60*60)+new Date()/1000|0); // Active for one hour
|
RDB.set('reset:' + reset_code + ':expiry', (60*60)+new Date()/1000|0); // Active for one hour
|
||||||
|
|
||||||
var reset_link = config.url + 'reset/' + reset_code,
|
var reset_link = nconf.get('url') + 'reset/' + reset_code,
|
||||||
reset_email = global.templates['emails/reset'].parse({'RESET_LINK': reset_link}),
|
reset_email = global.templates['emails/reset'].parse({'RESET_LINK': reset_link}),
|
||||||
reset_email_plaintext = global.templates['emails/reset_plaintext'].parse({ 'RESET_LINK': reset_link });
|
reset_email_plaintext = global.templates['emails/reset_plaintext'].parse({ 'RESET_LINK': reset_link });
|
||||||
|
|
||||||
var message = emailjs.message.create({
|
var message = emailjs.message.create({
|
||||||
text: reset_email_plaintext,
|
text: reset_email_plaintext,
|
||||||
from: config.mailer.from,
|
from: meta.config.mailer?meta.config.mailer.from:'localhost@example.org',
|
||||||
to: email,
|
to: email,
|
||||||
subject: 'Password Reset Requested',
|
subject: 'Password Reset Requested',
|
||||||
attachment: [
|
attachment: [
|
||||||
@@ -869,14 +880,17 @@ var utils = require('./../public/src/utils.js'),
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
commit: function(socket, code, password) {
|
commit: function(socket, code, password) {
|
||||||
this.validate(code, function(validated) {
|
this.validate(socket, code, function(validated) {
|
||||||
if (validated) {
|
if (validated) {
|
||||||
RDB.get('reset:' + code + ':uid', function(err, uid) {
|
RDB.get('reset:' + code + ':uid', function(err, uid) {
|
||||||
if (err) {
|
if (err) {
|
||||||
RDB.handle(err);
|
RDB.handle(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
User.setUserField(uid, 'password', password);
|
User.hashPassword(password, function(hash) {
|
||||||
|
User.setUserField(uid, 'password', hash);
|
||||||
|
});
|
||||||
|
|
||||||
RDB.del('reset:' + code + ':uid');
|
RDB.del('reset:' + code + ':uid');
|
||||||
RDB.del('reset:' + code + ':expiry');
|
RDB.del('reset:' + code + ':expiry');
|
||||||
|
|
||||||
|
|||||||
107
src/webserver.js
107
src/webserver.js
@@ -5,12 +5,12 @@ var express = require('express'),
|
|||||||
RedisStore = require('connect-redis')(express),
|
RedisStore = require('connect-redis')(express),
|
||||||
path = require('path'),
|
path = require('path'),
|
||||||
redis = require('redis'),
|
redis = require('redis'),
|
||||||
redisServer = redis.createClient(global.nconf.get('redis:port'), global.nconf.get('redis:host')),
|
redisServer = redis.createClient(nconf.get('redis:port'), nconf.get('redis:host')),
|
||||||
marked = require('marked'),
|
marked = require('marked'),
|
||||||
utils = require('../public/src/utils.js'),
|
utils = require('../public/src/utils.js'),
|
||||||
pkg = require('../package.json'),
|
pkg = require('../package.json'),
|
||||||
fs = require('fs'),
|
fs = require('fs'),
|
||||||
|
|
||||||
user = require('./user.js'),
|
user = require('./user.js'),
|
||||||
categories = require('./categories.js'),
|
categories = require('./categories.js'),
|
||||||
posts = require('./posts.js'),
|
posts = require('./posts.js'),
|
||||||
@@ -26,7 +26,7 @@ var express = require('express'),
|
|||||||
|
|
||||||
(function(app) {
|
(function(app) {
|
||||||
var templates = null;
|
var templates = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `options` object requires: req, res
|
* `options` object requires: req, res
|
||||||
* accepts: metaTags
|
* accepts: metaTags
|
||||||
@@ -36,15 +36,15 @@ var express = require('express'),
|
|||||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1.0' },
|
{ name: 'viewport', content: 'width=device-width, initial-scale=1.0' },
|
||||||
{ name: 'content-type', content: 'text/html; charset=UTF-8' },
|
{ name: 'content-type', content: 'text/html; charset=UTF-8' },
|
||||||
{ name: 'apple-mobile-web-app-capable', content: 'yes' },
|
{ name: 'apple-mobile-web-app-capable', content: 'yes' },
|
||||||
{ property: 'og:site_name', content: global.config.title || 'NodeBB' },
|
{ property: 'og:site_name', content: meta.config.title || 'NodeBB' },
|
||||||
],
|
],
|
||||||
metaString = utils.buildMetaTags(defaultMetaTags.concat(options.metaTags || [])),
|
metaString = utils.buildMetaTags(defaultMetaTags.concat(options.metaTags || [])),
|
||||||
templateValues = {
|
templateValues = {
|
||||||
cssSrc: global.config['theme:src'] || global.nconf.get('relative_path') + '/vendor/bootstrap/css/bootstrap.min.css',
|
cssSrc: meta.config['theme:src'] || nconf.get('relative_path') + '/vendor/bootstrap/css/bootstrap.min.css',
|
||||||
title: global.config['title'] || 'NodeBB',
|
title: meta.config['title'] || 'NodeBB',
|
||||||
browserTitle: global.config['title'] || 'NodeBB',
|
browserTitle: meta.config['title'] || 'NodeBB',
|
||||||
csrf: options.res.locals.csrf_token,
|
csrf: options.res.locals.csrf_token,
|
||||||
relative_path: global.nconf.get('relative_path'),
|
relative_path: nconf.get('relative_path'),
|
||||||
meta_tags: metaString
|
meta_tags: metaString
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ var express = require('express'),
|
|||||||
// Middlewares
|
// Middlewares
|
||||||
app.use(express.favicon(path.join(__dirname, '../', 'public', 'favicon.ico')));
|
app.use(express.favicon(path.join(__dirname, '../', 'public', 'favicon.ico')));
|
||||||
app.use(require('less-middleware')({ src: path.join(__dirname, '../', 'public') }));
|
app.use(require('less-middleware')({ src: path.join(__dirname, '../', 'public') }));
|
||||||
app.use(global.nconf.get('relative_path'), express.static(path.join(__dirname, '../', 'public')));
|
app.use(nconf.get('relative_path'), express.static(path.join(__dirname, '../', 'public')));
|
||||||
app.use(express.bodyParser()); // Puts POST vars in request.body
|
app.use(express.bodyParser()); // Puts POST vars in request.body
|
||||||
app.use(express.cookieParser()); // If you want to parse cookies (res.cookies)
|
app.use(express.cookieParser()); // If you want to parse cookies (res.cookies)
|
||||||
app.use(express.compress());
|
app.use(express.compress());
|
||||||
@@ -69,8 +69,11 @@ var express = require('express'),
|
|||||||
client: redisServer,
|
client: redisServer,
|
||||||
ttl: 60*60*24*14
|
ttl: 60*60*24*14
|
||||||
}),
|
}),
|
||||||
secret: global.nconf.get('secret'),
|
secret: nconf.get('secret'),
|
||||||
key: 'express.sid'
|
key: 'express.sid',
|
||||||
|
cookie: {
|
||||||
|
maxAge: 60*60*24*30 // 30 days
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
app.use(express.csrf());
|
app.use(express.csrf());
|
||||||
app.use(function(req, res, next) {
|
app.use(function(req, res, next) {
|
||||||
@@ -83,11 +86,11 @@ var express = require('express'),
|
|||||||
}
|
}
|
||||||
|
|
||||||
auth.initialize(app);
|
auth.initialize(app);
|
||||||
|
|
||||||
app.use(function(req, res, next) {
|
app.use(function(req, res, next) {
|
||||||
|
|
||||||
global.nconf.set('https', req.secure);
|
nconf.set('https', req.secure);
|
||||||
|
|
||||||
// Don't bother with session handling for API requests
|
// Don't bother with session handling for API requests
|
||||||
if (/^\/api\//.test(req.url)) return next();
|
if (/^\/api\//.test(req.url)) return next();
|
||||||
|
|
||||||
@@ -100,7 +103,7 @@ var express = require('express'),
|
|||||||
|
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use(app.router);
|
app.use(app.router);
|
||||||
|
|
||||||
app.use(function(req, res, next) {
|
app.use(function(req, res, next) {
|
||||||
@@ -108,41 +111,40 @@ var express = require('express'),
|
|||||||
|
|
||||||
// respond with html page
|
// respond with html page
|
||||||
if (req.accepts('html')) {
|
if (req.accepts('html')) {
|
||||||
|
|
||||||
//res.json('404', { url: req.url });
|
//res.json('404', { url: req.url });
|
||||||
res.redirect(global.nconf.get('relative_path') + '/404');
|
res.redirect(nconf.get('relative_path') + '/404');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// respond with json
|
// respond with json
|
||||||
if (req.accepts('json')) {
|
if (req.accepts('json')) {
|
||||||
console.log('sending 404 json');
|
|
||||||
res.send({ error: 'Not found' });
|
res.send({ error: 'Not found' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// default to plain-text. send()
|
// default to plain-text. send()
|
||||||
res.type('txt').send('Not found');
|
res.type('txt').send('Not found');
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use(function(err, req, res, next) {
|
app.use(function(err, req, res, next) {
|
||||||
|
|
||||||
// we may use properties of the error object
|
// we may use properties of the error object
|
||||||
// here and next(err) appropriately, or if
|
// here and next(err) appropriately, or if
|
||||||
// we possibly recovered from the error, simply next().
|
// we possibly recovered from the error, simply next().
|
||||||
console.error(err.stack);
|
console.error(err.stack);
|
||||||
|
|
||||||
res.status(err.status || 500);
|
res.status(err.status || 500);
|
||||||
|
|
||||||
res.json('500', { error: err.message });
|
res.json('500', { error: err.message });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
app.create_route = function(url, tpl) { // to remove
|
app.create_route = function(url, tpl) { // to remove
|
||||||
return '<script>templates.ready(function(){ajaxify.go("' + url + '", null, "' + tpl + '");});</script>';
|
return '<script>templates.ready(function(){ajaxify.go("' + url + '", null, "' + tpl + '");});</script>';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
app.namespace(global.nconf.get('relative_path'), function() {
|
|
||||||
|
app.namespace(nconf.get('relative_path'), function() {
|
||||||
|
|
||||||
auth.create_routes(app);
|
auth.create_routes(app);
|
||||||
admin.create_routes(app);
|
admin.create_routes(app);
|
||||||
@@ -150,20 +152,20 @@ var express = require('express'),
|
|||||||
installRoute.create_routes(app);
|
installRoute.create_routes(app);
|
||||||
testBed.create_routes(app);
|
testBed.create_routes(app);
|
||||||
apiRoute.create_routes(app);
|
apiRoute.create_routes(app);
|
||||||
|
|
||||||
|
|
||||||
// Basic Routes (entirely client-side parsed, goal is to move the rest of the crap in this file into this one section)
|
// Basic Routes (entirely client-side parsed, goal is to move the rest of the crap in this file into this one section)
|
||||||
(function() {
|
(function() {
|
||||||
var routes = ['login', 'register', 'account', 'recent', 'unread', 'popular', 'active', '403', '404'];
|
var routes = ['login', 'register', 'account', 'recent', 'unread', 'popular', 'active', '403', '404'];
|
||||||
|
|
||||||
for (var i=0, ii=routes.length; i<ii; i++) {
|
for (var i=0, ii=routes.length; i<ii; i++) {
|
||||||
(function(route) {
|
(function(route) {
|
||||||
|
|
||||||
app.get('/' + route, function(req, res) {
|
app.get('/' + route, function(req, res) {
|
||||||
if ((route === 'login' || route ==='register') && (req.user && req.user.uid > 0)) {
|
if ((route === 'login' || route ==='register') && (req.user && req.user.uid > 0)) {
|
||||||
|
|
||||||
user.getUserField(req.user.uid, 'userslug', function(userslug) {
|
user.getUserField(req.user.uid, 'userslug', function(err, userslug) {
|
||||||
res.redirect('/users/'+userslug);
|
res.redirect('/users/'+userslug);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -175,7 +177,7 @@ var express = require('express'),
|
|||||||
}(routes[i]));
|
}(routes[i]));
|
||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
|
||||||
app.get('/', function(req, res) {
|
app.get('/', function(req, res) {
|
||||||
async.parallel({
|
async.parallel({
|
||||||
@@ -184,9 +186,9 @@ var express = require('express'),
|
|||||||
req: req,
|
req: req,
|
||||||
res: res,
|
res: res,
|
||||||
metaTags: [
|
metaTags: [
|
||||||
{ name: "title", content: global.config.title || 'NodeBB' },
|
{ name: "title", content: meta.config.title || 'NodeBB' },
|
||||||
{ name: "description", content: global.config.description || '' },
|
{ name: "description", content: meta.config.description || '' },
|
||||||
{ property: 'og:title', content: 'Index | ' + (global.config.title || 'NodeBB') },
|
{ property: 'og:title', content: 'Index | ' + (meta.config.title || 'NodeBB') },
|
||||||
{ property: "og:type", content: 'website' }
|
{ property: "og:type", content: 'website' }
|
||||||
]
|
]
|
||||||
}, next);
|
}, next);
|
||||||
@@ -205,9 +207,10 @@ var express = require('express'),
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
app.get('/topic/:topic_id/:slug?', function(req, res) {
|
app.get('/topic/:topic_id/:slug?', function(req, res) {
|
||||||
|
|
||||||
var tid = req.params.topic_id;
|
var tid = req.params.topic_id;
|
||||||
if (tid.match(/^\d+\.rss$/)) {
|
if (tid.match(/^\d+\.rss$/)) {
|
||||||
fs.readFile('feeds/topics/' + tid, function (err, data) {
|
fs.readFile('feeds/topics/' + tid, function (err, data) {
|
||||||
@@ -215,7 +218,7 @@ var express = require('express'),
|
|||||||
res.type('text').send(404, "Unable to locate an rss feed at this location.");
|
res.type('text').send(404, "Unable to locate an rss feed at this location.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.type('xml').set('Content-Length', data.length).send(data);
|
res.type('xml').set('Content-Length', data.length).send(data);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -224,13 +227,19 @@ var express = require('express'),
|
|||||||
async.waterfall([
|
async.waterfall([
|
||||||
function(next) {
|
function(next) {
|
||||||
topics.getTopicWithPosts(tid, ((req.user) ? req.user.uid : 0), function(err, topicData) {
|
topics.getTopicWithPosts(tid, ((req.user) ? req.user.uid : 0), function(err, topicData) {
|
||||||
|
if(topicData) {
|
||||||
|
if(topicData.deleted === '1' && topicData.expose_tools === 0)
|
||||||
|
return next(new Error('Topic deleted'), null);
|
||||||
|
}
|
||||||
|
|
||||||
next(err, topicData);
|
next(err, topicData);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function(topicData, next) {
|
function(topicData, next) {
|
||||||
var posts = topicData.posts.push(topicData.main_posts[0]),
|
var posts = topicData.posts.push(topicData.main_posts[0]),
|
||||||
lastMod = 0,
|
lastMod = 0,
|
||||||
timestamp;
|
timestamp;
|
||||||
|
|
||||||
for(var x=0,numPosts=topicData.posts.length;x<numPosts;x++) {
|
for(var x=0,numPosts=topicData.posts.length;x<numPosts;x++) {
|
||||||
timestamp = parseInt(topicData.posts[x].timestamp, 10);
|
timestamp = parseInt(topicData.posts[x].timestamp, 10);
|
||||||
if (timestamp > lastMod) lastMod = timestamp;
|
if (timestamp > lastMod) lastMod = timestamp;
|
||||||
@@ -241,9 +250,9 @@ var express = require('express'),
|
|||||||
res: res,
|
res: res,
|
||||||
metaTags: [
|
metaTags: [
|
||||||
{ name: "title", content: topicData.topic_name },
|
{ name: "title", content: topicData.topic_name },
|
||||||
{ property: 'og:title', content: topicData.topic_name + ' | ' + (global.config.title || 'NodeBB') },
|
{ property: 'og:title', content: topicData.topic_name + ' | ' + (meta.config.title || 'NodeBB') },
|
||||||
{ property: "og:type", content: 'article' },
|
{ property: "og:type", content: 'article' },
|
||||||
{ property: "og:url", content: global.nconf.get('url') + 'topic/' + topicData.slug },
|
{ property: "og:url", content: nconf.get('url') + 'topic/' + topicData.slug },
|
||||||
{ property: 'og:image', content: topicData.main_posts[0].picture },
|
{ property: 'og:image', content: topicData.main_posts[0].picture },
|
||||||
{ property: "article:published_time", content: new Date(parseInt(topicData.main_posts[0].timestamp, 10)).toISOString() },
|
{ property: "article:published_time", content: new Date(parseInt(topicData.main_posts[0].timestamp, 10)).toISOString() },
|
||||||
{ property: 'article:modified_time', content: new Date(lastMod).toISOString() },
|
{ property: 'article:modified_time', content: new Date(lastMod).toISOString() },
|
||||||
@@ -271,7 +280,7 @@ var express = require('express'),
|
|||||||
|
|
||||||
app.get('/category/:category_id/:slug?', function(req, res) {
|
app.get('/category/:category_id/:slug?', function(req, res) {
|
||||||
var cid = req.params.category_id;
|
var cid = req.params.category_id;
|
||||||
|
|
||||||
if (cid.match(/^\d+\.rss$/)) {
|
if (cid.match(/^\d+\.rss$/)) {
|
||||||
fs.readFile('feeds/categories/' + cid, function (err, data) {
|
fs.readFile('feeds/categories/' + cid, function (err, data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -338,7 +347,7 @@ var express = require('express'),
|
|||||||
res.send( "User-agent: *\n" +
|
res.send( "User-agent: *\n" +
|
||||||
"Disallow: \n" +
|
"Disallow: \n" +
|
||||||
"Disallow: /admin/\n" +
|
"Disallow: /admin/\n" +
|
||||||
"Sitemap: " + global.nconf.get('url') + "sitemap.xml");
|
"Sitemap: " + nconf.get('url') + "sitemap.xml");
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/cid/:cid', function(req, res) {
|
app.get('/cid/:cid', function(req, res) {
|
||||||
@@ -374,24 +383,24 @@ var express = require('express'),
|
|||||||
app.build_header({ req: req, res: res }, function(err, header) {
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
res.send(
|
res.send(
|
||||||
header +
|
header +
|
||||||
'\n\t<script>templates.ready(function(){ajaxify.go("outgoing?url=' + req.query.url + '");});</script>' +
|
'\n\t<script>templates.ready(function(){ajaxify.go("outgoing?url=' + encodeURIComponent(req.query.url) + '", null, null, true);});</script>' +
|
||||||
templates['footer']
|
templates['footer']
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/search', function(req, res) {
|
app.get('/search', function(req, res) {
|
||||||
app.build_header({ req: req, res: res }, function(err, header) {
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
res.send(header + app.create_route("search", null, "search") + templates['footer']);
|
res.send(header + app.create_route("search", null, "search") + templates['footer']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/search/:term', function(req, res) {
|
app.get('/search/:term', function(req, res) {
|
||||||
app.build_header({ req: req, res: res }, function(err, header) {
|
app.build_header({ req: req, res: res }, function(err, header) {
|
||||||
res.send(header + app.create_route("search/"+req.params.term, null, "search") + templates['footer']);
|
res.send(header + app.create_route("search/"+req.params.term, null, "search") + templates['footer']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/reindex', function(req, res) {
|
app.get('/reindex', function(req, res) {
|
||||||
topics.reIndexAll(function(err) {
|
topics.reIndexAll(function(err) {
|
||||||
if(err) {
|
if(err) {
|
||||||
@@ -401,7 +410,7 @@ var express = require('express'),
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}(WebServer));
|
}(WebServer));
|
||||||
|
|||||||
@@ -16,18 +16,19 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
async = require('async'),
|
async = require('async'),
|
||||||
RedisStoreLib = require('connect-redis')(express),
|
RedisStoreLib = require('connect-redis')(express),
|
||||||
redis = require('redis'),
|
redis = require('redis'),
|
||||||
redisServer = redis.createClient(global.nconf.get('redis:port'), global.nconf.get('redis:host')),
|
redisServer = redis.createClient(nconf.get('redis:port'), nconf.get('redis:host')),
|
||||||
RedisStore = new RedisStoreLib({
|
RedisStore = new RedisStoreLib({
|
||||||
client: redisServer,
|
client: redisServer,
|
||||||
ttl: 60*60*24*14
|
ttl: 60*60*24*14
|
||||||
}),
|
}),
|
||||||
socketCookieParser = express.cookieParser(global.nconf.get('secret')),
|
socketCookieParser = express.cookieParser(nconf.get('secret')),
|
||||||
admin = {
|
admin = {
|
||||||
'categories': require('./admin/categories.js'),
|
'categories': require('./admin/categories.js'),
|
||||||
'user': require('./admin/user.js')
|
'user': require('./admin/user.js')
|
||||||
},
|
},
|
||||||
plugins = require('./plugins');
|
plugins = require('./plugins'),
|
||||||
|
winston = require('winston');
|
||||||
|
|
||||||
(function(io) {
|
(function(io) {
|
||||||
var users = {},
|
var users = {},
|
||||||
userSockets = {},
|
userSockets = {},
|
||||||
@@ -48,22 +49,22 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
|
|
||||||
userSockets[uid] = userSockets[uid] || [];
|
userSockets[uid] = userSockets[uid] || [];
|
||||||
userSockets[uid].push(socket);
|
userSockets[uid].push(socket);
|
||||||
|
|
||||||
if(uid) {
|
if(uid) {
|
||||||
socket.join('uid_' + uid);
|
socket.join('uid_' + uid);
|
||||||
io.sockets.in('global').emit('api:user.isOnline', isUserOnline(uid));
|
io.sockets.in('global').emit('api:user.isOnline', isUserOnline(uid));
|
||||||
|
|
||||||
user.getUserField(uid, 'username', function(username) {
|
user.getUserField(uid, 'username', function(err, username) {
|
||||||
socket.emit('event:connect', {status: 1, username:username});
|
socket.emit('event:connect', {status: 1, username:username});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
socket.on('disconnect', function() {
|
socket.on('disconnect', function() {
|
||||||
|
|
||||||
var index = userSockets[uid].indexOf(socket);
|
var index = userSockets[uid].indexOf(socket);
|
||||||
if(index !== -1) {
|
if(index !== -1) {
|
||||||
userSockets[uid].splice(index, 1);
|
userSockets[uid].splice(index, 1);
|
||||||
@@ -73,17 +74,17 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
delete users[sessionID];
|
delete users[sessionID];
|
||||||
if(uid)
|
if(uid)
|
||||||
io.sockets.in('global').emit('api:user.isOnline', isUserOnline(uid));
|
io.sockets.in('global').emit('api:user.isOnline', isUserOnline(uid));
|
||||||
}
|
}
|
||||||
|
|
||||||
for(var roomName in rooms) {
|
for(var roomName in rooms) {
|
||||||
|
|
||||||
socket.leave(roomName);
|
socket.leave(roomName);
|
||||||
|
|
||||||
if(rooms[roomName][socket.id]) {
|
if(rooms[roomName][socket.id]) {
|
||||||
delete rooms[roomName][socket.id];
|
delete rooms[roomName][socket.id];
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRoomBrowsingText(roomName);
|
updateRoomBrowsingText(roomName);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -105,7 +106,7 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
function getAnonymousCount(roomName) {
|
function getAnonymousCount(roomName) {
|
||||||
var clients = io.sockets.clients(roomName);
|
var clients = io.sockets.clients(roomName);
|
||||||
var anonCount = 0;
|
var anonCount = 0;
|
||||||
|
|
||||||
for(var i=0; i<clients.length; ++i) {
|
for(var i=0; i<clients.length; ++i) {
|
||||||
var hs = clients[i].handshake;
|
var hs = clients[i].handshake;
|
||||||
|
|
||||||
@@ -113,11 +114,11 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
++anonCount;
|
++anonCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return anonCount;
|
return anonCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
var uids = getUidsInRoom(rooms[roomName]);
|
var uids = getUidsInRoom(rooms[roomName]);
|
||||||
|
|
||||||
var anonymousCount = getAnonymousCount(roomName);
|
var anonymousCount = getAnonymousCount(roomName);
|
||||||
|
|
||||||
function userList(users, anonymousCount, userCount) {
|
function userList(users, anonymousCount, userCount) {
|
||||||
@@ -126,8 +127,8 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
for (var i = 0, ii=users.length; i<ii; ++i) {
|
for (var i = 0, ii=users.length; i<ii; ++i) {
|
||||||
usernames[i] = '<strong>' + '<a href="/users/'+users[i].userslug+'">' + users[i].username + '</a></strong>';
|
usernames[i] = '<strong>' + '<a href="/users/'+users[i].userslug+'">' + users[i].username + '</a></strong>';
|
||||||
}
|
}
|
||||||
|
|
||||||
var joiner = anonymousCount + userCount == 1 ? 'is' : 'are',
|
var joiner = anonymousCount + userCount == 1 ? 'is' : 'are',
|
||||||
userList = anonymousCount > 0 ? usernames.concat(util.format('%d guest%s', anonymousCount, anonymousCount > 1 ? 's' : '')) : usernames,
|
userList = anonymousCount > 0 ? usernames.concat(util.format('%d guest%s', anonymousCount, anonymousCount > 1 ? 's' : '')) : usernames,
|
||||||
lastUser = userList.length > 1 ? ' and ' + userList.pop() : '';
|
lastUser = userList.length > 1 ? ' and ' + userList.pop() : '';
|
||||||
|
|
||||||
@@ -145,18 +146,18 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
}
|
}
|
||||||
|
|
||||||
socket.on('event:enter_room', function(data) {
|
socket.on('event:enter_room', function(data) {
|
||||||
|
|
||||||
if (data.leave !== null) {
|
if (data.leave !== null) {
|
||||||
socket.leave(data.leave);
|
socket.leave(data.leave);
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.join(data.enter);
|
socket.join(data.enter);
|
||||||
|
|
||||||
rooms[data.enter] = rooms[data.enter] || {};
|
rooms[data.enter] = rooms[data.enter] || {};
|
||||||
|
|
||||||
if (uid) {
|
if (uid) {
|
||||||
rooms[data.enter][socket.id] = uid;
|
rooms[data.enter][socket.id] = uid;
|
||||||
|
|
||||||
if (data.leave && rooms[data.leave] && rooms[data.leave][socket.id]) {
|
if (data.leave && rooms[data.leave] && rooms[data.leave][socket.id]) {
|
||||||
delete rooms[data.leave][socket.id];
|
delete rooms[data.leave][socket.id];
|
||||||
}
|
}
|
||||||
@@ -167,18 +168,20 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
|
|
||||||
updateRoomBrowsingText(data.enter);
|
updateRoomBrowsingText(data.enter);
|
||||||
|
|
||||||
if (data.enter != 'admin')
|
if (data.enter != 'admin')
|
||||||
io.sockets.in('admin').emit('api:get_all_rooms', io.sockets.manager.rooms);
|
io.sockets.in('admin').emit('api:get_all_rooms', io.sockets.manager.rooms);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// BEGIN: API calls (todo: organize)
|
// BEGIN: API calls (todo: organize)
|
||||||
|
|
||||||
socket.on('api:updateHeader', function(data) {
|
socket.on('api:updateHeader', function(data) {
|
||||||
if(uid) {
|
if(uid) {
|
||||||
user.getUserFields(uid, data.fields, function(fields) {
|
user.getUserFields(uid, data.fields, function(err, fields) {
|
||||||
fields.uid = uid;
|
if(!err && fields) {
|
||||||
socket.emit('api:updateHeader', fields);
|
fields.uid = uid;
|
||||||
|
socket.emit('api:updateHeader', fields);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -186,12 +189,12 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
uid:0,
|
uid:0,
|
||||||
username: "Anonymous User",
|
username: "Anonymous User",
|
||||||
email: '',
|
email: '',
|
||||||
picture: require('gravatar').url('', {s:'24'}, https=global.nconf.get('https'))
|
picture: require('gravatar').url('', {s:'24'}, https=nconf.get('https'))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('user.exists', function(data) {
|
socket.on('user.exists', function(data) {
|
||||||
user.exists(utils.slugify(data.username), function(exists){
|
user.exists(utils.slugify(data.username), function(exists){
|
||||||
socket.emit('user.exists', {exists: exists});
|
socket.emit('user.exists', {exists: exists});
|
||||||
@@ -232,12 +235,12 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
|
|
||||||
socket.on('api:user.get_online_users', function(data) {
|
socket.on('api:user.get_online_users', function(data) {
|
||||||
var returnData = [];
|
var returnData = [];
|
||||||
|
|
||||||
for(var i=0; i<data.length; ++i) {
|
for(var i=0; i<data.length; ++i) {
|
||||||
var uid = data[i];
|
var uid = data[i];
|
||||||
if(isUserOnline(uid))
|
if(isUserOnline(uid))
|
||||||
returnData.push(uid);
|
returnData.push(uid);
|
||||||
else
|
else
|
||||||
returnData.push(0);
|
returnData.push(0);
|
||||||
}
|
}
|
||||||
socket.emit('api:user.get_online_users', returnData);
|
socket.emit('api:user.get_online_users', returnData);
|
||||||
@@ -250,30 +253,34 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
socket.on('api:user.changePassword', function(data, callback) {
|
socket.on('api:user.changePassword', function(data, callback) {
|
||||||
user.changePassword(uid, data, callback);
|
user.changePassword(uid, data, callback);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:user.updateProfile', function(data, callback) {
|
socket.on('api:user.updateProfile', function(data, callback) {
|
||||||
user.updateProfile(uid, data, callback);
|
user.updateProfile(uid, data, callback);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:user.changePicture', function(data, callback) {
|
socket.on('api:user.changePicture', function(data, callback) {
|
||||||
|
|
||||||
var type = data.type;
|
var type = data.type;
|
||||||
|
|
||||||
function updateHeader() {
|
function updateHeader() {
|
||||||
user.getUserFields(uid, ['picture'], function(fields) {
|
user.getUserFields(uid, ['picture'], function(err, fields) {
|
||||||
fields.uid = uid;
|
if(!err && fields) {
|
||||||
socket.emit('api:updateHeader', fields);
|
fields.uid = uid;
|
||||||
callback(true);
|
socket.emit('api:updateHeader', fields);
|
||||||
|
callback(true);
|
||||||
|
} else {
|
||||||
|
callback(false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(type === 'gravatar') {
|
if(type === 'gravatar') {
|
||||||
user.getUserField(uid, 'gravatarpicture', function(gravatar) {
|
user.getUserField(uid, 'gravatarpicture', function(err, gravatar) {
|
||||||
user.setUserField(uid, 'picture', gravatar);
|
user.setUserField(uid, 'picture', gravatar);
|
||||||
updateHeader();
|
updateHeader();
|
||||||
});
|
});
|
||||||
} else if(type === 'uploaded') {
|
} else if(type === 'uploaded') {
|
||||||
user.getUserField(uid, 'uploadedpicture', function(uploadedpicture) {
|
user.getUserField(uid, 'uploadedpicture', function(err, uploadedpicture) {
|
||||||
user.setUserField(uid, 'picture', uploadedpicture);
|
user.setUserField(uid, 'picture', uploadedpicture);
|
||||||
updateHeader();
|
updateHeader();
|
||||||
});
|
});
|
||||||
@@ -283,7 +290,7 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:user.follow', function(data, callback) {
|
socket.on('api:user.follow', function(data, callback) {
|
||||||
if(uid) {
|
if(uid) {
|
||||||
user.follow(uid, data.uid, callback);
|
user.follow(uid, data.uid, callback);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -326,21 +333,21 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result) {
|
if(result) {
|
||||||
posts.getTopicPostStats(socket);
|
posts.getTopicPostStats(socket);
|
||||||
|
|
||||||
socket.emit('event:alert', {
|
socket.emit('event:alert', {
|
||||||
title: 'Thank you for posting',
|
title: 'Thank you for posting',
|
||||||
message: 'You have successfully posted. Click here to view your post.',
|
message: 'You have successfully posted. Click here to view your post.',
|
||||||
type: 'notify',
|
type: 'notify',
|
||||||
timeout: 2000
|
timeout: 2000
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:topics.markAllRead', function(data, callback) {
|
socket.on('api:topics.markAllRead', function(data, callback) {
|
||||||
topics.markAllRead(uid, function(err, success) {
|
topics.markAllRead(uid, function(err, success) {
|
||||||
if(!err && success) {
|
if(!err && success) {
|
||||||
@@ -361,7 +368,7 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
posts.reply(data.topic_id, uid, data.content, data.images, function(err, result) {
|
posts.reply(data.topic_id, uid, data.content, data.images, function(err, result) {
|
||||||
if(err) {
|
if(err) {
|
||||||
if(err.message === 'content-too-short') {
|
if(err.message === 'content-too-short') {
|
||||||
@@ -378,20 +385,20 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result) {
|
if(result) {
|
||||||
|
|
||||||
posts.getTopicPostStats(socket);
|
posts.getTopicPostStats(socket);
|
||||||
|
|
||||||
socket.emit('event:alert', {
|
socket.emit('event:alert', {
|
||||||
title: 'Reply Successful',
|
title: 'Reply Successful',
|
||||||
message: 'You have successfully replied. Click here to view your reply.',
|
message: 'You have successfully replied. Click here to view your reply.',
|
||||||
type: 'notify',
|
type: 'notify',
|
||||||
timeout: 2000
|
timeout: 2000
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -477,9 +484,9 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
postTools.restore(uid, data.pid);
|
postTools.restore(uid, data.pid);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:notifications.get', function(data) {
|
socket.on('api:notifications.get', function(data, callback) {
|
||||||
user.notifications.get(uid, function(notifs) {
|
user.notifications.get(uid, function(notifs) {
|
||||||
socket.emit('api:notifications.get', notifs);
|
callback(notifs);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -499,44 +506,61 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on('getChatMessages', function(data, callback) {
|
||||||
|
var touid = data.touid;
|
||||||
|
require('./messaging').getMessages(uid, touid, function(err, messages) {
|
||||||
|
if(err)
|
||||||
|
return callback(null);
|
||||||
|
|
||||||
|
callback(messages);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
socket.on('sendChatMessage', function(data) {
|
socket.on('sendChatMessage', function(data) {
|
||||||
|
|
||||||
var touid = data.touid;
|
var touid = data.touid;
|
||||||
|
if(touid === uid || uid === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(userSockets[touid]) {
|
if(userSockets[touid]) {
|
||||||
var msg = utils.strip_tags(data.message),
|
var msg = utils.strip_tags(data.message),
|
||||||
numSockets = userSockets[touid].length;
|
numSockets = userSockets[touid].length;
|
||||||
|
|
||||||
user.getUserField(uid, 'username', function(username) {
|
user.getUserField(uid, 'username', function(err, username) {
|
||||||
var finalMessage = username + ' says : ' + msg;
|
var finalMessage = username + ' says : ' + msg;
|
||||||
|
|
||||||
for(var x=0;x<numSockets;x++) {
|
for(var x=0;x<numSockets;x++) {
|
||||||
userSockets[touid][x].emit('chatMessage', {fromuid:uid, username:username, message:finalMessage});
|
userSockets[touid][x].emit('chatMessage', {fromuid:uid, username:username, message:finalMessage});
|
||||||
}
|
}
|
||||||
|
|
||||||
notifications.create(finalMessage, 5, '#', 'notification_'+uid+'_'+touid, function(nid) {
|
notifications.create(finalMessage, 5, '#', 'notification_' + uid + '_' + touid, function(nid) {
|
||||||
notifications.push(nid, [touid], function(success) {
|
notifications.push(nid, [touid], function(success) {
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
require('./messaging').addMessage(uid, touid, msg, function(err, message) {
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:config.get', function(data) {
|
socket.on('api:config.get', function(data) {
|
||||||
meta.config.get(function(config) {
|
meta.configs.get(function(config) {
|
||||||
socket.emit('api:config.get', config);
|
socket.emit('api:config.get', config);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:config.set', function(data) {
|
socket.on('api:config.set', function(data) {
|
||||||
meta.config.set(data.key, data.value, function(err) {
|
meta.configs.set(data.key, data.value, function(err) {
|
||||||
if (!err) socket.emit('api:config.set', { status: 'ok' });
|
if (!err) socket.emit('api:config.set', { status: 'ok' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:config.remove', function(key) {
|
socket.on('api:config.remove', function(key) {
|
||||||
meta.config.remove(key);
|
meta.configs.remove(key);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:composer.push', function(data) {
|
socket.on('api:composer.push', function(data) {
|
||||||
@@ -544,7 +568,7 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
if (parseInt(data.tid) > 0) {
|
if (parseInt(data.tid) > 0) {
|
||||||
topics.getTopicData(data.tid, function(topicData) {
|
topics.getTopicData(data.tid, function(topicData) {
|
||||||
|
|
||||||
if (data.body)
|
if (data.body)
|
||||||
topicData.body = data.body;
|
topicData.body = data.body;
|
||||||
|
|
||||||
socket.emit('api:composer.push', {
|
socket.emit('api:composer.push', {
|
||||||
@@ -554,14 +578,16 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else if (parseInt(data.cid) > 0) {
|
} else if (parseInt(data.cid) > 0) {
|
||||||
user.getUserFields(uid, ['username', 'picture'], function(userData) {
|
user.getUserFields(uid, ['username', 'picture'], function(err, userData) {
|
||||||
socket.emit('api:composer.push', {
|
if(!err && userData) {
|
||||||
tid: 0,
|
socket.emit('api:composer.push', {
|
||||||
cid: data.cid,
|
tid: 0,
|
||||||
username: userData.username,
|
cid: data.cid,
|
||||||
picture: userData.picture,
|
username: userData.username,
|
||||||
title: undefined
|
picture: userData.picture,
|
||||||
});
|
title: undefined
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else if (parseInt(data.pid) > 0) {
|
} else if (parseInt(data.pid) > 0) {
|
||||||
async.parallel([
|
async.parallel([
|
||||||
@@ -627,18 +653,18 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:topic.loadMore', function(data, callback) {
|
socket.on('api:topic.loadMore', function(data, callback) {
|
||||||
var start = data.after,
|
var start = data.after,
|
||||||
end = start + 9;
|
end = start + 9;
|
||||||
|
|
||||||
topics.getTopicPosts(data.tid, start, end, uid, function(posts) {
|
topics.getTopicPosts(data.tid, start, end, uid, function(posts) {
|
||||||
callback({posts:posts});
|
callback({posts:posts});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:category.loadMore', function(data, callback) {
|
socket.on('api:category.loadMore', function(data, callback) {
|
||||||
var start = data.after,
|
var start = data.after,
|
||||||
end = start + 9;
|
end = start + 9;
|
||||||
|
|
||||||
categories.getCategoryTopics(data.cid, start, end, uid, function(topics) {
|
categories.getCategoryTopics(data.cid, start, end, uid, function(topics) {
|
||||||
callback({topics:topics});
|
callback({topics:topics});
|
||||||
});
|
});
|
||||||
@@ -652,11 +678,11 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
callback(latestTopics);
|
callback(latestTopics);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:topics.loadMoreUnreadTopics', function(data, callback) {
|
socket.on('api:topics.loadMoreUnreadTopics', function(data, callback) {
|
||||||
var start = data.after,
|
var start = data.after,
|
||||||
end = start + 9;
|
end = start + 9;
|
||||||
|
|
||||||
topics.getUnreadTopics(uid, start, end, function(unreadTopics) {
|
topics.getUnreadTopics(uid, start, end, function(unreadTopics) {
|
||||||
callback(unreadTopics);
|
callback(unreadTopics);
|
||||||
});
|
});
|
||||||
@@ -665,14 +691,14 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
socket.on('api:users.loadMore', function(data, callback) {
|
socket.on('api:users.loadMore', function(data, callback) {
|
||||||
var start = data.after,
|
var start = data.after,
|
||||||
end = start + 19;
|
end = start + 19;
|
||||||
|
|
||||||
user.getUsers(data.set, start, end, function(err, data) {
|
user.getUsers(data.set, start, end, function(err, data) {
|
||||||
if(err) {
|
if(err) {
|
||||||
console.log(err);
|
winston.err(err);
|
||||||
} else {
|
} else {
|
||||||
callback({users:data});
|
callback({users:data});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:admin.topics.getMore', function(data, callback) {
|
socket.on('api:admin.topics.getMore', function(data, callback) {
|
||||||
@@ -684,13 +710,13 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
socket.on('api:admin.categories.update', function(data) {
|
socket.on('api:admin.categories.update', function(data) {
|
||||||
admin.categories.update(data, socket);
|
admin.categories.update(data, socket);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:admin.user.makeAdmin', function(theirid) {
|
socket.on('api:admin.user.makeAdmin', function(theirid) {
|
||||||
if(uid && uid > 0) {
|
if(uid && uid > 0) {
|
||||||
admin.user.makeAdmin(uid, theirid, socket);
|
admin.user.makeAdmin(uid, theirid, socket);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:admin.user.removeAdmin', function(theirid) {
|
socket.on('api:admin.user.removeAdmin', function(theirid) {
|
||||||
if(uid && uid > 0) {
|
if(uid && uid > 0) {
|
||||||
admin.user.removeAdmin(uid, theirid, socket);
|
admin.user.removeAdmin(uid, theirid, socket);
|
||||||
@@ -703,14 +729,26 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on('api:admin.user.banUser', function(theirid) {
|
||||||
|
if(uid && uid > 0) {
|
||||||
|
admin.user.banUser(uid, theirid, socket);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('api:admin.user.unbanUser', function(theirid) {
|
||||||
|
if(uid && uid > 0) {
|
||||||
|
admin.user.unbanUser(uid, theirid, socket);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
socket.on('api:admin.user.search', function(username) {
|
socket.on('api:admin.user.search', function(username) {
|
||||||
if(uid && uid > 0) {
|
if(uid && uid > 0) {
|
||||||
user.search(username, function(data) {
|
user.search(username, function(data) {
|
||||||
socket.emit('api:admin.user.search', data);
|
socket.emit('api:admin.user.search', data);
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
socket.emit('api:admin.user.search', null);
|
socket.emit('api:admin.user.search', null);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:admin.themes.getInstalled', function(callback) {
|
socket.on('api:admin.themes.getInstalled', function(callback) {
|
||||||
@@ -726,10 +764,10 @@ var SocketIO = require('socket.io').listen(global.server, { log:false }),
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.on('api:meta.buildTitle', function(text, callback) {
|
socket.on('api:meta.buildTitle', function(text, callback) {
|
||||||
meta.title.build(text, uid, function(err, title) {
|
meta.title.build(text, uid, function(err, title, numNotifications) {
|
||||||
callback(title);
|
callback(title, numNotifications);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
}(SocketIO));
|
}(SocketIO));
|
||||||
|
|||||||
Reference in New Issue
Block a user