Start working on ACP

This commit is contained in:
calzoneman 2013-03-06 16:02:40 -06:00
parent 91b8a6cab6
commit 5ca419d3e3
10 changed files with 446 additions and 2 deletions

View File

@ -31,7 +31,7 @@ I'm using v0.8.20, please feel free to report which versions do/do not work
5. Install your distribution's `libmysqlclient` package
6. Install the libmysql node module: `npm install mysql-libmysqlclient`
7. Edit `config.js` and input your database details and connection port
8. Edit `www/assets/js/client.js` and change the value of `IO_URL` to `yourhostname:port` where `port` is the port defined in `config.js`
8. Edit `www/assets/js/iourl.js` and change the value of `IO_URL` to `yourhostname:port` where `port` is the port defined in `config.js`
Running
-------

101
database.js Normal file
View File

@ -0,0 +1,101 @@
var mysql = require('mysql-libmysqlclient');
var Config = require('./config.js');
var initialized = false;
exports.init = function() {
if(initialized)
return;
var db = mysql.createConnectionSync();
db.connectSync(Config.MYSQL_SERVER, Config.MYSQL_USER,
Config.MYSQL_PASSWORD, Config.MYSQL_DB);
var query = "CREATE TABLE IF NOT EXISTS `channels` \
(`id` INT NOT NULL, \
`name` VARCHAR(255) NOT NULL, \
PRIMARY KEY (`id`)) \
ENGINE = MyISAM;";
var results = db.querySync(query);
if(!results) {
console.log("Database initialization failed! Could not create channel table");
return false;
}
var query = "CREATE TABLE IF NOT EXISTS `registrations` \
(`id` INT NOT NULL, \
`uname` VARCHAR(20) NOT NULL, \
`pw` VARCHAR(64) NOT NULL, \
`global_rank` INT NOT NULL, \
PRIMARY KEY (`id`)) \
ENGINE = MyISAM;";
var results = db.querySync(query);
if(!results) {
console.log("Database initialization failed! Could not create registration table");
return false;
}
initialized = true;
return true;
}
exports.listChannels = function() {
if(!initialized)
return false;
var db = mysql.createConnectionSync();
db.connectSync(Config.MYSQL_SERVER, Config.MYSQL_USER,
Config.MYSQL_PASSWORD, Config.MYSQL_DB);
var query = "SELECT * FROM `channels`";
var results = db.querySync(query);
if(!results) {
console.log("Database channel listing failed!");
return false;
}
if(results) {
var rows = results.fetchAllSync();
db.closeSync();
return rows;
}
};
exports.listUsers = function() {
if(!initialized)
return false;
var db = mysql.createConnectionSync();
db.connectSync(Config.MYSQL_SERVER, Config.MYSQL_USER,
Config.MYSQL_PASSWORD, Config.MYSQL_DB);
var query = "SELECT * FROM `registrations`";
var results = db.querySync(query);
if(!results) {
console.log("Database user listing failed!");
return false;
}
if(results) {
var rows = results.fetchAllSync();
db.closeSync();
return rows;
}
};
exports.listChannelRanks = function(chan) {
if(!initialized)
return false;
var db = mysql.createConnectionSync();
db.connectSync(Config.MYSQL_SERVER, Config.MYSQL_USER,
Config.MYSQL_PASSWORD, Config.MYSQL_DB);
var query = "SELECT * FROM `chan_{}_ranks`"
.replace(/\{\}/, chan);
console.log(query);
var results = db.querySync(query);
if(!results) {
console.log("Database channel listing failed!");
return false;
}
if(results) {
var rows = results.fetchAllSync();
db.closeSync();
return rows;
}
};

View File

