FEATURE: auto grant an available title when removing old title
* FEATURE: auto grant an available title when removing old title
This commit is contained in:
parent
e622adfb89
commit
e402394375
|
@ -159,6 +159,15 @@ class Badge < ActiveRecord::Base
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.i18n_name(name)
|
||||||
|
name.downcase.tr(' ', '_')
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.display_name(name)
|
||||||
|
key = "badges.#{i18n_name(name)}.name"
|
||||||
|
I18n.t(key, default: name)
|
||||||
|
end
|
||||||
|
|
||||||
def awarded_for_trust_level?
|
def awarded_for_trust_level?
|
||||||
id <= 4
|
id <= 4
|
||||||
end
|
end
|
||||||
|
@ -191,8 +200,7 @@ class Badge < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def display_name
|
def display_name
|
||||||
key = "badges.#{i18n_name}.name"
|
self.class.display_name(name)
|
||||||
I18n.t(key, default: self.name)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def long_description
|
def long_description
|
||||||
|
@ -230,9 +238,8 @@ class Badge < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def i18n_name
|
def i18n_name
|
||||||
self.name.downcase.tr(' ', '_')
|
@i18n_name ||= self.class.i18n_name(name)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
|
|
|
@ -5,7 +5,7 @@ class GroupUser < ActiveRecord::Base
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
|
|
||||||
after_save :update_title
|
after_save :update_title
|
||||||
after_destroy :remove_title
|
after_destroy :grant_other_available_title
|
||||||
|
|
||||||
after_save :set_primary_group
|
after_save :set_primary_group
|
||||||
after_destroy :remove_primary_group, :recalculate_trust_level
|
after_destroy :remove_primary_group, :recalculate_trust_level
|
||||||
|
@ -43,13 +43,9 @@ class GroupUser < ActiveRecord::Base
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_title
|
def grant_other_available_title
|
||||||
if group.title.present?
|
if group.title.present? && group.title == user.title
|
||||||
DB.exec("
|
user.update!(title: user.next_best_title)
|
||||||
UPDATE users SET title = NULL
|
|
||||||
WHERE title = :title AND id = :id",
|
|
||||||
id: user_id, title: group.title
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -85,7 +81,6 @@ class GroupUser < ActiveRecord::Base
|
||||||
user.update!(group_locked_trust_level: highest_level)
|
user.update!(group_locked_trust_level: highest_level)
|
||||||
Promotion.recalculate(user)
|
Promotion.recalculate(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
|
|
|
@ -110,6 +110,7 @@ class User < ActiveRecord::Base
|
||||||
before_save :update_username_lower
|
before_save :update_username_lower
|
||||||
before_save :ensure_password_is_hashed
|
before_save :ensure_password_is_hashed
|
||||||
before_save :match_title_to_primary_group_changes
|
before_save :match_title_to_primary_group_changes
|
||||||
|
before_save :check_if_title_is_badged_granted
|
||||||
|
|
||||||
after_save :expire_tokens_if_password_changed
|
after_save :expire_tokens_if_password_changed
|
||||||
after_save :clear_global_notice_if_needed
|
after_save :clear_global_notice_if_needed
|
||||||
|
@ -1000,13 +1001,6 @@ class User < ActiveRecord::Base
|
||||||
@user_fields
|
@user_fields
|
||||||
end
|
end
|
||||||
|
|
||||||
def title=(val)
|
|
||||||
write_attribute(:title, val)
|
|
||||||
if !new_record? && user_profile
|
|
||||||
user_profile.update_column(:badge_granted_title, false)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def number_of_deleted_posts
|
def number_of_deleted_posts
|
||||||
Post.with_deleted
|
Post.with_deleted
|
||||||
.where(user_id: self.id)
|
.where(user_id: self.id)
|
||||||
|
@ -1123,6 +1117,19 @@ class User < ActiveRecord::Base
|
||||||
from_staged? && self.created_at && self.created_at < 1.day.ago
|
from_staged? && self.created_at && self.created_at < 1.day.ago
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def next_best_title
|
||||||
|
group_titles_query = groups.where("groups.title <> ''")
|
||||||
|
group_titles_query = group_titles_query.order("groups.id = #{primary_group_id} DESC") if primary_group_id
|
||||||
|
group_titles_query = group_titles_query.order("groups.primary_group DESC").limit(1)
|
||||||
|
|
||||||
|
if next_best_group_title = group_titles_query.pluck(:title).first
|
||||||
|
return next_best_group_title
|
||||||
|
end
|
||||||
|
|
||||||
|
next_best_badge_title = badges.where(allow_title: true).limit(1).pluck(:name).first
|
||||||
|
next_best_badge_title ? Badge.display_name(next_best_badge_title) : nil
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def badge_grant
|
def badge_grant
|
||||||
|
@ -1285,6 +1292,13 @@ class User < ActiveRecord::Base
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def check_if_title_is_badged_granted
|
||||||
|
if title_changed? && !new_record? && user_profile
|
||||||
|
badge_granted_title = title.present? && badges.where(allow_title: true, name: title).exists?
|
||||||
|
user_profile.update_column(:badge_granted_title, badge_granted_title)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def previous_visit_at_update_required?(timestamp)
|
def previous_visit_at_update_required?(timestamp)
|
||||||
seen_before? && (last_seen_at < (timestamp - SiteSetting.previous_visit_timeout_hours.hours))
|
seen_before? && (last_seen_at < (timestamp - SiteSetting.previous_visit_timeout_hours.hours))
|
||||||
end
|
end
|
||||||
|
|
|
@ -66,9 +66,6 @@ class UserUpdater
|
||||||
attributes[:title] != user.title &&
|
attributes[:title] != user.title &&
|
||||||
guardian.can_grant_title?(user, attributes[:title])
|
guardian.can_grant_title?(user, attributes[:title])
|
||||||
user.title = attributes[:title]
|
user.title = attributes[:title]
|
||||||
if user.badges.where(name: user.title).exists?
|
|
||||||
user_profile.badge_granted_title = true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
CATEGORY_IDS.each do |attribute, level|
|
CATEGORY_IDS.each do |attribute, level|
|
||||||
|
|
|
@ -80,4 +80,21 @@ describe Badge do
|
||||||
it { is_expected.to be true }
|
it { is_expected.to be true }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.i18n_name' do
|
||||||
|
it 'transforms to lower case letters, and replaces spaces with underscores' do
|
||||||
|
expect(Badge.i18n_name('Basic User')).to eq('basic_user')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '.display_name' do
|
||||||
|
it 'fetches from translations when i18n_name key exists' do
|
||||||
|
expect(Badge.display_name('basic_user')).to eq('Basic')
|
||||||
|
expect(Badge.display_name('Basic User')).to eq('Basic')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'fallbacks to argument value when translation does not exist' do
|
||||||
|
expect(Badge.display_name('Not In Translations')).to eq('Not In Translations')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -675,8 +675,9 @@ describe Group do
|
||||||
describe '#remove' do
|
describe '#remove' do
|
||||||
before { group.add(user) }
|
before { group.add(user) }
|
||||||
|
|
||||||
|
context 'when stripping title' do
|
||||||
it "only strips user's title if exact match" do
|
it "only strips user's title if exact match" do
|
||||||
group.update(title: 'Awesome')
|
group.update!(title: 'Awesome')
|
||||||
expect { group.remove(user) }.to change { user.reload.title }.from('Awesome').to(nil)
|
expect { group.remove(user) }.to change { user.reload.title }.from('Awesome').to(nil)
|
||||||
|
|
||||||
group.add(user)
|
group.add(user)
|
||||||
|
@ -684,6 +685,14 @@ describe Group do
|
||||||
expect { group.remove(user) }.to_not change { user.reload.title }
|
expect { group.remove(user) }.to_not change { user.reload.title }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "grants another title when the user has other available titles" do
|
||||||
|
group.update!(title: 'Awesome')
|
||||||
|
Fabricate(:group, title: 'Super').add(user)
|
||||||
|
|
||||||
|
expect { group.remove(user) }.to change { user.reload.title }.from('Awesome').to('Super')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "unsets the user's primary group" do
|
it "unsets the user's primary group" do
|
||||||
user.update(primary_group: group)
|
user.update(primary_group: group)
|
||||||
expect { group.remove(user) }.to change { user.reload.primary_group }.from(group).to(nil)
|
expect { group.remove(user) }.to change { user.reload.primary_group }.from(group).to(nil)
|
||||||
|
|
|
@ -1826,4 +1826,75 @@ describe User do
|
||||||
expect { user.update(primary_group: primary_group_a) }.to_not change { user.reload.title }
|
expect { user.update(primary_group: primary_group_a) }.to_not change { user.reload.title }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#title=' do
|
||||||
|
let(:badge) { Fabricate(:badge, name: 'Badge', allow_title: false) }
|
||||||
|
|
||||||
|
it 'sets badge_granted_title correctly' do
|
||||||
|
BadgeGranter.grant(badge, user)
|
||||||
|
|
||||||
|
user.update!(title: badge.name)
|
||||||
|
expect(user.user_profile.reload.badge_granted_title).to eq(false)
|
||||||
|
|
||||||
|
user.update!(title: 'Custom')
|
||||||
|
expect(user.user_profile.reload.badge_granted_title).to eq(false)
|
||||||
|
|
||||||
|
badge.update!(allow_title: true)
|
||||||
|
user.update!(title: badge.name)
|
||||||
|
expect(user.user_profile.reload.badge_granted_title).to eq(true)
|
||||||
|
|
||||||
|
user.update!(title: nil)
|
||||||
|
expect(user.user_profile.reload.badge_granted_title).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#next_best_title' do
|
||||||
|
let(:group_a) { Fabricate(:group, title: 'Group A') }
|
||||||
|
let(:group_b) { Fabricate(:group, title: 'Group B') }
|
||||||
|
let(:group_c) { Fabricate(:group, title: 'Group C') }
|
||||||
|
let(:badge) { Fabricate(:badge, name: 'Badge', allow_title: true) }
|
||||||
|
|
||||||
|
it 'only includes groups with title' do
|
||||||
|
group_a.add(user)
|
||||||
|
expect(user.next_best_title).to eq('Group A')
|
||||||
|
|
||||||
|
group_a.update!(title: nil)
|
||||||
|
expect(user.next_best_title).to eq(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'only includes badges that allow to be set as title' do
|
||||||
|
BadgeGranter.grant(badge, user)
|
||||||
|
expect(user.next_best_title).to eq('Badge')
|
||||||
|
|
||||||
|
badge.update!(allow_title: false)
|
||||||
|
expect(user.next_best_title).to eq(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "picks the next best title in the order: user's primary group, primary group, groups, and badges" do
|
||||||
|
group_a.add(user)
|
||||||
|
group_b.add(user)
|
||||||
|
group_c.add(user)
|
||||||
|
BadgeGranter.grant(badge, user)
|
||||||
|
|
||||||
|
group_a.update!(primary_group: true)
|
||||||
|
group_b.update!(primary_group: true)
|
||||||
|
user.update!(primary_group_id: group_a.id)
|
||||||
|
expect(user.next_best_title).to eq('Group A')
|
||||||
|
|
||||||
|
user.update!(primary_group_id: group_b.id)
|
||||||
|
expect(user.next_best_title).to eq('Group B')
|
||||||
|
|
||||||
|
group_b.remove(user)
|
||||||
|
expect(user.next_best_title).to eq('Group A')
|
||||||
|
|
||||||
|
group_a.remove(user)
|
||||||
|
expect(user.next_best_title).to eq('Group C')
|
||||||
|
|
||||||
|
group_c.remove(user)
|
||||||
|
expect(user.next_best_title).to eq('Badge')
|
||||||
|
|
||||||
|
BadgeGranter.revoke(UserBadge.find_by(user_id: user.id, badge_id: badge.id))
|
||||||
|
expect(user.next_best_title).to eq(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue