diff --git a/public/js/controllers/adminCtrl.js b/public/js/controllers/adminCtrl.js index 33059d5d86..c9fe8c4492 100644 --- a/public/js/controllers/adminCtrl.js +++ b/public/js/controllers/adminCtrl.js @@ -1,10 +1,12 @@ "use strict"; -habitrpg.controller("AdminCtrl", ['$scope', '$rootScope', 'User', 'Members', 'Notification', - function($scope, $rootScope, User, Members, Notification) { +habitrpg.controller("AdminCtrl", ['$scope', '$rootScope', 'User', 'Notification', 'API_URL', '$resource', + function($scope, $rootScope, User, Notification, API_URL, $resource) { + var Contributor = $resource(API_URL + '/api/v1/admin/members/:uid', {uid:'@_id'}); + $scope.profile = undefined; $scope.loadUser = function(uuid){ - $scope.profile = Members.Member.get({uid:uuid}); + $scope.profile = Contributor.get({uid:uuid}); } $scope.save = function(profile) { profile.$save(function(){ @@ -13,4 +15,5 @@ habitrpg.controller("AdminCtrl", ['$scope', '$rootScope', 'User', 'Members', 'No $scope._uuid = undefined; }) } + $scope.contributors = Contributor.query(); }]) \ No newline at end of file diff --git a/src/controllers/admin.js b/src/controllers/admin.js new file mode 100644 index 0000000000..3d38243c25 --- /dev/null +++ b/src/controllers/admin.js @@ -0,0 +1,56 @@ +var _ = require('lodash'); +var nconf = require('nconf'); +var async = require('async'); +var algos = require('habitrpg-shared/script/algos'); +var helpers = require('habitrpg-shared/script/helpers'); +var items = require('habitrpg-shared/script/items'); +var User = require('./../models/user').model; +var Group = require('./../models/group').model; +var api = module.exports; + +api.ensureAdmin = function(req, res, next) { + var user = res.locals.user; + if (!(user.contributor && user.contributor.admin)) return res.json(401, {err:"You don't have admin access"}); + next(); +} + +api.getMember = function(req, res) { + User.findById(req.params.uid) + .select('contributor balance profile.name') + .exec(function(err, user){ + if (err) return res.json(500,{err:err}); + if (!user) return res.json(400,{err:'User not found'}); + res.json(user); + }); +} + +api.listMembers = function(req, res) { + User.find({'contributor.level':{$exists:true}}) + .select('contributor balance profile.name') + .sort('contributor.text') + .exec(function(err, users){ + if (err) return res.json(500,{err:err}); + res.json(users); + }); +} + +api.updateMember = function(req, res) { + async.waterfall([ + function(cb){ + User.findById(req.params.uid, cb); + }, + function(member, cb){ + if (!member) return res.json(404, {err: "User not found"}); + if (req.body.contributor.level > (member.contributor && member.contributor.level || 0)) { + member.flags.contributor = true; + member.balance += (req.body.contributor.level - (member.contributor.level || 0))*.5 // +2 gems per tier + } + _.merge(member, _.pick(req.body, 'contributor')); + if (member.contributor.level >= 6) member.items.pets['Dragon-Hydra'] = 5; + member.save(cb); + } + ], function(err, saved){ + if (err) return res.json(500,{err:err}); + res.json(204); + }) +} \ No newline at end of file diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 2278a9a998..bf4e2db89d 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -17,7 +17,7 @@ var api = module.exports; */ var itemFields = 'items.armor items.head items.shield items.weapon items.currentPet items.pets'; // TODO just send down count(items.pets) for better performance -var partyFields = 'profile preferences stats achievements party backer contributor balance flags.rest auth.timestamps ' + itemFields; +var partyFields = 'profile preferences stats achievements party backer contributor flags.rest auth.timestamps ' + itemFields; var nameFields = 'profile.name'; var challengeFields = '_id name'; var guildPopulate = {path: 'members', select: nameFields, options: {limit: 15} }; @@ -46,29 +46,6 @@ api.getMember = function(req, res) { }) } -api.updateMember = function(req, res) { - var user = res.locals.user; - if (!(user.contributor && user.contributor.admin)) return res.json(401, {err:"You don't have access to save this user"}); - async.waterfall([ - function(cb){ - User.findById(req.params.uid, cb); - }, - function(member, cb){ - if (!member) return res.json(404, {err: "User not found"}); - if (req.body.contributor.level > (member.contributor && member.contributor.level || 0)) { - member.flags.contributor = true; - member.balance += (req.body.contributor.level - (member.contributor.level || 0))*.5 // +2 gems per tier - } - _.merge(member, _.pick(req.body, 'contributor')); - if (member.contributor.level >= 6) member.items.pets['Dragon-Hydra'] = 5; - member.save(cb); - } - ], function(err, saved){ - if (err) return res.json(500,{err:err}); - res.json(204); - }) -} - /** * Fetch groups list. This no longer returns party or tavern, as those can be requested indivdually * as /groups/party or /groups/tavern diff --git a/src/models/user.js b/src/models/user.js index 3809eac2f5..f1ac9ea5e5 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -71,6 +71,7 @@ var UserSchema = new Schema({ level: Number, // 1-7, see https://trello.com/c/wkFzONhE/277-contributor-gear admin: Boolean, text: String, // Artisan, Friend, Blacksmith, etc + contributions: String // a markdown textarea to list their contributions + links }, balance: Number, diff --git a/src/routes/api.js b/src/routes/api.js index 4eaaa796c2..cdee266826 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -3,6 +3,7 @@ var router = new express.Router(); var user = require('../controllers/user'); var groups = require('../controllers/groups'); var auth = require('../controllers/auth'); +var admin = require('../controllers/admin'); var challenges = require('../controllers/challenges'); var dataexport = require('../controllers/dataexport'); var nconf = require('nconf'); @@ -84,7 +85,11 @@ router["delete"]('/groups/:gid/chat/:messageId', auth.auth, groups.attachGroup, /* Members */ router.get('/members/:uid', groups.getMember); -router.post('/members/:uid', auth.auth, groups.updateMember); // only for admins + +/* Admin */ +router.get('/admin/members', auth.auth, admin.ensureAdmin, admin.listMembers); +router.get('/admin/members/:uid', auth.auth, admin.ensureAdmin, admin.getMember); +router.post('/admin/members/:uid', auth.auth, admin.ensureAdmin, admin.updateMember); // Market router.post('/market/buy', auth.auth, user.marketBuy); diff --git a/views/options/admin.jade b/views/options/admin.jade index e53f537161..4a2b0b7fcd 100644 --- a/views/options/admin.jade +++ b/views/options/admin.jade @@ -1,4 +1,5 @@ script(id='partials/options.admin.html', type="text/ng-template") + h2 Reward User form.form-horizontal(ng-submit='loadUser(_uuid)') .-options .option-group.option-large @@ -6,7 +7,6 @@ script(id='partials/options.admin.html', type="text/ng-template") button.btn(type='submit') Load User form.form-horizontal(ng-show='profile', ng-submit='save(profile)') h3 {{profile.profile.name}} - h4 Contributor Status .-options .control-group.option-large input.option-content(type='text', ng-model='profile.contributor.text', placeholder='Contributor Title (eg, "Blacksmith")') @@ -16,10 +16,36 @@ script(id='partials/options.admin.html', type="text/ng-template") br small [1-7] this determines which items, pets, and mounts are available. Also determines name-tag coloring.  a(target='_blank', href='https://trello.com/c/wkFzONhE/277-contributor-gear') More details. + .control-group.option-large + textarea.option-content(style='height:15em;', placeholder='Contributions', ng-model='profile.contributor.contributions') + include ../shared/formatting-help .control-group.option-medium label.checkbox input(type='checkbox', ng-model='profile.contributor.admin') | Admin // h4 Backer Status // Add backer stuff like tier, disable adds, etcs - button.btn-primary(type='submit') Save \ No newline at end of file + button.btn-primary(type='submit') Save + + br + br + br + h2 Current Contributors + table.table.table-striped + tr + thead + tr + th Name + th UUID + th Contrib Level + th Title + th Admin + th Contributions + tr(ng-repeat='contrib in contributors') + td + a.label(class='label-contributor-{{contrib.contributor.level}}', ng-click='clickMember(contrib._id, true)') {{contrib.profile.name}} + td {{contrib._id}} + td {{contrib.contributor.level}} + td {{contrib.contributor.text}} + td {{contrib.contributor.admin}} + td {{contrib.contributor.contributions}} \ No newline at end of file