@ -13,6 +13,7 @@ exports.Owner = 3;
exports.Siteadmin = 255;
var permissions = {
acp: exports.Siteadmin,
queue: exports.Moderator,
assignLeader: exports.Moderator,
kick: exports.Moderator,

View File

@ -11,6 +11,8 @@ var Config = require('./config.js');
var connect = require('connect');
var app = connect.createServer(connect.static(__dirname+'/www')).listen(Config.IO_PORT);
var io = require('socket.io').listen(app);
var Database = require('./database.js');
Database.init();
exports.channels = {};

58
user.js
View File

@ -10,6 +10,7 @@ var Rank = require('./rank.js');
var Auth = require('./auth.js');
var Channel = require('./channel.js').Channel;
var Server = require('./server.js');
var Database = require('./database.js');
// Represents a client connected via socket.io
var User = function(socket, ip) {
@ -133,7 +134,64 @@ User.prototype.initCallbacks = function() {
}
}.bind(this));
this.socket.on('adm', function(data) {
if(Rank.hasPermission(this, "acp")) {
this.handleAdm(data);
}
}.bind(this));
}
// Handle administration
User.prototype.handleAdm = function(data) {
if(data.cmd == "listloadedchannels") {
var chans = [];
for(var chan in Server.channels) {
var users = [];
for(var i = 0; i < Server.channels[chan].users.length; i++) {
users.push(Server.channels[chan].users[i].name);
}
chans.push({
chan: chan,
users: users
});
}
this.socket.emit('adm', {
cmd: "listloadedchannels",
chans: chans
});
}
else if(data.cmd == "listchannels") {
this.socket.emit('adm', {
cmd: "listchannels",
chans: Database.listChannels()
});
}
else if(data.cmd == "listusers") {
var users = [];
var dbusers = Database.listUsers();
if(!dbusers)
return;
for(var i = 0; i < dbusers.length; i++) {
users[i] = {
name: dbusers[i].uname,
rank: dbusers[i].global_rank
};
}
this.socket.emit('adm', {
cmd: "listusers",
users: users
});
}
else if(data.cmd == "listchannelranks") {
if(data.chan == undefined)
return;
this.socket.emit('adm', {
cmd: "listchannelranks",
ranks: Database.listChannelRanks(data.chan)
});
}
};
// Attempt to login
User.prototype.login = function(name, sha256) {

90
www/acp.html Normal file
View File

@ -0,0 +1,90 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Sync</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="Calvin 'calzoneman' Montgomery">
<link href="./assets/css/bootstrap.css" rel="stylesheet">
<link href="./assets/css/ytsync.css" rel="stylesheet">
<style>
body {
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
}
</style>
<link href="./assets/css/bootstrap-responsive.css" rel="stylesheet">
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="brand" href="#">Sync</a>
<div class="nav-collapse collapse">
<ul class="nav">
<li class="active"><a href="index.html">Home</a></li>
</ul>
<div class="navbar-form pull-right" id="loginform">
<input class="span2" id="username" type="text" placeholder="Username">
<input class="span2" id="password" type="password" placeholder="Password">
<button class="btn" id="login">Login</button>
</div>
<div class="navbar-form pull-right" id="logoutform" style="display: none;">
<button class="btn" id="logout">Logout</button>
</div>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div id="loggedin" class="span6" style="display: none;">
<h3 id="welcome"></h3>
</div>
</div>
<div class="row" style="margin-top: 20px;">
<div class="span6">
<h3>Channel List</h3>
<table id="chanlist" class="table table-bordered table-striped">
<thead>
<tr>
<th>id</th>
<th>Channel Name</th>
</tr>
</thead>
</table>
</div>
<div class="span6">
<h3 id="channelh3">Channel: </h3>
<input type="text" placeholder="New Rank">
<table id="chanranks" class="table table-bordered table-striped">
<thead>
<tr>
<th>Username</th>
<th>Rank</th>
</tr>
</thead>
</table>
</div>
</div>
<div class="row" style="margin-top: 50px;">
</div>
</div> <!-- /container -->
<script src="./assets/js/jquery.js"></script>
<script src="./assets/js/webtoolkit.sha256.js" type="text/javascript"></script>
<script src="./socket.io/socket.io.js"></script>
<script src="./assets/js/iourl.js"></script>
<script src="./assets/js/acp.js"></script>
</body>
</html>

183
www/assets/js/acp.js Normal file
View File

@ -0,0 +1,183 @@
/**
* Copyright 2013 Calvin 'calzoneman' Montgomery
*
* Licensed under Creative Commons Attribution-NonCommercial 3.0
* See http://creativecommons.org/licenses/by-nc/3.0/
*
*/
var RANK = 0;
var uname = readCookie('sync_uname');
var pw = readCookie('sync_pw');
var manageChannel = false;
var Rank = {
Guest: 0,
Member: 1,
Moderator: 2,
Owner: 3,
Siteadmin: 255
};
var socket = io.connect(IO_URL);
initCallbacks();
function initCallbacks() {
socket.on('adm', function(data) {
console.log(data);
if(data.cmd == "listchannels")
handleChannelList(data);
if(data.cmd == "listchannelranks")
handleChannelRanks(data);
});
socket.on('login', function(data) {
if(data.success && $('#password').val()) {
createCookie('sync_uname', uname, 1);
createCookie('sync_pw', pw, 1);
}
if(data.success) {
$('#loggedin').css('display', '');
$('#logoutform').css('display', '');
$('#loginform').css('display', 'none');
}
socket.emit('adm', {
cmd: "listloadedchannels"
});
socket.emit('adm', {
cmd: "listchannels"
});
socket.emit('adm', {
cmd: "listusers"
});
});
}
function handleChannelList(data) {
if($('#chanlist').children.length > 1)
$($('#chanlist').children()[1]).remove();
for(var i = 0; i < data.chans.length; i++) {
var row = $('<tr/>').appendTo($('#chanlist'));
var id = $('<td/>').appendTo(row).text(data.chans[i].id);
var name = $('<td/>').appendTo(row).text(data.chans[i].name);
var manage = $('<button/>').addClass("btn pull-right").appendTo(name)
.text('Manage Ranks');
var cname = data.chans[i].name;
manage.click(function() {
manageChannelRanks(this);
}.bind(cname));
}
}
function manageChannelRanks(name) {
manageChannel = name;
$('#channelh3').text('Channel: ' + name);
socket.emit('adm', {
cmd: "listchannelranks",
chan: name
});
}
function handleChannelRanks(data) {
if($('#chanranks').children.length > 1)
$($('#chanranks').children()[1]).remove();
for(var i = 0; i < data.ranks.length; i++) {
var row = $('<tr/>').appendTo($('#chanranks'));
var id = $('<td/>').appendTo(row).text(data.ranks[i].name);
var rank = $('<td/>').appendTo(row);
var rtxt = $('<span/>').appendTo(rank).text(data.ranks[i].rank);
var edit = $('<button/>').addClass("btn pull-right").appendTo(rank)
.text('Edit');
edit.click(function() {
var txt = rtxt.text();
rtxt.text('');
var textbox = $('<input/>').attr('type', 'text').attr('value', txt)
.insertBefore(edit, rank);
textbox.focus();
textbox.blur(function() {
rtxt.text(textbox.val());
socket.emit('adm', {
cmd: "updatechanrank",
chan: manageChannel,
user: id.text(),
rank: parseInt(textbox.val())
});
textbox.remove();
});
});
}
}
var params = {};
if(window.location.search) {
var parameters = window.location.search.substring(1).split('&');
for(var i = 0; i < parameters.length; i++) {
var s = parameters[i].split('=');
if(s.length != 2)
continue;
params[s[0]] = s[1];
}
}
if(uname != null && pw != null && pw != "false") {
socket.emit('login', {
name: uname,
sha256: pw
});
}
function loginClick() {
uname = $('#username').val();
if($('#password').val() == "")
pw = "";
else
pw = SHA256($('#password').val());
socket.emit('login', {
name: uname,
sha256: pw
});
};
$('#login').click(loginClick);
$('#username').keydown(function(ev) {
if(ev.key == 13)
loginClick();
});
$('#password').keydown(function(ev) {
if(ev.key == 13)
loginClick();
});
$('#logout').click(function() {
eraseCookie('sync_uname');
eraseCookie('sync_pw');
document.location.reload(true);
});
function createCookie(name,value,days) {
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
function eraseCookie(name) {
createCookie(name,"",-1);
}

View File

@ -6,7 +6,6 @@
*
*/
const IO_URL = "http://somewebsite:1337";
const SYNC_THRESHOLD = 2;
var LEADER = false;
var PLAYER = false;

9
www/assets/js/iourl.js Normal file
View File

@ -0,0 +1,9 @@
/**
* Copyright 2013 Calvin 'calzoneman' Montgomery
*
* Licensed under Creative Commons Attribution-NonCommercial 3.0
* See http://creativecommons.org/licenses/by-nc/3.0/
*
*/
const IO_URL = "http://localhost:1337";

View File

@ -94,6 +94,7 @@
<script src="./socket.io/socket.io.js"></script>
<script src="./assets/js/functions.js"></script>
<script src="./assets/js/callbacks.js"></script>
<script src="./assets/js/iourl.js"></script>
<script src="./assets/js/client.js"></script>
<script src="./assets/js/swf.js"></script>