Bug 1021762 - Update wm.org to use isSuperMentor, not isCollaborator
This commit is contained in:
Родитель
1ca9e9c93c
Коммит
35e77abdcf
|
@ -6,7 +6,8 @@
|
|||
"require": true,
|
||||
"console": true,
|
||||
"$": true,
|
||||
"angular": true
|
||||
"angular": true,
|
||||
"window": true
|
||||
},
|
||||
"bitwise": true,
|
||||
"curly": true,
|
||||
|
|
|
@ -111,14 +111,14 @@ module.exports = function (grunt) {
|
|||
mangle: false
|
||||
},
|
||||
files: {
|
||||
'public/compiled/app.min.js': ['public/js/angular/**/*.js']
|
||||
'public/compiled/app.min.js': ['public/js/angular/**/*.js', 'lib/badges-permissions-model.js']
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
angular: {
|
||||
files: ['public/js/angular/**/*.js'],
|
||||
files: ['public/js/angular/**/*.js', 'lib/badges-permissions-model.js'],
|
||||
tasks: ['uglify:app'],
|
||||
options: {
|
||||
spawn: false
|
||||
|
|
31
app.js
31
app.js
|
@ -305,10 +305,18 @@ app.use(function (err, req, res, next) {
|
|||
code: http.STATUS_CODES[err.status] ? err.status : 500
|
||||
};
|
||||
|
||||
console.error(err);
|
||||
console.error(err, err.stack);
|
||||
|
||||
res.status(error.code);
|
||||
res.render('error.html', error);
|
||||
res.format({
|
||||
'text/html': function () {
|
||||
res.render('error.html', error);
|
||||
},
|
||||
'application/json': function () {
|
||||
res.send(err.message);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
var middleware = require("./lib/middleware");
|
||||
|
@ -328,10 +336,6 @@ app.get('/', routes.angular);
|
|||
if (env.get('FLAGS_EXPLORE')) {
|
||||
app.get('/explore', routes.angular);
|
||||
app.get('/resources/:section?/:competency?', routes.angular);
|
||||
// Badges admin
|
||||
app.get('/admin/badges', middleware.checkAdmin, routes.angular);
|
||||
app.get('/admin/badges/:badge', middleware.checkAdmin, routes.angular);
|
||||
|
||||
} else {
|
||||
app.get("/resources", routes.gallery({
|
||||
layout: "starterMakes",
|
||||
|
@ -363,18 +367,21 @@ app.get("/privacy-makes", routes.gallery({
|
|||
// Initialize badges routes
|
||||
var badgesRoutes = routes.badges(env);
|
||||
|
||||
// Badge detail
|
||||
// Badge pages
|
||||
app.get("/badges/:badge?", badgesRoutes.details);
|
||||
// Badges admin
|
||||
app.get('/admin/badges', badgesRoutes.middleware.atleast('isMentor'), routes.angular);
|
||||
app.get('/admin/badges/:badge', badgesRoutes.middleware.hasPermissions('viewInstances'), routes.angular);
|
||||
|
||||
// Badges API
|
||||
app.get("/api/badges", badgesRoutes.getAll);
|
||||
app.post("/api/badges/:badge/apply", badgesRoutes.apply);
|
||||
app.post("/api/badges/:badge/claim", badgesRoutes.claim);
|
||||
app.post("/api/badges/:badge/issue", badgesRoutes.issue);
|
||||
app.get("/api/badges/:badge/instances", middleware.checkAdmin, badgesRoutes.getInstances);
|
||||
app.get("/api/badges/:badge/applications", badgesRoutes.getApplications);
|
||||
app.post("/api/badges/:badge/applications/:application/review", badgesRoutes.submitReview);
|
||||
app.delete("/api/badges/:badge/instance/email/:email", middleware.checkAdmin, badgesRoutes.deleteInstance);
|
||||
app.post("/api/badges/:badge/issue", badgesRoutes.middleware.hasPermissions('issue'), badgesRoutes.issue);
|
||||
app.get("/api/badges/:badge/instances", badgesRoutes.middleware.hasPermissions('viewInstances'), badgesRoutes.getInstances);
|
||||
app.get("/api/badges/:badge/applications", badgesRoutes.middleware.hasPermissions('applications'), badgesRoutes.getApplications);
|
||||
app.post("/api/badges/:badge/applications/:application/review", badgesRoutes.middleware.hasPermissions('applications'), badgesRoutes.submitReview);
|
||||
app.delete("/api/badges/:badge/instance/email/:email", badgesRoutes.middleware.hasPermissions('delete'), badgesRoutes.deleteInstance);
|
||||
|
||||
app.post("/api/submit-resource", routes.api.submitResource);
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
// Takes an options object with badge, action, and user
|
||||
// Returns true or false depending on if that user has permissions
|
||||
var module = module || undefined;
|
||||
|
||||
(function (module) {
|
||||
|
||||
var permissionsModel = function (options) {
|
||||
var permissions = {
|
||||
'webmaker-super-mentor': {
|
||||
'issue': 3,
|
||||
'applications': 3,
|
||||
'viewInstances': 3,
|
||||
'delete': 3
|
||||
},
|
||||
'webmaker-mentor': {
|
||||
'issue': 2,
|
||||
'applications': 2,
|
||||
'viewInstances': 2,
|
||||
'delete': 3
|
||||
},
|
||||
'*': {
|
||||
'issue': 1,
|
||||
'applications': 1,
|
||||
'viewInstances': 1,
|
||||
'delete': 3
|
||||
}
|
||||
};
|
||||
|
||||
if (!options) {
|
||||
throw new Error('You must pass an options object into permissionsModel');
|
||||
}
|
||||
if (!options.badge || !options.action || !options.user) {
|
||||
throw new Error('You must pass an options object with badge, action, and user into permissionsModel');
|
||||
}
|
||||
var badge = options.badge;
|
||||
var user = options.user;
|
||||
var action = options.action;
|
||||
|
||||
// Set highest level
|
||||
var level;
|
||||
if (user.isAdmin) {
|
||||
level = 3;
|
||||
} else if (user.isSuperMentor) {
|
||||
level = 2;
|
||||
} else if (user.isMentor) {
|
||||
level = 1;
|
||||
} else {
|
||||
level = 0;
|
||||
}
|
||||
|
||||
// Get badge model, if it exists
|
||||
var badgeModel = permissions[badge] || permissions['*'];
|
||||
|
||||
// Check action
|
||||
if (level >= badgeModel[action]) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Depending on the environment we need to export our "Make" object differently.
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = permissionsModel;
|
||||
} else {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(function () {
|
||||
return permissionsModel;
|
||||
});
|
||||
} else {
|
||||
window.badgesPermissionsModel = permissionsModel;
|
||||
}
|
||||
}
|
||||
}(module));
|
|
@ -32,8 +32,7 @@
|
|||
"id": "badges-admin",
|
||||
"title": "Badges Admin",
|
||||
"url": "admin/badges",
|
||||
"flag": "badges",
|
||||
"adminOnly": "true"
|
||||
"flag": "badges"
|
||||
},
|
||||
{
|
||||
"id": "search",
|
||||
|
|
|
@ -33,8 +33,7 @@ angular
|
|||
{
|
||||
id: 'badges-admin',
|
||||
title: 'Badges Admin',
|
||||
url: 'admin/badges',
|
||||
adminOnly: true
|
||||
url: 'admin/badges'
|
||||
},
|
||||
{
|
||||
id: 'search',
|
||||
|
@ -211,12 +210,19 @@ angular
|
|||
$scope.literacies = weblit.all();
|
||||
}
|
||||
])
|
||||
.controller('badgesAdminController', ['$scope', '$http', 'wmNav',
|
||||
function ($scope, $http, wmNav) {
|
||||
.controller('badgesAdminController', ['$scope', '$http', '$rootScope', 'wmNav',
|
||||
function ($scope, $http, $rootScope, wmNav) {
|
||||
wmNav.page('badges-admin');
|
||||
wmNav.section('explore');
|
||||
|
||||
$scope.badges = [];
|
||||
$scope.hasPermissions = function (badge) {
|
||||
return window.badgesPermissionsModel({
|
||||
badge: badge,
|
||||
user: $rootScope._user,
|
||||
action: 'applications'
|
||||
});
|
||||
};
|
||||
|
||||
$http
|
||||
.get('/api/badges')
|
||||
|
@ -252,6 +258,7 @@ angular
|
|||
.success(function (data) {
|
||||
$scope.badgesError = false;
|
||||
$scope.instances.unshift(data);
|
||||
$scope.issueEmail = '';
|
||||
})
|
||||
.error(onError);
|
||||
};
|
||||
|
@ -295,6 +302,11 @@ angular
|
|||
$scope.applications.splice(i, 1);
|
||||
}
|
||||
}
|
||||
if (review.decision === 'yes') {
|
||||
$scope.instances.unshift({
|
||||
email: review.email
|
||||
});
|
||||
}
|
||||
})
|
||||
.error(onError);
|
||||
});
|
||||
|
@ -321,7 +333,8 @@ angular
|
|||
|
||||
var ReviewApplicationController = function ($scope, $modalInstance, application) {
|
||||
$scope.review = {
|
||||
id: application.slug
|
||||
id: application.slug,
|
||||
email: application.learner
|
||||
};
|
||||
$scope.application = application;
|
||||
$scope.ok = function () {
|
||||
|
|
|
@ -47,7 +47,7 @@ angular
|
|||
|
||||
webmakerLoginService.on('newuser', function (assertion) {
|
||||
$modal.open({
|
||||
templateUrl: 'views/create-user-form.html',
|
||||
templateUrl: '/views/create-user-form.html',
|
||||
controller: createUserCtrl,
|
||||
resolve: {
|
||||
assertion: function () {
|
||||
|
|
|
@ -48,7 +48,9 @@
|
|||
<tbody>
|
||||
<tr ng-repeat="instance in instances">
|
||||
<td>{{ instance.email }}</td>
|
||||
<td class="text-right"><button class="btn btn-default" ng-click="revokeBadge(instance.email)"><span class="fa fa-times"></span><span class="sr-only">{{ "Revoke" | i18n }}</span></button></td>
|
||||
<td class="text-right">
|
||||
<button ng-if="_user.isAdmin" class="btn btn-default" ng-click="revokeBadge(instance.email)"><span class="fa fa-times"></span><span class="sr-only">{{ "Revoke" | i18n }}</span></button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</hgroup>
|
||||
<div>
|
||||
<div ng-repeat="badge in badges" class="row badge-row-admin">
|
||||
<a href="{{ baseUrl }}admin/badges/{{ badge.slug }}">
|
||||
<a ng-if="hasPermissions(badge.slug)" href="{{ baseUrl }}admin/badges/{{ badge.slug }}">
|
||||
<div class="col-xs-4 col-sm-2">
|
||||
<img ng-src="{{ badge.imageUrl }}">
|
||||
</div>
|
||||
|
|
|
@ -14,7 +14,11 @@
|
|||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown" ng-cloak ng-show="_user.email">
|
||||
<a class="navbar-user-info dropdown-toggle">
|
||||
<img class="user-info-avatar" ng-src="{{_user.avatar}}"> {{ 'Hi' | i18n }} <strong>{{_user.username}}</strong> <span class="label label-primary" ng-show="_user.isAdmin">admin</span> <span class="caret"></span>
|
||||
<img class="user-info-avatar" ng-src="{{_user.avatar}}"> {{ 'Hi' | i18n }} <strong>{{_user.username}}</strong>
|
||||
<span class="label label-primary" ng-show="_user.isAdmin">admin</span>
|
||||
<span class="label label-info" ng-show="!_user.isAdmin && _user.isSuperMentor">supermentor</span>
|
||||
<span class="label label-warning" ng-show="!_user.isAdmin && !_user.isSuperMentor && _user.isMentor">mentor</span>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="/me" target="_blank"><span class="fa fa-th-large"></span> {{ 'My makes' | i18n }}</a></li>
|
||||
|
|
|
@ -2,20 +2,75 @@ var BadgeClient = require('badgekit-api-client');
|
|||
|
||||
module.exports = function (env) {
|
||||
|
||||
// Error messages
|
||||
var errorHandlers = {
|
||||
unauthorized: function () {
|
||||
var err = new Error('You must be logged in to access this area.');
|
||||
err.status = 401;
|
||||
return err;
|
||||
},
|
||||
forbidden: function () {
|
||||
var err = new Error('You are not authorized to access this area. If you think you are supposed to have permissions, try logging out and in again, or contact help@webmaker.org');
|
||||
err.status = 403;
|
||||
return err;
|
||||
}
|
||||
};
|
||||
|
||||
var badgeClient = new BadgeClient(env.get('BADGES_ENDPOINT'), {
|
||||
key: env.get('BADGES_KEY'),
|
||||
secret: env.get('BADGES_SECRET')
|
||||
});
|
||||
|
||||
function isAdminOrSuperMentor(req) {
|
||||
if (req.session.user && (req.session.user.isAdmin || req.session.user.isCollaborator)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
var permissionsModel = require('../lib/badges-permissions-model.js');
|
||||
|
||||
return {
|
||||
middleware: {
|
||||
// Check if a use has at least a certain level of permissions
|
||||
// Can be 'admin', 'superMentor' or 'mentor'
|
||||
atleast: function (level) {
|
||||
var levels = ['isAdmin', 'isSuperMentor', 'isMentor'];
|
||||
return function (req, res, next) {
|
||||
var user = req.session.user;
|
||||
if (!level || levels.indexOf(level) <= -1) {
|
||||
var err = new Error('There is a problem with the permissions model: ' + level + ' is not a valid type of user.');
|
||||
return next(err);
|
||||
} else if (!user) {
|
||||
return next(errorHandlers.unauthorized());
|
||||
} else if (user.isAdmin) {
|
||||
return next();
|
||||
} else if (level === 'isSuperMentor' && (user.isAdmin || user.isSuperMentor)) {
|
||||
return next();
|
||||
} else if (level === 'isMentor' && (user.isAdmin || user.isSuperMentor || user.isMentor)) {
|
||||
return next();
|
||||
} else {
|
||||
return next(errorHandlers.forbidden());
|
||||
}
|
||||
};
|
||||
},
|
||||
// Does this user have permissions to issue, approve applications, see instances?
|
||||
hasPermissions: function (action) {
|
||||
return function (req, res, next) {
|
||||
var user = req.session.user;
|
||||
|
||||
if (!user) {
|
||||
return next(errorHandlers.unauthorized());
|
||||
}
|
||||
|
||||
var allowed = permissionsModel({
|
||||
badge: req.params.badge,
|
||||
user: req.session.user,
|
||||
action: action
|
||||
});
|
||||
|
||||
if (!allowed) {
|
||||
return next(errorHandlers.forbidden());
|
||||
} else {
|
||||
return next();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
},
|
||||
getAll: function (req, res, next) {
|
||||
badgeClient.getBadges({
|
||||
system: env.get('BADGES_SYSTEM')
|
||||
|
@ -89,7 +144,7 @@ module.exports = function (env) {
|
|||
}
|
||||
|
||||
// Can the current user issue this badge?
|
||||
var canIssue = req.session.user && (req.session.user.isAdmin || (req.session.user.isCollaborator && data.slug !== 'webmaker-super-mentor'));
|
||||
var canIssue = req.session.user && (req.session.user.isAdmin || (req.session.user.isSuperMentor && data.slug !== 'webmaker-super-mentor'));
|
||||
|
||||
res.render('badge-detail.html', {
|
||||
page: req.params.badge,
|
||||
|
@ -121,18 +176,6 @@ module.exports = function (env) {
|
|||
},
|
||||
issue: function (req, res, next) {
|
||||
|
||||
if (!isAdminOrSuperMentor(req)) {
|
||||
return res.send(400, {
|
||||
error: 'Sorry, you must be an admin or collaborator to issue badges'
|
||||
});
|
||||
}
|
||||
|
||||
if (req.params.badge === 'webmaker-super-mentor' && !req.session.user.isAdmin) {
|
||||
return res.send(400, {
|
||||
error: 'Sorry, you cannot issue a super mentor badge directly. Please have your applicant apply instead.'
|
||||
});
|
||||
}
|
||||
|
||||
var query = {
|
||||
system: env.get('BADGES_SYSTEM'),
|
||||
email: req.body.email,
|
||||
|
@ -186,14 +229,6 @@ module.exports = function (env) {
|
|||
});
|
||||
},
|
||||
getApplications: function (req, res, next) {
|
||||
if (!req.session.user) {
|
||||
return res.send(401, 'You must be logged in view applications');
|
||||
}
|
||||
|
||||
if (!isAdminOrSuperMentor) {
|
||||
return res.send(403, 'You are not authorized to view applications');
|
||||
}
|
||||
|
||||
badgeClient.getApplications({
|
||||
system: env.get('BADGES_SYSTEM'),
|
||||
badge: req.params.badge
|
||||
|
@ -229,7 +264,6 @@ module.exports = function (env) {
|
|||
reviewItems: req.body.reviewItems
|
||||
}
|
||||
};
|
||||
console.log(context, req.body.reviewItems);
|
||||
badgeClient.addReview(context, function (err, review) {
|
||||
if (err) {
|
||||
return res.send(500, err.message);
|
||||
|
@ -238,5 +272,4 @@ module.exports = function (env) {
|
|||
});
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче