From abd9b26642e477898041be1182e9b33256df1964 Mon Sep 17 00:00:00 2001
From: Robin Ward <robin.ward@gmail.com>
Date: Tue, 18 Aug 2015 21:24:09 -0400
Subject: [PATCH] Convert Badges / User Badges to ES6.

---
 Gemfile.lock                                  |  3 --
 .../controllers/admin-user-badges.js.es6      | 10 ++--
 .../admin/routes/admin-badges-show.js.es6     |  3 +-
 .../admin/routes/admin-badges.js.es6          |  4 +-
 .../admin/routes/admin-user-badges.js.es6     | 26 +++++++++
 .../admin/routes/admin_user_badges_route.js   | 32 -----------
 app/assets/javascripts/discourse.js           |  3 --
 .../discourse/controllers/badges/show.js.es6  |  4 +-
 .../mixins/badge-select-controller.js.es6     | 10 ++--
 .../discourse/models/badge-grouping.js.es6    | 16 ++++++
 .../models/{badge.js => badge.js.es6}         | 53 ++++++++-----------
 .../discourse/models/badge_grouping.js        | 10 ----
 .../{user_badge.js => user-badge.js.es6}      | 22 +++-----
 .../javascripts/discourse/models/user.js.es6  |  8 +--
 .../discourse/routes/badges-index.js.es6      |  6 ++-
 .../discourse/routes/badges-show.js.es6       |  9 ++--
 ...ute.js.es6 => discovery-categories.js.es6} |  4 +-
 .../routes/preferences-badge-title.js.es6     |  3 +-
 .../routes/preferences-card-badge.js.es6      |  3 +-
 .../discourse/routes/user-badges.js.es6       |  3 +-
 app/assets/javascripts/main_include.js        |  4 ++
 lib/discourse_plugin_registry.rb              |  4 +-
 .../controllers/admin-user-badges-test.js.es6 | 16 +++---
 test/javascripts/models/badge-test.js.es6     | 36 +++++++------
 .../javascripts/models/user-badge-test.js.es6 | 18 ++++---
 25 files changed, 156 insertions(+), 154 deletions(-)
 create mode 100644 app/assets/javascripts/admin/routes/admin-user-badges.js.es6
 delete mode 100644 app/assets/javascripts/admin/routes/admin_user_badges_route.js
 create mode 100644 app/assets/javascripts/discourse/models/badge-grouping.js.es6
 rename app/assets/javascripts/discourse/models/{badge.js => badge.js.es6} (83%)
 delete mode 100644 app/assets/javascripts/discourse/models/badge_grouping.js
 rename app/assets/javascripts/discourse/models/{user_badge.js => user-badge.js.es6} (86%)
 rename app/assets/javascripts/discourse/routes/{discovery-categories-route.js.es6 => discovery-categories.js.es6} (94%)

diff --git a/Gemfile.lock b/Gemfile.lock
index e5ed9c4b5..59aaea207 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -485,6 +485,3 @@ DEPENDENCIES
   uglifier
   unf
   unicorn
