mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-19 07:37:25 +01:00
admin: add list of contributors. Add contributor.contributions, textarea for links of contributions for tracking. move all admin stuff to dedicated controller & routes
This commit is contained in:
@@ -1,10 +1,12 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
habitrpg.controller("AdminCtrl", ['$scope', '$rootScope', 'User', 'Members', 'Notification',
|
habitrpg.controller("AdminCtrl", ['$scope', '$rootScope', 'User', 'Notification', 'API_URL', '$resource',
|
||||||
function($scope, $rootScope, User, Members, Notification) {
|
function($scope, $rootScope, User, Notification, API_URL, $resource) {
|
||||||
|
var Contributor = $resource(API_URL + '/api/v1/admin/members/:uid', {uid:'@_id'});
|
||||||
|
|
||||||
$scope.profile = undefined;
|
$scope.profile = undefined;
|
||||||
$scope.loadUser = function(uuid){
|
$scope.loadUser = function(uuid){
|
||||||
$scope.profile = Members.Member.get({uid:uuid});
|
$scope.profile = Contributor.get({uid:uuid});
|
||||||
}
|
}
|
||||||
$scope.save = function(profile) {
|
$scope.save = function(profile) {
|
||||||
profile.$save(function(){
|
profile.$save(function(){
|
||||||
@@ -13,4 +15,5 @@ habitrpg.controller("AdminCtrl", ['$scope', '$rootScope', 'User', 'Members', 'No
|
|||||||
$scope._uuid = undefined;
|
$scope._uuid = undefined;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
$scope.contributors = Contributor.query();
|
||||||
}])
|
}])
|
||||||
56
src/controllers/admin.js
Normal file
56
src/controllers/admin.js
Normal file
@@ -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);
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -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 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 nameFields = 'profile.name';
|
||||||
var challengeFields = '_id name';
|
var challengeFields = '_id name';
|
||||||
var guildPopulate = {path: 'members', select: nameFields, options: {limit: 15} };
|
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
|
* Fetch groups list. This no longer returns party or tavern, as those can be requested indivdually
|
||||||
* as /groups/party or /groups/tavern
|
* as /groups/party or /groups/tavern
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ var UserSchema = new Schema({
|
|||||||
level: Number, // 1-7, see https://trello.com/c/wkFzONhE/277-contributor-gear
|
level: Number, // 1-7, see https://trello.com/c/wkFzONhE/277-contributor-gear
|
||||||
admin: Boolean,
|
admin: Boolean,
|
||||||
text: String, // Artisan, Friend, Blacksmith, etc
|
text: String, // Artisan, Friend, Blacksmith, etc
|
||||||
|
contributions: String // a markdown textarea to list their contributions + links
|
||||||
},
|
},
|
||||||
|
|
||||||
balance: Number,
|
balance: Number,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ var router = new express.Router();
|
|||||||
var user = require('../controllers/user');
|
var user = require('../controllers/user');
|
||||||
var groups = require('../controllers/groups');
|
var groups = require('../controllers/groups');
|
||||||
var auth = require('../controllers/auth');
|
var auth = require('../controllers/auth');
|
||||||
|
var admin = require('../controllers/admin');
|
||||||
var challenges = require('../controllers/challenges');
|
var challenges = require('../controllers/challenges');
|
||||||
var dataexport = require('../controllers/dataexport');
|
var dataexport = require('../controllers/dataexport');
|
||||||
var nconf = require('nconf');
|
var nconf = require('nconf');
|
||||||
@@ -84,7 +85,11 @@ router["delete"]('/groups/:gid/chat/:messageId', auth.auth, groups.attachGroup,
|
|||||||
|
|
||||||
/* Members */
|
/* Members */
|
||||||
router.get('/members/:uid', groups.getMember);
|
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
|
// Market
|
||||||
router.post('/market/buy', auth.auth, user.marketBuy);
|
router.post('/market/buy', auth.auth, user.marketBuy);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
script(id='partials/options.admin.html', type="text/ng-template")
|
script(id='partials/options.admin.html', type="text/ng-template")
|
||||||
|
h2 Reward User
|
||||||
form.form-horizontal(ng-submit='loadUser(_uuid)')
|
form.form-horizontal(ng-submit='loadUser(_uuid)')
|
||||||
.-options
|
.-options
|
||||||
.option-group.option-large
|
.option-group.option-large
|
||||||
@@ -6,7 +7,6 @@ script(id='partials/options.admin.html', type="text/ng-template")
|
|||||||
button.btn(type='submit') Load User
|
button.btn(type='submit') Load User
|
||||||
form.form-horizontal(ng-show='profile', ng-submit='save(profile)')
|
form.form-horizontal(ng-show='profile', ng-submit='save(profile)')
|
||||||
h3 {{profile.profile.name}}
|
h3 {{profile.profile.name}}
|
||||||
h4 Contributor Status
|
|
||||||
.-options
|
.-options
|
||||||
.control-group.option-large
|
.control-group.option-large
|
||||||
input.option-content(type='text', ng-model='profile.contributor.text', placeholder='Contributor Title (eg, "Blacksmith")')
|
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
|
br
|
||||||
small [1-7] this determines which items, pets, and mounts are available. Also determines name-tag coloring.
|
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.
|
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
|
.control-group.option-medium
|
||||||
label.checkbox
|
label.checkbox
|
||||||
input(type='checkbox', ng-model='profile.contributor.admin')
|
input(type='checkbox', ng-model='profile.contributor.admin')
|
||||||
| Admin
|
| Admin
|
||||||
// h4 Backer Status
|
// h4 Backer Status
|
||||||
// Add backer stuff like tier, disable adds, etcs
|
// Add backer stuff like tier, disable adds, etcs
|
||||||
button.btn-primary(type='submit') Save
|
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}}
|
||||||
Reference in New Issue
Block a user