Adds primary user group as a class to quote (#5285)

* Adds primary user group as a class to quote

This feature addition will add the class `group-PRIMARY_USER_GROUP` to
the quote `aside`. `PRIMARY_USER_GROUP` will be the primary user group
of the user being quoted. This is similar to the class that is added to
a `topic-post`.

* Remove trailing whitespace

* Fix avatar in test

* Address PR comments

* Fix trailing whitespace
This commit is contained in:
ckeboss 2017-11-03 06:51:40 -07:00 committed by Robin Ward
parent d320f4840d
commit 93633865d9
8 changed files with 99 additions and 12 deletions

View File

@ -75,6 +75,19 @@ export default Ember.Component.extend({
return tinyAvatar(quotedPost.get('avatar_template'));
}
}
},
lookupPrimaryUserGroupByPostNumber: (postNumber, topicId) => {
const topic = this.get('topic');
if (!topic) { return; }
const posts = topic.get('postStream.posts');
if (posts && topicId === topic.get('id')) {
const quotedPost = posts.findBy("post_number", postNumber);
if (quotedPost) {
return quotedPost.primary_group_name;
}
}
}
};
},

View File

@ -9,7 +9,7 @@ const rule = {
let options = state.md.options.discourse;
let quoteInfo = attrs['_default'];
let username, postNumber, topicId, avatarImg, full;
let username, postNumber, topicId, avatarImg, primaryGroupName, full;
if (quoteInfo) {
let split = quoteInfo.split(/\,\s*/);
@ -34,9 +34,30 @@ const rule = {
}
}
if (options.lookupAvatarByPostNumber) {
// client-side, we can retrieve the avatar from the post
avatarImg = options.lookupAvatarByPostNumber(postNumber, topicId);
} else if (options.lookupAvatar) {
// server-side, we need to lookup the avatar from the username
avatarImg = options.lookupAvatar(username);
}
let token = state.push('bbcode_open', 'aside', 1);
token.attrs = [['class', 'quote']];
if (options.lookupPrimaryUserGroupByPostNumber) {
// client-side, we can retrieve the primary user group from the post
primaryGroupName = options.lookupPrimaryUserGroupByPostNumber(postNumber, topicId);
} else if (options.lookupPrimaryUserGroup) {
// server-side, we need to lookup the primary user group from the username
primaryGroupName = options.lookupPrimaryUserGroup(username);
}
let token = state.push('bbcode_open', 'aside', 1);
token.attrs = [];
if (primaryGroupName && primaryGroupName.length !== 0) {
token.attrs.push(['class', `quote group-${primaryGroupName}`]);
} else {
token.attrs.push(['class', 'quote']);
}
if (postNumber) {
token.attrs.push(['data-post', postNumber]);
@ -50,14 +71,6 @@ const rule = {
token.attrs.push(['data-full', 'true']);
}
if (options.lookupAvatarByPostNumber) {
// client-side, we can retrieve the avatar from the post
avatarImg = options.lookupAvatarByPostNumber(postNumber, topicId);
} else if (options.lookupAvatar) {
// server-side, we need to lookup the avatar from the username
avatarImg = options.lookupAvatar(username);
}
if (username) {
let offTopicQuote = options.topicId &&
postNumber &&
@ -132,4 +145,11 @@ export function setup(helper) {
});
helper.whiteList(['img[class=avatar]']);
helper.whiteList({
custom(tag, name, value) {
if (tag === 'aside' && name === 'class') {
return !!/^quote group\-(.+)$/.exec(value);
}
}
});
}

View File

@ -12,6 +12,7 @@ export function buildOptions(state) {
siteSettings,
getURL,
lookupAvatar,
lookupPrimaryUserGroup,
getTopicInfo,
topicId,
categoryHashtagLookup,
@ -19,6 +20,7 @@ export function buildOptions(state) {
getCurrentUser,
currentUser,
lookupAvatarByPostNumber,
lookupPrimaryUserGroupByPostNumber,
emojiUnicodeReplacer,
lookupInlineOnebox,
lookupImageUrls,
@ -50,6 +52,7 @@ export function buildOptions(state) {
getURL,
features,
lookupAvatar,
lookupPrimaryUserGroup,
getTopicInfo,
topicId,
categoryHashtagLookup,
@ -57,6 +60,7 @@ export function buildOptions(state) {
getCurrentUser,
currentUser,
lookupAvatarByPostNumber,
lookupPrimaryUserGroupByPostNumber,
mentionLookup,
emojiUnicodeReplacer,
lookupInlineOnebox,

View File

@ -158,6 +158,7 @@ module PrettyText
__optInput.getURL = __getURL;
__optInput.getCurrentUser = __getCurrentUser;
__optInput.lookupAvatar = __lookupAvatar;
__optInput.lookupPrimaryUserGroup = __lookupPrimaryUserGroup;
__optInput.getTopicInfo = __getTopicInfo;
__optInput.categoryHashtagLookup = __categoryLookup;
__optInput.mentionLookup = __mentionLookup;

View File

@ -25,6 +25,14 @@ module PrettyText
UrlHelper.schemaless(UrlHelper.absolute(user.avatar_template))
end
def lookup_primary_user_group(username)
return "" unless username
user = User.find_by(username_lower: username.downcase)
return "" unless user.present?
user.primary_group.try(:name) || ""
end
def mention_lookup(name)
return false if name.blank?
return "group" if Group.exists?(name: name)

View File

@ -73,6 +73,10 @@ function __lookupAvatar(p) {
return __utils.avatarImg({size: "tiny", avatarTemplate: __helpers.avatar_template(p) }, __getURL);
}
function __lookupPrimaryUserGroup(p) {
return __helpers.lookup_primary_user_group(p);
}
function __getCurrentUser(userId) {
return __helpers.get_current_user(userId);
}

View File

@ -113,6 +113,34 @@ describe PrettyText do
end
end
describe "with primary user group" do
let(:default_avatar) { "//test.localhost/uploads/default/avatars/42d/57c/46ce7ee487/{size}.png" }
let(:group) { Fabricate(:group) }
let!(:user) { Fabricate(:user, primary_group: group) }
before do
User.stubs(:default_template).returns(default_avatar)
end
it "adds primary group class to referenced users quote" do
topic = Fabricate(:topic, title: "this is a test topic")
expected = <<~HTML
<aside class="quote group-#{group.name}" data-topic="#{topic.id}" data-post="2">
<div class="title">
<div class="quote-controls"></div>
<img alt class='avatar' height='20' src='//test.localhost/uploads/default/avatars/42d/57c/46ce7ee487/40.png' width='20'><a href='http://test.localhost/t/this-is-a-test-topic/#{topic.id}/2'>This is a test topic</a>
</div>
<blockquote>
<p>ddd</p>
</blockquote>
</aside>
HTML
expect(cook("[quote=\"#{user.username}, post:2, topic:#{topic.id}\"]\nddd\n[/quote]", topic_id: 1)).to eq(n(expected))
end
end
it "can handle inline block bbcode" do
cooked = PrettyText.cook("[quote]te **s** t[/quote]")

View File

@ -244,7 +244,6 @@ QUnit.test("Quotes", assert => {
</aside>`,
"works with multiple lines");
assert.cookedOptions("[quote=\"bob, post:1\"]\nmy quote\n[/quote]",
{ topicId: 2, lookupAvatar: function() { } },
`<aside class=\"quote\" data-post=\"1\">
@ -270,6 +269,16 @@ QUnit.test("Quotes", assert => {
</aside>`,
"handles nested quotes properly");
assert.cookedOptions(`[quote="bob, post:1, topic:1"]\ntest quote\n[/quote]`, { lookupPrimaryUserGroupByPostNumber: () => "aUserGroup" },
`<aside class="quote group-aUserGroup" data-post="1" data-topic="1">
<div class="title">
<div class="quote-controls"></div>
bob:</div>
<blockquote>
<p>test quote</p>
</blockquote>
</aside>`,
"quote has group class");
});
QUnit.test("Mentions", assert => {