diff --git a/public/js/app.js b/public/js/app.js index 2e6b74e018..cdb890c820 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -146,6 +146,13 @@ window.habitrpg = angular.module('habitrpg', templateUrl: "partials/options.settings.html" }) + // Options > Settings + .state('options.admin', { + url: "/admin", + controller: 'AdminCtrl', + templateUrl: "partials/options.admin.html" + }) + var settings = JSON.parse(localStorage.getItem(STORAGE_SETTINGS_ID)); if (settings && settings.auth) { $httpProvider.defaults.headers.common['Content-Type'] = 'application/json;charset=utf-8'; diff --git a/public/js/controllers/adminCtrl.js b/public/js/controllers/adminCtrl.js new file mode 100644 index 0000000000..33059d5d86 --- /dev/null +++ b/public/js/controllers/adminCtrl.js @@ -0,0 +1,16 @@ +"use strict"; + +habitrpg.controller("AdminCtrl", ['$scope', '$rootScope', 'User', 'Members', 'Notification', + function($scope, $rootScope, User, Members, Notification) { + $scope.profile = undefined; + $scope.loadUser = function(uuid){ + $scope.profile = Members.Member.get({uid:uuid}); + } + $scope.save = function(profile) { + profile.$save(function(){ + Notification.text("User updated"); + $scope.profile = undefined; + $scope._uuid = undefined; + }) + } + }]) \ No newline at end of file diff --git a/public/js/services/memberServices.js b/public/js/services/memberServices.js index f969bb336c..3b375eca65 100644 --- a/public/js/services/memberServices.js +++ b/public/js/services/memberServices.js @@ -11,6 +11,8 @@ angular.module('memberServices', ['ngResource']). var Member = $resource(API_URL + '/api/v1/members/:uid', {uid:'@_id'}); var memberServices = { + Member: Member, + members: members, /** diff --git a/public/manifest.json b/public/manifest.json index f2540082fe..ee6d559b95 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -52,7 +52,8 @@ "js/controllers/inventoryCtrl.js", "js/controllers/marketCtrl.js", "js/controllers/footerCtrl.js", - "js/controllers/challengesCtrl.js" + "js/controllers/challengesCtrl.js", + "js/controllers/adminCtrl.js" ], "css": [ "bower_components/bootstrap/docs/assets/css/bootstrap.css", diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 39e62b330e..57ad9df379 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 flags.rest auth.timestamps ' + itemFields; +var partyFields = 'profile preferences stats achievements party backer contributor balance flags.rest auth.timestamps ' + itemFields; var nameFields = 'profile.name'; var challengeFields = '_id name'; var guildPopulate = {path: 'members', select: nameFields, options: {limit: 15} }; @@ -46,6 +46,24 @@ 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"}); + _.merge(member, _.pick(req.body, ['contributor', 'balance'])); + 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 f6af2060b1..eea15b64c1 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -54,12 +54,18 @@ var UserSchema = new Schema({ backer: { tier: Number, - admin: Boolean, + //admin: Boolean, // FIXME migrate to contributor.admin npc: String, - contributor: String, + //contributor: String, // FIXME migrate to contributor.text tokensApplied: Boolean }, + contributor: { + level: Number, // 1-7, see https://trello.com/c/wkFzONhE/277-contributor-gear + admin: Boolean, + text: String, // Artisan, Friend, Blacksmith, etc + }, + balance: Number, filters: {type: Schema.Types.Mixed, 'default': {}}, diff --git a/src/routes/api.js b/src/routes/api.js index 757ad4b8cd..6ee338f3f6 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -80,6 +80,7 @@ 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 // Market router.post('/market/buy', auth.auth, user.marketBuy); diff --git a/views/options/admin.jade b/views/options/admin.jade new file mode 100644 index 0000000000..aded591834 --- /dev/null +++ b/views/options/admin.jade @@ -0,0 +1,28 @@ +script(id='partials/options.admin.html', type="text/ng-template") + form.form-horizontal(ng-submit='loadUser(_uuid)') + .-options + .option-group.option-large + input.option-content(type='text', ng-model='_uuid', placeholder='UUID') + 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")') + .control-group.option-medium + input.option-content(type='number', step="any", ng-model='profile.contributor.level') + span.input-suffix Contrib Level + 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-medium + input.option-content(type='number', step="any", ng-model='profile.balance') + span.input-suffix $ (Gems/4) + .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 diff --git a/views/options/index.jade b/views/options/index.jade index e5a10f7865..7b987ce013 100644 --- a/views/options/index.jade +++ b/views/options/index.jade @@ -2,6 +2,7 @@ include ./profile include ./social/index include ./inventory/index include ./settings +include ./admin script(id='partials/options.html', type="text/ng-template") .grid @@ -26,6 +27,10 @@ script(id='partials/options.html', type="text/ng-template") a(ui-sref='options.settings') i.icon-wrench | Settings + li(ng-class="{ active: $state.includes('options.admin') }", ng-if='user.contributor.admin') + a(ui-sref='options.admin') + i.icon-cog + | Admin .tab-content .tab-pane.active