6772312ea7
The primary license of the project is changing to: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later with some specific files to be licensed under the one of two licenses: CC0-1.0 LGPL-3.0-or-later This commit is one of the many steps to relicense the entire codebase. Documentation granting permission for this relicensing (from all past contributors who hold copyrights) is on file with Software Freedom Conservancy, Inc.
143 lines
5.9 KiB
Ruby
143 lines
5.9 KiB
Ruby
# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
|
|
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
|