diff --git a/app/assets/javascripts/discourse/app/components/avatar-flair.js b/app/assets/javascripts/discourse/app/components/avatar-flair.js index 8e6331d3307..dbc3020f278 100644 --- a/app/assets/javascripts/discourse/app/components/avatar-flair.js +++ b/app/assets/javascripts/discourse/app/components/avatar-flair.js @@ -4,17 +4,17 @@ import { observes } from "discourse-common/utils/decorators"; export default MountWidget.extend({ widget: "avatar-flair", - @observes("flairURL", "flairBgColor", "flairColor") + @observes("flairName", "flairUrl", "flairBgColor", "flairColor") _rerender() { this.queueRerender(); }, buildArgs() { return { - primary_group_flair_url: this.flairURL, - primary_group_flair_bg_color: this.flairBgColor, - primary_group_flair_color: this.flairColor, - primary_group_name: this.groupName, + flair_name: this.flairName, + flair_url: this.flairUrl, + flair_bg_color: this.flairBgColor, + flair_color: this.flairColor, }; }, }); diff --git a/app/assets/javascripts/discourse/app/components/group-flair-inputs.js b/app/assets/javascripts/discourse/app/components/group-flair-inputs.js index 5a53a6f740d..b6a9cbaec04 100644 --- a/app/assets/javascripts/discourse/app/components/group-flair-inputs.js +++ b/app/assets/javascripts/discourse/app/components/group-flair-inputs.js @@ -67,8 +67,8 @@ export default Component.extend({ }, @discourseComputed("model.flair_url") - flairImageUrl(flairURL) { - return flairURL && flairURL.match(/\//) ? flairURL : null; + flairImageUrl(flairUrl) { + return flairUrl && flairUrl.includes("/") ? flairUrl : null; }, @discourseComputed( @@ -78,7 +78,7 @@ export default Component.extend({ "model.flairHexColor" ) flairPreviewStyle( - flairURL, + flairUrl, flairPreviewImage, flairBackgroundHexColor, flairHexColor @@ -86,7 +86,7 @@ export default Component.extend({ let style = ""; if (flairPreviewImage) { - style += `background-image: url(${escapeExpression(flairURL)});`; + style += `background-image: url(${escapeExpression(flairUrl)});`; } if (flairBackgroundHexColor) { diff --git a/app/assets/javascripts/discourse/app/components/user-avatar-flair.js b/app/assets/javascripts/discourse/app/components/user-avatar-flair.js index 35def72c694..079de882165 100644 --- a/app/assets/javascripts/discourse/app/components/user-avatar-flair.js +++ b/app/assets/javascripts/discourse/app/components/user-avatar-flair.js @@ -10,28 +10,23 @@ export default Component.extend({ if (!user) { return; } - return this.primaryGroupFlair(user) || this.automaticGroupFlair(user); - }, - primaryGroupFlair(user) { - if (user.primary_group_flair_url || user.primary_group_flair_bg_color) { + if (user.flair_url || user.flair_bg_color) { return { - flairURL: user.primary_group_flair_url, - flairBgColor: user.primary_group_flair_bg_color, - flairColor: user.primary_group_flair_color, - groupName: user.primary_group_name, + flairName: user.flair_name, + flairUrl: user.flair_url, + flairBgColor: user.flair_bg_color, + flairColor: user.flair_color, }; } - }, - automaticGroupFlair(user) { const autoFlairAttrs = autoGroupFlairForUser(this.site, user); if (autoFlairAttrs) { return { - flairURL: autoFlairAttrs.primary_group_flair_url, - flairBgColor: autoFlairAttrs.primary_group_flair_bg_color, - flairColor: autoFlairAttrs.primary_group_flair_color, - groupName: autoFlairAttrs.primary_group_name, + flairName: autoFlairAttrs.flair_name, + flairUrl: autoFlairAttrs.flair_url, + flairBgColor: autoFlairAttrs.flair_bg_color, + flairColor: autoFlairAttrs.flair_color, }; } }, diff --git a/app/assets/javascripts/discourse/app/controllers/group.js b/app/assets/javascripts/discourse/app/controllers/group.js index ba0b0ed4341..416bf58a76a 100644 --- a/app/assets/javascripts/discourse/app/controllers/group.js +++ b/app/assets/javascripts/discourse/app/controllers/group.js @@ -101,21 +101,6 @@ export default Controller.extend({ return (fullName || displayName).capitalize(); }, - @discourseComputed( - "model.name", - "model.flair_url", - "model.flair_bg_color", - "model.flair_color" - ) - avatarFlairAttributes(groupName, flairURL, flairBgColor, flairColor) { - return { - primary_group_flair_url: flairURL, - primary_group_flair_bg_color: flairBgColor, - primary_group_flair_color: flairColor, - primary_group_name: groupName, - }; - }, - @discourseComputed("model.messageable") displayGroupMessageButton(messageable) { return this.currentUser && messageable; diff --git a/app/assets/javascripts/discourse/app/controllers/preferences/account.js b/app/assets/javascripts/discourse/app/controllers/preferences/account.js index d78d084324a..c474ed14429 100644 --- a/app/assets/javascripts/discourse/app/controllers/preferences/account.js +++ b/app/assets/javascripts/discourse/app/controllers/preferences/account.js @@ -15,7 +15,12 @@ export default Controller.extend(CanCheckEmails, { init() { this._super(...arguments); - this.saveAttrNames = ["name", "title", "primary_group_id"]; + this.saveAttrNames = [ + "name", + "title", + "primary_group_id", + "flair_group_id", + ]; this.set("revoking", {}); }, @@ -45,6 +50,7 @@ export default Controller.extend(CanCheckEmails, { }, canSelectTitle: gt("model.availableTitles.length", 0), + canSelectFlair: gt("model.availableFlairs.length", 0), @discourseComputed("model.filteredGroups") canSelectPrimaryGroup(primaryGroupOptions) { @@ -132,6 +138,7 @@ export default Controller.extend(CanCheckEmails, { name: this.newNameInput, title: this.newTitleInput, primary_group_id: this.newPrimaryGroupInput, + flair_group_id: this.newFlairGroupId, }); return this.model diff --git a/app/assets/javascripts/discourse/app/lib/avatar-flair.js b/app/assets/javascripts/discourse/app/lib/avatar-flair.js index 3a8bb1f495d..ead1eafa365 100644 --- a/app/assets/javascripts/discourse/app/lib/avatar-flair.js +++ b/app/assets/javascripts/discourse/app/lib/avatar-flair.js @@ -56,10 +56,10 @@ function initializeAutoGroupFlair(site) { if (group && group.flair_url) { _noAutoFlair = false; _autoGroupFlair[groupName] = { - primary_group_flair_url: group.flair_url, - primary_group_flair_bg_color: group.flair_bg_color, - primary_group_flair_color: group.flair_color, - primary_group_name: group.name.replace(/_/g, " "), + flair_name: group.name.replace(/_/g, " "), + flair_url: group.flair_url, + flair_bg_color: group.flair_bg_color, + flair_color: group.flair_color, }; } }); diff --git a/app/assets/javascripts/discourse/app/lib/transform-post.js b/app/assets/javascripts/discourse/app/lib/transform-post.js index b2d5e01ce2c..b9695b51fed 100644 --- a/app/assets/javascripts/discourse/app/lib/transform-post.js +++ b/app/assets/javascripts/discourse/app/lib/transform-post.js @@ -21,9 +21,10 @@ export function transformBasicPost(post) { deletedByAvatarTemplate: null, deletedByUsername: null, primary_group_name: post.primary_group_name, - primary_group_flair_url: post.primary_group_flair_url, - primary_group_flair_bg_color: post.primary_group_flair_bg_color, - primary_group_flair_color: post.primary_group_flair_color, + flair_name: post.flair_name, + flair_url: post.flair_url, + flair_bg_color: post.flair_bg_color, + flair_color: post.flair_color, wiki: post.wiki, lastWikiEdit: post.last_wiki_edit, firstPost: post.post_number === 1, diff --git a/app/assets/javascripts/discourse/app/models/user.js b/app/assets/javascripts/discourse/app/models/user.js index 4d8a9cfe083..4b2b4e905f6 100644 --- a/app/assets/javascripts/discourse/app/models/user.js +++ b/app/assets/javascripts/discourse/app/models/user.js @@ -59,6 +59,7 @@ let userFields = [ "watching_first_post_tags", "date_of_birth", "primary_group_id", + "flair_group_id", "user_notification_schedule", ]; @@ -863,7 +864,7 @@ const User = RestModel.extend({ @discourseComputed("groups.@each.title", "badges.[]") availableTitles() { - let titles = []; + const titles = []; (this.groups || []).forEach((group) => { if (get(group, "title")) { @@ -888,6 +889,27 @@ const User = RestModel.extend({ }); }, + @discourseComputed("groups.[]") + availableFlairs() { + const flairs = []; + + if (this.groups) { + this.groups.forEach((group) => { + if (group.flair_url) { + flairs.push({ + id: group.id, + name: group.name, + url: group.flair_url, + bgColor: group.flair_bg_color, + color: group.flair_color, + }); + } + }); + } + + return flairs; + }, + @discourseComputed("user_option.text_size_seq", "user_option.text_size") currentTextSize(serverSeq, serverSize) { if (cookie("text_size")) { diff --git a/app/assets/javascripts/discourse/app/routes/preferences-account.js b/app/assets/javascripts/discourse/app/routes/preferences-account.js index a56664daf65..47bcae2b828 100644 --- a/app/assets/javascripts/discourse/app/routes/preferences-account.js +++ b/app/assets/javascripts/discourse/app/routes/preferences-account.js @@ -29,6 +29,7 @@ export default RestrictedUserRoute.extend({ newNameInput: user.get("name"), newTitleInput: user.get("title"), newPrimaryGroupInput: user.get("primary_group_id"), + newFlairGroupId: user.get("flair_group_id"), }); }, diff --git a/app/assets/javascripts/discourse/app/templates/components/group-card-contents.hbs b/app/assets/javascripts/discourse/app/templates/components/group-card-contents.hbs index 42d032eb68a..3527dac61e4 100644 --- a/app/assets/javascripts/discourse/app/templates/components/group-card-contents.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/group-card-contents.hbs @@ -4,10 +4,10 @@
{{avatar-flair - flairURL=group.flair_url + flairName=group.name + flairUrl=group.flair_url flairBgColor=group.flair_bg_color flairColor=group.flair_color - groupName=group.name }}
diff --git a/app/assets/javascripts/discourse/app/templates/components/user-avatar-flair.hbs b/app/assets/javascripts/discourse/app/templates/components/user-avatar-flair.hbs index f802da599d0..cf88fa58040 100644 --- a/app/assets/javascripts/discourse/app/templates/components/user-avatar-flair.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/user-avatar-flair.hbs @@ -1,7 +1,8 @@ {{#if flair}} {{avatar-flair - flairURL=flair.flairURL + flairName=flair.flairName + flairUrl=flair.flairUrl flairBgColor=flair.flairBgColor flairColor=flair.flairColor - groupName=flair.groupName}} + }} {{/if}} diff --git a/app/assets/javascripts/discourse/app/templates/group.hbs b/app/assets/javascripts/discourse/app/templates/group.hbs index 2ea514c60d9..b3a03b7b451 100644 --- a/app/assets/javascripts/discourse/app/templates/group.hbs +++ b/app/assets/javascripts/discourse/app/templates/group.hbs @@ -12,10 +12,10 @@ {{#if model.flair_url}}
{{avatar-flair - flairURL=model.flair_url + flairName=model.name + flairUrl=model.flair_url flairBgColor=model.flair_bg_color flairColor=model.flair_color - groupName=model.name }}
{{/if}} diff --git a/app/assets/javascripts/discourse/app/templates/groups/index.hbs b/app/assets/javascripts/discourse/app/templates/groups/index.hbs index dce8efb676e..6396cf57b1b 100644 --- a/app/assets/javascripts/discourse/app/templates/groups/index.hbs +++ b/app/assets/javascripts/discourse/app/templates/groups/index.hbs @@ -44,10 +44,11 @@ {{#if group.flair_url}} {{avatar-flair - flairURL=group.flair_url - flairBgColor=group.flair_bg_color - flairColor=group.flair_color - groupName=group.name}} + flairName=group.name + flairUrl=group.flair_url + flairBgColor=group.flair_bg_color + flairColor=group.flair_color + }} {{/if}} diff --git a/app/assets/javascripts/discourse/app/templates/preferences/account.hbs b/app/assets/javascripts/discourse/app/templates/preferences/account.hbs index daad557a38e..3e203fadcdb 100644 --- a/app/assets/javascripts/discourse/app/templates/preferences/account.hbs +++ b/app/assets/javascripts/discourse/app/templates/preferences/account.hbs @@ -158,6 +158,26 @@ onChange=(action (mut newTitleInput)) }} +
+ {{i18n "user.title.instructions"}} +
+ +{{/if}} + +{{#if canSelectFlair}} +
+ +
+ {{flair-chooser + value=newFlairGroupId + content=model.availableFlairs + none="user.flair.none" + onChange=(action (mut newFlairGroupId)) + }} +
+
+ {{i18n "user.flair.instructions"}} +
{{/if}} diff --git a/app/assets/javascripts/discourse/app/widgets/avatar-flair.js b/app/assets/javascripts/discourse/app/widgets/avatar-flair.js index 450b8bb40f0..ae1d0d4d101 100644 --- a/app/assets/javascripts/discourse/app/widgets/avatar-flair.js +++ b/app/assets/javascripts/discourse/app/widgets/avatar-flair.js @@ -6,19 +6,16 @@ createWidget("avatar-flair", { tagName: "div.avatar-flair", isIcon(attrs) { - return ( - attrs.primary_group_flair_url && - !attrs.primary_group_flair_url.includes("/") - ); + return attrs.flair_url && !attrs.flair_url.includes("/"); }, title(attrs) { - return attrs.primary_group_name; + return attrs.flair_name; }, buildClasses(attrs) { - let defaultClass = `avatar-flair-${attrs.primary_group_name} ${ - attrs.primary_group_flair_bg_color ? "rounded" : "" + let defaultClass = `avatar-flair-${attrs.flair_name} ${ + attrs.flair_bg_color ? "rounded" : "" }`; if (!this.isIcon(attrs)) { @@ -32,26 +29,21 @@ createWidget("avatar-flair", { let style = ""; if (!this.isIcon(attrs)) { style += - "background-image: url(" + - escapeExpression(attrs.primary_group_flair_url) + - "); "; + "background-image: url(" + escapeExpression(attrs.flair_url) + "); "; } - if (attrs.primary_group_flair_bg_color) { + if (attrs.flair_bg_color) { style += - "background-color: #" + - escapeExpression(attrs.primary_group_flair_bg_color) + - "; "; + "background-color: #" + escapeExpression(attrs.flair_bg_color) + "; "; } - if (attrs.primary_group_flair_color) { - style += - "color: #" + escapeExpression(attrs.primary_group_flair_color) + "; "; + if (attrs.flair_color) { + style += "color: #" + escapeExpression(attrs.flair_color) + "; "; } - return { style: style }; + return { style }; }, html(attrs) { if (this.isIcon(attrs)) { - const icon = convertIconClass(attrs.primary_group_flair_url); + const icon = convertIconClass(attrs.flair_url); return [iconNode(icon)]; } else { return []; diff --git a/app/assets/javascripts/discourse/app/widgets/post.js b/app/assets/javascripts/discourse/app/widgets/post.js index f03364e14ad..1021ecf76cd 100644 --- a/app/assets/javascripts/discourse/app/widgets/post.js +++ b/app/assets/javascripts/discourse/app/widgets/post.js @@ -187,7 +187,7 @@ createWidget("post-avatar", { const result = [body]; - if (attrs.primary_group_flair_url || attrs.primary_group_flair_bg_color) { + if (attrs.flair_url || attrs.flair_bg_color) { result.push(this.attach("avatar-flair", attrs)); } else { const autoFlairAttrs = autoGroupFlairForUser(this.site, attrs); diff --git a/app/assets/javascripts/discourse/app/widgets/search-menu-results.js b/app/assets/javascripts/discourse/app/widgets/search-menu-results.js index b8992303dee..3a5885d9479 100644 --- a/app/assets/javascripts/discourse/app/widgets/search-menu-results.js +++ b/app/assets/javascripts/discourse/app/widgets/search-menu-results.js @@ -102,10 +102,10 @@ createSearchResult({ let avatarFlair; if (group.flairUrl) { avatarFlair = this.attach("avatar-flair", { - primary_group_flair_url: group.flairUrl, - primary_group_flair_bg_color: group.flairBgColor, - primary_group_flair_color: group.flairColor, - primary_group_name: name, + flair_name: name, + flair_url: group.flairUrl, + flair_bg_color: group.flairBgColor, + flair_color: group.flairColor, }); } else { avatarFlair = iconNode("users"); diff --git a/app/assets/javascripts/discourse/app/widgets/topic-map.js b/app/assets/javascripts/discourse/app/widgets/topic-map.js index 7427717a801..9ecb167fc23 100644 --- a/app/assets/javascripts/discourse/app/widgets/topic-map.js +++ b/app/assets/javascripts/discourse/app/widgets/topic-map.js @@ -79,7 +79,7 @@ createWidget("topic-participant", { linkContents.push(h("span.post-count", attrs.post_count.toString())); } - if (attrs.primary_group_flair_url || attrs.primary_group_flair_bg_color) { + if (attrs.flair_url || attrs.flair_bg_color) { linkContents.push(this.attach("avatar-flair", attrs)); } else { const autoFlairAttrs = autoGroupFlairForUser(this.site, attrs); diff --git a/app/assets/javascripts/discourse/tests/fixtures/poll.js b/app/assets/javascripts/discourse/tests/fixtures/poll.js index 674c711a4b5..e1c33f7a078 100644 --- a/app/assets/javascripts/discourse/tests/fixtures/poll.js +++ b/app/assets/javascripts/discourse/tests/fixtures/poll.js @@ -571,9 +571,10 @@ export default { topic_slug: "14-the-title-must-be-longer-i-guess", display_username: "", primary_group_name: "Team", - primary_group_flair_url: null, - primary_group_flair_bg_color: "", - primary_group_flair_color: "", + flair_name: null, + flair_url: null, + flair_bg_color: "", + flair_color: "", version: 1, can_edit: false, can_delete: false, @@ -711,9 +712,10 @@ export default { avatar_template: "/user_avatar/localhost/markvanlan/{size}/11_2.png", post_count: 1, primary_group_name: "Team", - primary_group_flair_url: null, - primary_group_flair_color: "", - primary_group_flair_bg_color: "" + flair_name: null, + flair_url: null, + flair_color: "", + flair_bg_color: "" } ], created_by: { diff --git a/app/assets/javascripts/discourse/tests/fixtures/post.js b/app/assets/javascripts/discourse/tests/fixtures/post.js index bed4d1b4617..d8252dc786c 100644 --- a/app/assets/javascripts/discourse/tests/fixtures/post.js +++ b/app/assets/javascripts/discourse/tests/fixtures/post.js @@ -21,9 +21,10 @@ export default { topic_slug: "test-pm", display_username: null, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_bg_color: null, - primary_group_flair_color: null, + flair_name: null, + flair_url: null, + flair_bg_color: null, + flair_color: null, version: 1, can_edit: true, can_delete: false, diff --git a/app/assets/javascripts/discourse/tests/fixtures/topic.js b/app/assets/javascripts/discourse/tests/fixtures/topic.js index a5f8b7bbe68..cf9740bba86 100644 --- a/app/assets/javascripts/discourse/tests/fixtures/topic.js +++ b/app/assets/javascripts/discourse/tests/fixtures/topic.js @@ -27,9 +27,10 @@ export default { topic_slug: "lorem-ipsum-dolor-sit-amet", display_username: null, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_bg_color: null, - primary_group_flair_color: null, + flair_name: null, + flair_url: null, + flair_bg_color: null, + flair_color: null, version: 1, can_edit: true, can_delete: false, @@ -167,9 +168,10 @@ export default { avatar_template: "/letter_avatar_proxy/v4/letter/b/3be4f8/{size}.png", post_count: 1, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_color: null, - primary_group_flair_bg_color: null, + flair_name: null, + flair_url: null, + flair_color: null, + flair_bg_color: null, }, ], allowed_users: [ @@ -207,6 +209,7 @@ export default { grant_trust_level: null, incoming_email: null, has_messages: true, + flair_name: null, flair_url: null, flair_bg_color: "", flair_color: "", @@ -4217,9 +4220,10 @@ export default { topic_slug: "pm-for-testing", display_username: null, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_bg_color: null, - primary_group_flair_color: null, + flair_name: null, + flair_url: null, + flair_bg_color: null, + flair_color: null, version: 1, can_edit: true, can_delete: false, @@ -4269,9 +4273,10 @@ export default { topic_slug: "pm-for-testing", display_username: null, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_bg_color: null, - primary_group_flair_color: null, + flair_name: null, + flair_url: null, + flair_bg_color: null, + flair_color: null, version: 1, can_edit: true, can_delete: true, @@ -4363,6 +4368,7 @@ export default { grant_trust_level: null, incoming_email: null, has_messages: false, + flair_name: null, flair_url: null, flair_bg_color: null, flair_color: null, @@ -4384,9 +4390,10 @@ export default { avatar_template: "/images/avatar.png", post_count: 2, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_color: null, - primary_group_flair_bg_color: null, + flair_name: null, + flair_url: null, + flair_color: null, + flair_bg_color: null, }, ], suggested_topics: [ @@ -5064,9 +5071,10 @@ export default { topic_slug: "test-pm", display_username: null, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_bg_color: null, - primary_group_flair_color: null, + flair_name: null, + flair_url: null, + flair_bg_color: null, + flair_color: null, version: 1, can_edit: true, can_delete: false, @@ -5126,9 +5134,10 @@ export default { topic_slug: "test-pm", display_username: "Tim Lange", primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_bg_color: null, - primary_group_flair_color: null, + flair_name: null, + flair_url: null, + flair_bg_color: null, + flair_color: null, version: 1, can_edit: true, can_delete: true, @@ -5237,9 +5246,10 @@ export default { avatar_template: "/images/avatar.png", post_count: 2, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_color: null, - primary_group_flair_bg_color: null, + flair_name: null, + flair_url: null, + flair_color: null, + flair_bg_color: null, }, { id: 2, @@ -5248,9 +5258,10 @@ export default { avatar_template: "/images/avatar.png", post_count: 1, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_color: null, - primary_group_flair_bg_color: null, + flair_name: null, + flair_url: null, + flair_color: null, + flair_bg_color: null, }, ], notification_level: 3, @@ -5317,9 +5328,10 @@ export default { topic_slug: "a-topic-with-group-category-moderators", display_username: "", primary_group_name: "group_moderators", - primary_group_flair_url: "cheese", - primary_group_flair_bg_color: "ff0", - primary_group_flair_color: "", + flair_name: "group_moderators", + flair_url: "cheese", + flair_bg_color: "ff0", + flair_color: "", version: 1, can_edit: true, can_delete: false, @@ -5385,9 +5397,10 @@ export default { topic_slug: "a-topic-with-group-category-moderators", display_username: "", primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_bg_color: null, - primary_group_flair_color: null, + flair_name: null, + flair_url: null, + flair_bg_color: null, + flair_color: null, version: 1, can_edit: false, can_delete: false, @@ -5459,9 +5472,9 @@ export default { topic_slug: "a-topic-with-group-category-moderators", display_username: "", primary_group_name: "group_moderators", - primary_group_flair_url: "cheese", - primary_group_flair_bg_color: "ff0", - primary_group_flair_color: "", + flair_url: "cheese", + flair_bg_color: "ff0", + flair_color: "", version: 1, can_edit: true, can_delete: true, @@ -5596,9 +5609,10 @@ export default { avatar_template: "/images/avatar.png", post_count: 2, primary_group_name: "group_moderators", - primary_group_flair_url: "cheese", - primary_group_flair_color: "", - primary_group_flair_bg_color: "ff0", + flar_name: "group_moderators", + flair_url: "cheese", + flair_color: "", + flair_bg_color: "ff0", }, { id: 2, @@ -5607,9 +5621,10 @@ export default { avatar_template: "/images/avatar.png", post_count: 1, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_color: null, - primary_group_flair_bg_color: null, + flair_name: null, + flair_url: null, + flair_color: null, + flair_bg_color: null, }, ], created_by: { diff --git a/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js b/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js index 608d916cb7d..e1b428f0db8 100644 --- a/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js +++ b/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js @@ -2508,9 +2508,10 @@ export default { time_read: 0, recent_time_read: 0, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_bg_color: null, - primary_group_flair_color: null, + flair_name: null, + flair_url: null, + flair_bg_color: null, + flair_color: null, staged: false, second_factor_enabled: false, post_count: 0, @@ -2755,9 +2756,10 @@ export default { time_read: 0, recent_time_read: 0, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_bg_color: null, - primary_group_flair_color: null, + flair_name: null, + flair_url: null, + flair_bg_color: null, + flair_color: null, staged: false, featured_user_badge_ids: [17], }, @@ -2870,9 +2872,10 @@ export default { time_read: 0, recent_time_read: 0, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_bg_color: null, - primary_group_flair_color: null, + flair_name: null, + flair_url: null, + flair_bg_color: null, + flair_color: null, second_factor_enabled: false, second_factor_backup_enabled: false, associated_accounts: [], diff --git a/app/assets/javascripts/discourse/tests/integration/components/user-avatar-flair-test.js b/app/assets/javascripts/discourse/tests/integration/components/user-avatar-flair-test.js index bc457a57d06..d9ecf2f0397 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/user-avatar-flair-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/user-avatar-flair-test.js @@ -175,9 +175,10 @@ discourseModule( admin: false, moderator: false, trust_level: 3, - primary_group_flair_url: "fa-times", - primary_group_flair_bg_color: "123456", - primary_group_flair_color: "B0B0B0", + flair_name: "Band Geeks", + flair_url: "fa-times", + flair_bg_color: "123456", + flair_color: "B0B0B0", primary_group_name: "Band Geeks", }); setupSiteGroups(this); diff --git a/app/assets/javascripts/discourse/tests/integration/widgets/avatar-flair-test.js b/app/assets/javascripts/discourse/tests/integration/widgets/avatar-flair-test.js index 1ed63b8bc21..022b1e9f2e3 100644 --- a/app/assets/javascripts/discourse/tests/integration/widgets/avatar-flair-test.js +++ b/app/assets/javascripts/discourse/tests/integration/widgets/avatar-flair-test.js @@ -17,9 +17,9 @@ discourseModule( template: hbs`{{mount-widget widget="avatar-flair" args=args}}`, beforeEach() { this.set("args", { - primary_group_flair_url: "fa-bars", - primary_group_flair_bg_color: "CC0000", - primary_group_flair_color: "FFFFFF", + flair_url: "fa-bars", + flair_bg_color: "CC0000", + flair_color: "FFFFFF", }); }, test(assert) { @@ -37,7 +37,7 @@ discourseModule( template: hbs`{{mount-widget widget="avatar-flair" args=args}}`, beforeEach() { this.set("args", { - primary_group_flair_url: "/images/avatar.png", + flair_url: "/images/avatar.png", }); }, test(assert) { diff --git a/app/assets/javascripts/discourse/tests/integration/widgets/topic-participant-test.js b/app/assets/javascripts/discourse/tests/integration/widgets/topic-participant-test.js index 57acca0e2ca..1c81bed4973 100644 --- a/app/assets/javascripts/discourse/tests/integration/widgets/topic-participant-test.js +++ b/app/assets/javascripts/discourse/tests/integration/widgets/topic-participant-test.js @@ -39,8 +39,9 @@ discourseModule( avatar_template: "/images/avatar.png", post_count: 5, primary_group_name: "devs", - primary_group_flair_url: "/images/d-logo-sketch-small.png", - primary_group_flair_bg_color: "222", + flair_name: "devs", + flair_url: "/images/d-logo-sketch-small.png", + flair_bg_color: "222", }); }, diff --git a/app/assets/javascripts/select-kit/addon/components/flair-chooser.js b/app/assets/javascripts/select-kit/addon/components/flair-chooser.js new file mode 100644 index 00000000000..96e912e0959 --- /dev/null +++ b/app/assets/javascripts/select-kit/addon/components/flair-chooser.js @@ -0,0 +1,14 @@ +import ComboBoxComponent from "select-kit/components/combo-box"; + +export default ComboBoxComponent.extend({ + pluginApiIdentifiers: ["flair-chooser"], + classNames: ["flair-chooser"], + + selectKitOptions: { + selectedNameComponent: "selected-flair", + }, + + modifyComponentForRow() { + return "flair-row"; + }, +}); diff --git a/app/assets/javascripts/select-kit/addon/components/flair-row.js b/app/assets/javascripts/select-kit/addon/components/flair-row.js new file mode 100644 index 00000000000..6edbf8cab2b --- /dev/null +++ b/app/assets/javascripts/select-kit/addon/components/flair-row.js @@ -0,0 +1,7 @@ +import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row"; +import layout from "select-kit/templates/components/flair-row"; + +export default SelectKitRowComponent.extend({ + layout, + classNames: ["flair-row"], +}); diff --git a/app/assets/javascripts/select-kit/addon/components/selected-flair.js b/app/assets/javascripts/select-kit/addon/components/selected-flair.js new file mode 100644 index 00000000000..b4ddf9ac3a4 --- /dev/null +++ b/app/assets/javascripts/select-kit/addon/components/selected-flair.js @@ -0,0 +1,7 @@ +import SelectedNameComponent from "select-kit/components/selected-name"; +import layout from "select-kit/templates/components/flair-row"; + +export default SelectedNameComponent.extend({ + layout, + tagName: "", +}); diff --git a/app/assets/javascripts/select-kit/addon/templates/components/flair-row.hbs b/app/assets/javascripts/select-kit/addon/templates/components/flair-row.hbs new file mode 100644 index 00000000000..f4bdb2aa30b --- /dev/null +++ b/app/assets/javascripts/select-kit/addon/templates/components/flair-row.hbs @@ -0,0 +1,10 @@ +{{#if item.url}} + {{avatar-flair + flairName=item.name + flairUrl=item.url + flairBgColor=item.bgColor + flairColor=item.color + }} +{{/if}} + +{{label}} diff --git a/app/assets/stylesheets/common/select-kit/_index.scss b/app/assets/stylesheets/common/select-kit/_index.scss index 26789b351c1..2aabed53746 100644 --- a/app/assets/stylesheets/common/select-kit/_index.scss +++ b/app/assets/stylesheets/common/select-kit/_index.scss @@ -8,6 +8,7 @@ @import "composer-actions"; @import "dropdown-select-box"; @import "email-group-user-chooser"; +@import "flair-row"; @import "future-date-input-selector"; @import "icon-picker"; @import "list-setting"; diff --git a/app/assets/stylesheets/common/select-kit/flair-row.scss b/app/assets/stylesheets/common/select-kit/flair-row.scss new file mode 100644 index 00000000000..d6ecec579c2 --- /dev/null +++ b/app/assets/stylesheets/common/select-kit/flair-row.scss @@ -0,0 +1,29 @@ +.flair-chooser .select-kit-header, +.select-kit .flair-row { + .avatar-flair { + align-items: center; + background-position: center; + background-repeat: no-repeat; + background-size: 30px 30px; + display: flex; + justify-content: center; + margin-right: 5px; + height: 30px; + width: 30px; + + &.rounded { + background-size: (30px / 1.4) (30px / 1.4); + border-radius: 50%; + } + + .d-icon { + display: block; + height: (30px / 1.8); + width: (30px / 1.8); + } + } +} + +.select-kit.flair-chooser .select-kit-header { + padding: 2px 4px; +} diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index c59a97b71c4..0003cca8539 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -61,7 +61,7 @@ class PostsController < ApplicationController .where('posts.id <= ?', last_post_id) .where('posts.id > ?', last_post_id - 50) .includes(topic: :category) - .includes(user: :primary_group) + .includes(user: [:primary_group, :flair_group]) .includes(:reply_to_user) .limit(50) rss_description = I18n.t("rss_description.private_posts") @@ -71,7 +71,7 @@ class PostsController < ApplicationController .where('posts.id <= ?', last_post_id) .where('posts.id > ?', last_post_id - 50) .includes(topic: :category) - .includes(user: :primary_group) + .includes(user: [:primary_group, :flair_group]) .includes(:reply_to_user) .limit(50) rss_description = I18n.t("rss_description.posts") diff --git a/app/controllers/user_badges_controller.rb b/app/controllers/user_badges_controller.rb index ff130869348..ae67a4cb42d 100644 --- a/app/controllers/user_badges_controller.rb +++ b/app/controllers/user_badges_controller.rb @@ -10,7 +10,7 @@ class UserBadgesController < ApplicationController badge = fetch_badge_from_params user_badges = badge.user_badges.order('granted_at DESC, id DESC').limit(MAX_BADGES) - user_badges = user_badges.includes(:user, :granted_by, badge: :badge_type, post: :topic, user: :primary_group) + user_badges = user_badges.includes(:user, :granted_by, badge: :badge_type, post: :topic, user: [:primary_group, :flair_group]) grant_count = nil diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 0dac66fd07a..8e77c490905 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -112,6 +112,7 @@ class UsersController < ApplicationController :user_profile, :card_background_upload, :primary_group, + :flair_group, :primary_email ) @@ -1632,6 +1633,7 @@ class UsersController < ApplicationController :profile_background_upload_url, :card_background_upload_url, :primary_group_id, + :flair_group_id, :featured_topic_id ] diff --git a/app/models/topic_posters_summary.rb b/app/models/topic_posters_summary.rb index b7eb2a86475..e21dd42fbee 100644 --- a/app/models/topic_posters_summary.rb +++ b/app/models/topic_posters_summary.rb @@ -33,6 +33,7 @@ class TopicPostersSummary topic_poster.user = user topic_poster.description = descriptions_for(user) topic_poster.primary_group = user_lookup.primary_groups[user.id] + topic_poster.flair_group = user_lookup.flair_groups[user.id] if topic.last_post_user_id == user.id topic_poster.extras = +'latest' topic_poster.extras << ' single' if user_ids.uniq.size == 1 diff --git a/app/models/user.rb b/app/models/user.rb index f9a23792506..da4dbeda2ad 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -95,6 +95,7 @@ class User < ActiveRecord::Base has_one :card_background_upload, through: :user_profile belongs_to :approved_by, class_name: 'User' belongs_to :primary_group, class_name: 'Group' + belongs_to :flair_group, class_name: 'Group' has_many :muted_users, through: :muted_user_records has_many :ignored_users, through: :ignored_user_records @@ -133,7 +134,7 @@ class User < ActiveRecord::Base before_save :update_usernames before_save :ensure_password_is_hashed - before_save :match_title_to_primary_group_changes + before_save :match_primary_group_changes before_save :check_if_title_is_badged_granted after_save :expire_tokens_if_password_changed @@ -1619,12 +1620,16 @@ class User < ActiveRecord::Base end end - def match_title_to_primary_group_changes + def match_primary_group_changes return unless primary_group_id_changed? if title == Group.where(id: primary_group_id_was).pluck_first(:title) self.title = primary_group&.title end + + if flair_group_id == primary_group_id_was + self.flair_group_id = primary_group&.id + end end private @@ -1745,6 +1750,7 @@ end # group_locked_trust_level :integer # manual_locked_trust_level :integer # secure_identifier :string +# flair_group_id :integer # # Indexes # diff --git a/app/models/user_summary.rb b/app/models/user_summary.rb index 9edda802f38..1cd0b020684 100644 --- a/app/models/user_summary.rb +++ b/app/models/user_summary.rb @@ -198,9 +198,14 @@ protected if lookup_hash.present? primary_group = lookup.primary_groups[user_id] + flair_group = lookup.flair_groups[user_id] UserWithCount.new( - lookup_hash.attributes.merge(count: user_hash[user_id], primary_group: primary_group) + lookup_hash.attributes.merge( + count: user_hash[user_id], + primary_group: primary_group, + flair_group: flair_group + ) ) end end.compact.sort_by { |u| -u[:count] } diff --git a/app/serializers/concerns/user_primary_group_mixin.rb b/app/serializers/concerns/user_primary_group_mixin.rb index 184db2b0279..65441ebba47 100644 --- a/app/serializers/concerns/user_primary_group_mixin.rb +++ b/app/serializers/concerns/user_primary_group_mixin.rb @@ -4,9 +4,10 @@ module UserPrimaryGroupMixin def self.included(klass) klass.attributes :primary_group_name, - :primary_group_flair_url, - :primary_group_flair_bg_color, - :primary_group_flair_color, + :flair_name, + :flair_url, + :flair_bg_color, + :flair_color, :admin, :moderator, :trust_level @@ -20,28 +21,36 @@ module UserPrimaryGroupMixin object&.primary_group.present? end - def primary_group_flair_url - object&.primary_group&.flair_url + def flair_name + object&.flair_group&.name end - def include_primary_group_flair_url? - object&.primary_group&.flair_url.present? + def include_flair_group_name? + object&.flair_group.present? end - def primary_group_flair_bg_color - object&.primary_group&.flair_bg_color + def flair_url + object&.flair_group&.flair_url end - def include_primary_group_flair_bg_color? - object&.primary_group&.flair_bg_color.present? + def include_flair_url? + object&.flair_group&.flair_url.present? end - def primary_group_flair_color - object&.primary_group&.flair_color + def flair_bg_color + object&.flair_group&.flair_bg_color end - def include_primary_group_flair_color? - object&.primary_group&.flair_color.present? + def include_flair_bg_color? + object&.flair_group&.flair_bg_color.present? + end + + def flair_color + object&.flair_group&.flair_color + end + + def include_flair_color? + object&.flair_group&.flair_color.present? end def include_admin? diff --git a/app/serializers/current_user_serializer.rb b/app/serializers/current_user_serializer.rb index 8d7965819f5..dc0637fe236 100644 --- a/app/serializers/current_user_serializer.rb +++ b/app/serializers/current_user_serializer.rb @@ -48,6 +48,7 @@ class CurrentUserSerializer < BasicUserSerializer :previous_visit_at, :seen_notification_id, :primary_group_id, + :flair_group_id, :can_create_topic, :can_create_group, :link_posting_access, diff --git a/app/serializers/flair_group_serializer.rb b/app/serializers/flair_group_serializer.rb new file mode 100644 index 00000000000..45b217ea5d1 --- /dev/null +++ b/app/serializers/flair_group_serializer.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class FlairGroupSerializer < ApplicationSerializer + attributes :id, :name, :flair_url, :flair_bg_color, :flair_color +end diff --git a/app/serializers/post_serializer.rb b/app/serializers/post_serializer.rb index 3d6f81b44c3..d585090beda 100644 --- a/app/serializers/post_serializer.rb +++ b/app/serializers/post_serializer.rb @@ -36,9 +36,10 @@ class PostSerializer < BasicPostSerializer :category_id, :display_username, :primary_group_name, - :primary_group_flair_url, - :primary_group_flair_bg_color, - :primary_group_flair_color, + :flair_name, + :flair_url, + :flair_bg_color, + :flair_color, :version, :can_edit, :can_delete, @@ -188,16 +189,20 @@ class PostSerializer < BasicPostSerializer end end - def primary_group_flair_url - object.user&.primary_group&.flair_url + def flair_name + object.user&.flair_group&.name end - def primary_group_flair_bg_color - object.user&.primary_group&.flair_bg_color + def flair_url + object.user&.flair_group&.flair_url end - def primary_group_flair_color - object.user&.primary_group&.flair_color + def flair_bg_color + object.user&.flair_group&.flair_bg_color + end + + def flair_color + object.user&.flair_group&.flair_color end def link_counts diff --git a/app/serializers/primary_group_serializer.rb b/app/serializers/primary_group_serializer.rb index b46d389f8ab..3250056d40c 100644 --- a/app/serializers/primary_group_serializer.rb +++ b/app/serializers/primary_group_serializer.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true class PrimaryGroupSerializer < ApplicationSerializer - attributes :id, :name, :flair_url, :flair_bg_color, :flair_color + attributes :id, :name end diff --git a/app/serializers/topic_post_count_serializer.rb b/app/serializers/topic_post_count_serializer.rb index 08d1c624f49..90f5a89fa49 100644 --- a/app/serializers/topic_post_count_serializer.rb +++ b/app/serializers/topic_post_count_serializer.rb @@ -3,7 +3,7 @@ class TopicPostCountSerializer < BasicUserSerializer attributes :post_count, :primary_group_name, - :primary_group_flair_url, :primary_group_flair_color, :primary_group_flair_bg_color, + :flair_name, :flair_url, :flair_color, :flair_bg_color, :admin, :moderator, :trust_level, def id @@ -23,16 +23,20 @@ class TopicPostCountSerializer < BasicUserSerializer object[:user]&.primary_group&.name end - def primary_group_flair_url - object[:user]&.primary_group&.flair_url + def flair_name + object[:user]&.flair_group&.name end - def primary_group_flair_bg_color - object[:user]&.primary_group&.flair_bg_color + def flair_url + object[:user]&.flair_group&.flair_url end - def primary_group_flair_color - object[:user]&.primary_group&.flair_color + def flair_bg_color + object[:user]&.flair_group&.flair_bg_color + end + + def flair_color + object[:user]&.flair_group&.flair_color end def include_admin? diff --git a/app/serializers/topic_poster_serializer.rb b/app/serializers/topic_poster_serializer.rb index 6a6bc714f43..3dadd18a4c5 100644 --- a/app/serializers/topic_poster_serializer.rb +++ b/app/serializers/topic_poster_serializer.rb @@ -5,4 +5,5 @@ class TopicPosterSerializer < ApplicationSerializer has_one :user, serializer: PosterSerializer has_one :primary_group, serializer: PrimaryGroupSerializer + has_one :flair_group, serializer: FlairGroupSerializer end diff --git a/app/serializers/user_card_serializer.rb b/app/serializers/user_card_serializer.rb index 6136d5c737d..617db6a7265 100644 --- a/app/serializers/user_card_serializer.rb +++ b/app/serializers/user_card_serializer.rb @@ -59,9 +59,10 @@ class UserCardSerializer < BasicUserSerializer :recent_time_read, :primary_group_id, :primary_group_name, - :primary_group_flair_url, - :primary_group_flair_bg_color, - :primary_group_flair_color, + :flair_name, + :flair_url, + :flair_bg_color, + :flair_color, :featured_topic, :timezone @@ -181,19 +182,23 @@ class UserCardSerializer < BasicUserSerializer end def primary_group_name - object.primary_group.try(:name) + object.primary_group&.name end - def primary_group_flair_url - object.try(:primary_group).try(:flair_url) + def flair_name + object.flair_group&.name end - def primary_group_flair_bg_color - object.try(:primary_group).try(:flair_bg_color) + def flair_url + object.flair_group&.flair_url end - def primary_group_flair_color - object.try(:primary_group).try(:flair_color) + def flair_bg_color + object.flair_group&.flair_bg_color + end + + def flair_color + object.flair_group&.flair_color end def featured_topic diff --git a/app/serializers/user_summary_serializer.rb b/app/serializers/user_summary_serializer.rb index dc251b3ed1e..f6e87bb0559 100644 --- a/app/serializers/user_summary_serializer.rb +++ b/app/serializers/user_summary_serializer.rb @@ -29,9 +29,10 @@ class UserSummarySerializer < ApplicationSerializer :admin, :moderator, :trust_level, - :primary_group_flair_url, - :primary_group_flair_bg_color, - :primary_group_flair_color, + :flair_name, + :flair_url, + :flair_bg_color, + :flair_color, :primary_group_name def include_name? @@ -42,16 +43,20 @@ class UserSummarySerializer < ApplicationSerializer User.avatar_template(object[:username], object[:uploaded_avatar_id]) end - def primary_group_flair_url - object.primary_group&.flair_url + def flair_name + object.flair_group&.name end - def primary_group_flair_bg_color - object.primary_group&.flair_bg_color + def flair_url + object.flair_group&.flair_url end - def primary_group_flair_color - object.primary_group&.flair_color + def flair_bg_color + object.flair_group&.flair_bg_color + end + + def flair_color + object.flair_group&.flair_color end def primary_group_name diff --git a/app/serializers/web_hook_post_serializer.rb b/app/serializers/web_hook_post_serializer.rb index 108e099b25f..da7dd3bbd0a 100644 --- a/app/serializers/web_hook_post_serializer.rb +++ b/app/serializers/web_hook_post_serializer.rb @@ -28,9 +28,9 @@ class WebHookPostSerializer < PostSerializer actions_summary can_view_edit_history yours - primary_group_flair_url - primary_group_flair_bg_color - primary_group_flair_color + flair_url + flair_bg_color + flair_color notice }.each do |attr| define_method("include_#{attr}?") do diff --git a/app/services/user_updater.rb b/app/services/user_updater.rb index ce046d6e86a..7635b90fcc8 100644 --- a/app/services/user_updater.rb +++ b/app/services/user_updater.rb @@ -121,6 +121,13 @@ class UserUpdater user.primary_group_id = nil end + if attributes[:flair_group_id] && + attributes[:flair_group_id] != user.flair_group_id && + guardian.can_use_primary_group?(user, attributes[:flair_group_id]) + + user.flair_group_id = attributes[:flair_group_id] + end + CATEGORY_IDS.each do |attribute, level| if ids = attributes[attribute] CategoryUser.batch_set(user, level, ids) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index ac33686a382..f1247f14b00 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1646,6 +1646,11 @@ en: title: title: "Title" none: "(none)" + instructions: "appears after your username" + flair: + title: "Flair" + none: "(none)" + instructions: "icon displayed next to your profile picture" primary_group: title: "Primary Group" none: "(none)" diff --git a/db/migrate/20210625203049_add_flair_group_id_to_users.rb b/db/migrate/20210625203049_add_flair_group_id_to_users.rb new file mode 100644 index 00000000000..1261b1d5974 --- /dev/null +++ b/db/migrate/20210625203049_add_flair_group_id_to_users.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddFlairGroupIdToUsers < ActiveRecord::Migration[6.1] + def change + add_column :users, :flair_group_id, :integer, null: true + end +end diff --git a/lib/user_lookup.rb b/lib/user_lookup.rb index 4f6feb7e7ce..8ea880b4dd2 100644 --- a/lib/user_lookup.rb +++ b/lib/user_lookup.rb @@ -12,13 +12,33 @@ class UserLookup end def primary_groups - @groups ||= group_lookup_hash + @primary_groups ||= begin + hash = {} + users.values.each do |u| + if u.primary_group_id + hash[u.id] = groups[u.primary_group_id] + end + end + hash + end + end + + def flair_groups + @flair_groups ||= begin + hash = {} + users.values.each do |u| + if u.flair_group_id + hash[u.id] = groups[u.flair_group_id] + end + end + hash + end end private def self.lookup_columns - @user_lookup_columns ||= %i{id username name uploaded_avatar_id primary_group_id admin moderator trust_level} + @user_lookup_columns ||= %i{id username name uploaded_avatar_id primary_group_id flair_group_id admin moderator trust_level} end def self.group_lookup_columns @@ -37,23 +57,21 @@ class UserLookup hash end - def group_lookup_hash - users_with_primary_group = users.values.reject { |u| u.primary_group_id.nil? } + def groups + @group_lookup = begin + group_ids = users.values.map { |u| [u.primary_group_id, u.flair_group_id] } + group_ids.flatten! + group_ids.uniq! + group_ids.compact! - group_lookup = {} - group_ids = users_with_primary_group.map { |u| u.primary_group_id } - group_ids.uniq! + hash = {} - Group.includes(:flair_upload) - .where(id: group_ids) - .select(self.class.group_lookup_columns) - .each { |g| group_lookup[g.id] = g } + Group.includes(:flair_upload) + .where(id: group_ids) + .select(self.class.group_lookup_columns) + .each { |g| hash[g.id] = g } - hash = {} - users_with_primary_group.each do |u| - hash[u.id] = group_lookup[u.primary_group_id] + hash end - hash end - end diff --git a/plugins/poll/test/javascripts/acceptance/poll-in-reply-history-test.js.es6 b/plugins/poll/test/javascripts/acceptance/poll-in-reply-history-test.js.es6 index f2e08b0b46c..412fdbbe314 100644 --- a/plugins/poll/test/javascripts/acceptance/poll-in-reply-history-test.js.es6 +++ b/plugins/poll/test/javascripts/acceptance/poll-in-reply-history-test.js.es6 @@ -38,9 +38,9 @@ acceptance("Poll in a post reply history", function (needs) { topic_slug: "topic-with-a-poll-in-a-post-reply-history", display_username: null, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_bg_color: null, - primary_group_flair_color: null, + flair_url: null, + flair_bg_color: null, + flair_color: null, version: 1, can_edit: true, can_delete: true, @@ -337,9 +337,9 @@ acceptance("Poll in a post reply history", function (needs) { "/letter_avatar_proxy/v4/letter/a/bbce88/{size}.png", post_count: 4, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_color: null, - primary_group_flair_bg_color: null, + flair_url: null, + flair_color: null, + flair_bg_color: null, }, ], created_by: { @@ -385,9 +385,9 @@ acceptance("Poll in a post reply history", function (needs) { topic_slug: "topic-with-a-poll-in-a-post-reply-history", display_username: null, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_bg_color: null, - primary_group_flair_color: null, + flair_url: null, + flair_bg_color: null, + flair_color: null, version: 1, can_edit: false, can_delete: false, diff --git a/plugins/poll/test/javascripts/acceptance/poll-quote-test.js.es6 b/plugins/poll/test/javascripts/acceptance/poll-quote-test.js.es6 index f000d468e0b..8d7e075a531 100644 --- a/plugins/poll/test/javascripts/acceptance/poll-quote-test.js.es6 +++ b/plugins/poll/test/javascripts/acceptance/poll-quote-test.js.es6 @@ -35,9 +35,9 @@ acceptance("Poll quote", function (needs) { topic_slug: "topic-with-two-polls", display_username: null, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_bg_color: null, - primary_group_flair_color: null, + flair_url: null, + flair_bg_color: null, + flair_color: null, version: 1, can_edit: true, can_delete: false, @@ -154,9 +154,9 @@ acceptance("Poll quote", function (needs) { topic_slug: "topic-with-two-quoted-polls", display_username: null, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_bg_color: null, - primary_group_flair_color: null, + flair_url: null, + flair_bg_color: null, + flair_color: null, version: 1, can_edit: true, can_delete: false, @@ -399,9 +399,9 @@ acceptance("Poll quote", function (needs) { "/letter_avatar_proxy/v4/letter/b/3be4f8/{size}.png", post_count: 1, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_color: null, - primary_group_flair_bg_color: null, + flair_url: null, + flair_color: null, + flair_bg_color: null, }, ], created_by: { diff --git a/plugins/poll/test/javascripts/acceptance/poll-results-test.js.es6 b/plugins/poll/test/javascripts/acceptance/poll-results-test.js.es6 index ae60a0a7ddf..6adb069b3d7 100644 --- a/plugins/poll/test/javascripts/acceptance/poll-results-test.js.es6 +++ b/plugins/poll/test/javascripts/acceptance/poll-results-test.js.es6 @@ -38,9 +38,9 @@ acceptance("Poll results", function (needs) { topic_slug: "load-more-poll-voters", display_username: null, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_bg_color: null, - primary_group_flair_color: null, + flair_url: null, + flair_bg_color: null, + flair_color: null, version: 1, can_edit: true, can_delete: false, @@ -143,9 +143,9 @@ acceptance("Poll results", function (needs) { topic_slug: "load-more-poll-voters", display_username: null, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_bg_color: null, - primary_group_flair_color: null, + flair_url: null, + flair_bg_color: null, + flair_color: null, version: 1, can_edit: true, can_delete: false, @@ -499,9 +499,9 @@ acceptance("Poll results", function (needs) { "/letter_avatar_proxy/v4/letter/b/3be4f8/{size}.png", post_count: 1, primary_group_name: null, - primary_group_flair_url: null, - primary_group_flair_color: null, - primary_group_flair_bg_color: null, + flair_url: null, + flair_color: null, + flair_bg_color: null, admin: true, trust_level: 0, }, diff --git a/spec/fixtures/onebox/discourse_topic.response b/spec/fixtures/onebox/discourse_topic.response index 18ef0d722f1..8c078f31644 100644 --- a/spec/fixtures/onebox/discourse_topic.response +++ b/spec/fixtures/onebox/discourse_topic.response @@ -355,7 +355,7 @@ And that too in just over an year, way to go! [boom]"> - + diff --git a/spec/fixtures/onebox/discourse_topic_reply.response b/spec/fixtures/onebox/discourse_topic_reply.response index 36a5e7a4008..2412540fbec 100644 --- a/spec/fixtures/onebox/discourse_topic_reply.response +++ b/spec/fixtures/onebox/discourse_topic_reply.response @@ -351,7 +351,7 @@ And that too in just over an year, way to go! [boom]"> - + diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 73062c4392e..e59efade5af 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -2142,16 +2142,24 @@ describe User do end - describe '#match_title_to_primary_group_changes' do - let(:primary_group_a) { Fabricate(:group, title: 'A', users: [user]) } - let(:primary_group_b) { Fabricate(:group, title: 'B', users: [user]) } + describe '#match_primary_group_changes' do + let(:group_a) { Fabricate(:group, title: 'A', users: [user]) } + let(:group_b) { Fabricate(:group, title: 'B', users: [user]) } it "updates user's title only when it is blank or matches the previous primary group" do - expect { user.update(primary_group: primary_group_a) }.to change { user.reload.title }.from(nil).to('A') - expect { user.update(primary_group: primary_group_b) }.to change { user.reload.title }.from('A').to('B') + expect { user.update(primary_group: group_a) }.to change { user.reload.title }.from(nil).to('A') + expect { user.update(primary_group: group_b) }.to change { user.reload.title }.from('A').to('B') user.update(title: 'Different') - expect { user.update(primary_group: primary_group_a) }.to_not change { user.reload.title } + expect { user.update(primary_group: group_a) }.to_not change { user.reload.title } + end + + it "updates user's title only when it is blank or matches the previous primary group" do + expect { user.update(primary_group: group_a) }.to change { user.reload.flair_group }.from(nil).to(group_a) + expect { user.update(primary_group: group_b) }.to change { user.reload.flair_group }.from(group_a).to(group_b) + + user.update(flair_group: group_a) + expect { user.update(primary_group: group_a) }.to_not change { user.reload.flair_group } end end diff --git a/spec/requests/api/posts_spec.rb b/spec/requests/api/posts_spec.rb index a9e16cf834f..3aab1460201 100644 --- a/spec/requests/api/posts_spec.rb +++ b/spec/requests/api/posts_spec.rb @@ -51,9 +51,10 @@ describe 'posts' do category_id: { type: :integer }, display_username: { type: :string }, primary_group_name: { type: :string, nullable: true }, - primary_group_flair_url: { type: :string, nullable: true }, - primary_group_flair_bg_color: { type: :string, nullable: true }, - primary_group_flair_color: { type: :string, nullable: true }, + flair_name: { type: :string, nullable: true }, + flair_url: { type: :string, nullable: true }, + flair_bg_color: { type: :string, nullable: true }, + flair_color: { type: :string, nullable: true }, version: { type: :integer }, can_edit: { type: :boolean }, can_delete: { type: :boolean }, @@ -149,9 +150,10 @@ describe 'posts' do topic_slug: { type: :string }, display_username: { type: :string, nullable: true }, primary_group_name: { type: :string, nullable: true }, - primary_group_flair_url: { type: :string, nullable: true }, - primary_group_flair_bg_color: { type: :string, nullable: true }, - primary_group_flair_color: { type: :string, nullable: true }, + flair_name: { type: :string, nullable: true }, + flair_url: { type: :string, nullable: true }, + flair_bg_color: { type: :string, nullable: true }, + flair_color: { type: :string, nullable: true }, version: { type: :integer }, can_edit: { type: :boolean }, can_delete: { type: :boolean }, @@ -237,9 +239,9 @@ describe 'posts' do topic_slug: { type: :string }, display_username: { type: :string, nullable: true }, primary_group_name: { type: :string, nullable: true }, - primary_group_flair_url: { type: :string, nullable: true }, - primary_group_flair_bg_color: { type: :string, nullable: true }, - primary_group_flair_color: { type: :string, nullable: true }, + flair_url: { type: :string, nullable: true }, + flair_bg_color: { type: :string, nullable: true }, + flair_color: { type: :string, nullable: true }, version: { type: :integer }, can_edit: { type: :boolean }, can_delete: { type: :boolean }, @@ -359,9 +361,10 @@ describe 'posts' do topic_slug: { type: :string }, display_username: { type: :string }, primary_group_name: { type: :string, nullable: true }, - primary_group_flair_url: { type: :string, nullable: true }, - primary_group_flair_bg_color: { type: :string, nullable: true }, - primary_group_flair_color: { type: :string, nullable: true }, + flair_name: { type: :string, nullable: true }, + flair_url: { type: :string, nullable: true }, + flair_bg_color: { type: :string, nullable: true }, + flair_color: { type: :string, nullable: true }, version: { type: :integer }, can_edit: { type: :boolean }, can_delete: { type: :boolean }, diff --git a/spec/requests/api/schemas/json/topic_create_response.json b/spec/requests/api/schemas/json/topic_create_response.json index d14e56b85c3..5c1c21c3e45 100644 --- a/spec/requests/api/schemas/json/topic_create_response.json +++ b/spec/requests/api/schemas/json/topic_create_response.json @@ -79,19 +79,25 @@ "null" ] }, - "primary_group_flair_url": { + "flair_name": { "type": [ "string", "null" ] }, - "primary_group_flair_bg_color": { + "flair_url": { "type": [ "string", "null" ] }, - "primary_group_flair_color": { + "flair_bg_color": { + "type": [ + "string", + "null" + ] + }, + "flair_color": { "type": [ "string", "null" @@ -219,9 +225,10 @@ "topic_slug", "display_username", "primary_group_name", - "primary_group_flair_url", - "primary_group_flair_bg_color", - "primary_group_flair_color", + "flair_name", + "flair_url", + "flair_bg_color", + "flair_color", "version", "can_edit", "can_delete", diff --git a/spec/requests/api/topics_spec.rb b/spec/requests/api/topics_spec.rb index 540948db5df..e7e0e18300e 100644 --- a/spec/requests/api/topics_spec.rb +++ b/spec/requests/api/topics_spec.rb @@ -53,9 +53,10 @@ describe 'topics' do topic_slug: { type: :string }, display_username: { type: :string, nullable: true }, primary_group_name: { type: :string, nullable: true }, - primary_group_flair_url: { type: :string, nullable: true }, - primary_group_flair_bg_color: { type: :string, nullable: true }, - primary_group_flair_color: { type: :string, nullable: true }, + flair_name: { type: :string, nullable: true }, + flair_url: { type: :string, nullable: true }, + flair_bg_color: { type: :string, nullable: true }, + flair_color: { type: :string, nullable: true }, version: { type: :integer }, can_edit: { type: :boolean }, can_delete: { type: :boolean }, @@ -144,9 +145,10 @@ describe 'topics' do topic_slug: { type: :string }, display_username: { type: :string }, primary_group_name: { type: :string, nullable: true }, - primary_group_flair_url: { type: :string, nullable: true }, - primary_group_flair_bg_color: { type: :string, nullable: true }, - primary_group_flair_color: { type: :string, nullable: true }, + flair_name: { type: :string, nullable: true }, + flair_url: { type: :string, nullable: true }, + flair_bg_color: { type: :string, nullable: true }, + flair_color: { type: :string, nullable: true }, version: { type: :integer }, can_edit: { type: :boolean }, can_delete: { type: :boolean }, @@ -337,9 +339,10 @@ describe 'topics' do avatar_template: { type: :string }, post_count: { type: :integer }, primary_group_name: { type: :string, nullable: true }, - primary_group_flair_url: { type: :string, nullable: true }, - primary_group_flair_color: { type: :string, nullable: true }, - primary_group_flair_bg_color: { type: :string, nullable: true }, + flair_name: { type: :string, nullable: true }, + flair_url: { type: :string, nullable: true }, + flair_color: { type: :string, nullable: true }, + flair_bg_color: { type: :string, nullable: true }, } }, }, diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb index 935846c9fcf..57c414ec28b 100644 --- a/spec/requests/users_controller_spec.rb +++ b/spec/requests/users_controller_spec.rb @@ -3098,32 +3098,32 @@ describe UsersController do expect(json["user_summary"]["most_liked_by_users"][0]["trust_level"]).to eq(1) end - it "returns data for primary group flair when an icon is used for flair" do + it "returns data for flair when an icon is used" do group = Fabricate(:group, name: "Groupie", flair_bg_color: "#111111", flair_color: "#999999", flair_icon: "icon") - liker = Fabricate(:user, primary_group: group) + liker = Fabricate(:user, flair_group: group) create_and_like_post(user, liker) get "/u/#{user.username_lower}/summary.json" json = response.parsed_body - expect(json["user_summary"]["most_liked_by_users"][0]["primary_group_flair_url"]).to eq("icon") - expect(json["user_summary"]["most_liked_by_users"][0]["primary_group_name"]).to eq("Groupie") - expect(json["user_summary"]["most_liked_by_users"][0]["primary_group_flair_bg_color"]).to eq("#111111") - expect(json["user_summary"]["most_liked_by_users"][0]["primary_group_flair_color"]).to eq("#999999") + expect(json["user_summary"]["most_liked_by_users"][0]["flair_name"]).to eq("Groupie") + expect(json["user_summary"]["most_liked_by_users"][0]["flair_url"]).to eq("icon") + expect(json["user_summary"]["most_liked_by_users"][0]["flair_bg_color"]).to eq("#111111") + expect(json["user_summary"]["most_liked_by_users"][0]["flair_color"]).to eq("#999999") end - it "returns data for primary group flair when an image is used for flair" do + it "returns data for flair when an image is used" do upload = Fabricate(:upload) group = Fabricate(:group, name: "Groupie", flair_bg_color: "#111111", flair_upload: upload) - liker = Fabricate(:user, primary_group: group) + liker = Fabricate(:user, flair_group: group) create_and_like_post(user, liker) get "/u/#{user.username_lower}/summary.json" json = response.parsed_body - expect(json["user_summary"]["most_liked_by_users"][0]["primary_group_flair_url"]).to eq(upload.url) - expect(json["user_summary"]["most_liked_by_users"][0]["primary_group_name"]).to eq("Groupie") - expect(json["user_summary"]["most_liked_by_users"][0]["primary_group_flair_bg_color"]).to eq("#111111") + expect(json["user_summary"]["most_liked_by_users"][0]["flair_name"]).to eq("Groupie") + expect(json["user_summary"]["most_liked_by_users"][0]["flair_url"]).to eq(upload.url) + expect(json["user_summary"]["most_liked_by_users"][0]["flair_bg_color"]).to eq("#111111") end def create_and_like_post(likee, liker) diff --git a/spec/serializers/web_hook_post_serializer_spec.rb b/spec/serializers/web_hook_post_serializer_spec.rb index cc1f93c6301..4d1265e7033 100644 --- a/spec/serializers/web_hook_post_serializer_spec.rb +++ b/spec/serializers/web_hook_post_serializer_spec.rb @@ -11,20 +11,51 @@ RSpec.describe WebHookPostSerializer do end it 'should only include the required keys' do - count = serialized_for_user(admin).keys.count - difference = count - 42 - - expect(difference).to eq(0), lambda { - message = +"" - - if difference < 0 - message << "#{difference * -1} key(s) have been removed from this serializer." - else - message << "#{difference} key(s) have been added to this serializer." - end - - message << "\nPlease verify if those key(s) are required as part of the web hook's payload." - } + expect(serialized_for_user(admin).keys).to contain_exactly( + :id, + :name, + :username, + :avatar_template, + :created_at, + :cooked, + :post_number, + :post_type, + :updated_at, + :reply_count, + :reply_to_post_number, + :quote_count, + :incoming_link_count, + :reads, + :score, + :topic_id, + :topic_slug, + :topic_title, + :category_id, + :display_username, + :primary_group_name, + :flair_name, + :version, + :user_title, + :bookmarked, + :raw, + :moderator, + :admin, + :staff, + :user_id, + :hidden, + :trust_level, + :deleted_at, + :user_deleted, + :edit_reason, + :wiki, + :reviewable_id, + :reviewable_score_count, + :reviewable_score_pending_count, + :topic_posts_count, + :topic_filtered_posts_count, + :topic_archetype, + :category_slug + ) end it "includes category_id" do diff --git a/spec/serializers/web_hook_user_serializer_spec.rb b/spec/serializers/web_hook_user_serializer_spec.rb index c26b58f7aa2..68bc42fdc63 100644 --- a/spec/serializers/web_hook_user_serializer_spec.rb +++ b/spec/serializers/web_hook_user_serializer_spec.rb @@ -22,14 +22,59 @@ RSpec.describe WebHookUserSerializer do end it 'should only include the required keys' do - count = serializer.as_json.keys.count - difference = count - 51 - - expect(difference).to eq(0), lambda { - message = (difference < 0 ? - "#{difference * -1} key(s) have been removed from this serializer." : - "#{difference} key(s) have been added to this serializer.") + - "\nPlease verify if those key(s) are required as part of the web hook's payload." - } + expect(serializer.as_json.keys).to contain_exactly( + :id, + :username, + :name, + :avatar_template, + :email, + :secondary_emails, + :last_posted_at, + :last_seen_at, + :created_at, + :muted, + :trust_level, + :moderator, + :admin, + :title, + :badge_count, + :time_read, + :recent_time_read, + :primary_group_id, + :primary_group_name, + :flair_name, + :flair_url, + :flair_bg_color, + :flair_color, + :featured_topic, + :staged, + :pending_count, + :profile_view_count, + :second_factor_enabled, + :can_upload_profile_header, + :can_upload_user_card_background, + :post_count, + :locale, + :muted_category_ids, + :regular_category_ids, + :watched_tags, + :watching_first_post_tags, + :tracked_tags, + :muted_tags, + :tracked_category_ids, + :watched_category_ids, + :watched_first_post_category_ids, + :system_avatar_template, + :muted_usernames, + :ignored_usernames, + :allowed_pm_usernames, + :mailing_list_posts_per_day, + :user_notification_schedule, + :external_id, + :featured_user_badge_ids, + :invited_by, + :groups, + :user_option + ) end end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index db3de327c60..2e03f53ccae 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -153,9 +153,9 @@ RSpec.configure do |config| recent_time_read: { type: :integer }, primary_group_id: { type: :string, nullable: true }, primary_group_name: { type: :string, nullable: true }, - primary_group_flair_url: { type: :string, nullable: true }, - primary_group_flair_bg_color: { type: :string, nullable: true }, - primary_group_flair_color: { type: :string, nullable: true }, + flair_url: { type: :string, nullable: true }, + flair_bg_color: { type: :string, nullable: true }, + flair_color: { type: :string, nullable: true }, featured_topic: { type: :string, nullable: true }, staged: { type: :boolean }, can_edit: { type: :boolean },