mirror of
https://github.com/discourse/discourse.git
synced 2024-11-27 05:23:37 +08:00
a22aa7562a
Badges that are awarded multiple times can be favorite and not favorite at the same time. This caused few problems when users tried to favorite them as they were counted multiple times or their state was incorrectly displayed.
155 lines
4.7 KiB
Ruby
155 lines
4.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class UserBadgesController < ApplicationController
|
|
MAX_BADGES = 96 # This was limited in PR#2360 to make it divisible by 8
|
|
|
|
before_action :ensure_badges_enabled
|
|
|
|
def index
|
|
params.permit [:granted_before, :offset, :username]
|
|
|
|
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)
|
|
|
|
grant_count = nil
|
|
|
|
if params[:username]
|
|
user_id = User.where(username_lower: params[:username].downcase).pluck_first(:id)
|
|
user_badges = user_badges.where(user_id: user_id) if user_id
|
|
grant_count = badge.user_badges.where(user_id: user_id).count
|
|
end
|
|
|
|
if offset = params[:offset]
|
|
user_badges = user_badges.offset(offset.to_i)
|
|
end
|
|
|
|
user_badges = UserBadges.new(user_badges: user_badges,
|
|
username: params[:username],
|
|
grant_count: grant_count)
|
|
|
|
render_serialized(user_badges, UserBadgesSerializer, root: :user_badge_info, include_long_description: true)
|
|
end
|
|
|
|
def username
|
|
params.permit [:grouped]
|
|
|
|
user = fetch_user_from_params(include_inactive: current_user.try(:staff?) || (current_user && SiteSetting.show_inactive_accounts))
|
|
raise Discourse::NotFound unless guardian.can_see_profile?(user)
|
|
user_badges = user.user_badges
|
|
|
|
if params[:grouped]
|
|
user_badges = user_badges.group(:badge_id).select_for_grouping
|
|
end
|
|
|
|
user_badges = user_badges.includes(badge: [:badge_grouping, :badge_type, :image_upload])
|
|
.includes(post: :topic)
|
|
.includes(:granted_by)
|
|
|
|
render_serialized(
|
|
user_badges,
|
|
DetailedUserBadgeSerializer,
|
|
root: :user_badges,
|
|
)
|
|
end
|
|
|
|
def create
|
|
params.require(:username)
|
|
user = fetch_user_from_params
|
|
|
|
unless can_assign_badge_to_user?(user)
|
|
return render json: failed_json, status: 403
|
|
end
|
|
|
|
badge = fetch_badge_from_params
|
|
post_id = nil
|
|
|
|
if params[:reason].present?
|
|
unless is_badge_reason_valid? params[:reason]
|
|
return render json: failed_json.merge(message: I18n.t('invalid_grant_badge_reason_link')), status: 400
|
|
end
|
|
|
|
if route = Discourse.route_for(params[:reason])
|
|
if route[:controller] == "topics" && route[:action] == "show"
|
|
topic_id = (route[:id] || route[:topic_id]).to_i
|
|
post_number = route[:post_number] || 1
|
|
post_id = Post.find_by(topic_id: topic_id, post_number: post_number)&.id if topic_id > 0
|
|
end
|
|
end
|
|
end
|
|
|
|
user_badge = BadgeGranter.grant(badge, user, granted_by: current_user, post_id: post_id)
|
|
|
|
render_serialized(user_badge, DetailedUserBadgeSerializer, root: "user_badge")
|
|
end
|
|
|
|
def destroy
|
|
params.require(:id)
|
|
user_badge = UserBadge.find(params[:id])
|
|
|
|
unless can_assign_badge_to_user?(user_badge.user)
|
|
render json: failed_json, status: 403
|
|
return
|
|
end
|
|
|
|
BadgeGranter.revoke(user_badge, revoked_by: current_user)
|
|
render json: success_json
|
|
end
|
|
|
|
def toggle_favorite
|
|
params.require(:user_badge_id)
|
|
user_badge = UserBadge.find(params[:user_badge_id])
|
|
user_badges = user_badge.user.user_badges
|
|
|
|
unless can_favorite_badge?(user_badge)
|
|
return render json: failed_json, status: 403
|
|
end
|
|
|
|
if !user_badge.is_favorite && user_badges.select(:badge_id).distinct.where(is_favorite: true).count >= SiteSetting.max_favorite_badges
|
|
return render json: failed_json, status: 400
|
|
end
|
|
|
|
UserBadge
|
|
.where(user_id: user_badge.user_id, badge_id: user_badge.badge_id)
|
|
.update(is_favorite: !user_badge.is_favorite)
|
|
UserBadge.update_featured_ranks!(user_badge.user_id)
|
|
render_serialized(user_badge, DetailedUserBadgeSerializer, root: :user_badge)
|
|
end
|
|
|
|
private
|
|
|
|
# Get the badge from either the badge name or id specified in the params.
|
|
def fetch_badge_from_params
|
|
badge = nil
|
|
|
|
params.permit(:badge_name)
|
|
if params[:badge_name].nil?
|
|
params.require(:badge_id)
|
|
badge = Badge.find_by(id: params[:badge_id], enabled: true)
|
|
else
|
|
badge = Badge.find_by(name: params[:badge_name], enabled: true)
|
|
end
|
|
raise Discourse::NotFound if badge.blank?
|
|
|
|
badge
|
|
end
|
|
|
|
def can_assign_badge_to_user?(user)
|
|
master_api_call = current_user.nil? && is_api?
|
|
master_api_call || guardian.can_grant_badges?(user)
|
|
end
|
|
|
|
def can_favorite_badge?(user_badge)
|
|
current_user == user_badge.user && !(1..4).include?(user_badge.badge_id)
|
|
end
|
|
|
|
def ensure_badges_enabled
|
|
raise Discourse::NotFound unless SiteSetting.enable_badges?
|
|
end
|
|
|
|
def is_badge_reason_valid?(reason)
|
|
route = Discourse.route_for(reason)
|
|
route && (route[:controller] == 'posts' || route[:controller] == 'topics')
|
|
end
|
|
end
|