diff --git a/app/logical/parameter_builder.rb b/app/logical/parameter_builder.rb new file mode 100644 index 000000000..cdf1d154f --- /dev/null +++ b/app/logical/parameter_builder.rb @@ -0,0 +1,105 @@ +class ParameterBuilder + def self.serial_parameters(only_string, object) + only_array = split_only_string(only_string) + get_only_hash(only_array, object) + end + + def self.get_only_hash(only_array, object, seen_objects = []) + return {} if object.nil? + is_root = seen_objects.length == 0 + only_hash = {only: [], include: [], methods: []} + available_includes = object.available_includes + attributes, methods = object.api_attributes.partition { |attr| object.has_attribute?(attr) } + methods -= available_includes + # Attributes and/or methods may be included in the final pass, but not includes + seen_objects << object.class.name + only_array.each do |item| + match = item.match(/(\w+)\[(.+?)\]$/) + item = (match || [])[1] || item + item_sym = item.to_sym + was_seen = was_inclusion_seen(item, object.class, seen_objects) + if match && available_includes.include?(item_sym) && (!was_seen || is_root) + item_object = object.send(item_sym) + next if item_object.nil? + item_object = item_object[0] if item_object.is_a?(ActiveRecord::Relation) + item_array = split_only_string(match[2]) + item_hash = get_only_hash(item_array, item_object, seen_objects.clone) + only_hash[:include] << Hash[item_sym, item_hash] + elsif available_includes.include?(item_sym) && (!was_seen || is_root) + only_hash[:include] << item_sym + elsif attributes.include?(item_sym) + only_hash[:only] << item_sym + elsif methods.include?(item_sym) + only_hash[:methods] << item_sym + only_hash[:only] << item_sym + end + end + only_hash.delete(:include) if only_hash[:include].empty? + only_hash.delete(:methods) if only_hash[:methods].empty? + only_hash + end + + def self.includes_parameters(only_string, model_name) + only_array = split_only_string(only_string) + get_includes_array(only_array, model_name) + end + + def self.get_includes_array(only_array, model_name, seen_objects = []) + is_root = seen_objects.length == 0 + include_array = [] + model = Kernel.const_get(model_name) + available_includes = model.available_includes + # Attributes and/or methods may be included in the final pass, but not includes + seen_objects << model_name + only_array.each do |item| + binding.pry + match = item.match(/(\w+)\[(.+?)\]$/) + item = (match || [])[1] || item + item_sym = item.to_sym + was_seen = was_inclusion_seen(item, model, seen_objects) + if match && available_includes.include?(item_sym) && (!was_seen || is_root) + item_array = split_only_string(match[2]) + model.associated_models(item).each do |m| + item_array = get_includes_array(item_array, m, seen_objects.clone) + include_array << (item_array.empty? ? item_sym : Hash[item_sym, item_array]) + end + elsif available_includes.include?(item_sym) && (!was_seen || is_root) + include_array << item_sym + end + end + include_array + end + + def self.was_inclusion_seen(inclusion, class_object, seen_objects) + if class_object.reflections[inclusion] + inclusion_class = class_object.reflections[inclusion].class_name + max_seen = (class_object.multiple_includes.include?(inclusion.to_sym) ? 1 : 0) + seen_objects.count(inclusion_class) > max_seen + else + false + end + end + + def self.split_only_string(only_string) + only_array = [] + offset = 0 + position = 0 + level = 0 + loop do + str = only_string[Range.new(position, -1)] + match = str.match(/[,\[\]]/) + break unless match + start_pos, end_pos = match.offset(0) + if match[0] == "," && level.zero? + only_array << only_string[Range.new(offset, position + start_pos - 1)] + offset = position + end_pos + elsif match[0] == "[" + level += 1 + elsif match[0] == "]" + level -= 1 + end + position += end_pos + end + only_array << only_string[Range.new(offset, -1)] + end +end diff --git a/app/models/post_flag.rb b/app/models/post_flag.rb index 12d8835ce..1a34337fe 100644 --- a/app/models/post_flag.rb +++ b/app/models/post_flag.rb @@ -155,7 +155,7 @@ class PostFlag < ApplicationRecord end def uploader_id - @uploader_id ||= Post.find(post_id).uploader_id + post.uploader_id end def not_uploaded_by?(userid)