mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-27 09:36:19 -05:00
FEATURE: you can not drill down and see why you have badges
Clicking on badges filters down the list to a particular user.
This commit is contained in:
parent
a055c37939
commit
ca3e2b4da3
17 changed files with 188 additions and 27 deletions
|
@ -3,5 +3,13 @@ export default Ember.Component.extend({
|
|||
|
||||
showGrantCount: function() {
|
||||
return this.get('count') && this.get('count') > 1;
|
||||
}.property('count')
|
||||
}.property('count'),
|
||||
|
||||
badgeUrl: function(){
|
||||
// NOTE: I tried using a link-to helper here but the queryParams mean it fails
|
||||
var username = this.get('user.username_lower') || '';
|
||||
username = username !== '' ? "?username=" + username : '';
|
||||
return this.get('badge.url') + username;
|
||||
}.property("badge", "user")
|
||||
|
||||
});
|
||||
|
|
|
@ -1,17 +1,33 @@
|
|||
import UserBadge from 'discourse/models/user-badge';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
queryParams: ['username'],
|
||||
noMoreBadges: false,
|
||||
userBadges: null,
|
||||
needs: ["application"],
|
||||
|
||||
user: function(){
|
||||
if (this.get("username")) {
|
||||
return this.get('userBadges')[0].get('user');
|
||||
}
|
||||
}.property("username"),
|
||||
|
||||
grantCount: function() {
|
||||
if (this.get("username")) {
|
||||
return this.get('userBadges.grant_count');
|
||||
} else {
|
||||
return this.get('model.grant_count');
|
||||
}
|
||||
}.property('username', 'model', 'userBadges'),
|
||||
|
||||
actions: {
|
||||
loadMore() {
|
||||
const self = this;
|
||||
const userBadges = this.get('userBadges');
|
||||
|
||||
UserBadge.findByBadgeId(this.get('model.id'), {
|
||||
offset: userBadges.length
|
||||
offset: userBadges.length,
|
||||
username: this.get('username'),
|
||||
}).then(function(result) {
|
||||
userBadges.pushObjects(result);
|
||||
if(userBadges.length === 0){
|
||||
|
@ -22,11 +38,12 @@ export default Ember.Controller.extend({
|
|||
},
|
||||
|
||||
layoutClass: function(){
|
||||
var user = this.get("user") ? " single-user" : "";
|
||||
var ub = this.get("userBadges");
|
||||
if(ub && ub[0] && ub[0].post_id){
|
||||
return "user-badge-with-posts";
|
||||
return "user-badge-with-posts" + user;
|
||||
} else {
|
||||
return "user-badge-no-posts";
|
||||
return "user-badge-no-posts" + user;
|
||||
}
|
||||
}.property("userBadges"),
|
||||
|
||||
|
@ -34,7 +51,7 @@ export default Ember.Controller.extend({
|
|||
if (this.get('noMoreBadges')) { return false; }
|
||||
|
||||
if (this.get('userBadges')) {
|
||||
return this.get('model.grant_count') > this.get('userBadges.length');
|
||||
return this.get('grantCount') > this.get('userBadges.length');
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
export default Ember.ArrayController.extend({
|
||||
needs: ["user"],
|
||||
user: Em.computed.alias("controllers.user.model"),
|
||||
sortProperties: ['badge.badge_type.sort_order', 'badge.name'],
|
||||
orderBy: function(ub1, ub2){
|
||||
var sr1 = ub1.get('badge.badge_type.sort_order');
|
||||
|
|
|
@ -5,6 +5,10 @@ const Badge = RestModel.extend({
|
|||
|
||||
newBadge: Em.computed.none('id'),
|
||||
|
||||
url: function() {
|
||||
return Discourse.getURL(`/badges/${this.get('id')}/${this.get('slug')}`);
|
||||
}.property(),
|
||||
|
||||
/**
|
||||
@private
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ UserBadge.reopenClass({
|
|||
if ("user_badge" in json) {
|
||||
userBadges = [json.user_badge];
|
||||
} else {
|
||||
userBadges = json.user_badges;
|
||||
userBadges = (json.user_badge_info && json.user_badge_info.user_badges) || json.user_badges;
|
||||
}
|
||||
|
||||
userBadges = userBadges.map(function(userBadgeJson) {
|
||||
|
@ -73,6 +73,10 @@ UserBadge.reopenClass({
|
|||
if ("user_badge" in json) {
|
||||
return userBadges[0];
|
||||
} else {
|
||||
if (json.user_badge_info) {
|
||||
userBadges.grant_count = json.user_badge_info.grant_count;
|
||||
userBadges.username = json.user_badge_info.username;
|
||||
}
|
||||
return userBadges;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -2,6 +2,11 @@ import UserBadge from 'discourse/models/user-badge';
|
|||
import Badge from 'discourse/models/badge';
|
||||
|
||||
export default Discourse.Route.extend({
|
||||
queryParams: {
|
||||
username: {
|
||||
refreshModel: true
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
didTransition() {
|
||||
this.controllerFor("badges/show")._showFooter();
|
||||
|
@ -24,10 +29,13 @@ export default Discourse.Route.extend({
|
|||
}
|
||||
},
|
||||
|
||||
afterModel(model) {
|
||||
return UserBadge.findByBadgeId(model.get("id")).then(userBadges => {
|
||||
afterModel(model,transition) {
|
||||
const username = transition.queryParams && transition.queryParams.username;
|
||||
|
||||
return UserBadge.findByBadgeId(model.get("id"), {username}).then(userBadges => {
|
||||
this.userBadges = userBadges;
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
titleToken() {
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
<div class='row'>
|
||||
<div class='badge'>{{user-badge badge=model}}</div>
|
||||
<div class='description'>{{{model.displayDescriptionHtml}}}</div>
|
||||
<div class='grant-count'>{{i18n 'badges.granted' count=model.grant_count}}</div>
|
||||
{{#unless user}}
|
||||
<div class='grant-count'>{{i18n 'badges.granted' count=grantCount}}</div>
|
||||
{{/unless}}
|
||||
<div class='info'>{{i18n 'badges.allow_title'}} {{{view.allowTitle}}}<br>{{i18n 'badges.multiple_grant'}} {{{view.multipleGrant}}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -22,23 +24,48 @@
|
|||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if user}}
|
||||
<div class='badge-user-info'>
|
||||
{{#link-to 'user' user}}
|
||||
{{avatar user imageSize="extra_large"}}
|
||||
<div class="details clearfix">
|
||||
{{poster-name post=user}}
|
||||
</div>
|
||||
{{/link-to}}
|
||||
<div class='earned'>
|
||||
{{i18n 'badges.earned_n_times' count=grantCount}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if userBadges}}
|
||||
<div class={{unbound layoutClass}}>
|
||||
{{#each ub in userBadges}}
|
||||
<div class="badge-user">
|
||||
{{#link-to 'user' ub.user classNames="badge-info"}}
|
||||
{{avatar ub.user imageSize="large"}}
|
||||
<div class="details">
|
||||
<span class="username">{{ub.user.username}}</span>
|
||||
{{format-date ub.granted_at}}
|
||||
</div>
|
||||
{{/link-to}}
|
||||
{{#if user}}
|
||||
{{format-date ub.granted_at}}
|
||||
{{else}}
|
||||
{{#link-to 'user' ub.user classNames="badge-info"}}
|
||||
{{avatar ub.user imageSize="large"}}
|
||||
<div class="details">
|
||||
<span class="username">{{ub.user.username}}</span>
|
||||
{{format-date ub.granted_at}}
|
||||
</div>
|
||||
{{/link-to}}
|
||||
{{/if}}
|
||||
|
||||
{{#if ub.post_number}}
|
||||
<a class="post-link" href="{{unbound ub.topic.url}}/{{unbound ub.post_number}}">{{{ub.topic.fancyTitle}}}</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
|
||||
{{#unless canLoadMore}}
|
||||
{{#if user}}
|
||||
<a class='load-more' href='{{model.url}}'>{{i18n 'badges.more_with_badge'}}</a>
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
|
||||
</div>
|
||||
|
||||
{{conditional-loading-spinner condition=canLoadMore}}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{#link-to 'badges.show' badge}}
|
||||
<a href="{{badgeUrl}}">
|
||||
{{#badge-button badge=badge}}
|
||||
{{#if showGrantCount}}
|
||||
<span class="count">(× {{count}})</span>
|
||||
{{/if}}
|
||||
{{/badge-button}}
|
||||
{{/link-to}}
|
||||
</a>
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
{{#if showBadges}}
|
||||
<div class="badge-section">
|
||||
{{#each ub in user.featured_user_badges}}
|
||||
{{user-badge badge=ub.badge}}
|
||||
{{user-badge badge=ub.badge user=user}}
|
||||
{{/each}}
|
||||
{{#if showMoreBadges}}
|
||||
{{#link-to 'user.badges' user class="btn more-user-badges"}}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<section class='user-content user-badges-list'>
|
||||
{{#each ub in controller}}
|
||||
{{user-badge badge=ub.badge count=ub.count}}
|
||||
{{user-badge badge=ub.badge count=ub.count user=user}}
|
||||
{{/each}}
|
||||
</section>
|
||||
|
|
|
@ -187,6 +187,58 @@
|
|||
}
|
||||
}
|
||||
|
||||
.show-badge .badge-user-info {
|
||||
margin-left: 2%;
|
||||
.earned {
|
||||
margin-top: 15px;
|
||||
font-size: 1.3em;
|
||||
}
|
||||
.username {
|
||||
margin-top: 5px;
|
||||
display: block;
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 30%), scale-color($secondary, $lightness: 70%));
|
||||
}
|
||||
}
|
||||
|
||||
.show-badge .single-user {
|
||||
margin-left: 2%;
|
||||
padding-bottom: 20px;
|
||||
.load-more {
|
||||
padding-top: 30px;
|
||||
display: block;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.show-badge .single-user .badge-user {
|
||||
padding-left: 0;
|
||||
|
||||
text-align: left;
|
||||
display: block;
|
||||
margin: 20px 0;
|
||||
.badge-info {
|
||||
display: none;
|
||||
}
|
||||
.date {
|
||||
display: inline-block;
|
||||
font-size: 1.1em;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.post-link {
|
||||
font-size: 1.3em;
|
||||
width: 500px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
width: 800px;
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
clear: both;
|
||||
display: table;
|
||||
}
|
||||
}
|
||||
|
||||
.long-description.banner {
|
||||
width: 88%;
|
||||
margin-bottom: 20px;
|
||||
|
|
|
@ -1,16 +1,28 @@
|
|||
class UserBadgesController < ApplicationController
|
||||
def index
|
||||
params.permit [:granted_before, :offset]
|
||||
params.permit [:granted_before, :offset, :username]
|
||||
|
||||
badge = fetch_badge_from_params
|
||||
user_badges = badge.user_badges.order('granted_at DESC, id DESC').limit(96)
|
||||
user_badges = user_badges.includes(:user, :granted_by, badge: :badge_type, post: :topic)
|
||||
|
||||
grant_count = nil
|
||||
|
||||
if params[:username]
|
||||
user_id = User.where(username_lower: params[:username].downcase).pluck(:id).first
|
||||
user_badges = user_badges.where(user_id: user_id) if user_id
|
||||
grant_count = user_badges.count
|
||||
end
|
||||
|
||||
if offset = params[:offset]
|
||||
user_badges = user_badges.offset(offset.to_i)
|
||||
end
|
||||
|
||||
render_serialized(user_badges, UserBadgeSerializer, root: "user_badges", include_long_description: true)
|
||||
user_badges = UserBadges.new(user_badges: user_badges,
|
||||
username: params[:username],
|
||||
grant_count: grant_count)
|
||||
|
||||
render_serialized(user_badges, UserBadgesSerializer, root: :user_badge_info, include_long_description: true)
|
||||
end
|
||||
|
||||
def username
|
||||
|
@ -28,7 +40,7 @@ class UserBadgesController < ApplicationController
|
|||
.includes(post: :topic)
|
||||
.includes(:granted_by)
|
||||
|
||||
render_serialized(user_badges, DetailedUserBadgeSerializer, root: "user_badges")
|
||||
render_serialized(user_badges, DetailedUserBadgeSerializer, root: :user_badges)
|
||||
end
|
||||
|
||||
def create
|
||||
|
|
12
app/models/user_badges.rb
Normal file
12
app/models/user_badges.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
# view model for user badges
|
||||
class UserBadges
|
||||
alias :read_attribute_for_serialization :send
|
||||
|
||||
attr_accessor :user_badges, :username, :grant_count
|
||||
|
||||
def initialize(opts={})
|
||||
@user_badges = opts[:user_badges]
|
||||
@username = opts[:username]
|
||||
@grant_count = opts[:grant_count]
|
||||
end
|
||||
end
|
|
@ -1,9 +1,14 @@
|
|||
class UserBadgeSerializer < ApplicationSerializer
|
||||
|
||||
class UserSerializer < BasicUserSerializer
|
||||
attributes :name, :moderator, :admin
|
||||
end
|
||||
|
||||
attributes :id, :granted_at, :count, :post_id, :post_number
|
||||
|
||||
has_one :badge
|
||||
has_one :user, serializer: BasicUserSerializer, root: :users
|
||||
has_one :granted_by, serializer: BasicUserSerializer, root: :users
|
||||
has_one :user, serializer: UserSerializer, root: :users
|
||||
has_one :granted_by, serializer: UserSerializer, root: :users
|
||||
has_one :topic, serializer: BasicTopicSerializer
|
||||
|
||||
def include_count?
|
||||
|
|
4
app/serializers/user_badges_serializer.rb
Normal file
4
app/serializers/user_badges_serializer.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
class UserBadgesSerializer < ApplicationSerializer
|
||||
has_many :user_badges, embed: :objects
|
||||
attributes :grant_count, :username
|
||||
end
|
|
@ -2746,6 +2746,10 @@ en:
|
|||
mark_watching: '<b>m</b>, <b>w</b> Watch topic'
|
||||
|
||||
badges:
|
||||
earned_n_times:
|
||||
one: "Earned this badge 1 time"
|
||||
other: "Earned this badge %{count} times"
|
||||
more_with_badge: "Others with this badge"
|
||||
title: Badges
|
||||
allow_title: "can be used as a title"
|
||||
multiple_grant: "can be awarded multiple times"
|
||||
|
|
|
@ -12,9 +12,11 @@ describe UserBadgesController do
|
|||
|
||||
xhr :get, :index, badge_id: badge.id
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
parsed = JSON.parse(response.body)
|
||||
expect(parsed["topics"]).to eq(nil)
|
||||
expect(parsed["user_badges"][0]["post_id"]).to eq(nil)
|
||||
expect(parsed["badges"].length).to eq(1)
|
||||
expect(parsed["user_badge_info"]["user_badges"][0]["post_id"]).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -38,7 +40,7 @@ describe UserBadgesController do
|
|||
|
||||
expect(response.status).to eq(200)
|
||||
parsed = JSON.parse(response.body)
|
||||
expect(parsed["user_badges"].length).to eq(1)
|
||||
expect(parsed["user_badge_info"]["user_badges"].length).to eq(1)
|
||||
end
|
||||
|
||||
it 'includes counts when passed the aggregate argument' do
|
||||
|
|
Loading…
Reference in a new issue