472 lines
21 KiB
HTML
472 lines
21 KiB
HTML
<!DOCTYPE html>
|
|
|
|
<html>
|
|
<head>
|
|
<title>groups.js</title>
|
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
|
<meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
|
|
<link rel="stylesheet" media="all" href="docco.css" />
|
|
</head>
|
|
<body>
|
|
<div id="container">
|
|
<div id="background"></div>
|
|
|
|
<ul id="jump_to">
|
|
<li>
|
|
<a class="large" href="javascript:void(0);">Jump To …</a>
|
|
<a class="small" href="javascript:void(0);">+</a>
|
|
<div id="jump_wrapper">
|
|
<div id="jump_page">
|
|
|
|
|
|
<a class="source" href="auth.html">
|
|
auth.js
|
|
</a>
|
|
|
|
|
|
<a class="source" href="deprecated.html">
|
|
deprecated.js
|
|
</a>
|
|
|
|
|
|
<a class="source" href="groups.html">
|
|
groups.js
|
|
</a>
|
|
|
|
|
|
<a class="source" href="user.html">
|
|
user.js
|
|
</a>
|
|
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
|
|
<ul class="sections">
|
|
|
|
<li id="title">
|
|
<div class="annotation">
|
|
<h1>groups.js</h1>
|
|
</div>
|
|
</li>
|
|
|
|
|
|
|
|
<li id="section-1">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-1">¶</a>
|
|
</div>
|
|
<p>@see ../routes for routing</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre><span class="keyword">var</span> _ = require(<span class="string">'lodash'</span>);
|
|
<span class="keyword">var</span> nconf = require(<span class="string">'nconf'</span>);
|
|
<span class="keyword">var</span> async = require(<span class="string">'async'</span>);
|
|
<span class="keyword">var</span> algos = require(<span class="string">'habitrpg-shared/script/algos'</span>);
|
|
<span class="keyword">var</span> helpers = require(<span class="string">'habitrpg-shared/script/helpers'</span>);
|
|
<span class="keyword">var</span> items = require(<span class="string">'habitrpg-shared/script/items'</span>);
|
|
<span class="keyword">var</span> User = require(<span class="string">'./../models/user'</span>).model;
|
|
<span class="keyword">var</span> Group = require(<span class="string">'./../models/group'</span>).model;
|
|
<span class="keyword">var</span> api = module.exports;
|
|
|
|
<span class="comment">/*
|
|
------------------------------------------------------------------------
|
|
Groups
|
|
------------------------------------------------------------------------
|
|
*/</span>
|
|
|
|
<span class="keyword">var</span> usernameFields = <span class="string">'auth.local.username auth.facebook.displayName auth.facebook.givenName auth.facebook.familyName auth.facebook.name'</span>;
|
|
<span class="keyword">var</span> partyFields = <span class="string">'profile preferences items stats achievements party backer flags.rest auth.timestamps '</span> + usernameFields;
|
|
|
|
<span class="function"><span class="keyword">function</span> <span class="title">removeSelf</span><span class="params">(group, user)</span>{</span>
|
|
group.members = _.filter(group.members, <span class="keyword">function</span>(m){<span class="keyword">return</span> m._id != user._id});
|
|
}
|
|
|
|
api.getMember = <span class="keyword">function</span>(req, res) {
|
|
User.findById(req.params.uid).select(partyFields).exec(<span class="keyword">function</span>(err, user){
|
|
<span class="keyword">if</span> (err) <span class="keyword">return</span> res.json(<span class="number">500</span>,{err:err});
|
|
<span class="keyword">if</span> (!user) <span class="keyword">return</span> res.json(<span class="number">400</span>,{err:<span class="string">'User not found'</span>});
|
|
res.json(user);
|
|
})
|
|
}
|
|
|
|
<span class="comment">/**
|
|
* Get groups. If req.query.type privided, returned as an array (so ngResource can use). If not, returned as
|
|
* object {guilds, public, party, tavern}. req.query.type can be comma-separated `type=guilds,party`
|
|
* @param req
|
|
* @param res
|
|
* @param next
|
|
*/</span>
|
|
api.getGroups = <span class="keyword">function</span>(req, res, next) {
|
|
<span class="keyword">var</span> user = res.locals.user;
|
|
|
|
<span class="keyword">var</span> type = req.query.type && req.query.type.split(<span class="string">','</span>);</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-2">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-2">¶</a>
|
|
</div>
|
|
<p>First get all groups</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> async.parallel({
|
|
party: <span class="keyword">function</span>(cb) {
|
|
<span class="keyword">if</span> (type && !~type.indexOf(<span class="string">'party'</span>)) <span class="keyword">return</span> cb(<span class="literal">null</span>, {});
|
|
Group
|
|
.findOne({type: <span class="string">'party'</span>, members: {<span class="string">'$in'</span>: [user._id]}})
|
|
.populate({
|
|
path: <span class="string">'members'</span>,</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-3">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-3">¶</a>
|
|
</div>
|
|
<p>match: {_id: {$ne: user._id}}, //fixme this causes it to hang??</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> select: partyFields
|
|
})
|
|
.exec(cb);
|
|
},
|
|
guilds: <span class="keyword">function</span>(cb) {
|
|
<span class="keyword">if</span> (type && !~type.indexOf(<span class="string">'guilds'</span>)) <span class="keyword">return</span> cb(<span class="literal">null</span>, []);
|
|
Group.find({type: <span class="string">'guild'</span>, members: {<span class="string">'$in'</span>: [user._id]}}).populate(<span class="string">'members'</span>, usernameFields).exec(cb);</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-4">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-4">¶</a>
|
|
</div>
|
|
<pre><code> Group.find({type: 'guild', members: {'$in': [user._id]}}, cb);</code></pre>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> },
|
|
tavern: <span class="keyword">function</span>(cb) {
|
|
<span class="keyword">if</span> (type && !~type.indexOf(<span class="string">'tavern'</span>)) <span class="keyword">return</span> cb(<span class="literal">null</span>, {});
|
|
Group.findOne({_id: <span class="string">'habitrpg'</span>}, cb);
|
|
},
|
|
<span class="string">"public"</span>: <span class="keyword">function</span>(cb) {
|
|
<span class="keyword">if</span> (type && !~type.indexOf(<span class="string">'public'</span>)) <span class="keyword">return</span> cb(<span class="literal">null</span>, []);
|
|
Group.find({privacy: <span class="string">'public'</span>}, {name:<span class="number">1</span>, description:<span class="number">1</span>, members:<span class="number">1</span>}, cb);
|
|
}
|
|
}, <span class="keyword">function</span>(err, results){
|
|
<span class="keyword">if</span> (err) <span class="keyword">return</span> res.json(<span class="number">500</span>, {err: err});</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-5">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-5">¶</a>
|
|
</div>
|
|
<p>Remove self from party (see above failing <code>match</code> directive in <code>populate</code></p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> (results.party) {
|
|
removeSelf(results.party, user);
|
|
}</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-6">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-6">¶</a>
|
|
</div>
|
|
<p>Sort public groups by members length (not easily doable in mongoose)</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> results.public = _.sortBy(results.public, <span class="keyword">function</span>(group){
|
|
<span class="keyword">return</span> -group.members.length;
|
|
});</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-7">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-7">¶</a>
|
|
</div>
|
|
<p>If they're requesting a specific type, let's return it as an array so that $ngResource
|
|
can utilize it properly</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> (type) {
|
|
results = _.reduce(type, <span class="keyword">function</span>(m,t){
|
|
<span class="keyword">return</span> m.concat(_.isArray(results[t]) ? results[t] : [results[t]]);
|
|
}, []);
|
|
}
|
|
|
|
res.json(results);
|
|
})
|
|
};
|
|
|
|
<span class="comment">/**
|
|
* Get group
|
|
*/</span>
|
|
api.getGroup = <span class="keyword">function</span>(req, res, next) {
|
|
<span class="keyword">var</span> user = res.locals.user;
|
|
<span class="keyword">var</span> gid = req.params.gid;
|
|
|
|
Group.findById(gid).populate(<span class="string">'members'</span>, partyFields).exec(<span class="keyword">function</span>(err, group){
|
|
<span class="keyword">if</span> ( (group.type == <span class="string">'guild'</span> && group.privacy == <span class="string">'private'</span>) || group.type == <span class="string">'party'</span>) {
|
|
<span class="keyword">return</span> res.json(<span class="number">401</span>, {err: <span class="string">"You don't have access to this group"</span>});
|
|
}</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-8">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-8">¶</a>
|
|
</div>
|
|
<p>Remove self from party (see above failing <code>match</code> directive in <code>populate</code></p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">if</span> (group.type == <span class="string">'party'</span>) {
|
|
removeSelf(group, user);
|
|
}
|
|
res.json(group);
|
|
|
|
})
|
|
};
|
|
|
|
|
|
api.createGroup = <span class="keyword">function</span>(req, res, next) {
|
|
<span class="keyword">var</span> group = <span class="keyword">new</span> Group(req.body);
|
|
group.save(<span class="keyword">function</span>(err, saved){
|
|
<span class="keyword">if</span> (err) <span class="keyword">return</span> res.json(<span class="number">500</span>,{err:err});
|
|
res.json(saved);
|
|
})
|
|
}
|
|
|
|
api.updateGroup = <span class="keyword">function</span>(req, res, next) {
|
|
<span class="keyword">var</span> group = res.locals.group;
|
|
<span class="string">'name description logo websites logo leaderMessage'</span>.split(<span class="string">' '</span>).forEach(<span class="keyword">function</span>(attr){
|
|
group[attr] = req.body[attr];
|
|
});
|
|
async.series([
|
|
<span class="keyword">function</span>(cb){group.save(cb);},
|
|
<span class="keyword">function</span>(cb){
|
|
<span class="keyword">var</span> fields = group.type == <span class="string">'party'</span> ? partyFields : usernameFields;
|
|
Group.findById(group._id).populate(<span class="string">'members'</span>, fields).exec(cb);
|
|
}
|
|
], <span class="keyword">function</span>(err, results){
|
|
<span class="keyword">if</span> (err) <span class="keyword">return</span> res.json(<span class="number">500</span>,{err:err});
|
|
removeSelf(results[<span class="number">1</span>], res.locals.user);
|
|
res.json(results[<span class="number">1</span>]);
|
|
})
|
|
}
|
|
|
|
api.attachGroup = <span class="keyword">function</span>(req, res, next) {
|
|
Group.findById(req.params.gid, <span class="keyword">function</span>(err, group){
|
|
<span class="keyword">if</span>(err) <span class="keyword">return</span> res.json(<span class="number">500</span>, {err:err});
|
|
res.locals.group = group;
|
|
next();
|
|
})
|
|
}
|
|
|
|
api.postChat = <span class="keyword">function</span>(req, res, next) {
|
|
<span class="keyword">var</span> user = res.locals.user
|
|
<span class="keyword">var</span> group = res.locals.group;
|
|
<span class="keyword">var</span> message = {
|
|
id: helpers.uuid(),
|
|
uuid: user._id,
|
|
contributor: user.backer && user.backer.contributor,
|
|
npc: user.backer && user.backer.npc,
|
|
text: req.query.message, <span class="comment">// FIXME this should be body, but ngResource is funky</span>
|
|
user: helpers.username(user.auth, user.profile.name),
|
|
timestamp: +(<span class="keyword">new</span> Date)
|
|
};
|
|
|
|
group.chat.unshift(message);
|
|
group.chat.splice(<span class="number">200</span>);
|
|
|
|
<span class="keyword">if</span> (group.type === <span class="string">'party'</span>) {
|
|
user.party.lastMessageSeen = message.id;
|
|
user.save();
|
|
}
|
|
|
|
async.series([
|
|
<span class="keyword">function</span>(cb){group.save(cb)},
|
|
<span class="keyword">function</span>(cb){
|
|
Group.findById(group._id).populate(<span class="string">'members'</span>, partyFields).exec(cb);
|
|
}
|
|
], <span class="keyword">function</span>(err, results){
|
|
<span class="keyword">if</span> (err) <span class="keyword">return</span> res.json(<span class="number">500</span>, {err:err});</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-9">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-9">¶</a>
|
|
</div>
|
|
<p>TODO This is less efficient, but see <a href="https://github.com/lefnire/habitrpg/commit/41255dc#commitcomment-4014583">https://github.com/lefnire/habitrpg/commit/41255dc#commitcomment-4014583</a></p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> <span class="keyword">var</span> saved = results[<span class="number">1</span>];
|
|
removeSelf(saved, user);
|
|
|
|
res.json(saved);
|
|
})
|
|
}
|
|
|
|
api.deleteChatMessage = <span class="keyword">function</span>(req, res, next){
|
|
<span class="keyword">var</span> user = res.locals.user
|
|
<span class="keyword">var</span> group = res.locals.group;
|
|
<span class="keyword">var</span> message = _.find(group.chat, {id: req.params.messageId, uuid: user.id});
|
|
|
|
<span class="keyword">if</span>(message === <span class="literal">undefined</span>) <span class="keyword">return</span> res.json(<span class="number">404</span>, {err: <span class="string">"Message not found!"</span>});
|
|
|
|
<span class="keyword">if</span>(user.id !== message.uuid){
|
|
<span class="keyword">if</span>(!user.backer || (user.backer && !user.backer.admin)){
|
|
<span class="keyword">return</span> res.json(<span class="number">401</span>, {err: <span class="string">"Not authorized to delete this message!"</span>})
|
|
}
|
|
}
|
|
|
|
group.chat = _.without(group.chat, message);
|
|
|
|
group.save(<span class="keyword">function</span>(err, data){
|
|
<span class="keyword">if</span>(err) <span class="keyword">return</span> res.json(<span class="number">500</span>, {err: err});
|
|
|
|
res.send(<span class="number">204</span>);
|
|
});
|
|
}
|
|
|
|
api.join = <span class="keyword">function</span>(req, res, next) {
|
|
<span class="keyword">var</span> user = res.locals.user,
|
|
group = res.locals.group;
|
|
|
|
<span class="keyword">if</span> (group.type == <span class="string">'party'</span> && group._id == (user.invitations && user.invitations.party && user.invitations.party.id)) {
|
|
user.invitations.party = <span class="literal">undefined</span>;
|
|
user.save();
|
|
}
|
|
<span class="keyword">else</span> <span class="keyword">if</span> (group.type == <span class="string">'guild'</span> && user.invitations && user.invitations.guilds) {
|
|
<span class="keyword">var</span> i = _.findIndex(user.invitations.guilds, {id:group._id});
|
|
<span class="keyword">if</span> (~i) user.invitations.guilds.splice(i,<span class="number">1</span>);
|
|
user.save();
|
|
}
|
|
|
|
group.members.push(user._id);
|
|
async.series([
|
|
<span class="keyword">function</span>(cb){
|
|
group.save(cb);
|
|
},
|
|
<span class="keyword">function</span>(cb){
|
|
Group.findById(group._id).populate(<span class="string">'members'</span>, partyFields).exec(cb);
|
|
}
|
|
], <span class="keyword">function</span>(err, results){
|
|
<span class="keyword">if</span> (err) <span class="keyword">return</span> res.json(<span class="number">500</span>,{err:err});
|
|
res.json(results[<span class="number">1</span>]);
|
|
});
|
|
}
|
|
|
|
api.leave = <span class="keyword">function</span>(req, res, next) {
|
|
<span class="keyword">var</span> user = res.locals.user,
|
|
group = res.locals.group;
|
|
|
|
Group.update({_id:group._id},{$pull:{members:user._id}}, <span class="keyword">function</span>(err, saved){
|
|
<span class="keyword">if</span> (err) <span class="keyword">return</span> res.json(<span class="number">500</span>,{err:err});
|
|
res.send(<span class="number">200</span>, {_id: saved._id});
|
|
})
|
|
}
|
|
|
|
api.invite = <span class="keyword">function</span>(req, res, next) {
|
|
<span class="keyword">var</span> group = res.locals.group;
|
|
<span class="keyword">var</span> uuid = req.query.uuid;
|
|
|
|
User.findById(uuid, <span class="keyword">function</span>(err,invite){
|
|
<span class="keyword">if</span> (err) <span class="keyword">return</span> res.json(<span class="number">500</span>,{err:err});
|
|
<span class="keyword">if</span> (!invite)
|
|
<span class="keyword">return</span> res.json(<span class="number">400</span>,{err:<span class="string">'User with id '</span>+req.query.uid+<span class="string">' not found'</span>});
|
|
<span class="keyword">if</span> (group.type == <span class="string">'guild'</span>) {
|
|
<span class="keyword">if</span> (_.contains(group.members,uuid))
|
|
<span class="keyword">return</span> res.json(<span class="number">400</span>,{err: <span class="string">"User already in that group"</span>});
|
|
<span class="keyword">if</span> (invite.invitations && invite.invitations.guilds && _.find(invite.invitations.guilds, {id:group._id}))
|
|
<span class="keyword">return</span> res.json(<span class="number">400</span>, {err:<span class="string">"User already invited to that group"</span>});
|
|
sendInvite();
|
|
} <span class="keyword">else</span> <span class="keyword">if</span> (group.type == <span class="string">'party'</span>) {
|
|
<span class="keyword">if</span> (invite.invitations && !_.isEmpty(invite.invitations.party))
|
|
<span class="keyword">return</span> res.json(<span class="number">400</span>,{err:<span class="string">"User already pending invitation."</span>});
|
|
Group.find({type:<span class="string">'party'</span>, members:{$<span class="keyword">in</span>:[uuid]}}, <span class="keyword">function</span>(err, groups){
|
|
<span class="keyword">if</span> (err) <span class="keyword">return</span> res.json(<span class="number">500</span>,{err:err});
|
|
<span class="keyword">if</span> (!_.isEmpty(groups))
|
|
<span class="keyword">return</span> res.json(<span class="number">400</span>,{err:<span class="string">"User already in a party."</span>})
|
|
sendInvite();
|
|
})
|
|
}
|
|
|
|
<span class="function"><span class="keyword">function</span> <span class="title">sendInvite</span> <span class="params">()</span>{</span>
|
|
<span class="keyword">if</span>(group.type === <span class="string">'guild'</span>){
|
|
invite.invitations.guilds.push({id: group._id, name: group.name});
|
|
}<span class="keyword">else</span>{</pre></div></div>
|
|
|
|
</li>
|
|
|
|
|
|
<li id="section-10">
|
|
<div class="annotation">
|
|
|
|
<div class="pilwrap ">
|
|
<a class="pilcrow" href="#section-10">¶</a>
|
|
</div>
|
|
<p>req.body.type in 'guild', 'party'</p>
|
|
|
|
</div>
|
|
|
|
<div class="content"><div class='highlight'><pre> invite.invitations.party = {id: group._id, name: group.name}
|
|
}
|
|
|
|
invite.save();
|
|
Group.findById(group._id)
|
|
.populate(<span class="string">'members'</span>, partyFields).exec(<span class="keyword">function</span>(err, saved){
|
|
res.json(saved);
|
|
});
|
|
|
|
}
|
|
});
|
|
}</pre></div></div>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</div>
|
|
</body>
|
|
</html>
|