From 9b26c8584ef48ddd4587f5af974192d18708a4c2 Mon Sep 17 00:00:00 2001 From: Vikhyat Korrapati Date: Wed, 5 Mar 2014 18:22:20 +0530 Subject: [PATCH] Initial badge system implementation. --- .../controllers/admin_badge_controller.js | 19 ++ .../controllers/admin_badges_controller.js | 91 ++++++++++ .../controllers/admin_user_controller.js | 4 + .../admin/routes/admin_badges_route.js | 14 ++ .../javascripts/admin/routes/admin_routes.js | 2 + .../admin/templates/admin.js.handlebars | 1 + .../admin/templates/badges.js.handlebars | 62 +++++++ .../admin/templates/user_index.js.handlebars | 6 + .../javascripts/discourse/models/badge.js | 164 ++++++++++++++++++ .../discourse/models/user_badge.js | 57 ++++++ .../stylesheets/common/admin/admin_base.scss | 24 +++ app/controllers/admin/badges_controller.rb | 44 +++++ app/controllers/user_badges_controller.rb | 58 +++++++ app/models/badge.rb | 24 +++ app/models/badge_type.rb | 21 +++ app/models/user.rb | 1 + app/models/user_badge.rb | 26 +++ app/serializers/badge_serializer.rb | 5 + app/serializers/badge_type_serializer.rb | 3 + app/serializers/user_badge_serializer.rb | 6 + app/services/badge_granter.rb | 34 ++++ config/locales/client.en.yml | 17 ++ config/locales/server.en.yml | 8 + config/routes.rb | 8 + config/site_settings.yml | 3 + db/fixtures/700_badge_types.rb | 17 ++ .../20140304200606_create_badge_types.rb | 12 ++ db/migrate/20140304201403_create_badges.rb | 14 ++ .../20140305100909_create_user_badges.rb | 12 ++ lib/guardian.rb | 1 + .../admin/badges_controller_spec.rb | 60 +++++++ .../user_badges_controller_spec.rb | 79 +++++++++ spec/fabricators/badge_fabricator.rb | 9 + spec/models/badge.rb | 17 ++ spec/models/badge_type.rb | 12 ++ spec/models/user_badge.rb | 20 +++ spec/models/user_spec.rb | 1 + spec/services/badge_granter_spec.rb | 61 +++++++ .../admin_badges_controller_test.js | 81 +++++++++ test/javascripts/models/badge_test.js | 69 ++++++++ test/javascripts/models/user_badge_test.js | 19 ++ 41 files changed, 1186 insertions(+) create mode 100644 app/assets/javascripts/admin/controllers/admin_badge_controller.js create mode 100644 app/assets/javascripts/admin/controllers/admin_badges_controller.js create mode 100644 app/assets/javascripts/admin/routes/admin_badges_route.js create mode 100644 app/assets/javascripts/admin/templates/badges.js.handlebars create mode 100644 app/assets/javascripts/discourse/models/badge.js create mode 100644 app/assets/javascripts/discourse/models/user_badge.js create mode 100644 app/controllers/admin/badges_controller.rb create mode 100644 app/controllers/user_badges_controller.rb create mode 100644 app/models/badge.rb create mode 100644 app/models/badge_type.rb create mode 100644 app/models/user_badge.rb create mode 100644 app/serializers/badge_serializer.rb create mode 100644 app/serializers/badge_type_serializer.rb create mode 100644 app/serializers/user_badge_serializer.rb create mode 100644 app/services/badge_granter.rb create mode 100644 db/fixtures/700_badge_types.rb create mode 100644 db/migrate/20140304200606_create_badge_types.rb create mode 100644 db/migrate/20140304201403_create_badges.rb create mode 100644 db/migrate/20140305100909_create_user_badges.rb create mode 100644 spec/controllers/admin/badges_controller_spec.rb create mode 100644 spec/controllers/user_badges_controller_spec.rb create mode 100644 spec/fabricators/badge_fabricator.rb create mode 100644 spec/models/badge.rb create mode 100644 spec/models/badge_type.rb create mode 100644 spec/models/user_badge.rb create mode 100644 spec/services/badge_granter_spec.rb create mode 100644 test/javascripts/admin/controllers/admin_badges_controller_test.js create mode 100644 test/javascripts/models/badge_test.js create mode 100644 test/javascripts/models/user_badge_test.js diff --git a/app/assets/javascripts/admin/controllers/admin_badge_controller.js b/app/assets/javascripts/admin/controllers/admin_badge_controller.js new file mode 100644 index 00000000000..d45f280d1ed --- /dev/null +++ b/app/assets/javascripts/admin/controllers/admin_badge_controller.js @@ -0,0 +1,19 @@ +/** + This is the itemController for `Discourse.AdminBadgesController`. Its main purpose + is to indicate which badge was selected. + + @class AdminBadgeController + @extends Discourse.ObjectController + @namespace Discourse + @module Discourse +**/ + +Discourse.AdminBadgeController = Discourse.ObjectController.extend({ + /** + Whether this badge has been selected. + + @property selected + @type {Boolean} + **/ + selected: Discourse.computed.propertyEqual('model.name', 'parentController.selectedItem.name') +}); diff --git a/app/assets/javascripts/admin/controllers/admin_badges_controller.js b/app/assets/javascripts/admin/controllers/admin_badges_controller.js new file mode 100644 index 00000000000..705aad55385 --- /dev/null +++ b/app/assets/javascripts/admin/controllers/admin_badges_controller.js @@ -0,0 +1,91 @@ +/** + This controller supports the interface for dealing with badges. + + @class AdminBadgesController + @extends Ember.ArrayController + @namespace Discourse + @module Discourse +**/ +Discourse.AdminBadgesController = Ember.ArrayController.extend({ + itemController: 'adminBadge', + + /** + Show the displayName only if it is different from the name. + + @property showDisplayName + @type {Boolean} + **/ + showDisplayName: Discourse.computed.propertyNotEqual('selectedItem.name', 'selectedItem.displayName'), + + /** + We don't allow setting a description if a translation for the given badge name + exists. + + @property canEditDescription + @type {Boolean} + **/ + canEditDescription: Em.computed.none('selectedItem.translatedDescription'), + + actions: { + + /** + Create a new badge and select it. + + @method newBadge + **/ + newBadge: function() { + var badge = Discourse.Badge.create({ + name: I18n.t('admin.badges.new_badge') + }); + this.pushObject(badge); + this.send('selectBadge', badge); + }, + + /** + Select a particular badge. + + @method selectBadge + @param {Discourse.Badge} badge The badge to be selected + **/ + selectBadge: function(badge) { + this.set('selectedItem', badge); + }, + + /** + Save the selected badge. + + @method save + **/ + save: function() { + var badge = this.get('selectedItem'); + badge.set('disableSave', true); + badge.save().then(function() { + badge.set('disableSave', false); + }); + }, + + /** + Confirm before destroying the selected badge. + + @method destroy + **/ + destroy: function() { + var self = this; + return bootbox.confirm(I18n.t("admin.badges.delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), function(result) { + if (result) { + var selected = self.get('selectedItem'); + selected.destroy().then(function() { + // Success. + self.set('selectedItem', null); + self.get('model').removeObject(selected); + }, function() { + // Failure. + bootbox.alert(I18n.t('generic_error')); + }); + } + }); + } + + } + +}); diff --git a/app/assets/javascripts/admin/controllers/admin_user_controller.js b/app/assets/javascripts/admin/controllers/admin_user_controller.js index c0674fd6d04..ec146502764 100644 --- a/app/assets/javascripts/admin/controllers/admin_user_controller.js +++ b/app/assets/javascripts/admin/controllers/admin_user_controller.js @@ -24,6 +24,10 @@ Discourse.AdminUserIndexController = Discourse.ObjectController.extend({ return Discourse.SiteSettings.must_approve_users; }.property(), + showBadges: function() { + return Discourse.SiteSettings.enable_badges; + }.property(), + primaryGroupDirty: Discourse.computed.propertyNotEqual('originalPrimaryGroupId', 'primary_group_id'), actions: { diff --git a/app/assets/javascripts/admin/routes/admin_badges_route.js b/app/assets/javascripts/admin/routes/admin_badges_route.js new file mode 100644 index 00000000000..1c606b5578e --- /dev/null +++ b/app/assets/javascripts/admin/routes/admin_badges_route.js @@ -0,0 +1,14 @@ +Discourse.AdminBadgesRoute = Discourse.Route.extend({ + + model: function() { + return Discourse.Badge.findAll(); + }, + + setupController: function(controller, model) { + Discourse.ajax('/admin/badges/types').then(function(json) { + controller.set('badgeTypes', json.badge_types); + }); + controller.set('model', model); + } + +}); diff --git a/app/assets/javascripts/admin/routes/admin_routes.js b/app/assets/javascripts/admin/routes/admin_routes.js index 3b847a36dac..21b2b38b6a6 100644 --- a/app/assets/javascripts/admin/routes/admin_routes.js +++ b/app/assets/javascripts/admin/routes/admin_routes.js @@ -57,5 +57,7 @@ Discourse.Route.buildRoutes(function() { }); }); + this.route('badges'); + }); }); diff --git a/app/assets/javascripts/admin/templates/admin.js.handlebars b/app/assets/javascripts/admin/templates/admin.js.handlebars index f8044020fe4..43f18b5e2c1 100644 --- a/app/assets/javascripts/admin/templates/admin.js.handlebars +++ b/app/assets/javascripts/admin/templates/admin.js.handlebars @@ -24,6 +24,7 @@
  • {{#link-to 'admin.customize'}}{{i18n admin.customize.title}}{{/link-to}}
  • {{#link-to 'admin.api'}}{{i18n admin.api.title}}{{/link-to}}
  • {{#link-to 'admin.backups'}}{{i18n admin.backups.title}}{{/link-to}}
  • +
  • {{#link-to 'admin.badges'}}{{i18n admin.badges.title}}{{/link-to}}
  • {{/if}} diff --git a/app/assets/javascripts/admin/templates/badges.js.handlebars b/app/assets/javascripts/admin/templates/badges.js.handlebars new file mode 100644 index 00000000000..ff39e74181b --- /dev/null +++ b/app/assets/javascripts/admin/templates/badges.js.handlebars @@ -0,0 +1,62 @@ +
    + +
    +

    {{i18n admin.badges.title}}

    + + +
    + + {{#if selectedItem}} + {{#with selectedItem}} +
    +
    +
    + + {{input type="text" name="name" value=name}} +
    + + {{#if controller.showDisplayName}} +
    + {{i18n admin.badges.display_name}} + {{displayName}} +
    + {{/if}} + +
    + + {{view Ember.Select name="badge_type_id" value=badge_type_id + content=controller.badgeTypes + optionValuePath="content.id" + optionLabelPath="content.name"}} +
    + +
    + + {{#if controller.canEditDescription}} + {{textarea name="description" value=description}} + {{else}} + {{textarea name="description" value=translatedDescription disabled=true}} + {{/if}} +
    + +
    + + {{i18n admin.badges.delete}} +
    +
    +
    + {{/with}} + {{/if}} + +
    diff --git a/app/assets/javascripts/admin/templates/user_index.js.handlebars b/app/assets/javascripts/admin/templates/user_index.js.handlebars index a99918adeeb..8af5cd2c5f3 100644 --- a/app/assets/javascripts/admin/templates/user_index.js.handlebars +++ b/app/assets/javascripts/admin/templates/user_index.js.handlebars @@ -336,6 +336,12 @@ +{{#if showBadges}} +
    +

    {{i18n admin.badges.title}}

    +
    +{{/if}} +