diff --git a/app/assets/javascripts/discourse/controllers/badges/index.js.es6 b/app/assets/javascripts/discourse/controllers/badges/index.js.es6 index 7a52169dd08..862ac75c41a 100644 --- a/app/assets/javascripts/discourse/controllers/badges/index.js.es6 +++ b/app/assets/javascripts/discourse/controllers/badges/index.js.es6 @@ -1,4 +1,32 @@ -export default Ember.ArrayController.extend({ - sortProperties: ['displayName'], - sortAscending: true +export default Ember.Controller.extend({ + badgeGroups: function(){ + var sorted = _.sortBy(this.get('model'), function(badge){ + var pos = badge.get('badge_grouping.position'); + var type = badge.get('badge_type_id'); + var name = badge.get('displayName'); + + return ("000" + pos).slice(-4) + (10-type) + name; + }); + + var grouped = []; + var group = [], groupId; + + sorted.forEach(function(badge){ + if(groupId !== badge.badge_grouping_id){ + if(group && group.length > 0){ + grouped.push({badges: group, badgeGrouping: group[0].badge_grouping}); + } + group = []; + groupId = badge.badge_grouping_id; + } + group.push(badge); + }); + + if(group && group.length > 0){ + grouped.push({badges: group, badgeGrouping: group[0].badge_grouping}); + } + + return grouped; + + }.property('model') }); diff --git a/app/assets/javascripts/discourse/controllers/badges/show.js.es6 b/app/assets/javascripts/discourse/controllers/badges/show.js.es6 index 5d734809ef8..c448069af30 100644 --- a/app/assets/javascripts/discourse/controllers/badges/show.js.es6 +++ b/app/assets/javascripts/discourse/controllers/badges/show.js.es6 @@ -7,6 +7,23 @@ @module Discourse **/ export default Discourse.ObjectController.extend({ + + actions: { + loadMore: function() { + var self = this; + var userBadges = this.get('userBadges'); + + Discourse.UserBadge.findByBadgeId(this.get('model.id'), { + offset: userBadges.length + }).then(function(userBadges) { + self.get('userBadges').pushObjects(userBadges); + if(userBadges.length === 0){ + self.set('noMoreBadges', true); + } + }); + } + }, + layoutClass: function(){ var ub = this.get("userBadges"); if(ub && ub[0] && ub[0].post_id){ @@ -16,14 +33,15 @@ export default Discourse.ObjectController.extend({ } }.property("userBadges"), - grantDates: Em.computed.mapBy('userBadges', 'grantedAt'), - minGrantedAt: Em.computed.min('grantDates'), - canLoadMore: function() { + if(this.get('noMoreBadges')) { + return false; + } + if (this.get('userBadges')) { return this.get('model.grant_count') > this.get('userBadges.length'); } else { return false; } - }.property('model.grant_count', 'userBadges.length') + }.property('noMoreBadges', 'model.grant_count', 'userBadges.length') }); diff --git a/app/assets/javascripts/discourse/models/badge.js b/app/assets/javascripts/discourse/models/badge.js index 8d017ee8504..17198074bd6 100644 --- a/app/assets/javascripts/discourse/models/badge.js +++ b/app/assets/javascripts/discourse/models/badge.js @@ -165,6 +165,13 @@ Discourse.Badge.reopenClass({ }); } + var badgeGroupings = {}; + if ('badge_groupings' in json) { + json.badge_groupings.forEach(function(badgeGroupingJson) { + badgeGroupings[badgeGroupingJson.id] = Discourse.BadgeGrouping.create(badgeGroupingJson); + }); + } + // Create Badge objects. var badges = []; if ("badge" in json) { @@ -175,8 +182,10 @@ Discourse.Badge.reopenClass({ badges = badges.map(function(badgeJson) { var 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; }); + if ("badge" in json) { return badges[0]; } else { diff --git a/app/assets/javascripts/discourse/models/badge_grouping.js b/app/assets/javascripts/discourse/models/badge_grouping.js new file mode 100644 index 00000000000..dd59d078fab --- /dev/null +++ b/app/assets/javascripts/discourse/models/badge_grouping.js @@ -0,0 +1,10 @@ +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 index 85c05cc6a33..7d594e7a2cb 100644 --- a/app/assets/javascripts/discourse/models/user_badge.js +++ b/app/assets/javascripts/discourse/models/user_badge.js @@ -111,11 +111,11 @@ Discourse.UserBadge.reopenClass({ **/ findByBadgeId: function(badgeId, options) { if (!options) { options = {}; } - var url = "/user_badges.json?badge_id=" + badgeId; - if (options.granted_before) { - url = url + "&granted_before=" + encodeURIComponent(options.granted_before); - } - return Discourse.ajax(url).then(function(json) { + options.badge_id = badgeId; + + return Discourse.ajax("/user_badges.json", { + data: options + }).then(function(json) { return Discourse.UserBadge.createFromJson(json); }); }, diff --git a/app/assets/javascripts/discourse/routes/badges_show_route.js b/app/assets/javascripts/discourse/routes/badges_show_route.js index 842bf36e324..4da70063b44 100644 --- a/app/assets/javascripts/discourse/routes/badges_show_route.js +++ b/app/assets/javascripts/discourse/routes/badges_show_route.js @@ -28,16 +28,5 @@ Discourse.BadgesShowRoute = Ember.Route.extend({ }); controller.set('model', model); Discourse.set('title', model.get('displayName')); - }, - - actions: { - loadMore: function() { - var self = this; - Discourse.UserBadge.findByBadgeId(this.currentModel.get('id'), { - granted_before: this.get('controller.minGrantedAt') / 1000 - }).then(function(userBadges) { - self.get('controller.userBadges').pushObjects(userBadges); - }); - } } }); diff --git a/app/assets/javascripts/discourse/templates/badges/index.js.handlebars b/app/assets/javascripts/discourse/templates/badges/index.js.handlebars index 91dc57a9dc9..a03d45b9a13 100644 --- a/app/assets/javascripts/discourse/templates/badges/index.js.handlebars +++ b/app/assets/javascripts/discourse/templates/badges/index.js.handlebars @@ -3,13 +3,18 @@ - {{#each}} - - - - - + {{#each badgeGroups}} + + + {{#each this.badges}} + + + + + + + {{/each}} {{/each}}
{{#if this.has_badge}}{{/if}}{{user-badge badge=this}}{{{displayDescriptionHtml}}}{{i18n badges.granted count=grant_count}}

{{this.badgeGrouping.displayName}}

{{#if this.has_badge}}{{/if}}{{user-badge badge=this}}{{{displayDescriptionHtml}}}{{i18n badges.granted count=grant_count}}
diff --git a/app/assets/stylesheets/common/base/user-badges.scss b/app/assets/stylesheets/common/base/user-badges.scss index 07503b54e93..97a30e58844 100644 --- a/app/assets/stylesheets/common/base/user-badges.scss +++ b/app/assets/stylesheets/common/base/user-badges.scss @@ -75,6 +75,15 @@ table.badges-listing { font-size: $base-font-size; } + tr.title td { + padding-top: 30px; + padding-bottom: 15px; + } + + tr.title { + border-top: 0px solid; + } + td { padding: 10px 0px; } diff --git a/app/controllers/badges_controller.rb b/app/controllers/badges_controller.rb index 6f57c2b175f..77e4a164d09 100644 --- a/app/controllers/badges_controller.rb +++ b/app/controllers/badges_controller.rb @@ -3,13 +3,21 @@ class BadgesController < ApplicationController def index badges = Badge.all - badges = badges.where(enabled: true, listable: true) if(params[:only_listable] == "true") || !request.xhr? - badges = badges.includes(:badge_grouping).to_a + + if (params[:only_listable] == "true") || !request.xhr? + # NOTE: this is sorted client side if needed + badges = badges.includes(:badge_grouping) + .where(enabled: true, listable: true) + + end + + badges = badges.to_a + user_badges = nil if current_user user_badges = Set.new(current_user.user_badges.select('distinct badge_id').pluck(:badge_id)) end - serialized = MultiJson.dump(serialize_data(badges, BadgeSerializer, root: "badges", user_badges: user_badges, include_grouping: true)) + serialized = MultiJson.dump(serialize_data(badges, BadgeIndexSerializer, root: "badges", user_badges: user_badges)) respond_to do |format| format.html do store_preloaded "badges", serialized diff --git a/app/controllers/user_badges_controller.rb b/app/controllers/user_badges_controller.rb index 946289a006b..797ea8f7448 100644 --- a/app/controllers/user_badges_controller.rb +++ b/app/controllers/user_badges_controller.rb @@ -7,11 +7,11 @@ class UserBadgesController < ApplicationController user_badges = user.user_badges else badge = fetch_badge_from_params - user_badges = badge.user_badges.order('granted_at DESC').limit(96) + user_badges = badge.user_badges.order('granted_at DESC, id DESC').limit(96) end - if params[:granted_before] - user_badges = user_badges.where('granted_at < ?', Time.at(params[:granted_before].to_f)) + if offset = params[:offset] + user_badges = user_badges.offset(offset.to_i) end user_badges = user_badges.includes(:user, :granted_by, badge: :badge_type, post: :topic) diff --git a/app/models/badge.rb b/app/models/badge.rb index 5936e2858f3..71aa1d27437 100644 --- a/app/models/badge.rb +++ b/app/models/badge.rb @@ -1,6 +1,4 @@ class Badge < ActiveRecord::Base - belongs_to :badge_grouping - # badge ids Welcome = 5 NicePost = 6 @@ -145,6 +143,8 @@ SQL end belongs_to :badge_type + belongs_to :badge_grouping + has_many :user_badges, dependent: :destroy validates :name, presence: true, uniqueness: true diff --git a/app/models/badge_grouping.rb b/app/models/badge_grouping.rb index 27d1694beea..066bd79331a 100644 --- a/app/models/badge_grouping.rb +++ b/app/models/badge_grouping.rb @@ -1,12 +1,10 @@ class BadgeGrouping < ActiveRecord::Base - module Position - GettingStarted = 10 - Community = 11 - Posting = 12 - TrustLevel = 13 - Other = 14 - end + GettingStarted = 1 + Community = 2 + Posting = 3 + TrustLevel = 4 + Other = 5 has_many :badges end diff --git a/app/serializers/badge_grouping_serializer.rb b/app/serializers/badge_grouping_serializer.rb index 694b3efe47d..7331a610cfa 100644 --- a/app/serializers/badge_grouping_serializer.rb +++ b/app/serializers/badge_grouping_serializer.rb @@ -1,3 +1,3 @@ class BadgeGroupingSerializer < ApplicationSerializer - attributes :id, :name, :description + attributes :id, :name, :description, :position end diff --git a/app/serializers/badge_index_serializer.rb b/app/serializers/badge_index_serializer.rb new file mode 100644 index 00000000000..533c71133e5 --- /dev/null +++ b/app/serializers/badge_index_serializer.rb @@ -0,0 +1,12 @@ +class BadgeIndexSerializer < BadgeSerializer + attributes :has_badge + has_one :badge_grouping + + def include_has_badge? + @options[:user_badges] + end + + def has_badge + @options[:user_badges].include?(object.id) + end +end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 1c594bb774d..26c0613d9c7 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1962,6 +1962,17 @@ en: other: "%{count} granted" select_badge_for_title: Select a badge to use as your title no_title: "" + badge_grouping: + getting_started: + name: Getting Started + community: + name: Community + trust_level: + name: Trust Level + other: + name: Other + posting: + name: Posting badge: editor: name: Editor diff --git a/db/fixtures/006_badges.rb b/db/fixtures/006_badges.rb index 59fc5aa7742..eebda42753d 100644 --- a/db/fixtures/006_badges.rb +++ b/db/fixtures/006_badges.rb @@ -1,34 +1,42 @@ BadgeGrouping.seed do |g| - g.id = 1 + g.id = BadgeGrouping::GettingStarted g.name = "Getting Started" - g.position = BadgeGrouping::Position::GettingStarted + g.position = 10 end BadgeGrouping.seed do |g| - g.id = 2 + g.id = BadgeGrouping::Community g.name = "Community" - g.position = BadgeGrouping::Position::Community + g.position = 11 end BadgeGrouping.seed do |g| - g.id = 3 + g.id = BadgeGrouping::Posting g.name = "Posting" - g.position = BadgeGrouping::Position::Posting + g.position = 12 end BadgeGrouping.seed do |g| - g.id = 4 + g.id = BadgeGrouping::TrustLevel g.name = "Trust Level" - g.position = BadgeGrouping::Position::TrustLevel + g.position = 13 end BadgeGrouping.seed do |g| - g.id = 5 + g.id = BadgeGrouping::Other g.name = "Other" - g.position = BadgeGrouping::Position::Other + g.position = 14 end +# BUGFIX +Badge.exec_sql 'UPDATE badges + SET badge_grouping_id = NULL + WHERE NOT EXISTS ( + SELECT 1 FROM badge_groupings g + WHERE g.id = badge_grouping_id + )' + # Trust level system badges. trust_level_badges = [ {id: 1, name: "Basic User", type: BadgeType::Bronze}, @@ -43,7 +51,7 @@ trust_level_badges.each do |spec| b.default_name = spec[:name] b.badge_type_id = spec[:type] b.query = Badge::Queries.trust_level(spec[:id]) - b.default_badge_grouping_id = BadgeGrouping::Position::TrustLevel + b.default_badge_grouping_id = BadgeGrouping::TrustLevel # allow title for leader and elder b.allow_title = spec[:id] > 2 @@ -57,7 +65,7 @@ Badge.seed do |b| b.multiple_grant = false b.target_posts = false b.query = Badge::Queries::Reader - b.default_badge_grouping_id = BadgeGrouping::Position::GettingStarted + b.default_badge_grouping_id = BadgeGrouping::GettingStarted b.auto_revoke = false end @@ -68,7 +76,7 @@ Badge.seed do |b| b.multiple_grant = false b.target_posts = false b.query = Badge::Queries::ReadGuidelines - b.default_badge_grouping_id = BadgeGrouping::Position::GettingStarted + b.default_badge_grouping_id = BadgeGrouping::GettingStarted end Badge.seed do |b| @@ -78,7 +86,7 @@ Badge.seed do |b| b.multiple_grant = false b.target_posts = true b.query = Badge::Queries::FirstLink - b.default_badge_grouping_id = BadgeGrouping::Position::GettingStarted + b.default_badge_grouping_id = BadgeGrouping::GettingStarted end Badge.seed do |b| @@ -88,7 +96,7 @@ Badge.seed do |b| b.multiple_grant = false b.target_posts = true b.query = Badge::Queries::FirstQuote - b.default_badge_grouping_id = BadgeGrouping::Position::GettingStarted + b.default_badge_grouping_id = BadgeGrouping::GettingStarted end Badge.seed do |b| @@ -98,7 +106,7 @@ Badge.seed do |b| b.multiple_grant = false b.target_posts = true b.query = Badge::Queries::FirstLike - b.default_badge_grouping_id = BadgeGrouping::Position::GettingStarted + b.default_badge_grouping_id = BadgeGrouping::GettingStarted end Badge.seed do |b| @@ -108,7 +116,7 @@ Badge.seed do |b| b.multiple_grant = false b.target_posts = false b.query = Badge::Queries::FirstFlag - b.default_badge_grouping_id = BadgeGrouping::Position::Community + b.default_badge_grouping_id = BadgeGrouping::Community end Badge.seed do |b| @@ -118,7 +126,7 @@ Badge.seed do |b| b.multiple_grant = false b.target_posts = true b.query = Badge::Queries::FirstShare - b.default_badge_grouping_id = BadgeGrouping::Position::GettingStarted + b.default_badge_grouping_id = BadgeGrouping::GettingStarted end Badge.seed do |b| @@ -128,7 +136,7 @@ Badge.seed do |b| b.multiple_grant = false b.target_posts = true b.query = Badge::Queries::Welcome - b.default_badge_grouping_id = BadgeGrouping::Position::Community + b.default_badge_grouping_id = BadgeGrouping::Community end Badge.seed do |b| @@ -137,7 +145,7 @@ Badge.seed do |b| b.badge_type_id = BadgeType::Bronze b.multiple_grant = false b.query = Badge::Queries::Autobiographer - b.default_badge_grouping_id = BadgeGrouping::Position::GettingStarted + b.default_badge_grouping_id = BadgeGrouping::GettingStarted end Badge.seed do |b| @@ -146,7 +154,7 @@ Badge.seed do |b| b.badge_type_id = BadgeType::Bronze b.multiple_grant = false b.query = Badge::Queries::Editor - b.default_badge_grouping_id = BadgeGrouping::Position::Community + b.default_badge_grouping_id = BadgeGrouping::Community end # @@ -165,6 +173,6 @@ like_badges.each do |spec| b.multiple_grant = spec[:multiple] b.target_posts = true b.query = Badge::Queries.like_badge(Badge.like_badge_counts[spec[:id]]) - b.default_badge_grouping_id = BadgeGrouping::Position::Posting + b.default_badge_grouping_id = BadgeGrouping::Posting end end diff --git a/db/migrate/20140718041445_set_default_badge_grouping.rb b/db/migrate/20140718041445_set_default_badge_grouping.rb new file mode 100644 index 00000000000..6a02fcbae21 --- /dev/null +++ b/db/migrate/20140718041445_set_default_badge_grouping.rb @@ -0,0 +1,5 @@ +class SetDefaultBadgeGrouping < ActiveRecord::Migration + def change + change_column :badges, :badge_grouping_id, :integer, null: false, default: 5 + end +end