This refactors Pundit policies to only rely on the current user, not on the current user and the current HTTP request. In retrospect, it was a bad idea to include the current request in the Pundit context. It bleeds out everywhere and there are many contexts (in tests and models) where we only have the current user, not the current request. The previous commit got rid of the only two places where we used it.
70 lines
2.4 KiB
Ruby
70 lines
2.4 KiB
Ruby
module RecommenderService
|
|
module_function
|
|
|
|
MIN_POST_FAVS = 5
|
|
MIN_USER_FAVS = 50
|
|
CACHE_LIFETIME = 4.hours
|
|
|
|
def enabled?
|
|
Danbooru.config.recommender_server.present?
|
|
end
|
|
|
|
def available_for_post?(post)
|
|
enabled? && post.fav_count > MIN_POST_FAVS
|
|
end
|
|
|
|
def available_for_user?(user)
|
|
enabled? && user.favorite_count > MIN_USER_FAVS
|
|
end
|
|
|
|
def recommend_for_user(user, tags: nil, limit: 50)
|
|
response = Danbooru::Http.cache(CACHE_LIFETIME).get("#{Danbooru.config.recommender_server}/recommend/#{user.id}", params: { limit: limit })
|
|
return [] if response.status != 200
|
|
|
|
process_recs(response.parse, tags: tags, uploader: user, favoriter: user)
|
|
end
|
|
|
|
def recommend_for_post(post, tags: nil, limit: 50)
|
|
response = Danbooru::Http.cache(CACHE_LIFETIME).get("#{Danbooru.config.recommender_server}/similar/#{post.id}", params: { limit: limit })
|
|
return [] if response.status != 200
|
|
|
|
process_recs(response.parse, post: post, tags: tags)
|
|
end
|
|
|
|
def process_recs(recs, post: nil, uploader: nil, favoriter: nil, tags: nil)
|
|
posts = Post.where(id: recs.map(&:first))
|
|
posts = posts.where.not(id: post.id) if post
|
|
posts = posts.where.not(uploader_id: uploader.id) if uploader
|
|
posts = posts.where.not(id: favoriter.favorites.select(:post_id)) if favoriter
|
|
posts = posts.where(id: Post.user_tag_match(tags).reorder(nil).select(:id)) if tags.present?
|
|
|
|
id_to_score = recs.to_h
|
|
recs = posts.map { |post| { score: id_to_score[post.id], post: post } }
|
|
recs = recs.sort_by { |rec| -rec[:score] }
|
|
recs
|
|
end
|
|
|
|
def search(params)
|
|
if params[:user_name].present?
|
|
user = User.find_by_name(params[:user_name])
|
|
elsif params[:user_id].present?
|
|
user = User.find(params[:user_id])
|
|
elsif params[:post_id].present?
|
|
post = Post.find(params[:post_id])
|
|
end
|
|
|
|
if user.present?
|
|
raise User::PrivilegeError unless Pundit.policy!(CurrentUser.user, user).can_see_favorites?
|
|
max_recommendations = params.fetch(:max_recommendations, user.favorite_count + 500).to_i.clamp(0, 50000)
|
|
recs = RecommenderService.recommend_for_user(user, tags: params[:post_tags_match], limit: max_recommendations)
|
|
elsif post.present?
|
|
max_recommendations = params.fetch(:max_recommendations, 100).to_i.clamp(0, 1000)
|
|
recs = RecommenderService.recommend_for_post(post, tags: params[:post_tags_match], limit: max_recommendations)
|
|
else
|
|
recs = []
|
|
end
|
|
|
|
recs
|
|
end
|
|
end
|