mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
Merge pull request #2372 from vikhyat/badge-system
Multiple grant badges
This commit is contained in:
@@ -9,14 +9,54 @@
|
||||
Discourse.AdminBadgesController = Ember.ArrayController.extend({
|
||||
itemController: 'adminBadge',
|
||||
queryParams: ['badgeId'],
|
||||
badgeId: Em.computed.alias('selectedId'),
|
||||
|
||||
/**
|
||||
ID of the currently selected badge.
|
||||
|
||||
@property badgeId
|
||||
@property selectedId
|
||||
@type {Integer}
|
||||
**/
|
||||
badgeId: Em.computed.alias('selectedItem.id'),
|
||||
selectedId: null,
|
||||
|
||||
/**
|
||||
Badge that is currently selected.
|
||||
|
||||
@property selectedItem
|
||||
@type {Discourse.Badge}
|
||||
**/
|
||||
selectedItem: function() {
|
||||
if (this.get('selectedId') === undefined || this.get('selectedId') === "undefined") {
|
||||
// New Badge
|
||||
return this.get('newBadge');
|
||||
} else {
|
||||
// Existing Badge
|
||||
var selectedId = parseInt(this.get('selectedId'));
|
||||
return this.get('model').filter(function(badge) {
|
||||
return parseInt(badge.get('id')) === selectedId;
|
||||
})[0];
|
||||
}
|
||||
}.property('selectedId', 'newBadge'),
|
||||
|
||||
/**
|
||||
Unsaved badge, if one exists.
|
||||
|
||||
@property newBadge
|
||||
@type {Discourse.Badge}
|
||||
**/
|
||||
newBadge: function() {
|
||||
return this.get('model').filter(function(badge) {
|
||||
return badge.get('id') === undefined;
|
||||
})[0];
|
||||
}.property('model.@each.id'),
|
||||
|
||||
/**
|
||||
Whether a new unsaved badge exists.
|
||||
|
||||
@property newBadgeExists
|
||||
@type {Discourse.Badge}
|
||||
**/
|
||||
newBadgeExists: Em.computed.notEmpty('newBadge'),
|
||||
|
||||
/**
|
||||
We don't allow setting a description if a translation for the given badge
|
||||
@@ -42,7 +82,7 @@ Discourse.AdminBadgesController = Ember.ArrayController.extend({
|
||||
|
||||
@method newBadge
|
||||
**/
|
||||
newBadge: function() {
|
||||
createNewBadge: function() {
|
||||
var badge = Discourse.Badge.create({
|
||||
name: I18n.t('admin.badges.new_badge')
|
||||
});
|
||||
@@ -57,7 +97,7 @@ Discourse.AdminBadgesController = Ember.ArrayController.extend({
|
||||
@param {Discourse.Badge} badge The badge to be selected
|
||||
**/
|
||||
selectBadge: function(badge) {
|
||||
this.set('selectedItem', badge);
|
||||
this.set('selectedId', badge.get('id'));
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -80,7 +120,7 @@ Discourse.AdminBadgesController = Ember.ArrayController.extend({
|
||||
// Delete immediately if the selected badge is new.
|
||||
if (!this.get('selectedItem.id')) {
|
||||
this.get('model').removeObject(this.get('selectedItem'));
|
||||
this.set('selectedItem', null);
|
||||
this.set('selectedId', null);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -90,7 +130,7 @@ Discourse.AdminBadgesController = Ember.ArrayController.extend({
|
||||
var selected = self.get('selectedItem');
|
||||
selected.destroy().then(function() {
|
||||
// Success.
|
||||
self.set('selectedItem', null);
|
||||
self.set('selectedId', null);
|
||||
self.get('model').removeObject(selected);
|
||||
}, function() {
|
||||
// Failure.
|
||||
|
||||
@@ -27,7 +27,7 @@ Discourse.AdminUserBadgesController = Ember.ArrayController.extend({
|
||||
|
||||
var badges = [];
|
||||
this.get('badges').forEach(function(badge) {
|
||||
if (!granted[badge.get('id')]) {
|
||||
if (badge.get('multiple_grant') || !granted[badge.get('id')]) {
|
||||
badges.push(badge);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
<button {{action newBadge}} class='btn'><i class="fa fa-plus"></i>{{i18n admin.badges.new}}</button>
|
||||
<button {{action createNewBadge}} {{bind-attr disabled=newBadgeExists}} class='btn'><i class="fa fa-plus"></i>{{i18n admin.badges.new}}</button>
|
||||
</div>
|
||||
|
||||
{{#if selectedItem}}
|
||||
@@ -47,7 +47,7 @@
|
||||
{{#if controller.canEditDescription}}
|
||||
{{textarea name="description" value=description}}
|
||||
{{else}}
|
||||
{{textarea name="description" value=translatedDescription disabled=true}}
|
||||
{{textarea name="description" value=displayDescription disabled=true}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
@@ -58,6 +58,13 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span>
|
||||
{{input type="checkbox" checked=multiple_grant disabled=readOnly}}
|
||||
{{i18n admin.badges.multiple_grant}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{{#unless readOnly}}
|
||||
<div class='buttons'>
|
||||
<button {{action save}} {{bind-attr disabled=controller.disableSave}} class='btn btn-primary'>{{i18n admin.badges.save}}</button>
|
||||
|
||||
@@ -3,5 +3,9 @@ Discourse.UserBadgeComponent = Ember.Component.extend({
|
||||
|
||||
badgeTypeClassName: function() {
|
||||
return "badge-type-" + this.get('badge.badge_type.name').toLowerCase();
|
||||
}.property('badge.badge_type.name')
|
||||
}.property('badge.badge_type.name'),
|
||||
|
||||
showGrantCount: function() {
|
||||
return this.get('count') && this.get('count') > 1;
|
||||
}.property('count')
|
||||
});
|
||||
|
||||
@@ -40,8 +40,8 @@ Discourse.Badge = Discourse.Model.extend({
|
||||
}.property('name', 'i18nNameKey'),
|
||||
|
||||
/**
|
||||
The i18n translated description for this badge. Returns the original
|
||||
description if no translation exists.
|
||||
The i18n translated description for this badge. Returns the null if no
|
||||
translation exists.
|
||||
|
||||
@property translatedDescription
|
||||
@type {String}
|
||||
@@ -50,11 +50,23 @@ Discourse.Badge = Discourse.Model.extend({
|
||||
var i18nKey = "badges.badge." + this.get('i18nNameKey') + ".description",
|
||||
translation = I18n.t(i18nKey);
|
||||
if (translation.indexOf(i18nKey) !== -1) {
|
||||
translation = this.get('description');
|
||||
translation = null;
|
||||
}
|
||||
return translation;
|
||||
}.property('i18nNameKey'),
|
||||
|
||||
/**
|
||||
Display-friendly description string. Returns either a translation or the
|
||||
original description string.
|
||||
|
||||
@property displayDescription
|
||||
@type {String}
|
||||
**/
|
||||
displayDescription: function() {
|
||||
var translated = this.get('translatedDescription');
|
||||
return translated === null ? this.get('description') : translated;
|
||||
}.property('description', 'translatedDescription'),
|
||||
|
||||
/**
|
||||
Update this badge with the response returned by the server on save.
|
||||
|
||||
@@ -103,7 +115,8 @@ Discourse.Badge = Discourse.Model.extend({
|
||||
name: this.get('name'),
|
||||
description: this.get('description'),
|
||||
badge_type_id: this.get('badge_type_id'),
|
||||
allow_title: this.get('allow_title')
|
||||
allow_title: !!this.get('allow_title'),
|
||||
multiple_grant: !!this.get('multiple_grant')
|
||||
}
|
||||
}).then(function(json) {
|
||||
self.updateFromJson(json);
|
||||
|
||||
@@ -79,10 +79,15 @@ Discourse.UserBadge.reopenClass({
|
||||
|
||||
@method findByUsername
|
||||
@param {String} username
|
||||
@param {Object} options
|
||||
@returns {Promise} a promise that resolves to an array of `Discourse.UserBadge`.
|
||||
**/
|
||||
findByUsername: function(username) {
|
||||
return Discourse.ajax("/user_badges.json?username=" + username).then(function(json) {
|
||||
findByUsername: function(username, options) {
|
||||
var url = "/user_badges.json?username=" + username;
|
||||
if (options && options.aggregated) {
|
||||
url += "&aggregated=true";
|
||||
}
|
||||
return Discourse.ajax(url).then(function(json) {
|
||||
return Discourse.UserBadge.createFromJson(json);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
**/
|
||||
Discourse.UserBadgesRoute = Discourse.Route.extend({
|
||||
model: function() {
|
||||
return Discourse.UserBadge.findByUsername(this.modelFor('user').get('username_lower'));
|
||||
return Discourse.UserBadge.findByUsername(this.modelFor('user').get('username_lower'), {aggregated: true});
|
||||
},
|
||||
|
||||
setupController: function(controller, model) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{{#each}}
|
||||
<tr>
|
||||
<td class='badge'>{{user-badge badge=this}}</td>
|
||||
<td class='description'>{{translatedDescription}}</td>
|
||||
<td class='description'>{{displayDescription}}</td>
|
||||
<td class='grant-count'>{{i18n badges.granted count=grant_count}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<table class='badges-listing'>
|
||||
<tr>
|
||||
<td class='badge'>{{user-badge badge=this}}</td>
|
||||
<td class='description'>{{translatedDescription}}</td>
|
||||
<td class='description'>{{displayDescription}}</td>
|
||||
<td class='grant-count'>{{i18n badges.granted count=grant_count}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
{{#link-to 'badges.show' badge}}
|
||||
<span {{bind-attr class=":user-badge badgeTypeClassName" data-badge-name="badge.name" title="badge.translatedDescription"}}>
|
||||
<span {{bind-attr class=":user-badge badgeTypeClassName" data-badge-name="badge.name" title="badge.displayDescription"}}>
|
||||
<i class='fa fa-certificate'></i>
|
||||
{{badge.displayName}}
|
||||
{{#if showGrantCount}}
|
||||
<span class="count">(× {{count}})</span>
|
||||
{{/if}}
|
||||
</span>
|
||||
{{/link-to}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<section class='user-content user-badges-list'>
|
||||
{{#each}}
|
||||
{{user-badge badge=badge}}
|
||||
{{user-badge badge=badge count=count}}
|
||||
{{/each}}
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user