Commit 63b3503b authored by BrokenEagle's avatar BrokenEagle

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
parent dd425830
......@@ -34,6 +34,25 @@ class ApplicationController < ActionController::Base
end
end
def model_includes(params, model = nil)
if params[:only] && ["json", "xml"].include?(params[:format])
includes_array = ParameterBuilder.includes_parameters(params[:only], model_name)
elsif params[:action] == "index"
includes_array = default_includes(params)
else
includes_array = []
end
includes_array
end
def default_includes(*)
[]
end
def model_name
controller_name.classify
end
def redirect_to_show(items)
redirect_to send("#{controller_path.singularize}_path", items.first, format: request.format.symbol)
end
......
......@@ -3,7 +3,7 @@ class ArtistCommentariesController < ApplicationController
before_action :member_only, only: [:create_or_update, :revert]
def index
@commentaries = ArtistCommentary.paginated_search(params)
@commentaries = ArtistCommentary.paginated_search(params).includes(model_includes(params))
respond_with(@commentaries)
end
......@@ -36,6 +36,14 @@ class ArtistCommentariesController < ApplicationController
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[{post: [:uploader]}]
end
end
def commentary_params
params.fetch(:artist_commentary, {}).except(:post_id).permit(%i[
original_description original_title translated_description translated_title
......
......@@ -2,7 +2,7 @@ class ArtistCommentaryVersionsController < ApplicationController
respond_to :html, :xml, :json
def index
@commentary_versions = ArtistCommentaryVersion.paginated_search(params)
@commentary_versions = ArtistCommentaryVersion.paginated_search(params).includes(model_includes(params))
respond_with(@commentary_versions)
end
......@@ -12,4 +12,14 @@ class ArtistCommentaryVersionsController < ApplicationController
format.html { redirect_to artist_commentary_versions_path(search: { post_id: @commentary_version.post_id }) }
end
end
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[{post: [:uploader]}, :updater]
end
end
end
......@@ -3,10 +3,10 @@ class ArtistUrlsController < ApplicationController
before_action :member_only, except: [:index]
def index
@artist_urls = ArtistUrl.includes(:artist).paginated_search(params)
@artist_urls = ArtistUrl.paginated_search(params).includes(model_includes(params))
respond_with(@artist_urls) do |format|
format.json { render json: @artist_urls.to_json(include: "artist") }
format.xml { render xml: @artist_urls.to_xml(include: "artist", root: "artist-urls") }
format.json { render json: @artist_urls.to_json(format_params) }
format.xml { render xml: @artist_urls.to_xml(format_params) }
end
end
......@@ -18,6 +18,27 @@ class ArtistUrlsController < ApplicationController
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[{artist: [:urls]}]
else
[:artist]
end
end
def format_params
param_hash = {}
if params[:only]
param_hash[:only] = params[:only]
else
param_hash[:include] = [:artist]
end
if request.format.symbol == :xml
param_hash[:root] = "artist-urls"
end
param_hash
end
def artist_url_params
permitted_params = %i[is_active]
......
......@@ -2,7 +2,7 @@ class ArtistVersionsController < ApplicationController
respond_to :html, :xml, :json
def index
@artist_versions = ArtistVersion.includes(:updater).paginated_search(params)
@artist_versions = ArtistVersion.paginated_search(params).includes(model_includes(params))
respond_with(@artist_versions)
end
......@@ -12,4 +12,14 @@ class ArtistVersionsController < ApplicationController
format.html { redirect_to artist_versions_path(search: { artist_id: @artist_version.artist_id }) }
end
end
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[:updater, {artist: [:urls]}]
end
end
end
......@@ -31,10 +31,7 @@ class ArtistsController < ApplicationController
# XXX
params[:search][:name] = params.delete(:name) if params[:name]
@artists = Artist.includes(:urls).paginated_search(params)
@artists = @artists.includes(:tag) if request.format.html?
@artists = @artists.includes(:urls) if !request.format.html?
@artists = Artist.paginated_search(params).includes(model_includes(params))
respond_with(@artists)
end
......@@ -81,6 +78,14 @@ class ArtistsController < ApplicationController
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[:urls]
else
[:urls, :tag]
end
end
def item_matches_params(artist)
if params[:search][:any_name_or_url_matches]
artist.name == Artist.normalize_name(params[:search][:any_name_or_url_matches])
......
......@@ -12,10 +12,8 @@ class BansController < ApplicationController
end
def index
@bans = Ban.paginated_search(params, count_pages: true)
respond_with(@bans) do |fmt|
fmt.html { @bans = @bans.includes(:user, :banner) }
end
@bans = Ban.paginated_search(params, count_pages: true).includes(model_includes(params))
respond_with(@bans)
end
def show
......@@ -50,6 +48,14 @@ class BansController < ApplicationController
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[:user, :banner]
end
end
def ban_params(context)
permitted_params = %i[reason duration expires_at]
permitted_params += %i[user_id user_name] if context == :create
......
......@@ -42,12 +42,20 @@ class BulkUpdateRequestsController < ApplicationController
end
def index
@bulk_update_requests = BulkUpdateRequest.includes(:user, :approver, :forum_topic, forum_post: [:votes]).paginated_search(params, count_pages: true)
@bulk_update_requests = BulkUpdateRequest.paginated_search(params, count_pages: true).includes(model_includes(params))
respond_with(@bulk_update_requests)
end
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[:user, :approver, :forum_topic, {forum_post: [:votes]}]
end
end
def load_bulk_update_request
@bulk_update_request = BulkUpdateRequest.find(params[:id])
end
......
......@@ -5,7 +5,7 @@ class CommentVotesController < ApplicationController
rescue_with CommentVote::Error, ActiveRecord::RecordInvalid, status: 422
def index
@comment_votes = CommentVote.includes(:user, comment: [:creator, :post]).paginated_search(params, count_pages: true)
@comment_votes = CommentVote.paginated_search(params, count_pages: true).includes(model_includes(params))
respond_with(@comment_votes)
end
......@@ -20,4 +20,14 @@ class CommentVotesController < ApplicationController
@comment.unvote!
respond_with(@comment)
end
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[:user, {comment: [:creator, {post: [:uploader]}]}]
end
end
end
class CommentsController < ApplicationController
respond_to :html, :xml, :json
respond_to :html, :xml, :json, :atom
respond_to :js, only: [:new, :destroy, :undelete]
before_action :member_only, :except => [:index, :search, :show]
skip_before_action :api_check
......@@ -74,6 +74,18 @@ class CommentsController < ApplicationController
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[:creator, :updater]
elsif params[:format] == "atom"
[:creator, :post]
else
includes_array = [:creator, :updater, {post: [:uploader]}]
includes_array << :votes if CurrentUser.is_member?
includes_array
end
end
def index_for_post
@post = Post.find(params[:post_id])
@comments = @post.comments
......@@ -90,12 +102,8 @@ class CommentsController < ApplicationController
end
def index_by_comment
@comments = Comment.includes(:creator, :updater).paginated_search(params)
respond_with(@comments) do |format|
format.atom do
@comments = @comments.includes(:post, :creator).load
end
end
@comments = Comment.paginated_search(params).includes(model_includes(params))
respond_with(@comments)
end
def check_privilege(comment)
......
......@@ -15,7 +15,7 @@ class DmailsController < ApplicationController
end
def index
@dmails = Dmail.visible.paginated_search(params, defaults: { folder: "received" }, count_pages: true)
@dmails = Dmail.visible.paginated_search(params, defaults: { folder: "received" }, count_pages: true).includes(model_includes(params))
respond_with(@dmails)
end
......@@ -51,6 +51,14 @@ class DmailsController < ApplicationController
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[:owner, :to, :from]
end
end
def check_show_privilege(dmail)
raise User::PrivilegeError unless dmail.visible_to?(CurrentUser.user, params[:key])
end
......
......@@ -2,7 +2,17 @@ class DtextLinksController < ApplicationController
respond_to :html, :xml, :json
def index
@dtext_links = DtextLink.includes(:model).paginated_search(params)
@dtext_links = DtextLink.paginated_search(params).includes(model_includes(params))
respond_with(@dtext_links)
end
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[:model]
end
end
end
......@@ -4,7 +4,7 @@ class FavoriteGroupsController < ApplicationController
def index
params[:search][:creator_id] ||= params[:user_id]
@favorite_groups = FavoriteGroup.paginated_search(params)
@favorite_groups = FavoriteGroup.paginated_search(params).includes(model_includes(params))
respond_with(@favorite_groups)
end
......@@ -61,6 +61,14 @@ class FavoriteGroupsController < ApplicationController
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[:creator]
end
end
def check_write_privilege(favgroup)
raise User::PrivilegeError unless favgroup.editable_by?(CurrentUser.user)
end
......
......@@ -3,7 +3,7 @@ class ForumPostVotesController < ApplicationController
before_action :member_only, only: [:create, :destroy]
def index
@forum_post_votes = ForumPostVote.includes(creator: [], forum_post: [:topic]).paginated_search(params, count_pages: true)
@forum_post_votes = ForumPostVote.paginated_search(params, count_pages: true).includes(model_includes(params))
respond_with(@forum_post_votes)
end
......@@ -21,6 +21,14 @@ class ForumPostVotesController < ApplicationController
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[:creator, {forum_post: [:topic]}]
end
end
def forum_post_vote_params
params.fetch(:forum_post_vote, {}).permit(:score)
end
......
......@@ -24,7 +24,7 @@ class ForumPostsController < ApplicationController
end
def index
@forum_posts = ForumPost.paginated_search(params).includes(:topic)
@forum_posts = ForumPost.paginated_search(params).includes(model_includes(params))
respond_with(@forum_posts)
end
......@@ -68,6 +68,14 @@ class ForumPostsController < ApplicationController
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[:topic, :creator]
end
end
def load_post
@forum_post = ForumPost.find(params[:id])
@forum_topic = @forum_post.topic
......
......@@ -23,10 +23,7 @@ class ForumTopicsController < ApplicationController
params[:search][:order] ||= "sticky" if request.format == Mime::Type.lookup("text/html")
params[:limit] ||= 40
@forum_topics = ForumTopic.paginated_search(params)
@forum_topics = @forum_topics.includes(:creator, :updater, :forum_topic_visit_by_current_user).load if request.format.html?
@forum_topics = @forum_topics.includes(:creator, :original_post).load if request.format.atom?
@forum_topics = ForumTopic.paginated_search(params).includes(model_includes(params))
respond_with(@forum_topics)
end
......@@ -80,6 +77,16 @@ class ForumTopicsController < ApplicationController
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
elsif params[:format] == "atom"
[:creator, :original_post]
else
[:creator, :updater, :forum_topic_visit_by_current_user]
end
end
def normalize_search
if params[:title_matches]
params[:search] ||= {}
......
......@@ -3,16 +3,30 @@ class IpAddressesController < ApplicationController
before_action :moderator_only
def index
@ip_addresses = IpAddress.visible(CurrentUser.user).paginated_search(params)
@ip_addresses = IpAddress.visible(CurrentUser.user).paginated_search(params).includes(model_includes(params))
if search_params[:group_by] == "ip_addr"
@ip_addresses = @ip_addresses.group_by_ip_addr(search_params[:ipv4_masklen], search_params[:ipv6_masklen])
elsif search_params[:group_by] == "user"
@ip_addresses = @ip_addresses.group_by_user.includes(:user)
else
@ip_addresses = @ip_addresses.includes(:user, :model)
@ip_addresses = @ip_addresses.group_by_user
end
respond_with(@ip_addresses)
end
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
if params[:search][:group_by] == "user"
[:user]
elsif params[:search][:group_by] == "ip_addr"
[]
else
[:user, :model]
end
end
end
end
......@@ -12,7 +12,7 @@ class IpBansController < ApplicationController
end
def index
@ip_bans = IpBan.includes(:creator).paginated_search(params, count_pages: true)
@ip_bans = IpBan.paginated_search(params, count_pages: true).includes(model_includes(params))
respond_with(@ip_bans)
end
......@@ -24,6 +24,14 @@ class IpBansController < ApplicationController
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[:creator]
end
end
def ip_ban_params
params.fetch(:ip_ban, {}).permit(%i[ip_addr reason])
end
......
......@@ -3,6 +3,7 @@ class LegacyController < ApplicationController
def posts
@post_set = PostSets::Post.new(tag_query, params[:page], params[:limit], format: "json")
@post_set.posts = @post_set.posts.includes(:uploader)
@posts = @post_set.posts.map(&:legacy_attributes)
respond_with(@posts) do |format|
......
......@@ -2,7 +2,7 @@ class ModActionsController < ApplicationController
respond_to :html, :xml, :json
def index
@mod_actions = ModAction.includes(:creator).paginated_search(params)
@mod_actions = ModAction.paginated_search(params).includes(model_includes(params))
respond_with(@mod_actions)
end
......@@ -12,4 +12,14 @@ class ModActionsController < ApplicationController
fmt.html { redirect_to mod_actions_path(search: { id: @mod_action.id }) }
end
end
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[:creator]
end
end
end
......@@ -10,7 +10,7 @@ class ModerationReportsController < ApplicationController
end
def index
@moderation_reports = ModerationReport.paginated_search(params, count_pages: true).includes(:creator, :model)
@moderation_reports = ModerationReport.paginated_search(params, count_pages: true).includes(model_includes(params))
respond_with(@moderation_reports)
end
......@@ -29,6 +29,14 @@ class ModerationReportsController < ApplicationController
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[:creator, :model]
end
end
def model_type
params.fetch(:moderation_report, {}).fetch(:model_type)
end
......
......@@ -12,12 +12,24 @@ module Moderator
end
def index
@post_disapprovals = PostDisapproval.includes(:user).paginated_search(params)
@post_disapprovals = PostDisapproval.paginated_search(params).includes(model_includes(params))
respond_with(@post_disapprovals)
end
private
def model_name
"PostDisapproval"
end
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[:user]
end
end
def post_disapproval_params
params.require(:post_disapproval).permit(%i[post_id reason message])
end
......
......@@ -2,8 +2,7 @@ class NoteVersionsController < ApplicationController
respond_to :html, :xml, :json
def index
@note_versions = NoteVersion.paginated_search(params)
@note_versions = @note_versions.includes(:updater) if request.format.html?
@note_versions = NoteVersion.paginated_search(params).includes(model_includes(params))
respond_with(@note_versions)
end
......@@ -13,4 +12,14 @@ class NoteVersionsController < ApplicationController
format.html { redirect_to note_versions_path(search: { note_id: @note_version.note_id }) }
end
end
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[:updater]
end
end
end
......@@ -6,8 +6,7 @@ class NotesController < ApplicationController
end
def index
@notes = Note.includes(:creator).paginated_search(params)
@notes = @notes.includes(:creator) if request.format.html?
@notes = Note.paginated_search(params).includes(model_includes(params))
respond_with(@notes)
end
......@@ -60,6 +59,14 @@ class NotesController < ApplicationController
private
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[:creator]
else
[:creator, :post]
end
end
def note_params(context)
permitted_params = %i[x y width height body]
permitted_params += %i[post_id html_id] if context == :create
......
......@@ -8,7 +8,7 @@ class PoolVersionsController < ApplicationController
@pool = Pool.find(params[:search][:pool_id])
end
@pool_versions = PoolArchive.paginated_search(params).includes(:updater, :pool)
@pool_versions = PoolArchive.paginated_search(params).includes(model_includes(params))
respond_with(@pool_versions)
end
......@@ -27,6 +27,18 @@ class PoolVersionsController < ApplicationController
private
def model_name
"PoolArchive"
end
def default_includes(params)
if ["json", "xml"].include?(params[:format])
[]
else
[:updater, :pool]
end
end
def set_timeout
PoolArchive.connection.execute("SET statement_timeout = #{CurrentUser.user.statement_timeout}")
yield
......
......@@ -17,7 +17,7 @@ class PoolsController < ApplicationController
end
def index
@pools = Pool.includes(:creator).paginated_search(params, count_pages: true)
@pools = Pool.paginated_search(params, count_pages: true).includes(model_includes(params))
respond_with(@pools)
end
......@@ -90,6 +90,10 @@ class PoolsController < ApplicationController
private
def default_includes(params)
[:creator]
end
def item_matches_params(pool)
if params[:search][:name_matches]
Pool.normalize_name_for_search(pool.name) == Pool.normalize_name_for_search(params[:search][:name_matches])
......
......@@ -8,7 +8,7 @@ class PostAppealsController < ApplicationController
end
def index
@post_appeals = PostAppeal.includes(:creator).paginated_search(params).includes(post: [:appeals, :uploader, :approver])
@post_appeals = PostAppeal.paginated_search(params).includes(model_includes(params))
respond_with(@post_appeals)
end
......@@ -26,6 +26,14 @@ class PostAppealsController < ApplicationController