Add ability to use nested only parameter

- The only string works much the same as before with its comma separation
-- Nested includes are indicated with square brackets "[ ]"
-- The nested include is the value immediately preceding the square brackets
-- The only string is the comma separated string inside those brackets
- Default includes are split between format types when necessary
-- This prevents unnecessary includes from being added on page load
- Available includes are those items which are allowed to be accessible to the user
-- Some aren't because they are sensitive, such as the creator of a flag
-- Some aren't because the number of associated items is too large
- The amount of times the same model can be included to prevent recursions
-- One exception is the root model may include the same model once
--- e.g. the user model can include the inviter which is also the user model
-- Another exception is if the include is a has_many association
--- e.g. artist urls can include the artist, and then artist urls again
This commit is contained in:
BrokenEagle
2020-02-12 23:46:36 +00:00
parent dd425830ca
commit 63b3503bfc
85 changed files with 634 additions and 85 deletions

View File

@@ -322,6 +322,26 @@ class ApplicationRecord < ActiveRecord::Base
@api_attributes += including
@api_attributes
end
def available_includes
[]
end
def multiple_includes
reflections.reject { |k,v| v.macro != :has_many }.keys.map(&:to_sym)
end
def associated_models(name)
if reflections[name].options[:polymorphic]
associated_models = reflections[name].active_record.try(:model_types) || []
else
associated_models = [reflections[name].class_name]
end
end
end
def available_includes
self.class.available_includes
end
def api_attributes
@@ -338,25 +358,24 @@ class ApplicationRecord < ActiveRecord::Base
def serializable_hash(options = {})
options ||= {}
options[:only] ||= []
options[:include] ||= []
options[:methods] ||= []
if options[:only] && options[:only].is_a?(String)
options.delete(:methods)
options.delete(:include)
options.merge!(ParameterBuilder.serial_parameters(options[:only], self))
else
options[:methods] ||= []
attributes, methods = api_attributes.partition { |attr| has_attribute?(attr) }
methods += options[:methods]
options[:only] ||= attributes + methods
options[:only] = options[:only].map(&:to_sym)
attributes, methods = api_attributes.partition { |attr| has_attribute?(attr) }
methods += options[:methods]
includes = options[:include]
if options[:only].present?
attributes &= options[:only]
methods &= options[:only]
includes &= options[:only]
end
options[:only] = attributes
options[:methods] = methods
options[:include] = includes
options[:only] = attributes
options[:methods] = methods
options.delete(:methods) if options[:methods].empty?
end
hash = super(options)
hash.transform_keys { |key| key.delete("?") }

View File

@@ -508,4 +508,8 @@ class Artist < ApplicationRecord
"Deleted"
end
end
def self.available_includes
[:creator, :members, :urls, :wiki_page, :tag_alias, :tag]
end
end

View File

@@ -144,4 +144,8 @@ class ArtistCommentary < ApplicationRecord
extend SearchMethods
include VersionMethods
def self.available_includes
[:post]
end
end

View File

@@ -27,4 +27,8 @@ class ArtistCommentaryVersion < ApplicationRecord
def unchanged_empty?(field)
self[field].strip.empty? && (previous.nil? || previous[field].strip.empty?)
end
def self.available_includes
[:post, :updater]
end
end

View File

@@ -126,4 +126,8 @@ class ArtistUrl < ApplicationRecord
rescue Addressable::URI::InvalidURIError => error
errors[:url] << "'#{uri}' is malformed: #{error}"
end
def self.available_includes
[:artist]
end
end

View File

@@ -66,4 +66,8 @@ class ArtistVersion < ApplicationRecord
def was_unbanned
!is_banned && previous.is_banned
end
def self.available_includes
[:updater, :artist]
end
end

View File

