Baris Usakli 12 years ago
commit 283dbc477b

@ -36,6 +36,11 @@ var config = {
"facebook": { "facebook": {
"app_id": '', "app_id": '',
"secret": '' "secret": ''
},
// Privileged Actions Reputation Thresholds
"privilege_thresholds": {
"manage_thread": 1000
} }
} }

@ -204,6 +204,10 @@ footer.footer {
background: #fff; background: #fff;
} }
&.deleted {
-moz-opacity: 0.30;
opacity: 0.30;
}
} }
#user_label { #user_label {

@ -41,7 +41,6 @@ var ajaxify = {};
jQuery('#content').fadeOut(100); jQuery('#content').fadeOut(100);
load_template(function() { load_template(function() {
console.log('called');
exec_body_scripts(content); exec_body_scripts(content);
ajaxify.enable(); ajaxify.enable();

@ -2,7 +2,7 @@
<ul class="topic-container"> <ul class="topic-container">
<!-- BEGIN topics --> <!-- BEGIN topics -->
<a href="../../topic/{topics.slug}"><li class="topic-row"> <a href="../../topic/{topics.slug}"><li class="topic-row">
<h4>{topics.title}</h4> <h4><i class="{topics.icon}"></i> {topics.title}</h4>
<p>Posted {topics.relativeTime} ago by <span class="username">{topics.username}</span>. {topics.post_count} posts.</p> <p>Posted {topics.relativeTime} ago by <span class="username">{topics.username}</span>. {topics.post_count} posts.</p>
</li></a> </li></a>
<!-- END topics --> <!-- END topics -->

@ -34,31 +34,72 @@
</ul> </ul>
<hr /> <hr />
<button id="post_reply" class="btn btn-primary btn-large post_reply">Reply</button> <button id="post_reply" class="btn btn-primary btn-large post_reply">Reply</button>
<div class="btn-group pull-right"> <div class="btn-group pull-right" id="thread-tools" style="visibility: hidden;">
<button class="btn dropdown-toggle" data-toggle="dropdown">Thread Tools <span class="caret"></span></button> <button class="btn dropdown-toggle" data-toggle="dropdown">Thread Tools <span class="caret"></span></button>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="#">Lock/Unlock Thread</a></li> <li><a href="#" id="lock_thread"><i class="icon-lock"></i> Lock Thread</a></li>
<li class="divider"></li> <li class="divider"></li>
<li><a href="#"><span class="text-error">Delete Thread</span></a></li> <li><a href="#" id="delete_thread"><span class="text-error"><i class="icon-trash"></i> Delete Thread</span></a></li>
</ul> </ul>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
(function() { (function() {
var locked = '{locked}'; var expose_tools = '{expose_tools}',
tid = '{topic_id}',
thread_state = {
locked: '{locked}',
deleted: '{deleted}'
};
jQuery('document').ready(function() { jQuery('document').ready(function() {
var room = 'topic_' + '{topic_id}'; var room = 'topic_' + '{topic_id}',
adminTools = document.getElementById('thread-tools');
app.enter_room(room); app.enter_room(room);
set_up_posts(); set_up_posts();
if (locked === '1') set_locked_state(true); if (thread_state.locked === '1') set_locked_state(true);
if (thread_state.deleted === '1') set_delete_state(true);
if (expose_tools === '1') {
var deleteThreadEl = document.getElementById('delete_thread'),
lockThreadEl = document.getElementById('lock_thread');
adminTools.style.visibility = 'inherit';
// Add events to the thread tools
deleteThreadEl.addEventListener('click', function(e) {
e.preventDefault();
if (thread_state.deleted !== '1') {
if (confirm('really delete thread? (THIS DIALOG TO BE REPLACED WITH BOOTBOX)')) {
socket.emit('api:topic.delete', { tid: tid });
}
} else {
if (confirm('really restore thread? (THIS DIALOG TO BE REPLACED WITH BOOTBOX)')) {
socket.emit('api:topic.restore', { tid: tid });
}
}
});
lockThreadEl.addEventListener('click', function(e) {
e.preventDefault();
if (thread_state.locked !== '1') {
if (confirm('really lock thread? (THIS DIALOG TO BE REPLACED WITH BOOTBOX)')) {
socket.emit('api:topic.lock', { tid: tid });
}
} else {
if (confirm('really unlock thread? (THIS DIALOG TO BE REPLACED WITH BOOTBOX)')) {
socket.emit('api:topic.unlock', { tid: tid });
}
}
});
}
}); });
ajaxify.register_events(['event:rep_up', 'event:rep_down', 'event:new_post', 'api:get_users_in_room']); ajaxify.register_events(['event:rep_up', 'event:rep_down', 'event:new_post', 'api:get_users_in_room', 'event:topic_deleted']);
socket.on('api:get_users_in_room', function(users) { socket.on('api:get_users_in_room', function(users) {
var anonymous = users.anonymous, var anonymous = users.anonymous,
usernames = users.usernames, usernames = users.usernames,
@ -88,7 +129,6 @@
adjust_rep(-1, data.pid, data.uid); adjust_rep(-1, data.pid, data.uid);
}); });
socket.on('event:new_post', function(data) { socket.on('event:new_post', function(data) {
var html = templates.prepare(templates['topic'].blocks['posts']).parse(data), var html = templates.prepare(templates['topic'].blocks['posts']).parse(data),
uniqueid = new Date().getTime(); uniqueid = new Date().getTime();
@ -97,7 +137,31 @@
set_up_posts(uniqueid); set_up_posts(uniqueid);
}); });
socket.on('event:topic_deleted', function(data) {
if (data.tid === tid && data.status === 'ok') {
set_locked_state(true);
set_delete_state(true);
}
});
socket.on('event:topic_restored', function(data) {
if (data.tid === tid && data.status === 'ok') {
set_locked_state(false);
set_delete_state(false);
}
});
socket.on('event:topic_locked', function(data) {
if (data.tid === tid && data.status === 'ok') {
set_locked_state(true);
}
});
socket.on('event:topic_unlocked', function(data) {
if (data.tid === tid && data.status === 'ok') {
set_locked_state(false);
}
});
function adjust_rep(value, pid, uid) { function adjust_rep(value, pid, uid) {
var post_rep = jQuery('.post_rep_' + pid), var post_rep = jQuery('.post_rep_' + pid),
@ -119,11 +183,11 @@
else div = '#' + div; else div = '#' + div;
jQuery(div + ' .post_reply').click(function() { jQuery(div + ' .post_reply').click(function() {
if (locked !== '1') app.open_post_window('reply', "{topic_id}", "{topic_name}"); if (thread_state.locked !== '1') app.open_post_window('reply', "{topic_id}", "{topic_name}");
}); });
jQuery(div + ' .quote').click(function() { jQuery(div + ' .quote').click(function() {
if (locked !== '1') app.open_post_window('quote', "{topic_id}", "{topic_name}"); if (thread_state.locked !== '1') app.open_post_window('quote', "{topic_id}", "{topic_name}");
// this needs to be looked at, obviously. only single line quotes work well I think maybe replace all \r\n with > ? // this needs to be looked at, obviously. only single line quotes work well I think maybe replace all \r\n with > ?
document.getElementById('post_content').innerHTML = '> ' + document.getElementById('content_' + this.id.replace('quote_', '')).innerHTML; document.getElementById('post_content').innerHTML = '> ' + document.getElementById('content_' + this.id.replace('quote_', '')).innerHTML;
@ -142,13 +206,15 @@
uid = ids[1]; uid = ids[1];
if (this.children[1].className == 'icon-star-empty') { if (thread_state.locked !== '1') {
this.children[1].className = 'icon-star'; if (this.children[1].className == 'icon-star-empty') {
socket.emit('api:posts.favourite', {pid: pid, room_id: app.current_room}); this.children[1].className = 'icon-star';
} socket.emit('api:posts.favourite', {pid: pid, room_id: app.current_room});
else { }
this.children[1].className = 'icon-star-empty'; else {
socket.emit('api:posts.unfavourite', {pid: pid, room_id: app.current_room}); this.children[1].className = 'icon-star-empty';
socket.emit('api:posts.unfavourite', {pid: pid, room_id: app.current_room});
}
} }
}); });
} }
@ -158,21 +224,54 @@
postReplyBtns = document.querySelectorAll('#post-container .post_reply'), postReplyBtns = document.querySelectorAll('#post-container .post_reply'),
quoteBtns = document.querySelectorAll('#post-container .quote'), quoteBtns = document.querySelectorAll('#post-container .quote'),
numReplyBtns = postReplyBtns.length, numReplyBtns = postReplyBtns.length,
lockThreadEl = document.getElementById('lock_thread'),
x; x;
if (locked === true) { if (locked === true) {
lockThreadEl.innerHTML = '<i class="icon-unlock"></i> Unlock Thread';
threadReplyBtn.disabled = true; threadReplyBtn.disabled = true;
threadReplyBtn.innerHTML = 'Locked <i class="icon-lock"></i>'; threadReplyBtn.innerHTML = 'Locked <i class="icon-lock"></i>';
for(x=0;x<numReplyBtns;x++) { for(x=0;x<numReplyBtns;x++) {
postReplyBtns[x].innerHTML = 'Locked <i class="icon-lock"></i>'; postReplyBtns[x].innerHTML = 'Locked <i class="icon-lock"></i>';
quoteBtns[x].style.display = 'none'; quoteBtns[x].style.display = 'none';
} }
thread_state.locked = '1';
} else { } else {
lockThreadEl.innerHTML = '<i class="icon-lock"></i> Lock Thread';
threadReplyBtn.disabled = false; threadReplyBtn.disabled = false;
threadReplyBtn.innerHTML = 'Reply'; threadReplyBtn.innerHTML = 'Reply';
for(x=0;x<numReplyBtns;x++) { for(x=0;x<numReplyBtns;x++) {
postReplyBtns[x].innerHTML = 'Reply <i class="icon-reply"></i>'; postReplyBtns[x].innerHTML = 'Reply <i class="icon-reply"></i>';
quoteBtns[x].style.display = 'inline-block'; quoteBtns[x].style.display = 'inline-block';
} }
thread_state.locked = '0';
}
}
function set_delete_state(deleted) {
var deleteThreadEl = document.getElementById('delete_thread'),
deleteTextEl = deleteThreadEl.getElementsByTagName('span')[0],
threadEl = document.querySelector('.post-container'),
deleteNotice = document.getElementById('thread-deleted') || document.createElement('div');
if (deleted) {
deleteTextEl.innerHTML = '<i class="icon-comment"></i> Restore Thread';
$(threadEl).addClass('deleted');
// Spawn a 'deleted' notice at the top of the page
deleteNotice.setAttribute('id', 'thread-deleted');
deleteNotice.className = 'alert';
deleteNotice.innerHTML = 'This thread has been deleted. Only users with thread management privileges can see it.<br /><br /><a href="/">Home</a>';
document.getElementById('content').insertBefore(deleteNotice, threadEl);
thread_state.deleted = '1';
} else {
deleteTextEl.innerHTML = '<i class="icon-trash"></i> Delete Thread';
$(threadEl).removeClass('deleted');
deleteNotice.parentNode.removeChild(deleteNotice);
thread_state.deleted = '0';
} }
} }
})(); })();

@ -1,7 +1,8 @@
var RDB = require('./redis.js'), var RDB = require('./redis.js'),
utils = require('./utils.js'), utils = require('./utils.js'),
marked = require('marked'), marked = require('marked'),
user = require('./user.js'); user = require('./user.js'),
config = require('../config.js');
(function(Posts) { (function(Posts) {
@ -9,12 +10,12 @@ var RDB = require('./redis.js'),
if (start == null) start = 0; if (start == null) start = 0;
if (end == null) end = start + 10; if (end == null) end = start + 10;
var post_data, user_data, thread_data, vote_data; var post_data, user_data, thread_data, vote_data, viewer_data;
//compile thread after all data is asynchronously called //compile thread after all data is asynchronously called
function generateThread() { function generateThread() {
if (!post_data ||! user_data || !thread_data || !vote_data) return; if (!post_data ||! user_data || !thread_data || !vote_data || !viewer_data) return;
var posts = []; var posts = [];
@ -33,14 +34,16 @@ var RDB = require('./redis.js'),
'user_rep' : user_data[uid].reputation || 0, 'user_rep' : user_data[uid].reputation || 0,
'gravatar' : user_data[uid].picture, 'gravatar' : user_data[uid].picture,
'fav_star_class' : vote_data[pid] ? 'icon-star' : 'icon-star-empty', 'fav_star_class' : vote_data[pid] ? 'icon-star' : 'icon-star-empty',
'display_moderator_tools' : uid === current_user ? 'show' : 'hide' 'display_moderator_tools' : uid == current_user ? 'show' : 'hide'
}); });
} }
callback({ callback({
'topic_name':thread_data.topic_name, 'topic_name':thread_data.topic_name,
'locked': parseInt(thread_data.locked) || 0, 'locked': parseInt(thread_data.locked) || 0,
'deleted': parseInt(thread_data.deleted) || 0,
'topic_id': tid, 'topic_id': tid,
'expose_tools': viewer_data.reputation >= config.privilege_thresholds.manage_thread ? 1 : 0,
'posts': posts 'posts': posts
}); });
} }
@ -76,6 +79,7 @@ var RDB = require('./redis.js'),
.mget(post_rep) .mget(post_rep)
.get('tid:' + tid + ':title') .get('tid:' + tid + ':title')
.get('tid:' + tid + ':locked') .get('tid:' + tid + ':locked')
.get('tid:' + tid + ':deleted')
.exec(function(err, replies) { .exec(function(err, replies) {
post_data = { post_data = {
pid: pids, pid: pids,
@ -87,7 +91,8 @@ var RDB = require('./redis.js'),
thread_data = { thread_data = {
topic_name: replies[4], topic_name: replies[4],
locked: replies[5] locked: replies[5] || 0,
deleted: replies[6] || 0
}; };
user.getMultipleUserFields(post_data.uid, ['username','reputation','picture'], function(user_details){ user.getMultipleUserFields(post_data.uid, ['username','reputation','picture'], function(user_details){
@ -95,7 +100,13 @@ var RDB = require('./redis.js'),
generateThread(); generateThread();
}); });
}); });
});
user.getUserField(current_user, 'reputation', function(reputation){
viewer_data = {
reputation: reputation
};
generateThread();
}); });
} }
@ -116,8 +127,8 @@ var RDB = require('./redis.js'),
user.getUserFields(uid, ['username','reputation','picture'], function(data){ user.getUserFields(uid, ['username','reputation','picture'], function(data){
var timestamp = new Date().getTime(); var timestamp = new Date().getTime();
socket.in('topic_' + tid).emit('event:new_post', { io.sockets.in('topic_' + tid).emit('event:new_post', {
'posts' : [ 'posts' : [
{ {
'pid' : pid, 'pid' : pid,

@ -1,7 +1,8 @@
var RDB = require('./redis.js'), var RDB = require('./redis.js'),
posts = require('./posts.js'), posts = require('./posts.js'),
utils = require('./utils.js'), utils = require('./utils.js'),
user = require('./user.js'); user = require('./user.js'),
configs = require('../config.js');
(function(Topics) { (function(Topics) {
@ -23,14 +24,18 @@ var RDB = require('./redis.js'),
uid = [], uid = [],
timestamp = [], timestamp = [],
slug = [], slug = [],
postcount = []; postcount = [],
locked = [],
deleted = [];
for (var i=0, ii=tids.length; i<ii; i++) { for (var i=0, ii=tids.length; i<ii; i++) {
title.push('tid:' + tids[i] + ':title'); title.push('tid:' + tids[i] + ':title');
uid.push('tid:' + tids[i] + ':uid'); uid.push('tid:' + tids[i] + ':uid');
timestamp.push('tid:' + tids[i] + ':timestamp'); timestamp.push('tid:' + tids[i] + ':timestamp');
slug.push('tid:' + tids[i] + ':slug'); slug.push('tid:' + tids[i] + ':slug');
postcount.push('tid:' + tids[i] + ':postcount'); postcount.push('tid:' + tids[i] + ':postcount'),
locked.push('tid:' + tids[i] + ':locked'),
deleted.push('tid:' + tids[i] + ':deleted');
} }
if (tids.length > 0) { if (tids.length > 0) {
@ -40,21 +45,23 @@ var RDB = require('./redis.js'),
.mget(timestamp) .mget(timestamp)
.mget(slug) .mget(slug)
.mget(postcount) .mget(postcount)
.mget(locked)
.mget(deleted)
.exec(function(err, replies) { .exec(function(err, replies) {
title = replies[0]; title = replies[0];
uid = replies[1]; uid = replies[1];
timestamp = replies[2]; timestamp = replies[2];
slug = replies[3]; slug = replies[3];
postcount = replies[4]; postcount = replies[4];
locked = replies[5];
deleted = replies[6];
user.get_usernames_by_uids(uid, function(userNames) { user.get_usernames_by_uids(uid, function(userNames) {
var topics = []; var topics = [];
for (var i=0, ii=title.length; i<ii; i++) { for (var i=0, ii=title.length; i<ii; i++) {
if (deleted[i] === '1') continue;
topics.push({ topics.push({
'title' : title[i], 'title' : title[i],
'uid' : uid[i], 'uid' : uid[i],
@ -62,7 +69,9 @@ var RDB = require('./redis.js'),
'timestamp' : timestamp[i], 'timestamp' : timestamp[i],
'relativeTime': utils.relativeTime(timestamp[i]), 'relativeTime': utils.relativeTime(timestamp[i]),
'slug' : slug[i], 'slug' : slug[i],
'post_count' : postcount[i] 'post_count' : postcount[i],
icon: locked[i] === '1' ? 'icon-lock' : 'hide',
deleted: deleted[i]
}); });
} }
@ -139,8 +148,71 @@ var RDB = require('./redis.js'),
timeout: 2000 timeout: 2000
}); });
}); });
}; };
Topics.lock = function(tid, uid, socket) {
user.getUserField(uid, 'reputation', function(rep) {
if (rep >= configs.privilege_thresholds.manage_thread) {
// Mark thread as locked
RDB.set('tid:' + tid + ':locked', 1);
if (socket) {
io.sockets.in('topic_' + tid).emit('event:topic_locked', {
tid: tid,
status: 'ok'
});
}
}
});
}
Topics.unlock = function(tid, uid, socket) {
user.getUserField(uid, 'reputation', function(rep) {
if (rep >= configs.privilege_thresholds.manage_thread) {
// Mark thread as locked
RDB.del('tid:' + tid + ':locked');
if (socket) {
io.sockets.in('topic_' + tid).emit('event:topic_unlocked', {
tid: tid,
status: 'ok'
});
}
}
});
}
Topics.delete = function(tid, uid, socket) {
user.getUserField(uid, 'reputation', function(rep) {
if (rep >= configs.privilege_thresholds.manage_thread) {
// Mark thread as deleted
RDB.set('tid:' + tid + ':deleted', 1);
Topics.lock(tid, uid);
if (socket) {
io.sockets.in('topic_' + tid).emit('event:topic_deleted', {
tid: tid,
status: 'ok'
});
}
}
});
}
Topics.restore = function(tid, uid, socket) {
user.getUserField(uid, 'reputation', function(rep) {
if (rep >= configs.privilege_thresholds.manage_thread) {
// Mark thread as deleted
RDB.del('tid:' + tid + ':deleted');
Topics.unlock(tid, uid);
if (socket) {
io.sockets.in('topic_' + tid).emit('event:topic_restored', {
tid: tid,
status: 'ok'
});
}
}
});
}
}(exports)); }(exports));

@ -411,9 +411,8 @@ passport.deserializeUser(function(uid, done) {
app.get('/test', function(req, res) { app.get('/test', function(req, res) {
global.modules.posts.get(function(data) { global.modules.topics.delete(1, 1);
res.send('<pre>' + JSON.stringify(data, null, 4) + '</pre>'); res.send();
}, 1, 1);
}); });
}(WebServer)); }(WebServer));

@ -62,10 +62,7 @@ var SocketIO = require('socket.io').listen(global.server,{log:false}),
socket.emit('event:connect', {status: 1}); socket.emit('event:connect', {status: 1});
socket.on('disconnect', function() { socket.on('disconnect', function() {
console.log('Got disconnect! SESSION ID : '+hs.sessionID+' USER ID : '+uid);
delete users[hs.sessionID]; delete users[hs.sessionID];
console.log(users);
}); });
@ -177,6 +174,22 @@ var SocketIO = require('socket.io').listen(global.server,{log:false}),
socket.on('api:user.active.get_record', function() { socket.on('api:user.active.get_record', function() {
modules.user.active.get_record(socket); modules.user.active.get_record(socket);
}); });
socket.on('api:topic.delete', function(data) {
modules.topics.delete(data.tid, uid, socket);
});
socket.on('api:topic.restore', function(data) {
modules.topics.restore(data.tid, uid, socket);
});
socket.on('api:topic.lock', function(data) {
modules.topics.lock(data.tid, uid, socket);
});
socket.on('api:topic.unlock', function(data) {
modules.topics.unlock(data.tid, uid, socket);
});
}); });
}(SocketIO)); }(SocketIO));

Loading…
Cancel
Save