Bug 1021762 - Update wm.org to use isSuperMentor, not isCollaborator

This commit is contained in:
Kate Hudson 2014-06-11 17:57:08 -04:00
Родитель 1ca9e9c93c
Коммит 35e77abdcf
11 изменённых файлов: 190 добавлений и 56 удалений

Просмотреть файл

@ -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
Просмотреть файл

@ -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",

23
public/js/angular/controllers.js поставляемый
Просмотреть файл

@ -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 () {

2
public/js/angular/webmaker-login.js поставляемый
Просмотреть файл

@ -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) {
});
}
};
};