-
-BUNDLED WITH
-   1.10.6
diff --git a/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6 b/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6
index e66d82162..b85fbaf06 100644
--- a/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6
+++ b/app/assets/javascripts/admin/controllers/admin-user-badges.js.es6
@@ -1,3 +1,5 @@
+import UserBadge from 'discourse/models/user-badge';
+
 export default Ember.ArrayController.extend({
   needs: ["adminUser"],
   user: Em.computed.alias('controllers.adminUser.model'),
@@ -86,7 +88,7 @@ export default Ember.ArrayController.extend({
     **/
     grantBadge: function(badgeId) {
       var self = this;
-      Discourse.UserBadge.grant(badgeId, this.get('user.username'), this.get('badgeReason')).then(function(userBadge) {
+      UserBadge.grant(badgeId, this.get('user.username'), this.get('badgeReason')).then(function(userBadge) {
         self.set('badgeReason', '');
         self.pushObject(userBadge);
         Ember.run.next(function() {
@@ -102,12 +104,6 @@ export default Ember.ArrayController.extend({
       });
     },
 
-    /**
-      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) {
diff --git a/app/assets/javascripts/admin/routes/admin-badges-show.js.es6 b/app/assets/javascripts/admin/routes/admin-badges-show.js.es6
index 648730d9b..c283ff737 100644
--- a/app/assets/javascripts/admin/routes/admin-badges-show.js.es6
+++ b/app/assets/javascripts/admin/routes/admin-badges-show.js.es6
@@ -1,3 +1,4 @@
+import Badge from 'discourse/models/badge';
 import showModal from 'discourse/lib/show-modal';
 
 export default Ember.Route.extend({
@@ -7,7 +8,7 @@ export default Ember.Route.extend({
 
   model(params) {
     if (params.badge_id === "new") {
-      return Discourse.Badge.create({
+      return Badge.create({
         name: I18n.t('admin.badges.new_badge')
       });
     }
diff --git a/app/assets/javascripts/admin/routes/admin-badges.js.es6 b/app/assets/javascripts/admin/routes/admin-badges.js.es6
index 3d417f53c..592743766 100644
--- a/app/assets/javascripts/admin/routes/admin-badges.js.es6
+++ b/app/assets/javascripts/admin/routes/admin-badges.js.es6
@@ -1,3 +1,5 @@
+import Badge from 'discourse/models/badge';
+
 export default Discourse.Route.extend({
   _json: null,
 
@@ -5,7 +7,7 @@ export default Discourse.Route.extend({
     var self = this;
     return Discourse.ajax('/admin/badges.json').then(function(json) {
       self._json = json;
-      return Discourse.Badge.createFromJson(json);
+      return Badge.createFromJson(json);
     });
   },
 
diff --git a/app/assets/javascripts/admin/routes/admin-user-badges.js.es6 b/app/assets/javascripts/admin/routes/admin-user-badges.js.es6
new file mode 100644
index 000000000..205c1647c
--- /dev/null
+++ b/app/assets/javascripts/admin/routes/admin-user-badges.js.es6
@@ -0,0 +1,26 @@
+import UserBadge from 'discourse/models/user-badge';
+import Badge from 'discourse/models/badge';
+
+export default Discourse.Route.extend({
+  model() {
+    const username = this.modelFor('adminUser').get('username');
+    return UserBadge.findByUsername(username);
+  },
+
+  setupController(controller, model) {
+    // Find all badges.
+    controller.set('loading', true);
+    Badge.findAll().then(function(badges) {
+      controller.set('badges', badges);
+      if (badges.length > 0) {
+        var grantableBadges = controller.get('grantableBadges');
+        if (grantableBadges.length > 0) {
+          controller.set('selectedBadgeId', grantableBadges[0].get('id'));
+        }
+      }
+      controller.set('loading', false);
+    });
+    // Set the model.
+    controller.set('model', model);
+  }
+});
diff --git a/app/assets/javascripts/admin/routes/admin_user_badges_route.js b/app/assets/javascripts/admin/routes/admin_user_badges_route.js
deleted file mode 100644
index f681e6f91..000000000
--- a/app/assets/javascripts/admin/routes/admin_user_badges_route.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
-  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.modelFor('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) {
-        var grantableBadges = controller.get('grantableBadges');
-        if (grantableBadges.length > 0) {
-          controller.set('selectedBadgeId', grantableBadges[0].get('id'));
-        }
-      }
-      controller.set('loading', false);
-    });
-    // Set the model.
-    controller.set('model', model);
-  }
-});
diff --git a/app/assets/javascripts/discourse.js b/app/assets/javascripts/discourse.js
index 02b2bad07..e12c8243d 100644
--- a/app/assets/javascripts/discourse.js
+++ b/app/assets/javascripts/discourse.js
@@ -157,9 +157,6 @@ window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, {
   })
 });
 
-// TODO: Remove this, it is in for backwards compatibiltiy with plugins
-Discourse.HasCurrentUser = {};
-
 function proxyDep(propName, moduleFunc, msg) {
   if (Discourse.hasOwnProperty(propName)) { return; }
   Object.defineProperty(Discourse, propName, {
diff --git a/app/assets/javascripts/discourse/controllers/badges/show.js.es6 b/app/assets/javascripts/discourse/controllers/badges/show.js.es6
index 1083fd37f..a5a899f64 100644
--- a/app/assets/javascripts/discourse/controllers/badges/show.js.es6
+++ b/app/assets/javascripts/discourse/controllers/badges/show.js.es6
@@ -1,3 +1,5 @@
+import UserBadge from 'discourse/models/user-badge';
+
 export default Ember.Controller.extend({
   noMoreBadges: false,
   userBadges: null,
@@ -8,7 +10,7 @@ export default Ember.Controller.extend({
       const self = this;
       const userBadges = this.get('userBadges');
 
-      Discourse.UserBadge.findByBadgeId(this.get('model.id'), {
+      UserBadge.findByBadgeId(this.get('model.id'), {
         offset: userBadges.length
       }).then(function(result) {
         userBadges.pushObjects(result);
diff --git a/app/assets/javascripts/discourse/mixins/badge-select-controller.js.es6 b/app/assets/javascripts/discourse/mixins/badge-select-controller.js.es6
index ea800461e..5c57ffa42 100644
--- a/app/assets/javascripts/discourse/mixins/badge-select-controller.js.es6
+++ b/app/assets/javascripts/discourse/mixins/badge-select-controller.js.es6
@@ -1,12 +1,14 @@
+import Badge from 'discourse/models/badge';
+
 export default Ember.Mixin.create({
   saving: false,
   saved: false,
 
   selectableUserBadges: function() {
-    var items = this.get('filteredList');
+    let items = this.get('filteredList');
     items = _.uniq(items, false, function(e) { return e.get('badge.name'); });
     items.unshiftObject(Em.Object.create({
-      badge: Discourse.Badge.create({name: I18n.t('badges.none')})
+      badge: Badge.create({name: I18n.t('badges.none')})
     }));
     return items;
   }.property('filteredList'),
@@ -20,8 +22,8 @@ export default Ember.Mixin.create({
   }.property('saving'),
 
   selectedUserBadge: function() {
-    var selectedUserBadgeId = parseInt(this.get('selectedUserBadgeId'));
-    var selectedUserBadge = null;
+    const selectedUserBadgeId = parseInt(this.get('selectedUserBadgeId'));
+    let selectedUserBadge = null;
     this.get('selectableUserBadges').forEach(function(userBadge) {
       if (userBadge.get('id') === selectedUserBadgeId) {
         selectedUserBadge = userBadge;
diff --git a/app/assets/javascripts/discourse/models/badge-grouping.js.es6 b/app/assets/javascripts/discourse/models/badge-grouping.js.es6
new file mode 100644
index 000000000..605d4d6d2
--- /dev/null
+++ b/app/assets/javascripts/discourse/models/badge-grouping.js.es6
@@ -0,0 +1,16 @@
+import computed from 'ember-addons/ember-computed-decorators';
+import RestModel from 'discourse/models/rest';
+
+export default RestModel.extend({
+
+  @computed('name')
+  i18nNameKey() {
+    return this.get('name').toLowerCase().replace(/\s/g, '_');
+  },
+
+  @computed
+  displayName() {
+    const i18nKey = `badges.badge_grouping.${this.get('i18nNameKey')}.name`;
+    return I18n.t(i18nKey, {defaultValue: this.get('name')});
+  }
+});
diff --git a/app/assets/javascripts/discourse/models/badge.js b/app/assets/javascripts/discourse/models/badge.js.es6
similarity index 83%
rename from app/assets/javascripts/discourse/models/badge.js
rename to app/assets/javascripts/discourse/models/badge.js.es6
index 5ae1b6195..670a84111 100644
--- a/app/assets/javascripts/discourse/models/badge.js
+++ b/app/assets/javascripts/discourse/models/badge.js.es6
@@ -1,22 +1,12 @@
-/**
-  A data model representing a badge on Discourse
+import BadgeGrouping from 'discourse/models/badge-grouping';
+import RestModel from 'discourse/models/rest';
 
-  @class Badge
-  @extends Discourse.Model
-  @namespace Discourse
-  @module Discourse
-**/
-Discourse.Badge = Discourse.Model.extend({
-  /**
-    Is this a new badge?
+const Badge = RestModel.extend({
 
-    @property newBadge
-    @type {String}
-  **/
   newBadge: Em.computed.none('id'),
 
   hasQuery: function(){
-    var query = this.get('query');
+    const query = this.get('query');
     return query && query.trim().length > 0;
   }.property('query'),
 
@@ -40,7 +30,7 @@ Discourse.Badge = Discourse.Model.extend({
     @type {String}
   **/
   displayName: function() {
-    var i18nKey = "badges.badge." + this.get('i18nNameKey') + ".name";
+    const i18nKey = "badges.badge." + this.get('i18nNameKey') + ".name";
     return I18n.t(i18nKey, {defaultValue: this.get('name')});
   }.property('name', 'i18nNameKey'),
 
@@ -52,8 +42,8 @@ Discourse.Badge = Discourse.Model.extend({
     @type {String}
   **/
   translatedDescription: function() {
-    var i18nKey = "badges.badge." + this.get('i18nNameKey') + ".description",
-        translation = I18n.t(i18nKey);
+    const i18nKey = "badges.badge." + this.get('i18nNameKey') + ".description";
+    let translation = I18n.t(i18nKey);
     if (translation.indexOf(i18nKey) !== -1) {
       translation = null;
     }
@@ -73,7 +63,7 @@ Discourse.Badge = Discourse.Model.extend({
     @type {String}
   **/
   displayDescriptionHtml: function() {
-    var translated = this.get('translatedDescription');
+    const translated = this.get('translatedDescription');
     return (translated === null ? this.get('description') : translated) || "";
   }.property('description', 'translatedDescription'),
 
@@ -84,7 +74,7 @@ Discourse.Badge = Discourse.Model.extend({
     @param {Object} json The JSON response returned by the server
   **/
   updateFromJson: function(json) {
-    var self = this;
+    const self = this;
     if (json.badge) {
       Object.keys(json.badge).forEach(function(key) {
         self.set(key, json.badge[key]);
@@ -100,7 +90,7 @@ Discourse.Badge = Discourse.Model.extend({
   },
 
   badgeTypeClassName: function() {
-    var type = this.get('badge_type.name') || "";
+    const type = this.get('badge_type.name') || "";
     return "badge-type-" + type.toLowerCase();
   }.property('badge_type.name'),
 
@@ -111,9 +101,9 @@ Discourse.Badge = Discourse.Model.extend({
     @returns {Promise} A promise that resolves to the updated `Discourse.Badge`
   **/
   save: function(data) {
-    var url = "/admin/badges",
-        requestType = "POST",
-        self = this;
+    let url = "/admin/badges",
+        requestType = "POST";
+    const self = this;
 
     if (this.get('id')) {
       // We are updating an existing badge.
@@ -146,7 +136,7 @@ Discourse.Badge = Discourse.Model.extend({
   }
 });
 
-Discourse.Badge.reopenClass({
+Badge.reopenClass({
   /**
     Create `Discourse.Badge` instances from the server JSON response.
 
@@ -156,29 +146,29 @@ Discourse.Badge.reopenClass({
   **/
   createFromJson: function(json) {
     // Create BadgeType objects.
-    var badgeTypes = {};
+    const badgeTypes = {};
     if ('badge_types' in json) {
       json.badge_types.forEach(function(badgeTypeJson) {
         badgeTypes[badgeTypeJson.id] = Ember.Object.create(badgeTypeJson);
       });
     }
 
-    var badgeGroupings = {};
+    const badgeGroupings = {};
     if ('badge_groupings' in json) {
       json.badge_groupings.forEach(function(badgeGroupingJson) {
-        badgeGroupings[badgeGroupingJson.id] = Discourse.BadgeGrouping.create(badgeGroupingJson);
+        badgeGroupings[badgeGroupingJson.id] = BadgeGrouping.create(badgeGroupingJson);
       });
     }
 
     // Create Badge objects.
-    var badges = [];
+    let badges = [];
     if ("badge" in json) {
       badges = [json.badge];
     } else {
       badges = json.badges;
     }
     badges = badges.map(function(badgeJson) {
-      var badge = Discourse.Badge.create(badgeJson);
+      const badge = Discourse.Badge.create(badgeJson);
       badge.set('badge_type', badgeTypes[badge.get('badge_type_id')]);
       badge.set('badge_grouping', badgeGroupings[badge.get('badge_grouping_id')]);
       return badge;
@@ -198,7 +188,7 @@ Discourse.Badge.reopenClass({
     @returns {Promise} a promise that resolves to an array of `Discourse.Badge`
   **/
   findAll: function(opts) {
-    var listable = "";
+    let listable = "";
     if(opts && opts.onlyListable){
       listable = "?only_listable=true";
     }
@@ -220,3 +210,6 @@ Discourse.Badge.reopenClass({
     });
   }
 });
+
+export default Badge;
+
diff --git a/app/assets/javascripts/discourse/models/badge_grouping.js b/app/assets/javascripts/discourse/models/badge_grouping.js
deleted file mode 100644
index dd59d078f..000000000
--- a/app/assets/javascripts/discourse/models/badge_grouping.js
+++ /dev/null
@@ -1,10 +0,0 @@
-Discourse.BadgeGrouping= Discourse.Model.extend({
-  i18nNameKey: function() {
-    return this.get('name').toLowerCase().replace(/\s/g, '_');
-  }.property('name'),
-
-  displayName: function(){
-    var i18nKey = "badges.badge_grouping." + this.get('i18nNameKey') + ".name";
-    return I18n.t(i18nKey, {defaultValue: this.get('name')});
-  }.property()
-});
diff --git a/app/assets/javascripts/discourse/models/user_badge.js b/app/assets/javascripts/discourse/models/user-badge.js.es6
similarity index 86%
rename from app/assets/javascripts/discourse/models/user_badge.js
rename to app/assets/javascripts/discourse/models/user-badge.js.es6
index 158e70e46..f5e2209f9 100644
--- a/app/assets/javascripts/discourse/models/user_badge.js
+++ b/app/assets/javascripts/discourse/models/user-badge.js.es6
@@ -1,12 +1,6 @@
-/**
-  A data model representing a user badge grant on Discourse
+import Badge from 'discourse/models/badge';
 
-  @class UserBadge
-  @extends Discourse.Model
-  @namespace Discourse
-  @module Discourse
-**/
-Discourse.UserBadge = Discourse.Model.extend({
+const UserBadge = Discourse.Model.extend({
   postUrl: function() {
     if(this.get('topic_title')) {
       return "/t/-/" + this.get('topic_id') + "/" + this.get('post_number');
@@ -25,14 +19,8 @@ Discourse.UserBadge = Discourse.Model.extend({
   }
 });
 
-Discourse.UserBadge.reopenClass({
-  /**
-    Create `Discourse.UserBadge` instances from the server JSON response.
+UserBadge.reopenClass({
 
-    @method createFromJson
-    @param {Object} json The JSON returned by the server
-    @returns Array or instance of `Discourse.UserBadge` depending on the input JSON
-  **/
   createFromJson: function(json) {
     // Create User objects.
     if (json.users === undefined) { json.users = []; }
@@ -51,7 +39,7 @@ Discourse.UserBadge.reopenClass({
     // Create the badges.
     if (json.badges === undefined) { json.badges = []; }
     var badges = {};
-    Discourse.Badge.createFromJson(json).forEach(function(badge) {
+    Badge.createFromJson(json).forEach(function(badge) {
       badges[badge.get('id')] = badge;
     });
 
@@ -146,3 +134,5 @@ Discourse.UserBadge.reopenClass({
     });
   }
 });
+
+export default UserBadge;
diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6
index e270aaff7..079c50828 100644
--- a/app/assets/javascripts/discourse/models/user.js.es6
+++ b/app/assets/javascripts/discourse/models/user.js.es6
@@ -6,6 +6,8 @@ import UserPostsStream from 'discourse/models/user-posts-stream';
 import Singleton from 'discourse/mixins/singleton';
 import { longDate } from 'discourse/lib/formatter';
 import computed from 'ember-addons/ember-computed-decorators';
+import Badge from 'discourse/models/badge';
+import UserBadge from 'discourse/models/user-badge';
 
 const User = RestModel.extend({
 
@@ -299,8 +301,8 @@ const User = RestModel.extend({
       }
 
       if (!Em.isEmpty(json.user.featured_user_badge_ids)) {
-        var userBadgesMap = {};
-        Discourse.UserBadge.createFromJson(json).forEach(function(userBadge) {
+        const userBadgesMap = {};
+        UserBadge.createFromJson(json).forEach(function(userBadge) {
           userBadgesMap[ userBadge.get('id') ] = userBadge;
         });
         json.user.featured_user_badges = json.user.featured_user_badge_ids.map(function(id) {
@@ -309,7 +311,7 @@ const User = RestModel.extend({
       }
 
       if (json.user.card_badge) {
-        json.user.card_badge = Discourse.Badge.create(json.user.card_badge);
+        json.user.card_badge = Badge.create(json.user.card_badge);
       }
 
       user.setProperties(json.user);
diff --git a/app/assets/javascripts/discourse/routes/badges-index.js.es6 b/app/assets/javascripts/discourse/routes/badges-index.js.es6
index dfb207391..683033faa 100644
--- a/app/assets/javascripts/discourse/routes/badges-index.js.es6
+++ b/app/assets/javascripts/discourse/routes/badges-index.js.es6
@@ -1,9 +1,11 @@
+import Badge from 'discourse/models/badge';
+
 export default Discourse.Route.extend({
   model() {
     if (PreloadStore.get("badges")) {
-      return PreloadStore.getAndRemove("badges").then(json => Discourse.Badge.createFromJson(json));
+      return PreloadStore.getAndRemove("badges").then(json => Badge.createFromJson(json));
     } else {
-      return Discourse.Badge.findAll({ onlyListable: true });
+      return Badge.findAll({ onlyListable: true });
     }
   },
 
diff --git a/app/assets/javascripts/discourse/routes/badges-show.js.es6 b/app/assets/javascripts/discourse/routes/badges-show.js.es6
index cc4cf0eaa..5f835d76d 100644
--- a/app/assets/javascripts/discourse/routes/badges-show.js.es6
+++ b/app/assets/javascripts/discourse/routes/badges-show.js.es6
@@ -1,3 +1,6 @@
+import UserBadge from 'discourse/models/user-badge';
+import Badge from 'discourse/models/badge';
+
 export default Discourse.Route.extend({
   actions: {
     didTransition() {
@@ -15,14 +18,14 @@ export default Discourse.Route.extend({
 
   model(params) {
     if (PreloadStore.get("badge")) {
-      return PreloadStore.getAndRemove("badge").then(json => Discourse.Badge.createFromJson(json));
+      return PreloadStore.getAndRemove("badge").then(json => Badge.createFromJson(json));
     } else {
-      return Discourse.Badge.findById(params.id);
+      return Badge.findById(params.id);
     }
   },
 
   afterModel(model) {
-    return Discourse.UserBadge.findByBadgeId(model.get("id")).then(userBadges => {
+    return UserBadge.findByBadgeId(model.get("id")).then(userBadges => {
       this.userBadges = userBadges;
     });
   },
diff --git a/app/assets/javascripts/discourse/routes/discovery-categories-route.js.es6 b/app/assets/javascripts/discourse/routes/discovery-categories.js.es6
similarity index 94%
rename from app/assets/javascripts/discourse/routes/discovery-categories-route.js.es6
rename to app/assets/javascripts/discourse/routes/discovery-categories.js.es6
index 61fd853d1..5bbd7aa66 100644
--- a/app/assets/javascripts/discourse/routes/discovery-categories-route.js.es6
+++ b/app/assets/javascripts/discourse/routes/discovery-categories.js.es6
@@ -1,7 +1,7 @@
 import showModal from "discourse/lib/show-modal";
 import OpenComposer from "discourse/mixins/open-composer";
 
-Discourse.DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, {
+const DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, {
   renderTemplate() {
     this.render("navigation/categories", { outlet: "navigation-bar" });
     this.render("discovery/categories", { outlet: "list-container" });
@@ -67,4 +67,4 @@ Discourse.DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, {
   }
 });
 
-export default Discourse.DiscoveryCategoriesRoute;
+export default DiscoveryCategoriesRoute;
diff --git a/app/assets/javascripts/discourse/routes/preferences-badge-title.js.es6 b/app/assets/javascripts/discourse/routes/preferences-badge-title.js.es6
index 0c7a22d8b..141a852b9 100644
--- a/app/assets/javascripts/discourse/routes/preferences-badge-title.js.es6
+++ b/app/assets/javascripts/discourse/routes/preferences-badge-title.js.es6
@@ -1,8 +1,9 @@
+import UserBadge from 'discourse/models/badge';
 import RestrictedUserRoute from "discourse/routes/restricted-user";
 
 export default RestrictedUserRoute.extend({
   model: function() {
-    return Discourse.UserBadge.findByUsername(this.modelFor('user').get('username'));
+    return UserBadge.findByUsername(this.modelFor('user').get('username'));
   },
 
   renderTemplate: function() {
diff --git a/app/assets/javascripts/discourse/routes/preferences-card-badge.js.es6 b/app/assets/javascripts/discourse/routes/preferences-card-badge.js.es6
index 37ad604ec..8ec81a95d 100644
--- a/app/assets/javascripts/discourse/routes/preferences-card-badge.js.es6
+++ b/app/assets/javascripts/discourse/routes/preferences-card-badge.js.es6
@@ -1,8 +1,9 @@
+import UserBadge from 'discourse/models/user-badge';
 import RestrictedUserRoute from "discourse/routes/restricted-user";
 
 export default RestrictedUserRoute.extend({
   model: function() {
-    return Discourse.UserBadge.findByUsername(this.modelFor('user').get('username'));
+    return UserBadge.findByUsername(this.modelFor('user').get('username'));
   },
 
   renderTemplate: function() {
diff --git a/app/assets/javascripts/discourse/routes/user-badges.js.es6 b/app/assets/javascripts/discourse/routes/user-badges.js.es6
index fcd099d76..9a67afbb9 100644
--- a/app/assets/javascripts/discourse/routes/user-badges.js.es6
+++ b/app/assets/javascripts/discourse/routes/user-badges.js.es6
@@ -1,8 +1,9 @@
 import ViewingActionType from "discourse/mixins/viewing-action-type";
+import UserBadge from 'discourse/models/user-badge';
 
 export default Discourse.Route.extend(ViewingActionType, {
   model() {
-    return Discourse.UserBadge.findByUsername(this.modelFor("user").get("username_lower"), { grouped: true });
+    return UserBadge.findByUsername(this.modelFor("user").get("username_lower"), { grouped: true });
   },
 
   setupController(controller, model) {
diff --git a/app/assets/javascripts/main_include.js b/app/assets/javascripts/main_include.js
index 0c02cfe92..ce051e83d 100644
--- a/app/assets/javascripts/main_include.js
+++ b/app/assets/javascripts/main_include.js
@@ -25,6 +25,9 @@
 //= require ./discourse/lib/eyeline
 //= require ./discourse/helpers/register-unbound
 //= require ./discourse/mixins/scrolling
+//= require ./discourse/models/rest
+//= require ./discourse/models/badge-grouping
+//= require ./discourse/models/badge
 //= require_tree ./discourse/mixins
 //= require ./discourse/lib/ajax-error
 //= require ./discourse/lib/markdown
@@ -51,6 +54,7 @@
 //= require ./discourse/models/draft
 //= require ./discourse/models/composer
 //= require ./discourse/models/invite
+//= require ./discourse/models/user-badge
 //= require ./discourse/controllers/discovery-sortable
 //= require ./discourse/controllers/navigation/default
 //= require ./discourse/views/grouped
diff --git a/lib/discourse_plugin_registry.rb b/lib/discourse_plugin_registry.rb
index f3003c4e3..5ca364b1a 100644
--- a/lib/discourse_plugin_registry.rb
+++ b/lib/discourse_plugin_registry.rb
@@ -87,7 +87,9 @@ class DiscoursePluginRegistry
     self.asset_globs.each do |g|
       root, ext, options = *g
 
-      next if options[:admin] && !each_options[:admin]
+      if each_options[:admin]
+        next unless options[:admin]
+      end
 
       Dir.glob("#{root}/**/*") do |f|
         yield f, ext
diff --git a/test/javascripts/admin/controllers/admin-user-badges-test.js.es6 b/test/javascripts/admin/controllers/admin-user-badges-test.js.es6
index 8f1a61976..5c06c69c5 100644
--- a/test/javascripts/admin/controllers/admin-user-badges-test.js.es6
+++ b/test/javascripts/admin/controllers/admin-user-badges-test.js.es6
@@ -1,16 +1,18 @@
+import Badge from 'discourse/models/badge';
+
 moduleFor('controller:admin-user-badges', {
   needs: ['controller:adminUser']
 });
 
 test("grantableBadges", function() {
-  var badge_first = Discourse.Badge.create({id: 3, name: "A Badge"});
-  var badge_middle = Discourse.Badge.create({id: 1, name: "My Badge"});
-  var badge_last = Discourse.Badge.create({id: 2, name: "Zoo Badge"});
-  var controller = this.subject({ badges: [badge_last, badge_first, badge_middle] });
-  var sorted_names = [badge_first.name, badge_middle.name, badge_last.name];
-  var badge_names = controller.get('grantableBadges').map(function(badge) {
+  const badgeFirst = Badge.create({id: 3, name: "A Badge"});
+  const badgeMiddle = Badge.create({id: 1, name: "My Badge"});
+  const badgeLast = Badge.create({id: 2, name: "Zoo Badge"});
+  const controller = this.subject({ badges: [badgeLast, badgeFirst, badgeMiddle] });
+  const sortedNames = [badgeFirst.name, badgeMiddle.name, badgeLast.name];
+  const badgeNames = controller.get('grantableBadges').map(function(badge) {
     return badge.name;
   });
 
-  deepEqual(badge_names, sorted_names, "sorts badges by name");
+  deepEqual(badgeNames, sortedNames, "sorts badges by name");
 });
diff --git a/test/javascripts/models/badge-test.js.es6 b/test/javascripts/models/badge-test.js.es6
index 5087321ee..a91b49ecd 100644
--- a/test/javascripts/models/badge-test.js.es6
+++ b/test/javascripts/models/badge-test.js.es6
@@ -1,43 +1,45 @@
-module("Discourse.Badge");
+import Badge from 'discourse/models/badge';
+
+module("model:badge");
 
 test('newBadge', function() {
-  var badge1 = Discourse.Badge.create({name: "New Badge"}),
-      badge2 = Discourse.Badge.create({id: 1, name: "Old Badge"});
+  const badge1 = Badge.create({name: "New Badge"}),
+      badge2 = Badge.create({id: 1, name: "Old Badge"});
   ok(badge1.get('newBadge'), "badges without ids are new");
   ok(!badge2.get('newBadge'), "badges with ids are not new");
 });
 
 test('displayName', function() {
-  var badge1 = Discourse.Badge.create({id: 1, name: "Test Badge 1"});
+  const badge1 = Badge.create({id: 1, name: "Test Badge 1"});
   equal(badge1.get('displayName'), "Test Badge 1", "falls back to the original name in the absence of a translation");
 
   sandbox.stub(I18n, "t").returnsArg(0);
-  var badge2 = Discourse.Badge.create({id: 2, name: "Test Badge 2"});
+  const badge2 = Badge.create({id: 2, name: "Test Badge 2"});
   equal(badge2.get('displayName'), "badges.badge.test_badge_2.name", "uses translation when available");
 });
 
 test('translatedDescription', function() {
-  var badge1 = Discourse.Badge.create({id: 1, name: "Test Badge 1", description: "TEST"});
+  const badge1 = Badge.create({id: 1, name: "Test Badge 1", description: "TEST"});
   equal(badge1.get('translatedDescription'), null, "returns null when no translation exists");
 
-  var badge2 = Discourse.Badge.create({id: 2, name: "Test Badge 2 **"});
+  const badge2 = Badge.create({id: 2, name: "Test Badge 2 **"});
   sandbox.stub(I18n, "t").returns("description translation");
   equal(badge2.get('translatedDescription'), "description translation", "users translated description");
 });
 
 test('displayDescription', function() {
-  var badge1 = Discourse.Badge.create({id: 1, name: "Test Badge 1", description: "TEST"});
+  const badge1 = Badge.create({id: 1, name: "Test Badge 1", description: "TEST"});
   equal(badge1.get('displayDescription'), "TEST", "returns original description when no translation exists");
 
-  var badge2 = Discourse.Badge.create({id: 2, name: "Test Badge 2 **"});
+  const badge2 = Badge.create({id: 2, name: "Test Badge 2 **"});
   sandbox.stub(I18n, "t").returns("description translation");
   equal(badge2.get('displayDescription'), "description translation", "users translated description");
 });
 
 test('createFromJson array', function() {
-  var badgesJson = {"badge_types":[{"id":6,"name":"Silver 1"}],"badges":[{"id":1126,"name":"Badge 1","description":null,"badge_type_id":6}]};
+  const badgesJson = {"badge_types":[{"id":6,"name":"Silver 1"}],"badges":[{"id":1126,"name":"Badge 1","description":null,"badge_type_id":6}]};
 
-  var badges = Discourse.Badge.createFromJson(badgesJson);
+  const badges = Badge.createFromJson(badgesJson);
 
   ok(Array.isArray(badges), "returns an array");
   equal(badges[0].get('name'), "Badge 1", "badge details are set");
@@ -45,16 +47,16 @@ test('createFromJson array', function() {
 });
 
 test('createFromJson single', function() {
-  var badgeJson = {"badge_types":[{"id":6,"name":"Silver 1"}],"badge":{"id":1126,"name":"Badge 1","description":null,"badge_type_id":6}};
+  const badgeJson = {"badge_types":[{"id":6,"name":"Silver 1"}],"badge":{"id":1126,"name":"Badge 1","description":null,"badge_type_id":6}};
 
-  var badge = Discourse.Badge.createFromJson(badgeJson);
+  const badge = Badge.createFromJson(badgeJson);
 
   ok(!Array.isArray(badge), "does not returns an array");
 });
 
 test('updateFromJson', function() {
-  var badgeJson = {"badge_types":[{"id":6,"name":"Silver 1"}],"badge":{"id":1126,"name":"Badge 1","description":null,"badge_type_id":6}};
-  var badge = Discourse.Badge.create({name: "Badge 1"});
+  const badgeJson = {"badge_types":[{"id":6,"name":"Silver 1"}],"badge":{"id":1126,"name":"Badge 1","description":null,"badge_type_id":6}};
+  const badge = Badge.create({name: "Badge 1"});
   badge.updateFromJson(badgeJson);
   equal(badge.get('id'), 1126, "id is set");
   equal(badge.get('badge_type.name'), "Silver 1", "badge_type reference is set");
@@ -62,7 +64,7 @@ test('updateFromJson', function() {
 
 test('save', function() {
   sandbox.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve({}));
-  var badge = Discourse.Badge.create({name: "New Badge", description: "This is a new badge.", badge_type_id: 1});
+  const badge = Badge.create({name: "New Badge", description: "This is a new badge.", badge_type_id: 1});
   // TODO: clean API
   badge.save(["name", "description", "badge_type_id"]);
   ok(Discourse.ajax.calledOnce, "saved badge");
@@ -70,7 +72,7 @@ test('save', function() {
 
 test('destroy', function() {
   sandbox.stub(Discourse, 'ajax');
-  var badge = Discourse.Badge.create({name: "New Badge", description: "This is a new badge.", badge_type_id: 1});
+  const badge = Badge.create({name: "New Badge", description: "This is a new badge.", badge_type_id: 1});
   badge.destroy();
   ok(!Discourse.ajax.calledOnce, "no AJAX call for a new badge");
   badge.set('id', 3);
diff --git a/test/javascripts/models/user-badge-test.js.es6 b/test/javascripts/models/user-badge-test.js.es6
index 70942b395..bf2a5bf98 100644
--- a/test/javascripts/models/user-badge-test.js.es6
+++ b/test/javascripts/models/user-badge-test.js.es6
@@ -1,10 +1,12 @@
-module("Discourse.UserBadge");
+import UserBadge from 'discourse/models/user-badge';
 
-var singleBadgeJson = {"badges":[{"id":874,"name":"Badge 2","description":null,"badge_type_id":7}],"badge_types":[{"id":7,"name":"Silver 2"}],"users":[{"id":13470,"username":"anne3","avatar_template":"//www.gravatar.com/avatar/a4151b1fd72089c54e2374565a87da7f.png?s={size}\u0026r=pg\u0026d=identicon"}],"user_badge":{"id":665,"granted_at":"2014-03-09T20:30:01.190-04:00","badge_id":874,"granted_by_id":13470}},
+module("model:user-badge");
+
+const singleBadgeJson = {"badges":[{"id":874,"name":"Badge 2","description":null,"badge_type_id":7}],"badge_types":[{"id":7,"name":"Silver 2"}],"users":[{"id":13470,"username":"anne3","avatar_template":"//www.gravatar.com/avatar/a4151b1fd72089c54e2374565a87da7f.png?s={size}\u0026r=pg\u0026d=identicon"}],"user_badge":{"id":665,"granted_at":"2014-03-09T20:30:01.190-04:00","badge_id":874,"granted_by_id":13470}},
     multipleBadgesJson = {"badges":[{"id":880,"name":"Badge 8","description":null,"badge_type_id":13}],"badge_types":[{"id":13,"name":"Silver 8"}],"users":[],"user_badges":[{"id":668,"granted_at":"2014-03-09T20:30:01.420-04:00","badge_id":880,"granted_by_id":null}]};
 
 test('createFromJson single', function() {
-  var userBadge = Discourse.UserBadge.createFromJson(singleBadgeJson);
+  const userBadge = UserBadge.createFromJson(singleBadgeJson);
   ok(!Array.isArray(userBadge), "does not return an array");
   equal(userBadge.get('badge.name'), "Badge 2", "badge reference is set");
   equal(userBadge.get('badge.badge_type.name'), "Silver 2", "badge.badge_type reference is set");
@@ -12,7 +14,7 @@ test('createFromJson single', function() {
 });
 
 test('createFromJson array', function() {
-  var userBadges = Discourse.UserBadge.createFromJson(multipleBadgesJson);
+  const userBadges = UserBadge.createFromJson(multipleBadgesJson);
   ok(Array.isArray(userBadges), "returns an array");
   equal(userBadges[0].get('granted_by'), null, "granted_by reference is not set when null");
 });
@@ -20,7 +22,7 @@ test('createFromJson array', function() {
 asyncTestDiscourse('findByUsername', function() {
   expect(2);
   sandbox.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve(multipleBadgesJson));
-  Discourse.UserBadge.findByUsername("anne3").then(function(badges) {
+  UserBadge.findByUsername("anne3").then(function(badges) {
     ok(Array.isArray(badges), "returns an array");
     start();
   });
@@ -30,7 +32,7 @@ asyncTestDiscourse('findByUsername', function() {
 asyncTestDiscourse('findByBadgeId', function() {
   expect(2);
   sandbox.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve(multipleBadgesJson));
-  Discourse.UserBadge.findByBadgeId(880).then(function(badges) {
+  UserBadge.findByBadgeId(880).then(function(badges) {
     ok(Array.isArray(badges), "returns an array");
     start();
   });
@@ -40,7 +42,7 @@ asyncTestDiscourse('findByBadgeId', function() {
 asyncTestDiscourse('grant', function() {
   expect(2);
   sandbox.stub(Discourse, 'ajax').returns(Ember.RSVP.resolve(singleBadgeJson));
-  Discourse.UserBadge.grant(1, "username").then(function(userBadge) {
+  UserBadge.grant(1, "username").then(function(userBadge) {
     ok(!Array.isArray(userBadge), "does not return an array");
     start();
   });
@@ -49,7 +51,7 @@ asyncTestDiscourse('grant', function() {
 
 test('revoke', function() {
   sandbox.stub(Discourse, 'ajax');
-  var userBadge = Discourse.UserBadge.create({id: 1});
+  const userBadge = UserBadge.create({id: 1});
   userBadge.revoke();
   ok(Discourse.ajax.calledOnce, "makes an AJAX call");
 });