From bd8f88afa35a3d20f26e2978f433031fd36aa82c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B1=E5=8D=9A=E4=BA=9E?= Date: Tue, 14 May 2024 08:59:52 +0800 Subject: [PATCH] Add copy feature. --- .../admin/property_hires_controller.rb | 12 +- app/models/property.rb | 245 +++++++++++++++++- app/views/admin/property_hires/_form.html.erb | 17 +- .../admin/property_hires/_form_file.html.erb | 4 +- .../admin/property_hires/_index.html.erb | 1 + app/views/admin/property_hires/copy.html.erb | 6 + config/locales/en.yml | 2 + config/locales/zh_tw.yml | 2 + config/routes.rb | 1 + 9 files changed, 275 insertions(+), 15 deletions(-) create mode 100644 app/views/admin/property_hires/copy.html.erb diff --git a/app/controllers/admin/property_hires_controller.rb b/app/controllers/admin/property_hires_controller.rb index 7192fb1..83fb226 100644 --- a/app/controllers/admin/property_hires_controller.rb +++ b/app/controllers/admin/property_hires_controller.rb @@ -45,6 +45,12 @@ class Admin::PropertyHiresController < OrbitAdminController @bookings = PHire.where(:hiring_person_id => current_user.member_profile.id.to_s).desc(:created_at).page(params[:page]).per(10) end + def copy + @property = Property.where(:uid => params[:id].split("-").last).first.clone_new #rescue nil + create_set (false) + @locations = PropertyLocation.all.desc(:created_at).collect{|loc| [loc.title, loc.id.to_s]} + @locations << ["Other", "other_location"] + end def new @property = Property.new create_set (false) @@ -116,7 +122,11 @@ class Admin::PropertyHiresController < OrbitAdminController end def create - if Property.create(property_params) + tmp_property_params = property_params + if tmp_property_params["copy_id"] && tmp_property_params["clone_p_hires"].blank? + tmp_property_params["except_clone_relations"] = ["p_hires","p_hire_field_values"] + end + if Property.create(tmp_property_params) redirect_to admin_property_hires_path end end diff --git a/app/models/property.rb b/app/models/property.rb index 14e97f6..4ff42f4 100644 --- a/app/models/property.rb +++ b/app/models/property.rb @@ -59,6 +59,8 @@ class Property field :enable_fields_sort , type: Boolean, default: false field :custom_field_names, type: Array field :default_field_names, type: Array + field :copy_id + field :except_clone_relations, :type=>Array, :default => [] belongs_to :property_location has_many :p_hires has_many :hire_email_sets, :autosave => true, :dependent => :destroy, :inverse_of => :property @@ -108,11 +110,17 @@ class Property max_position = -1 if max_position.nil? self.order_position = max_position + 1 @no_validate = true - self.default_field_names = self.get_all_fields(true) - self.custom_field_names = self.get_all_fields(true) + if self.copy_id.present? + self.clone_new(true) + self.created_at = DateTime.now + self.updated_at = DateTime.now + else + self.default_field_names = self.get_all_fields(true) + self.custom_field_names = self.get_all_fields(true) + end end before_save do - unless @no_validate + unless @no_validate || self.new_record? self.custom_field_names = [] if self.custom_field_names.nil? self.default_field_names = self.get_all_fields(true) self.class::FIELDSNAME.each do |f| @@ -532,8 +540,8 @@ class Property def carousel_image_width (self.custom_carousel_image_width.blank? ? PropertyHireSetting.first.carousel_image_width : self.custom_carousel_image_width) rescue "75%" end - def get_attribute_value(attribute_field, signup_id) - SeminarSignupValue.find_by(seminar_signup_field_id: attribute_field.id, seminar_signup_id: signup_id) + def get_attribute_value(attribute_field, p_hire_id) + PHireFieldValue.find_by(p_hire_field_id: attribute_field.id, p_hire_id: p_hire_id) end def get_attribute_values(attribute_type=nil) @@ -574,4 +582,231 @@ class Property user = OrbitHelper.current_user (!disable_no_logins_view_calendar && self.can_be_hired) || user end + def clone_new(clone_mode=false) + @records_all = {} + if clone_mode + clone_target = self.class.find(object.copy_id) rescue nil + else + clone_target = self + end + property,clone_target = clone_new_for_object(self,clone_target,clone_mode) + property + end + def fix_uploader(clone_relation, r, f) + if !@clone_mode || (clone_relation[f].blank? && clone_relation.send(f).blank?) + clone_relation[f] = r[f] + if @clone_mode + clone_relation.send(f).retrieve_from_store!(r[f]) + else + org_id = clone_relation.id + clone_relation.id = r.id + clone_relation.send(f).retrieve_from_store!(r[f]) + clone_relation.id = org_id + end + source_filepath = r.send(f).file.file + if @clone_mode + dest_filepath = clone_relation.send(f).file.file + FileUtils.mkdir_p(File.dirname(dest_filepath)) + FileUtils.cp(source_filepath,dest_filepath) + end + elsif (clone_relation.send(f).file rescue nil) + clone_relation[f] = File.basename(clone_relation.send(f).file.file.to_s) + end + end + def clone_new_for_object(object,clone_target=nil,clone_mode=false,fix_only=false) + @except_clone_relations ||= self.except_clone_relations + if clone_mode || fix_only + new_object = object + clone_target = object.class.find(object.copy_id) rescue nil if clone_target.nil? + else + clone_target = object if clone_target.nil? + new_object = object.dup + end + return if @except_clone_relations.include?(new_object.class.to_s.underscore) + @records_all["#{new_object.class.to_s.underscore}_ids"] = {} if @records_all["#{new_object.class.to_s.underscore}_ids"].nil? + begin + @records_all["#{new_object.class.to_s.underscore}_ids"][clone_target.id] = new_object + rescue + nil + end + if !clone_target.nil? && !new_object.nil? + unless fix_only + if clone_mode + initialize_fields = [] + if new_object.fields.keys.include?("uid") + new_object.generate_uid + end + else + initialize_fields = ["uid","created_at","updated_at"] + end + initialize_fields.each do |f| + new_object.send("#{f}=",nil) if new_object.fields.keys.include?(f) + end + end + relations_fields = clone_target.relations.except("impressions").keys + all_fields = clone_target.fields.keys - relations_fields + all_fields = all_fields - relations_fields.map{|k| "#{k}_id"} + all_fields = all_fields - relations_fields.map{|k| "#{k.singularize}_ids"} + new_object_class_name = new_object.class.to_s.underscore + unless @parent_level + unsort_relation_keys = clone_target.relations.keys - ['taggings'] + fields_to_delete = [new_object_class_name] + tmp_relations_fields = [new_object_class_name] + while relations_fields.count > 0 + tmp_singularize_relations_fields = tmp_relations_fields.map{|f| f.singularize} + approve_append = nil + relations_fields.each do |k| + belongs_to_class = clone_target.relations[k].class_name.constantize.relations.select{|k,v| v.macro == :belongs_to}.keys + has_many_class = clone_target.relations[k].class_name.constantize.relations.select{|k,v| v.macro.to_s.start_with?('has') }.keys + if (belongs_to_class - tmp_singularize_relations_fields).count == 0 + other_has_many_class = (has_many_class - unsort_relation_keys) + if other_has_many_class.count == 0 + tmp_relations_fields << k + else + org_k = k.to_s + result = other_has_many_class.map do |k| + belongs_to_class = k.classify.constantize.relations.select{|kk,v| v.macro == :belongs_to}.keys + has_many_class = k.classify.constantize.relations.select{|kk,v| v.macro.to_s.start_with?('has') }.keys + if (belongs_to_class - tmp_singularize_relations_fields - [org_k]).count == 0 + true + else + fields_to_delete = fields_to_delete.concat(belongs_to_class) + tmp_relations_fields.concat(belongs_to_class) + false + end + end + if result.select{|t| !t}.count == 0 + if (fields_to_delete.map{|f| f.pluralize} - tmp_relations_fields).count == 0 + tmp_relations_fields << k + elsif clone_target.relations[k].class_name.constantize.fields.keys.include?("key") + tmp_relations_fields << k + elsif (clone_target.relations[k].class_name.constantize.relations.keys.map{|f| f.singularize} & fields_to_delete).count != 0 + approve_append = k + end + end + end + elsif !unsort_relation_keys.include?(clone_target.relations[k].class_name.underscore) && !unsort_relation_keys.include?(clone_target.relations[k].class_name.underscore.pluralize) + tmp_relations_fields << k + end + end + tmp_relations_fields << approve_append if approve_append.present? + approve_append = nil + relations_fields = relations_fields - tmp_relations_fields + relations_fields -= @relations_fields if @relations_fields + end + relations_fields = tmp_relations_fields + fields_to_delete.each{|f| relations_fields.delete(f)} + end + if @parent_level + relations_fields -= @relations_fields + else + @clone_mode = clone_mode + @relations_fields = relations_fields + end + @parent_level = true + if clone_mode + all_fields.each do |f| + next if f == "uid" + unless new_object.send("#{f}_changed?") && new_object.send("#{f}_changed_from_default?") + unless fix_only + new_object.send("#{f}=",clone_target.send(f)) + end + if new_object.class.uploaders.include?(f.to_sym) + fix_uploader(new_object, clone_target, f) + end + end + end + else + all_fields.each do |f| + if new_object.class.uploaders.include?(f.to_sym) + fix_uploader(new_object, clone_target, f) + end + end + end + relations_fields.each do |f| + no_dup_flag = false + if clone_target.relations[f].macro == :belongs_to || clone_target.relations[f].macro == :has_one + no_dup_flag = new_object.send(f).present? + elsif clone_target.relations[f].macro == :has_many || clone_target.relations[f].macro == :has_and_belongs_to_many + no_dup_flag = new_object.send(f).to_a.count != 0 + elsif clone_target.relations[f].macro == :embeds_many #Fix localize fields + if new_object.send(f).to_a.count != 0 + need_fix_fields = new_object.send(f).to_a[0].fields.select{|k,v| (v.options[:localize] rescue false)}.keys + locale = I18n.locale.to_s + embeded_records = new_object.send(f).map do |embeded_record| + need_fix_fields.each do |f| + if (embeded_record[f][locale].class != String rescue false) + embeded_record.send("#{f}_translations=",embeded_record[f][locale]) + else + embeded_record.send("#{f}_translations=",embeded_record[f]) + end + end + embeded_record + end + new_object.send("#{f}=",embeded_records) + end + end + if clone_target.relations[f].macro == :belongs_to || clone_target.relations[f].class_name == "MemberProfile" + if f == 'taggable' + map_f = @taggable_name + else + map_f = f + end + if @records_all["#{map_f}_ids"].nil? + new_object.send("#{f}_id=",clone_target.send("#{f}_id")) + else + obj = @records_all["#{map_f}_ids"][clone_target.send("#{f}_id")] + if obj + new_object.send("#{f}_id=", obj.id) + new_object.send("#{f}=", obj) + end + end + elsif clone_target.relations[f].macro == :has_one + next if @except_clone_relations.include?(f) + need_clone_relation = clone_target.send(f) + next if need_clone_relation.nil? + clone_relation = new_object.send(f) + if clone_relation.nil? + clone_relation, need_clone_relation = clone_new_for_object(need_clone_relation.dup, need_clone_relation, clone_mode, fix_only) + else + clone_relation, r = clone_new_for_object(clone_relation, r, clone_mode, true) + end + new_object.send("#{f}=",clone_relation) + elsif clone_target.relations[f].macro == :has_many || clone_target.relations[f].macro == :has_and_belongs_to_many + next if @except_clone_relations.include?(f) + clone_relations = [] + need_clone_relations = clone_target.send(f).asc(:_id).to_a + file_flag = false + if f == 'taggings' + @taggable_name = new_object.class.to_s.underscore + end + need_clone_relations.each_with_index do |r,i| + clone_relation = new_object.send(f)[i] + if clone_relation.nil? + clone_relation, r = clone_new_for_object(r.dup, r, clone_mode, fix_only) + else + clone_relation, r = clone_new_for_object(clone_relation, r, clone_mode, true) + end + clone_relations << clone_relation + end + if !no_dup_flag || (no_dup_flag && file_flag) + new_object_relations = new_object.send(f).to_a + new_object_relations_count = new_object_relations.count + if new_object_relations_count != 0 + if clone_relations.count > new_object_relations_count + clone_relations = clone_relations[0...new_object_relations_count] + else + clone_relations = clone_relations.concat(new_object.send(f)[clone_relations.count...new_object_relations_count]) + end + new_object.send("#{f}=",clone_relations) + else + new_object.send("#{f}=",clone_relations) + end + end + end + end + new_object.copy_id = clone_target.id if new_object.fields.keys.include?("copy_id") + return new_object, clone_target + end + end end \ No newline at end of file diff --git a/app/views/admin/property_hires/_form.html.erb b/app/views/admin/property_hires/_form.html.erb index c585bbf..2ccea8d 100644 --- a/app/views/admin/property_hires/_form.html.erb +++ b/app/views/admin/property_hires/_form.html.erb @@ -1,6 +1,7 @@ <% hire_method = Admin::PropertyHiresHelper::HireMethod hire_method.set_input_name('property') + with_id = !(@property.new_record?) %>