diff --git a/app/assets/javascripts/admin/controllers/admin_user_badges_controller.js b/app/assets/javascripts/admin/controllers/admin_user_badges_controller.js
new file mode 100644
index 00000000000..a534195a129
--- /dev/null
+++ b/app/assets/javascripts/admin/controllers/admin_user_badges_controller.js
@@ -0,0 +1,52 @@
+/**
+ This controller supports the interface for granting and revoking badges from
+ individual users.
+
+ @class AdminUserBadgesController
+ @extends Ember.ArrayController
+ @namespace Discourse
+ @module Discourse
+**/
+Discourse.AdminUserBadgesController = Ember.ArrayController.extend({
+ needs: ["adminUser"],
+ user: Em.computed.alias('controllers.adminUser'),
+ sortProperties: ['granted_at'],
+ sortAscending: false,
+
+ actions: {
+
+ /**
+ Grant the selected badge to the user.
+
+ @method grantBadge
+ @param {Integer} badgeId id of the badge we want to grant.
+ **/
+ grantBadge: function(badgeId) {
+ var self = this;
+ Discourse.UserBadge.grant(badgeId, this.get('user.username')).then(function(userBadge) {
+ self.pushObject(userBadge);
+ }, function() {
+ // Failure
+ bootbox.alert(I18n.t('generic_error'));
+ });
+ },
+
+ /**
+ Revoke the selected userBadge.
+
+ @method revokeBadge
+ @param {Discourse.UserBadge} userBadge the `Discourse.UserBadge` instance that needs to be revoked.
+ **/
+ revokeBadge: function(userBadge) {
+ var self = this;
+ return bootbox.confirm(I18n.t("admin.badges.revoke_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) {
+ if (result) {
+ userBadge.revoke().then(function() {
+ self.get('model').removeObject(userBadge);
+ });
+ }
+ });
+ }
+
+ }
+});
diff --git a/app/assets/javascripts/admin/routes/admin_routes.js b/app/assets/javascripts/admin/routes/admin_routes.js
index 21b2b38b6a6..1143df781ce 100644
--- a/app/assets/javascripts/admin/routes/admin_routes.js
+++ b/app/assets/javascripts/admin/routes/admin_routes.js
@@ -47,6 +47,7 @@ Discourse.Route.buildRoutes(function() {
this.resource('adminUsers', { path: '/users' }, function() {
this.resource('adminUser', { path: '/:username' }, function() {
+ this.route('badges');
this.route('leaderRequirements', { path: '/leader_requirements' });
});
this.resource('adminUsersList', { path: '/list' }, function() {
diff --git a/app/assets/javascripts/admin/routes/admin_user_badges_route.js b/app/assets/javascripts/admin/routes/admin_user_badges_route.js
new file mode 100644
index 00000000000..b1184b3b12e
--- /dev/null
+++ b/app/assets/javascripts/admin/routes/admin_user_badges_route.js
@@ -0,0 +1,31 @@
+/**
+ Shows all of the badges that have been granted to a user, and allow granting and
+ revoking badges.
+
+ @class AdminUserBadgesRoute
+ @extends Discourse.Route
+ @namespace Discourse
+ @module Discourse
+**/
+Discourse.AdminUserBadgesRoute = Discourse.Route.extend({
+ model: function() {
+ var username = this.controllerFor('adminUser').get('username');
+ return Discourse.UserBadge.findByUsername(username);
+ },
+
+ setupController: function(controller, model) {
+ // Find all badges.
+ controller.set('loading', true);
+ Discourse.Badge.findAll().then(function(badges) {
+ controller.set('badges', badges);
+ if (badges.length > 0) {
+ controller.set('selectedBadgeId', badges[0].get('id'));
+ } else {
+ controller.set('noBadges', true);
+ }
+ controller.set('loading', false);
+ });
+ // Set the model.
+ controller.set('model', model);
+ }
+});
diff --git a/app/assets/javascripts/admin/templates/user_badges.js.handlebars b/app/assets/javascripts/admin/templates/user_badges.js.handlebars
new file mode 100644
index 00000000000..aec5a82889f
--- /dev/null
+++ b/app/assets/javascripts/admin/templates/user_badges.js.handlebars
@@ -0,0 +1,61 @@
+
+
+
+ - {{#link-to 'adminUser' user}} {{user.username}}{{/link-to}}
+
+
+
+
+{{#if loading}}
+ {{i18n loading}}
+{{else}}
+
+
{{i18n admin.badges.grant_badge}}
+ {{#if noBadges}}
+
{{i18n admin.badges.no_badges}}
+ {{else}}
+
+ {{combobox valueAttribute="id" value=controller.selectedBadgeId content=controller.badges}}
+
+ {{/if}}
+
+
+
+
+
{{i18n admin.badges.granted_badges}}
+
+
+
+
+ {{i18n admin.badges.name}} |
+ {{i18n admin.badges.badge_type}} |
+ {{i18n admin.badges.granted_by}} |
+ {{i18n admin.badges.granted_at}} |
+ |
+
+
+ {{#each}}
+
+ {{badge.displayName}} |
+ {{badge.badge_type.name}} |
+
+ {{#link-to 'adminUser' badge.granted_by}}
+ {{avatar granted_by imageSize="tiny"}}
+ {{granted_by.username}}
+ {{/link-to}}
+ |
+ {{unboundAgeWithTooltip granted_at}} |
+
+
+ |
+
+ {{else}}
+
+
+ {{i18n admin.badges.no_user_badges name=user.username}}
+ |
+
+ {{/each}}
+
+
+{{/if}}
diff --git a/app/assets/javascripts/admin/templates/user_index.js.handlebars b/app/assets/javascripts/admin/templates/user_index.js.handlebars
index 8af5cd2c5f3..53c731de8ef 100644
--- a/app/assets/javascripts/admin/templates/user_index.js.handlebars
+++ b/app/assets/javascripts/admin/templates/user_index.js.handlebars
@@ -77,6 +77,18 @@
+ {{#if showBadges}}
+
+
{{i18n admin.badges.title}}
+
+ TODO featured badges
+
+
+ {{#link-to 'adminUser.badges' this class="btn"}}{{i18n admin.badges.edit_badges}}{{/link-to}}
+
+
+ {{/if}}
+
@@ -336,12 +348,6 @@
-{{#if showBadges}}
-
- {{i18n admin.badges.title}}
-
-{{/if}}
-