mirror of
https://github.com/ENSL/ensl_gathers.git
synced 2025-02-17 01:12:20 +00:00
Added basic voting implementation
This commit is contained in:
parent
6ccd424db3
commit
cf2b9643fb
10 changed files with 266 additions and 66 deletions
|
@ -27,13 +27,14 @@ npm start
|
||||||
- ENSL.org: Authentication
|
- ENSL.org: Authentication
|
||||||
- ENSL.org: Pull user data and bans
|
- ENSL.org: Pull user data and bans
|
||||||
- ENSL.org: API to allow ENSL to pull current gather status
|
- ENSL.org: API to allow ENSL to pull current gather status
|
||||||
- Steam Integration: Pull hive stats
|
- Hive Integration: Pull stats
|
||||||
- Steam Integration: Outbound steam messaging
|
- Steam Integration: Outbound steam messaging
|
||||||
- Admin tools
|
- Admin tools - kick user/edit messages
|
||||||
- Add a backend datastore to persist gather data and messages
|
- Add a backend datastore to persist gather data and messages
|
||||||
- Add sounds
|
- Add sounds
|
||||||
- Add WebRTC for internal voice comms
|
- WebRTC?
|
||||||
- Add user lifeform + div information
|
- Add user lifeform + div information
|
||||||
|
- Show online status
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
|
@ -2,29 +2,35 @@
|
||||||
|
|
||||||
var winston = require("winston");
|
var winston = require("winston");
|
||||||
var User = require("../lib/user/user");
|
var User = require("../lib/user/user");
|
||||||
var enslClient = require("../lib/ensl/client")();
|
var client = require("../lib/ensl/client")();
|
||||||
var chatController = require("../lib/chat/controller");
|
var chatController = require("../lib/chat/controller");
|
||||||
var gatherController = require("../lib/gather/controller");
|
var gatherController = require("../lib/gather/controller");
|
||||||
var userController = require("../lib/user/controller");
|
var userController = require("../lib/user/controller");
|
||||||
|
|
||||||
var createUser = require("../spec/helpers/index.js").createUser;
|
var getRandomUser = function (callback) {
|
||||||
|
var id = Math.floor(Math.random() * 5000) + 1;
|
||||||
|
console.log(id);
|
||||||
|
client.getUserById({
|
||||||
|
id: id
|
||||||
|
}, function (error, response, body) {
|
||||||
|
if (response.statusCode !== 200) return getRandomUser(callback);
|
||||||
|
return callback(error, response, body);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = function (io) {
|
module.exports = function (io) {
|
||||||
var rootNamespace = io.of('/')
|
var rootNamespace = io.of('/')
|
||||||
|
|
||||||
// Authorisation
|
// Authorisation
|
||||||
io.use(function (socket, next) {
|
io.use(function (socket, next) {
|
||||||
var id = Math.floor(Math.random() * 5000) + 1;
|
getRandomUser(function (error, _, body) {
|
||||||
enslClient.getUserById({
|
|
||||||
id: id
|
|
||||||
}, function (error, response, body) {
|
|
||||||
if (error) {
|
if (error) {
|
||||||
winston.error(error);
|
winston.error(error);
|
||||||
return next(error)
|
return next(error)
|
||||||
};
|
};
|
||||||
socket._user = new User(body);
|
socket._user = new User(body);
|
||||||
next();
|
next();
|
||||||
});
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
userController(rootNamespace);
|
userController(rootNamespace);
|
||||||
|
|
|
@ -16,12 +16,56 @@
|
||||||
var Gather = require("./gather");
|
var Gather = require("./gather");
|
||||||
var gather = new Gather();
|
var gather = new Gather();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ***** Temporary code to test voting *****
|
||||||
|
|
||||||
|
var User = require("../user/user");
|
||||||
|
var client = require("../ensl/client")();
|
||||||
|
var async = require("async");
|
||||||
|
|
||||||
|
var getRandomUser = function (callback) {
|
||||||
|
var id = Math.floor(Math.random() * 5000) + 1;
|
||||||
|
console.log(id);
|
||||||
|
client.getUserById({
|
||||||
|
id: id
|
||||||
|
}, function (error, response, body) {
|
||||||
|
if (response.statusCode !== 200) return getRandomUser(callback);
|
||||||
|
return callback(error, response, body);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var instructions = [];
|
||||||
|
for (var i = 0; i < 11; i++) {
|
||||||
|
instructions.push(function (callback) {
|
||||||
|
getRandomUser(function (error, response, body) {
|
||||||
|
if (error) return callback(error);
|
||||||
|
if (gather.can("addGatherer")) {
|
||||||
|
gather.addGatherer(new User(body));
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
async.parallel(instructions, function (error) {
|
||||||
|
if (error) {
|
||||||
|
console.log("Error while adding gatherers", error);
|
||||||
|
} else {
|
||||||
|
console.log("Loaded gatherers");
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ***** Temporary code to test voting *****
|
||||||
|
|
||||||
|
|
||||||
module.exports = function (namespace) {
|
module.exports = function (namespace) {
|
||||||
var refreshGather = function () {
|
var refreshGather = function () {
|
||||||
namespace.sockets.forEach(function (socket) {
|
namespace.sockets.forEach(function (socket) {
|
||||||
socket.emit("gather:refresh", {
|
socket.emit("gather:refresh", {
|
||||||
gather: gather.toJson(),
|
gather: gather.toJson(),
|
||||||
user: socket._user
|
currentUser: socket._user
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -46,7 +90,10 @@ module.exports = function (namespace) {
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("gather:vote", function (data) {
|
socket.on("gather:vote", function (data) {
|
||||||
|
if (data.leader) {
|
||||||
|
gather.selectLeader(socket._user, data.leader.candidate);
|
||||||
|
}
|
||||||
|
refreshGather();
|
||||||
});
|
});
|
||||||
|
|
||||||
refreshGather();
|
refreshGather();
|
||||||
|
|
|
@ -156,6 +156,7 @@ Gather.prototype.leaderVotes = function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
Gather.prototype.voteForLeader = function (voter, candidate) {
|
Gather.prototype.voteForLeader = function (voter, candidate) {
|
||||||
|
// Find voter and then assign their vote to candidate id
|
||||||
this.gatherers.forEach(function (gatherer, index, array) {
|
this.gatherers.forEach(function (gatherer, index, array) {
|
||||||
if (gatherer.id === voter.id) {
|
if (gatherer.id === voter.id) {
|
||||||
array[index].voteForLeader(candidate);
|
array[index].voteForLeader(candidate);
|
||||||
|
|
|
@ -23,8 +23,14 @@ function Gatherer (user) {
|
||||||
this.team = "lobby";
|
this.team = "lobby";
|
||||||
}
|
}
|
||||||
|
|
||||||
Gatherer.prototype.voteForLeader = function (user) {
|
Gatherer.prototype.voteForLeader = function (candidate) {
|
||||||
this.leaderVote = user.id;
|
if (candidate === null) {
|
||||||
|
return this.leaderVote = null;
|
||||||
|
}
|
||||||
|
if (typeof candidate === 'number') {
|
||||||
|
return this.leaderVote = candidate;
|
||||||
|
}
|
||||||
|
this.leaderVote = candidate.id;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Gatherer;
|
module.exports = Gatherer;
|
|
@ -64,7 +64,7 @@ var UserMenu = React.createClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
componentDidMount: function () {
|
componentDidMount: function () {
|
||||||
socket.on('userCount', this.updateUsers);
|
socket.on('users:update', this.updateUsers);
|
||||||
},
|
},
|
||||||
updateUsers: function (data) {
|
updateUsers: function (data) {
|
||||||
this.setProps({
|
this.setProps({
|
||||||
|
@ -197,22 +197,65 @@ var ChatMessage = React.createClass({
|
||||||
});
|
});
|
||||||
|
|
||||||
var CurrentUser = React.createClass({
|
var CurrentUser = React.createClass({
|
||||||
getDefaultProps: function () {
|
|
||||||
return {
|
|
||||||
username: "",
|
|
||||||
avatar: ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
componentDidMount: function () {
|
componentDidMount: function () {
|
||||||
|
var self = this;
|
||||||
|
socket.on("users:update", function (data) {
|
||||||
|
self.setProps({
|
||||||
|
user: data.currentUser
|
||||||
|
});
|
||||||
|
});
|
||||||
|
socket.emit("users:refresh", {});
|
||||||
},
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
return (
|
if (this.props.user) {
|
||||||
<a href="#">{this.props.user.username} <img src={this.props.user.avatar}
|
return (
|
||||||
alt="User Avatar"
|
<a href="#">{this.props.user.username} <img src={this.props.user.avatar}
|
||||||
height="20"
|
alt="User Avatar"
|
||||||
width="20" /></a>
|
height="20"
|
||||||
);
|
width="20" /></a>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var VoteButton = React.createClass({
|
||||||
|
cancelVote: function (e) {
|
||||||
|
socket.emit("gather:vote", {
|
||||||
|
leader: {
|
||||||
|
candidate: null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
vote: function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
socket.emit("gather:vote", {
|
||||||
|
leader: {
|
||||||
|
candidate: parseInt(e.target.value, 10)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
render: function () {
|
||||||
|
if (this.props.currentGatherer === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (this.props.currentGatherer.leaderVote === this.props.candidate.id) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={this.cancelVote}
|
||||||
|
className="btn btn-xs btn-success">Voted
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={this.vote}
|
||||||
|
className="btn btn-xs btn-default"
|
||||||
|
value={this.props.candidate.id}>Vote
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -351,7 +394,7 @@ var Gather = React.createClass({
|
||||||
joinedGather: function () {
|
joinedGather: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
return this.props.gather.gatherers.some(function (gatherer) {
|
return this.props.gather.gatherers.some(function (gatherer) {
|
||||||
return gatherer.user.id === self.props.user.id;
|
return gatherer.user.id === self.props.currentUser.id;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
componentDidMount: function () {
|
componentDidMount: function () {
|
||||||
|
@ -359,7 +402,7 @@ var Gather = React.createClass({
|
||||||
socket.on("gather:refresh", function (data) {
|
socket.on("gather:refresh", function (data) {
|
||||||
self.setProps({
|
self.setProps({
|
||||||
gather: data.gather,
|
gather: data.gather,
|
||||||
user: data.user
|
currentUser: data.currentUser
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -384,6 +427,14 @@ var Gather = React.createClass({
|
||||||
inviteToGather: function (e) {
|
inviteToGather: function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
},
|
},
|
||||||
|
currentGatherer: function () {
|
||||||
|
var current = null;
|
||||||
|
var self = this;
|
||||||
|
this.props.gather.gatherers.forEach(function (gatherer) {
|
||||||
|
if (gatherer.id === self.props.currentUser.id) current = gatherer;
|
||||||
|
});
|
||||||
|
return current;
|
||||||
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
var joinButton;
|
var joinButton;
|
||||||
if (this.joinedGather()) {
|
if (this.joinedGather()) {
|
||||||
|
@ -407,7 +458,7 @@ var Gather = React.createClass({
|
||||||
<br />
|
<br />
|
||||||
{this.stateDescription()}
|
{this.stateDescription()}
|
||||||
</div>
|
</div>
|
||||||
<Gatherers gatherers={this.props.gather.gatherers} />
|
<Gatherers gather={this.props.gather} currentGatherer={this.currentGatherer()} />
|
||||||
<GatherProgress gather={this.props.gather} />
|
<GatherProgress gather={this.props.gather} />
|
||||||
<div className="panel-footer text-right">
|
<div className="panel-footer text-right">
|
||||||
<ul className="list-inline">
|
<ul className="list-inline">
|
||||||
|
@ -431,13 +482,14 @@ var LeaderPoll = React.createClass({
|
||||||
|
|
||||||
var Gatherers = React.createClass({
|
var Gatherers = React.createClass({
|
||||||
render: function () {
|
render: function () {
|
||||||
var gatherers = this.props.gatherers.map(function (gatherer) {
|
var self = this;
|
||||||
|
var gatherers = this.props.gather.gatherers.map(function (gatherer) {
|
||||||
var lifeforms = (
|
var lifeforms = (
|
||||||
gatherer.user.ability.lifeforms.map(function (lifeform) {
|
gatherer.user.ability.lifeforms.map(function (lifeform) {
|
||||||
return (<span className="label label-default">{lifeform}</span>);
|
return (<span className="label label-default">{lifeform}</span>);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
var division = (<span className="label label-primary">{gatherer.user.ability.division}</span>);
|
|
||||||
var commBadge;
|
var commBadge;
|
||||||
if (gatherer.user.ability.commander) {
|
if (gatherer.user.ability.commander) {
|
||||||
commBadge = (<img src="/images/commander.png"
|
commBadge = (<img src="/images/commander.png"
|
||||||
|
@ -446,16 +498,32 @@ var Gatherers = React.createClass({
|
||||||
width="20" />);
|
width="20" />);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var division = (<span className="label label-primary">{gatherer.user.ability.division}</span>);
|
||||||
|
var action = lifeforms;
|
||||||
|
if (self.props.gather.state === "election") {
|
||||||
|
var votes = self.props.gather.gatherers.reduce(function (acc, voter) {
|
||||||
|
if (voter.leaderVote === gatherer.id) acc++;
|
||||||
|
return acc;
|
||||||
|
}, 0)
|
||||||
|
action = (
|
||||||
|
<div className="text-right">
|
||||||
|
<small>{votes + " votes"} </small>
|
||||||
|
|
||||||
|
<VoteButton currentGatherer={self.props.currentGatherer} candidate={gatherer} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr key={gatherer.user.id}>
|
<tr key={gatherer.user.id}>
|
||||||
<td className="col-md-1">{commBadge}</td>
|
<td className="col-md-1">{commBadge}</td>
|
||||||
<td className="col-md-5">{gatherer.user.username}</td>
|
<td className="col-md-5">{gatherer.user.username}</td>
|
||||||
<td className="col-md-3">{division} </td>
|
<td className="col-md-3">{division} </td>
|
||||||
<td className="col-md-3">{lifeforms} </td>
|
<td className="col-md-2">{action} </td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
if (this.props.gatherers.length) {
|
if (this.props.gather.gatherers.length) {
|
||||||
return (
|
return (
|
||||||
<div className="panel-body">
|
<div className="panel-body">
|
||||||
<div className="panel panel-default">
|
<div className="panel panel-default">
|
||||||
|
|
|
@ -20,7 +20,7 @@ var enslClient = require("../ensl/client")();
|
||||||
|
|
||||||
module.exports = function (namespace) {
|
module.exports = function (namespace) {
|
||||||
var refreshUsers = function (socket) {
|
var refreshUsers = function (socket) {
|
||||||
var receiver = (socket !== undefined) ? socket : namespace;
|
var receivers = (socket !== undefined) ? [socket] : namespace.sockets;
|
||||||
|
|
||||||
var newCache = {};
|
var newCache = {};
|
||||||
namespace.sockets.forEach(function (socket) {
|
namespace.sockets.forEach(function (socket) {
|
||||||
|
@ -37,16 +37,19 @@ module.exports = function (namespace) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
receiver.emit('userCount', {
|
receivers.forEach(function (socket) {
|
||||||
count: users.length,
|
socket.emit('users:update', {
|
||||||
users: users
|
count: users.length,
|
||||||
});
|
users: users,
|
||||||
|
currentUser: socket._user
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace.on('connection', function (socket) {
|
namespace.on('connection', function (socket) {
|
||||||
refreshUsers();
|
refreshUsers();
|
||||||
|
|
||||||
socket.on('refreshUsers', refreshUsers.bind(null, socket));
|
socket.on('users:refresh', refreshUsers.bind(null, socket));
|
||||||
|
|
||||||
socket.on("users:authorize", function (data) {
|
socket.on("users:authorize", function (data) {
|
||||||
var id = parseInt(data.id, 10);
|
var id = parseInt(data.id, 10);
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/cblanc/sws_gathers",
|
"homepage": "https://github.com/cblanc/sws_gathers",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"async": "^1.4.0",
|
||||||
"express": "~4.13.1",
|
"express": "~4.13.1",
|
||||||
"express-handlebars": "~2.0.1",
|
"express-handlebars": "~2.0.1",
|
||||||
"extend": "^3.0.0",
|
"extend": "^3.0.0",
|
||||||
|
|
112
public/js/app.js
112
public/js/app.js
File diff suppressed because one or more lines are too long
|
@ -231,9 +231,8 @@ describe("Gather Model:", function () {
|
||||||
describe("toJson", function () {
|
describe("toJson", function () {
|
||||||
it ("returns a json representation of the gather instance", function () {
|
it ("returns a json representation of the gather instance", function () {
|
||||||
var output = gather.toJson();
|
var output = gather.toJson();
|
||||||
assert.isArray(output.lobby);
|
assert.isArray(output.gatherers);
|
||||||
assert.isArray(output.marines);
|
assert.isString(output.state);
|
||||||
assert.isArray(output.aliens);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("leaderVotes", function () {
|
describe("leaderVotes", function () {
|
||||||
|
|
Loading…
Reference in a new issue