2018-03-25 16:15:39 +00:00
|
|
|
# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
|
2018-03-25 17:30:42 +00:00
|
|
|
require 'delayed_job_helper'
|
|
|
|
require 'qx'
|
|
|
|
require 'update/update_custom_field_joins'
|
|
|
|
|
|
|
|
module InsertCustomFieldJoins
|
|
|
|
|
|
|
|
# Bulk insert many field joins into many supporters
|
|
|
|
# for every field name, find or create it for the nonprofit
|
|
|
|
# field_data should be an array of arrays liks [['Company', 'Pixar'],
|
|
|
|
# ['Shirt-size', 'Small']]
|
|
|
|
def self.find_or_create(np_id, supporter_ids, field_data)
|
|
|
|
ParamValidation.new({np_id: np_id, supporter_ids: supporter_ids, field_data: field_data},
|
|
|
|
{
|
|
|
|
:np_id => {
|
|
|
|
:required => true,
|
|
|
|
:is_integer=> true
|
|
|
|
},
|
|
|
|
:supporter_ids => {
|
|
|
|
:required => true,
|
|
|
|
:is_array => true,
|
|
|
|
:min_length => 1
|
|
|
|
},
|
|
|
|
:field_data => {
|
|
|
|
:required => true,
|
|
|
|
:is_array => true,
|
|
|
|
:min_length => 1
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
#make sure the np exists
|
|
|
|
np = Nonprofit.where("id = ? ", np_id).first
|
|
|
|
unless np
|
|
|
|
raise ParamValidation::ValidationError.new("#{np_id} is not a valid non-profit", {:key => :np_id})
|
|
|
|
end
|
|
|
|
|
|
|
|
#make sure the supporters_ids exist
|
|
|
|
supporter_ids.each {|id|
|
|
|
|
unless np.supporters.where('id = ?', id).exists?
|
|
|
|
raise ParamValidation::ValidationError.new("#{id} is not a valid supporter for nonprofit #{np_id}", {:key => :supporter_ids})
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
Qx.transaction do
|
|
|
|
# get the custom_field_master_id for each field_data name
|
|
|
|
cfm_id_to_value = field_data.map { |name, value|
|
|
|
|
cfm = CustomFieldMaster.where("nonprofit_id = ? and name = ?", np_id, name).first
|
|
|
|
unless cfm
|
|
|
|
cfm = CustomFieldMaster.create!(:nonprofit => np, :name => name)
|
|
|
|
end
|
|
|
|
{:custom_field_master_id => cfm.id, :value => value}
|
|
|
|
}
|
|
|
|
|
|
|
|
return in_bulk(np_id, supporter_ids, cfm_id_to_value)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
# Validation: *np_id is valid, corresponds to real nonprofit
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# @param [Integer] np_id nonprofit_id whose custom_fields this applies to
|
|
|
|
# @param [Array<Integer>] supporter_ids the supporter ids in which the custom fields should be modified
|
|
|
|
# @param [Array<Hash<Symbol, Object>>] field_data the fields you'd like to modify. Each item is a hash with following keys:
|
|
|
|
# * custom_field_master_id [Integer] for the key corresponding to custom_field_master_id
|
|
|
|
# * value [Object] the expected value of the field. If this key is an empty string, we remove the custom_field
|
|
|
|
def self.in_bulk(np_id, supporter_ids, field_data)
|
|
|
|
begin
|
|
|
|
ParamValidation.new({
|
|
|
|
np_id: np_id,
|
|
|
|
supporter_ids: supporter_ids,
|
|
|
|
field_data: field_data
|
|
|
|
}, {
|
|
|
|
np_id: {required: true, is_integer: true},
|
|
|
|
supporter_ids: {required:true, is_array: true},
|
|
|
|
field_data: { required: true, is_array: true}
|
|
|
|
# array_of_hashes: {
|
|
|
|
# selected: {required: true}, tag_master_id: {required: true, is_integer: true}
|
|
|
|
# }
|
|
|
|
|
|
|
|
})
|
|
|
|
rescue ParamValidation::ValidationError => e
|
|
|
|
return {json: {error: "Validation error\n #{e.message}", errors: e.data}, status: :unprocessable_entity}
|
|
|
|
end
|
|
|
|
|
|
|
|
begin
|
|
|
|
return {json: {error: "Nonprofit #{np_id} is not valid"}, status: :unprocessable_entity} unless Nonprofit.exists?(np_id)
|
|
|
|
|
|
|
|
# verify that the supporters belong to the nonprofit
|
|
|
|
supporter_ids = Supporter.where('nonprofit_id = ? and id IN (?)', np_id, supporter_ids).pluck(:id)
|
|
|
|
unless supporter_ids.any?
|
|
|
|
return {json: {inserted_count: 0, removed_count: 0}, status: :ok}
|
|
|
|
end
|
|
|
|
|
|
|
|
# filtering the tag_data to this nonprofit
|
|
|
|
valid_ids = CustomFieldMaster.where('nonprofit_id = ? and id IN (?)', np_id, field_data.map {|fd| fd[:custom_field_master_id] }).pluck(:id).to_a
|
|
|
|
filtered_field_data = field_data.select {|i| valid_ids.include? i[:custom_field_master_id ].to_i}
|
|
|
|
|
|
|
|
# first, delete the items which should be removed
|
|
|
|
to_insert, to_remove = filtered_field_data.partition{|t|
|
|
|
|
!t[:value].blank?
|
|
|
|
}
|
|
|
|
deleted = []
|
|
|
|
if to_remove.any?
|
|
|
|
deleted = Qx.delete_from(:custom_field_joins)
|
|
|
|
.where("supporter_id IN ($ids)", ids: supporter_ids)
|
|
|
|
.and_where("custom_field_master_id in ($fields)", fields: to_remove.map{|t| t[:custom_field_master_id]})
|
|
|
|
.returning('*')
|
|
|
|
.execute
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
# next add only the selected tag_joins
|
|
|
|
|
|
|
|
if to_insert.any?
|
|
|
|
insert_data = supporter_ids.map{|id| to_insert.map{|cfm| {supporter_id: id, custom_field_master_id: cfm[:custom_field_master_id], value: cfm[:value]}}}.flatten
|
|
|
|
cfj = Qx.insert_into(:custom_field_joins)
|
|
|
|
.values(insert_data)
|
|
|
|
.timestamps
|
|
|
|
.on_conflict()
|
|
|
|
.conflict_columns(:supporter_id, :custom_field_master_id).upsert(:custom_field_join_supporter_unique_idx)
|
|
|
|
.returning('*')
|
|
|
|
.execute
|
|
|
|
else
|
|
|
|
cfj = []
|
|
|
|
end
|
|
|
|
rescue ActiveRecord::ActiveRecordError => e
|
|
|
|
return {json: {error: "A DB error occurred. Please contact support. \n #{e.message}"}, status: :unprocessable_entity}
|
|
|
|
end
|
|
|
|
|
|
|
|
# Create an activity for the modified tags for every supporter
|
|
|
|
# TODO
|
|
|
|
# activity_data = tags.map{|tag| {supporter_id: tag['supporter_id'], nonprofit_id: np_id, attachment_id: tag['id'], attachment_type: 'TagJoin', profile_id: profile_id}}
|
|
|
|
# activities = Psql.execute( Qexpr.new.insert(:activities, activity_data) )
|
|
|
|
|
|
|
|
# Sync mailchimp lists, if present
|
|
|
|
#Mailchimp.delay.sync_supporters_to_list_from_tag_joins(np_id, supporter_ids, tag_data)
|
|
|
|
|
|
|
|
return {json: {inserted_count: cfj.count, removed_count: deleted.count }, status: :ok}
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|