models: factor out api_attributes to policies.
Refactor models so that we define attribute API permissions in policy files instead of directly in models. This is cleaner because a) permissions are better handled by policies and b) which attributes are visible to the API is an API-level concern that models shouldn't have to care about. This fixes an issue with not being able to precompile CSS/JS assets unless the database was up and running. This was a problem when building Docker images because we don't have a database at build time. We needed the database because `api_attributes` was a class-level macro in some places, which meant it ran at boot time, but this triggered a database call because api_attributes used database introspection to get the list of allowed API attributes.
This commit is contained in:
@@ -31,19 +31,6 @@ class ApplicationRecord < ActiveRecord::Base
|
|||||||
|
|
||||||
concerning :ApiMethods do
|
concerning :ApiMethods do
|
||||||
class_methods do
|
class_methods do
|
||||||
def api_attributes(*attributes, including: [])
|
|
||||||
return @api_attributes if @api_attributes
|
|
||||||
|
|
||||||
if attributes.present?
|
|
||||||
@api_attributes = attributes
|
|
||||||
else
|
|
||||||
@api_attributes = attribute_types.reject { |name, attr| attr.type.in?([:inet, :tsvector]) }.keys.map(&:to_sym)
|
|
||||||
end
|
|
||||||
|
|
||||||
@api_attributes += including
|
|
||||||
@api_attributes
|
|
||||||
end
|
|
||||||
|
|
||||||
def available_includes
|
def available_includes
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
@@ -65,8 +52,9 @@ class ApplicationRecord < ActiveRecord::Base
|
|||||||
self.class.available_includes
|
self.class.available_includes
|
||||||
end
|
end
|
||||||
|
|
||||||
def api_attributes
|
# XXX deprecated, shouldn't expose this as an instance method.
|
||||||
self.class.api_attributes
|
def api_attributes(user: CurrentUser.user)
|
||||||
|
Pundit.policy!([user, nil], self).api_attributes
|
||||||
end
|
end
|
||||||
|
|
||||||
def html_data_attributes
|
def html_data_attributes
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ class Dmail < ApplicationRecord
|
|||||||
after_save :update_unread_dmail_count
|
after_save :update_unread_dmail_count
|
||||||
after_commit :send_email, on: :create
|
after_commit :send_email, on: :create
|
||||||
|
|
||||||
api_attributes including: [:key]
|
|
||||||
deletable
|
deletable
|
||||||
|
|
||||||
scope :read, -> { where(is_read: true) }
|
scope :read, -> { where(is_read: true) }
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
class ModAction < ApplicationRecord
|
class ModAction < ApplicationRecord
|
||||||
belongs_to :creator, :class_name => "User"
|
belongs_to :creator, :class_name => "User"
|
||||||
|
|
||||||
api_attributes including: [:category_id]
|
|
||||||
|
|
||||||
# ####DIVISIONS#####
|
# ####DIVISIONS#####
|
||||||
# Groups: 0-999
|
# Groups: 0-999
|
||||||
# Individual: 1000-1999
|
# Individual: 1000-1999
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ class Pool < ApplicationRecord
|
|||||||
after_save :create_version
|
after_save :create_version
|
||||||
after_create :synchronize!
|
after_create :synchronize!
|
||||||
|
|
||||||
api_attributes including: [:post_count]
|
|
||||||
deletable
|
deletable
|
||||||
|
|
||||||
scope :series, -> { where(category: "series") }
|
scope :series, -> { where(category: "series") }
|
||||||
|
|||||||
@@ -1125,15 +1125,6 @@ class Post < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
module ApiMethods
|
module ApiMethods
|
||||||
def api_attributes
|
|
||||||
attributes = super
|
|
||||||
attributes += [:has_large, :has_visible_children, :is_favorited?] + TagCategory.categories.map {|x| "tag_string_#{x}".to_sym}
|
|
||||||
attributes += [:file_url, :large_file_url, :preview_file_url] if visible?
|
|
||||||
attributes -= [:md5, :file_ext] if !visible?
|
|
||||||
attributes -= [:fav_string] if !CurrentUser.is_moderator?
|
|
||||||
attributes
|
|
||||||
end
|
|
||||||
|
|
||||||
def legacy_attributes
|
def legacy_attributes
|
||||||
hash = {
|
hash = {
|
||||||
"has_comments" => last_commented_at.present?,
|
"has_comments" => last_commented_at.present?,
|
||||||
@@ -1471,16 +1462,16 @@ class Post < ApplicationRecord
|
|||||||
CurrentUser.safe_mode? && (rating != "s" || Danbooru.config.safe_mode_restricted_tags.any? { |tag| tag.in?(tag_array) })
|
CurrentUser.safe_mode? && (rating != "s" || Danbooru.config.safe_mode_restricted_tags.any? { |tag| tag.in?(tag_array) })
|
||||||
end
|
end
|
||||||
|
|
||||||
def levelblocked?
|
def levelblocked?(user = CurrentUser.user)
|
||||||
!CurrentUser.is_gold? && Danbooru.config.restricted_tags.any? { |tag| tag.in?(tag_array) }
|
!user.is_gold? && Danbooru.config.restricted_tags.any? { |tag| tag.in?(tag_array) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def banblocked?
|
def banblocked?(user = CurrentUser.user)
|
||||||
is_banned? && !CurrentUser.is_gold?
|
is_banned? && !user.is_gold?
|
||||||
end
|
end
|
||||||
|
|
||||||
def visible?
|
def visible?(user = CurrentUser.user)
|
||||||
!safeblocked? && !levelblocked? && !banblocked?
|
!safeblocked? && !levelblocked?(user) && !banblocked?(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def reload(options = nil)
|
def reload(options = nil)
|
||||||
|
|||||||
@@ -73,10 +73,4 @@ class PostDisapproval < ApplicationRecord
|
|||||||
message = nil if message.blank?
|
message = nil if message.blank?
|
||||||
super(message)
|
super(message)
|
||||||
end
|
end
|
||||||
|
|
||||||
def api_attributes
|
|
||||||
attributes = super
|
|
||||||
attributes -= [:creator_id] unless Pundit.policy!([CurrentUser.user, nil], self).can_view_creator?
|
|
||||||
attributes
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -75,16 +75,7 @@ class PostFlag < ApplicationRecord
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
module ApiMethods
|
|
||||||
def api_attributes
|
|
||||||
attributes = super + [:category]
|
|
||||||
attributes -= [:creator_id] unless Pundit.policy!([CurrentUser.user, nil], self).can_view_flagger?
|
|
||||||
attributes
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
extend SearchMethods
|
extend SearchMethods
|
||||||
include ApiMethods
|
|
||||||
|
|
||||||
def category
|
def category
|
||||||
case reason
|
case reason
|
||||||
|
|||||||
@@ -267,10 +267,6 @@ class PostVersion < ApplicationRecord
|
|||||||
post.save!
|
post.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
def api_attributes
|
|
||||||
super + [:obsolete_added_tags, :obsolete_removed_tags, :unchanged_tags]
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.available_includes
|
def self.available_includes
|
||||||
[:updater, :post]
|
[:updater, :post]
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -420,30 +420,6 @@ class User < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
module ApiMethods
|
module ApiMethods
|
||||||
def api_attributes
|
|
||||||
attributes = %i[
|
|
||||||
id created_at name inviter_id level
|
|
||||||
post_upload_count post_update_count note_update_count is_banned
|
|
||||||
can_approve_posts can_upload_free level_string
|
|
||||||
]
|
|
||||||
|
|
||||||
if id == CurrentUser.user.id
|
|
||||||
attributes += BOOLEAN_ATTRIBUTES
|
|
||||||
attributes += %i[
|
|
||||||
updated_at last_logged_in_at last_forum_read_at
|
|
||||||
comment_threshold default_image_size
|
|
||||||
favorite_tags blacklisted_tags time_zone per_page
|
|
||||||
custom_style favorite_count api_regen_multiplier
|
|
||||||
api_burst_limit remaining_api_limit statement_timeout
|
|
||||||
favorite_group_limit favorite_limit tag_query_limit
|
|
||||||
is_comment_limited?
|
|
||||||
max_saved_searches theme
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
attributes
|
|
||||||
end
|
|
||||||
|
|
||||||
# extra attributes returned for /users/:id.json but not for /users.json.
|
# extra attributes returned for /users/:id.json but not for /users.json.
|
||||||
def full_attributes
|
def full_attributes
|
||||||
%i[
|
%i[
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ class WikiPage < ApplicationRecord
|
|||||||
has_many :versions, -> {order("wiki_page_versions.id ASC")}, :class_name => "WikiPageVersion", :dependent => :destroy
|
has_many :versions, -> {order("wiki_page_versions.id ASC")}, :class_name => "WikiPageVersion", :dependent => :destroy
|
||||||
has_many :dtext_links, as: :model, dependent: :destroy
|
has_many :dtext_links, as: :model, dependent: :destroy
|
||||||
|
|
||||||
api_attributes including: [:category_name]
|
|
||||||
deletable
|
deletable
|
||||||
|
|
||||||
module SearchMethods
|
module SearchMethods
|
||||||
|
|||||||
@@ -69,4 +69,8 @@ class ApplicationPolicy
|
|||||||
def permitted_attributes_for_edit
|
def permitted_attributes_for_edit
|
||||||
permitted_attributes_for_update
|
permitted_attributes_for_update
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def api_attributes
|
||||||
|
record.class.attribute_types.reject { |name, attr| attr.type.in?([:inet, :tsvector]) }.keys.map(&:to_sym)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -30,4 +30,8 @@ class DmailPolicy < ApplicationPolicy
|
|||||||
def permitted_attributes_for_update
|
def permitted_attributes_for_update
|
||||||
[:is_read, :is_deleted]
|
[:is_read, :is_deleted]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def api_attributes
|
||||||
|
super + [:key]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
5
app/policies/mod_action_policy.rb
Normal file
5
app/policies/mod_action_policy.rb
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
class ModActionPolicy < ApplicationPolicy
|
||||||
|
def api_attributes
|
||||||
|
super + [:category_id]
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -22,4 +22,8 @@ class PoolPolicy < ApplicationPolicy
|
|||||||
def permitted_attributes
|
def permitted_attributes
|
||||||
[:name, :description, :category, :post_ids, :post_ids_string, post_ids: []]
|
[:name, :description, :category, :post_ids, :post_ids_string, post_ids: []]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def api_attributes
|
||||||
|
super + [:post_count]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,4 +10,10 @@ class PostDisapprovalPolicy < ApplicationPolicy
|
|||||||
def permitted_attributes
|
def permitted_attributes
|
||||||
[:post_id, :reason, :message]
|
[:post_id, :reason, :message]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def api_attributes
|
||||||
|
attributes = super
|
||||||
|
attributes -= [:creator_id] unless can_view_creator?
|
||||||
|
attributes
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,4 +10,10 @@ class PostFlagPolicy < ApplicationPolicy
|
|||||||
def permitted_attributes
|
def permitted_attributes
|
||||||
[:post_id, :reason]
|
[:post_id, :reason]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def api_attributes
|
||||||
|
attributes = super + [:category]
|
||||||
|
attributes -= [:creator_id] unless can_view_flagger?
|
||||||
|
attributes
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class PostPolicy < ApplicationPolicy
|
|||||||
end
|
end
|
||||||
|
|
||||||
def visible?
|
def visible?
|
||||||
record.visible?
|
record.visible?(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_view_uploader?
|
def can_view_uploader?
|
||||||
@@ -85,4 +85,14 @@ class PostPolicy < ApplicationPolicy
|
|||||||
(:is_status_locked if can_lock_status?),
|
(:is_status_locked if can_lock_status?),
|
||||||
].compact
|
].compact
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def api_attributes
|
||||||
|
attributes = super
|
||||||
|
attributes += [:has_large, :has_visible_children, :is_favorited?]
|
||||||
|
attributes += TagCategory.categories.map {|x| "tag_string_#{x}".to_sym}
|
||||||
|
attributes += [:file_url, :large_file_url, :preview_file_url] if visible?
|
||||||
|
attributes -= [:md5, :file_ext] if !visible?
|
||||||
|
attributes -= [:fav_string] if !user.is_moderator?
|
||||||
|
attributes
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -6,4 +6,8 @@ class PostVersionPolicy < ApplicationPolicy
|
|||||||
def can_mass_undo?
|
def can_mass_undo?
|
||||||
user.is_builder?
|
user.is_builder?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def api_attributes
|
||||||
|
super + [:obsolete_added_tags, :obsolete_removed_tags, :unchanged_tags]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -51,6 +51,30 @@ class UserPolicy < ApplicationPolicy
|
|||||||
].compact
|
].compact
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def api_attributes
|
||||||
|
attributes = %i[
|
||||||
|
id created_at name inviter_id level
|
||||||
|
post_upload_count post_update_count note_update_count is_banned
|
||||||
|
can_approve_posts can_upload_free level_string
|
||||||
|
]
|
||||||
|
|
||||||
|
if record.id == user.id
|
||||||
|
attributes += User::BOOLEAN_ATTRIBUTES
|
||||||
|
attributes += %i[
|
||||||
|
updated_at last_logged_in_at last_forum_read_at
|
||||||
|
comment_threshold default_image_size
|
||||||
|
favorite_tags blacklisted_tags time_zone per_page
|
||||||
|
custom_style favorite_count api_regen_multiplier
|
||||||
|
api_burst_limit remaining_api_limit statement_timeout
|
||||||
|
favorite_group_limit favorite_limit tag_query_limit
|
||||||
|
is_comment_limited?
|
||||||
|
max_saved_searches theme
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
attributes
|
||||||
|
end
|
||||||
|
|
||||||
alias_method :profile?, :show?
|
alias_method :profile?, :show?
|
||||||
alias_method :settings?, :edit?
|
alias_method :settings?, :edit?
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -14,4 +14,8 @@ class WikiPagePolicy < ApplicationPolicy
|
|||||||
def permitted_attributes
|
def permitted_attributes
|
||||||
[:title, :body, :other_names, :other_names_string, :is_deleted, (:is_locked if can_edit_locked?)].compact
|
[:title, :body, :other_names, :other_names_string, :is_deleted, (:is_locked if can_edit_locked?)].compact
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def api_attributes
|
||||||
|
super + [:category_name]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user