@@ -115,4 +115,8 @@ class Ban < ApplicationRecord
def create_unban_mod_action
ModAction.log(%{Unbanned <@#{user_name}>}, :user_unban)
end
def self.available_includes
[:user, :banner]
end
end

View File

@@ -216,4 +216,8 @@ class BulkUpdateRequest < ApplicationRecord
forum_topic_id
)
end
def self.available_includes
[:user, :forum_topic, :forum_post, :approver]
end
end

View File

@@ -174,4 +174,10 @@ class Comment < ApplicationRecord
def quoted_response
DText.quote(body, creator.name)
end
def self.available_includes
includes_array = [:post, :creator, :updater]
includes_array << :moderation_reports if CurrentUser.is_moderator?
includes_array
end
end

View File

@@ -51,4 +51,8 @@ class CommentVote < ApplicationRecord
def initialize_user
self.user_id = CurrentUser.user.id
end
def self.available_includes
[:comment, :user]
end
end

View File

@@ -195,4 +195,10 @@ class Dmail < ApplicationRecord
def dtext_shortlink(key: false, **options)
key ? "dmail ##{id}/#{self.key}" : "dmail ##{id}"
end
def self.available_includes
includes_array = [:owner, :to, :from]
includes_array << :moderation_reports if CurrentUser.is_moderator?
includes_array
end
end

View File

@@ -8,6 +8,10 @@ class DtextLink < ApplicationRecord
scope :wiki_page, -> { where(model_type: "WikiPage") }
scope :forum_post, -> { where(model_type: "ForumPost") }
def self.model_types
%w[WikiPage ForumPost]
end
def self.new_from_dtext(dtext)
links = []
@@ -71,4 +75,8 @@ class DtextLink < ApplicationRecord
# because it can't index values that take up more than 1/3 of an 8kb page.
self.link_target = self.link_target.truncate(2048, omission: "")
end
def self.available_includes
[:model]
end
end

View File

@@ -168,4 +168,8 @@ class FavoriteGroup < ApplicationRecord
def viewable_by?(user)
creator_id == user.id || is_public
end
def self.available_includes
[:creator]
end
end

View File

@@ -223,4 +223,10 @@ class ForumPost < ApplicationRecord
def dtext_shortlink
"forum ##{id}"
end
def self.available_includes
includes_array = [:creator, :updater, :topic, :dtext_links, :votes, :tag_alias, :tag_implication, :bulk_update_request]
includes_array << :moderation_reports if CurrentUser.is_moderator?
includes_array
end
end

View File

@@ -53,4 +53,8 @@ class ForumPostVote < ApplicationRecord
raise
end
end
def self.available_includes
[:creator]
end
end

View File

@@ -177,4 +177,10 @@ class ForumTopic < ApplicationRecord
def update_orignal_post
original_post&.update_columns(:updater_id => updater.id, :updated_at => Time.now)
end
def self.available_includes
includes_array = [:creator, :updater, :original_post]
includes_array << :moderation_reports if CurrentUser.is_moderator?
includes_array
end
end

View File

@@ -49,4 +49,8 @@ class IpAddress < ApplicationRecord
def html_data_attributes
super & attributes.keys.map(&:to_sym)
end
def self.available_includes
[:user, :model]
end
end

View File

@@ -42,4 +42,8 @@ class IpBan < ApplicationRecord
str += "/" + ip_addr.prefix.to_s if has_subnet?
str
end
def self.available_includes
[:creator]
end
end

View File

@@ -83,4 +83,8 @@ class ModAction < ApplicationRecord
def initialize_creator
self.creator_id = CurrentUser.id
end
def self.available_includes
[:creator]
end
end

View File

@@ -19,6 +19,10 @@ class ModerationReport < ApplicationRecord
!Rails.env.production?
end
def self.model_types
%w[User Dmail Comment ForumPost]
end
def forum_topic_title
"Reports requiring moderation"
end
@@ -83,4 +87,8 @@ class ModerationReport < ApplicationRecord
q.apply_default_order(params)
end
def self.available_includes
[:creator, :model]
end
end

View File

@@ -158,4 +158,8 @@ class Note < ApplicationRecord
end
end
end
def self.available_includes
[:creator, :post]
end
end

View File

@@ -44,4 +44,8 @@ class NoteVersion < ApplicationRecord
def was_undeleted
is_active && !previous.is_active
end
def self.available_includes
[:updater, :note, :post]
end
end

View File

@@ -312,4 +312,8 @@ class Pool < ApplicationRecord
errors[:base] << "You cannot removes posts from pools within the first week of sign up"
end
end
def self.available_includes
[:creator]
end
end

View File

@@ -148,4 +148,8 @@ class PoolArchive < ApplicationRecord
def pretty_name
name.tr("_", " ")
end
def self.available_includes
[:updater, :pool]
end
end

View File

@@ -1787,4 +1787,11 @@ class Post < ApplicationRecord
save
end
def self.available_includes
includes_array = [:uploader, :updater, :approver, :parent, :upload, :artist_commentary, :flags, :appeals, :notes, :comments, :children, :approvals, :replacements]
includes_array << :moderation_reports if CurrentUser.is_moderator?
includes_array << :disapprovals if CurrentUser.user.is_approver?
includes_array
end
end

View File

@@ -62,4 +62,8 @@ class PostAppeal < ApplicationRecord
def appeal_count_for_creator
creator.post_appeals.recent.count
end
def self.available_includes
[:creator, :post]
end
end

View File

@@ -40,4 +40,8 @@ class PostApproval < ApplicationRecord
q = q.search_attributes(params, :user, :post)
q.apply_default_order(params)
end
def self.available_includes
[:user, :post]
end
end

View File

@@ -274,5 +274,9 @@ class PostArchive < ApplicationRecord
super + [:obsolete_added_tags, :obsolete_removed_tags, :unchanged_tags, :updater_name]
end
def self.available_includes
[:updater, :post]
end
memoize :previous, :tag_array, :changes, :added_tags_with_fields, :removed_tags_with_fields, :obsolete_removed_tags, :obsolete_added_tags, :unchanged_tags
end

View File

@@ -67,4 +67,8 @@ class PostDisapproval < ApplicationRecord
end
end
end
def self.available_includes
[:user, :post]
end
end

View File

@@ -161,4 +161,10 @@ class PostFlag < ApplicationRecord
def not_uploaded_by?(userid)
uploader_id != userid
end
def self.available_includes
includes_array = [:post]
includes_array << :creator if CurrentUser.user.is_moderator?
includes_array
end
end

View File

@@ -33,4 +33,8 @@ class PostReplacement < ApplicationRecord
tags = tags.map { |tag| "-#{tag}" }
tags.join(" ")
end
def self.available_includes
[:creator, :post]
end
end

View File

@@ -68,4 +68,8 @@ class PostVote < ApplicationRecord
1
end
end
def self.available_includes
[:user, :post]
end
end

View File

@@ -171,4 +171,8 @@ class SavedSearch < ApplicationRecord
def disable_labels=(value)
CurrentUser.update(disable_categorized_saved_searches: true) if value.to_s.truthy?
end
def self.available_includes
[:user]
end
end

View File

@@ -918,6 +918,10 @@ class Tag < ApplicationRecord
Post.tag_match(name)
end
def self.available_includes
[:wiki_page, :artist, :antecedent_alias, :consequent_aliases, :antecedent_implications, :consequent_implications]
end
include ApiMethods
include CountMethods
include CategoryMethods

View File

@@ -219,6 +219,10 @@ class TagRelationship < ApplicationRecord
)
end
def self.available_includes
[:creator, :approver, :forum_post, :forum_topic, :antecedent_tag, :consequent_tag, :antecedent_wiki, :consequent_wiki]
end
extend SearchMethods
include MessageMethods
end

View File

@@ -247,4 +247,8 @@ class Upload < ApplicationRecord
def upload_as_pending?
as_pending.to_s.truthy?
end
def self.available_includes
[:uploader, :post]
end
end

View File

@@ -754,4 +754,8 @@ class User < ApplicationRecord
def dtext_shortlink(**options)
"<@#{name}>"
end
def self.available_includes
[:inviter]
end
end

View File

@@ -85,4 +85,8 @@ class UserFeedback < ApplicationRecord
def editable_by?(editor)
(editor.is_moderator? && editor != user) || (creator == editor && !is_deleted?)
end
def self.available_includes
[:creator, :user]
end
end

View File

@@ -250,4 +250,8 @@ class WikiPage < ApplicationRecord
title
end
end
def self.available_includes
[:tag, :artist, :dtext_links]
end
end

View File

@@ -54,4 +54,8 @@ class WikiPageVersion < ApplicationRecord
def category_name
Tag.category_for(title)
end
def self.available_includes
[:updater, :wiki_page, :artist]
end
end