Change import and delete subscribers to multi process.

This commit is contained in:
BoHung Chiu 2022-05-24 11:18:37 +08:00
parent 4735b107d7
commit 7fd1c7765f
6 changed files with 227 additions and 55 deletions

View File

@ -15,7 +15,11 @@ class Admin::EPaperSubscribersController < OrbitAdminController
@subscribers = EPaperSubscriber.order_by(sort) @subscribers = EPaperSubscriber.order_by(sort)
@subscribers = search_data(@subscribers,[:email]).page(params[:page]).per(10) @subscribers = search_data(@subscribers,[:email]).page(params[:page]).per(10)
render :partial => "index" if request.xhr? @thread = (params[:thread_id] ? Multithread.find(params[:thread_id]) : nil rescue nil)
if @thread && @thread.status[:status] == 'finish'
@thread = nil
end
render :partial => "index" if request.xhr?
end end
def destroy def destroy
@ -43,52 +47,77 @@ class Admin::EPaperSubscribersController < OrbitAdminController
render :partial => 'modal_select', :layout => false render :partial => 'modal_select', :layout => false
end end
def import_from_excel def import_from_excel
workbook = RubyXL::Parser.parse(params["import_file"].tempfile) thread = Multithread.where(:key=>'import_epaper_subscribers').first
subscribe_sheet = workbook['Subscribe'] if thread.nil?
unsubscribe_sheet = workbook['Unsubscribe'] thread = Multithread.create(:key=>'import_epaper_subscribers',:status=>{:status=>'Processing'})
subscribe_sheet.each_with_index do |row, i| else
next if i < 1 thread.update(:status=>{:status=>'Processing'})
c0 = row.cells[0] end
c1 = row.cells[1] Thread.new do
if c0 workbook = RubyXL::Parser.parse(params["import_file"].tempfile)
email = c0.value subscribe_sheet = workbook['Subscribe']
if email.present? unsubscribe_sheet = workbook['Unsubscribe']
subscriber = EPaperSubscriber.where(:email=>email).first all_count = (subscribe_sheet ? (subscribe_sheet.count - 1) : 0) + (unsubscribe_sheet ? (unsubscribe_sheet.count - 1) : 0)
if subscriber.nil? puts_every_count = all_count * 3 / 100
subscriber = EPaperSubscriber.new(:email=>email) current_count = 0
finish_percent = 0
thread.update(:status=>{:status=>'Importing','all_count'=>all_count,'current_count'=>current_count,'finish_percent'=>finish_percent})
subscribe_sheet.each_with_index do |row, i|
next if i < 1
c0 = row.cells[0]
c1 = row.cells[1]
if c0
email = c0.value
if email.present?
subscriber = EPaperSubscriber.where(:email=>email).first
if subscriber.nil?
subscriber = EPaperSubscriber.new(:email=>email)
end
language = c1.value
if language.blank?
language = I18n.locale.to_s
end
subscriber.subscribed = true
subscriber.language = language
subscriber.save
end end
language = c1.value end
if language.blank? current_count += 1
language = I18n.locale.to_s if current_count % puts_every_count == 0
end finish_percent = (current_count * 100.0 / all_count).round(1)
subscriber.subscribed = true thread.update(:status=>{:status=>'Importing','all_count'=>all_count,'current_count'=>current_count,'finish_percent'=>finish_percent})
subscriber.language = language
subscriber.save
end end
end end
end unsubscribe_sheet.each_with_index do |row, i|
unsubscribe_sheet.each_with_index do |row, i| next if i < 1
next if i < 1 c0 = row.cells[0]
c0 = row.cells[0] c1 = row.cells[1]
c1 = row.cells[1] if c0
if c0 email = c0.value
email = c0.value if email.present?
if email.present? subscriber = EPaperSubscriber.where(:email=>email).first
subscriber = EPaperSubscriber.where(:email=>email).first if subscriber.nil?
if subscriber.nil? subscriber = EPaperSubscriber.new(:email=>email)
subscriber = EPaperSubscriber.new(:email=>email) end
language = c1.value
if language.blank?
language = I18n.locale.to_s
end
subscriber.subscribed = false
subscriber.language = language
subscriber.save
end end
language = c1.value end
if language.blank? current_count += 1
language = I18n.locale.to_s if current_count % puts_every_count == 0
end finish_percent = (current_count * 100.0 / all_count).round(1)
subscriber.subscribed = false thread.update(:status=>{:status=>'Importing','all_count'=>all_count,'current_count'=>current_count,'finish_percent'=>finish_percent})
subscriber.language = language
subscriber.save
end end
end end
finish_percent = 100
thread.update(:status=>{:status=>'finish','all_count'=>all_count,'current_count'=>current_count,'finish_percent'=>finish_percent})
end end
redirect_to admin_e_paper_subscribers_path redirect_to admin_e_paper_subscribers_path(thread_id: thread.id)
end end
def download_excel_format def download_excel_format
@ -100,12 +129,42 @@ class Admin::EPaperSubscribersController < OrbitAdminController
} }
end end
end end
def batch_delete_subscribers
@thread = (params[:thread_id] ? Multithread.find(params[:thread_id]) : nil rescue nil)
if @thread && @thread.status[:status] == 'finish'
@thread = nil
end
end
def delete_subscribers def delete_subscribers
subscriber_ids = params['subscriber_ids'] subscriber_ids = params['subscriber_ids']
if subscriber_ids thread = Multithread.where(:key=>'delete_epaper_subscribers').first
EPaperSubscriber.where(:id.in=>subscriber_ids).destroy if thread.nil?
thread = Multithread.create(:key=>'delete_epaper_subscriber',:status=>{:status=>'Processing'})
else
thread.update(:status=>{:status=>'Processing'})
end end
redirect_to admin_e_paper_subscribers_path if subscriber_ids
all_count = subscriber_ids.count
puts_every_count = all_count * 3 / 100
current_count = 0
finish_percent = 0
thread.update(:status=>{:status=>'Deleting','all_count'=>all_count,'current_count'=>current_count,'finish_percent'=>finish_percent})
Thread.new do
EPaperSubscriber.where(:id.in=>subscriber_ids).to_a.each do |s|
s.destroy
current_count += 1
if current_count % puts_every_count == 0
finish_percent = (current_count * 100.0 / all_count).round(1)
thread.update(:status=>{:status=>'Deleting','all_count'=>all_count,'current_count'=>current_count,'finish_percent'=>finish_percent})
end
end
finish_percent = 100
thread.update(:status=>{:status=>'finish','all_count'=>all_count,'current_count'=>current_count,'finish_percent'=>finish_percent})
end
thread.update(:status=>{:status=>'finish'})
else
thread.update(:status=>{:status=>'finish'})
end
redirect_to admin_e_paper_subscribers_batch_delete_subscribers_path(thread_id: thread.id)
end end
end end

View File

@ -1,3 +1,22 @@
<% if @thread %>
<div id="threadModal" class="modal hide fade in" tabindex="-1" role="dialog" aria-labelledby="threadModal" aria-hidden="false">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h3 id="threadModal"><%=t("e_paper.#{@thread.key}")%></h3>
</div>
<div class="modal-body">
<div class="thread-status"><%= @thread.status[:status] %></div>
<div><span class="thread-current-count"><%= @thread.status[:current_count].to_i %></span>/<span class="thread-all-count"><%= @thread.status[:all_count].to_i %></span></div>
<span class="thread-finish_percent"><%= @thread.status[:finish_percent].to_i %></span> % finished
</div>
<div class="modal-footer">
<button class="btn" id="modal-close-btn" style="width: 4em;" data-dismiss="modal" aria-hidden="true"><%=t('close')%></button>
</div>
</div>
</div>
</div>
<% end %>
<table class="table main-list"> <table class="table main-list">
<thead> <thead>
<tr class="sort-header"> <tr class="sort-header">
@ -34,6 +53,9 @@
content_tag(:div, link_to(t("e_paper.export"), admin_e_paper_subscribers_export_excel_path + '.xlsx', :class=>"btn btn-success"), class: "pull-right") content_tag(:div, link_to(t("e_paper.export"), admin_e_paper_subscribers_export_excel_path + '.xlsx', :class=>"btn btn-success"), class: "pull-right")
%> %>
<div class="dropup upload-button pull-right"> <div class="dropup upload-button pull-right">
<% if @thread %>
<button class="show_progress btn btn-primary" type="button"><%= t("e_paper.show_progress") %></button>
<% end %>
<button class="btn btn-info dropdown-toggle" type="button" data-toggle="dropdown"> <button class="btn btn-info dropdown-toggle" type="button" data-toggle="dropdown">
<i class="icon-upload-alt icon-white"></i><%= t('personal_journal.upload') %> <i class="icon-upload-alt icon-white"></i><%= t('personal_journal.upload') %>
<span class="caret"></span> <span class="caret"></span>
@ -48,4 +70,47 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<script>
$(document).ready(function(){
function update_thread(){
$.post("<%=admin_threads_get_status_path%>",{"id": "<%=params[:thread_id]%>"}).done(function(data){
var finish_percent = data["finish_percent"];
var current_count = data["current_count"];
var all_count = data["all_count"];
var is_finish = (data["status"] == "finish");
if(finish_percent){
$("#threadModal .modal-body .thread-status").text(data["status"]);
if(data["status"] != 'Processing'){
$("#threadModal .modal-body .thread-current-count").text(current_count);
$("#threadModal .modal-body .thread-all-count").text(all_count);
}
$("#threadModal .modal-body .thread-finish_percent").text(finish_percent)
}
if(!is_finish){
window.time_out_id = window.setTimeout(update_thread, 1000);
}else{
if(window.time_out_id)
window.clearTimeout(window.time_out_id);
window.setTimeout(function(){
$("#threadModal").modal("hide");
alert(data["status"]);
}, 3000);
return;
}
});
}
if($("#threadModal").length != 0){
$("#threadModal").on('hidden.bs.modal',function(){
window.clearTimeout(window.time_out_id);
})
$("#threadModal").on('shown.bs.modal',function(){
window.time_out_id = window.setTimeout(update_thread, 1000);
})
$("#threadModal").modal("show");
$(".show_progress").click(function(){
$("#threadModal").modal("show");
})
}
})
</script>

View File

@ -161,6 +161,10 @@
}; };
}; };
function select_subscribers(){ function select_subscribers(){
if(window.still_processing){
return;
}
window.still_processing = true;
window.selected_subscriber_ids = []; window.selected_subscriber_ids = [];
var subscriber_cards = $('#member-filter [name="subscriber_ids[]"]:checked').map(function(i, subscriber){ var subscriber_cards = $('#member-filter [name="subscriber_ids[]"]:checked').map(function(i, subscriber){
window.selected_subscriber_ids.push(subscriber.value); window.selected_subscriber_ids.push(subscriber.value);
@ -177,6 +181,7 @@
} }
$('#members_field').change(); $('#members_field').change();
$("#member-filter").modal('hide'); $("#member-filter").modal('hide');
window.still_processing = false;
} }
$(document).ready(function(){ $(document).ready(function(){
$('#subscribers_form [type="submit"]').click(select_subscribers); $('#subscribers_form [type="submit"]').click(select_subscribers);

View File

@ -40,6 +40,9 @@
<button class="btn" id="remove_subscribers" style="display: none;"><i class="icon-trash"></i> <%=t('site.edit_members.delete_from_choice') %></button> <button class="btn" id="remove_subscribers" style="display: none;"><i class="icon-trash"></i> <%=t('site.edit_members.delete_from_choice') %></button>
<button class="btn btn-danger" id="remove_subscribers_forever" style="display: none;"><i class="icon-trash"></i> <%=t('e_paper.delete_subscribers') %></button> <button class="btn btn-danger" id="remove_subscribers_forever" style="display: none;"><i class="icon-trash"></i> <%=t('e_paper.delete_subscribers') %></button>
<!-- <button class="btn" id="edit_members" style="display: none;"><i class="icon-trash"></i> <%=t('site.edit_members.edit_members') %></button> --> <!-- <button class="btn" id="edit_members" style="display: none;"><i class="icon-trash"></i> <%=t('site.edit_members.edit_members') %></button> -->
<% if @thread %>
<button class="show_progress btn btn-primary" type="button"><%= t("e_paper.show_progress") %></button>
<% end %>
</div> </div>
</div> </div>
<% if @thread %> <% if @thread %>
@ -47,10 +50,12 @@
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h3 id="threadModal"><%=t("site.edit_members.#{@thread.key}")%></h3> <h3 id="threadModal"><%=t("e_paper.#{@thread.key}")%></h3>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<%= @thread.status[:finish_percent] %> % finished <div class="thread-status"><%= @thread.status[:status] %></div>
<div><span class="thread-current-count"><%= @thread.status[:current_count].to_i %></span>/<span class="thread-all-count"><%= @thread.status[:all_count].to_i %></span></div>
<span class="thread-finish_percent"><%= @thread.status[:finish_percent].to_i %></span> % finished
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn" id="modal-close-btn" style="width: 4em;" data-dismiss="modal" aria-hidden="true"><%=t('close')%></button> <button class="btn" id="modal-close-btn" style="width: 4em;" data-dismiss="modal" aria-hidden="true"><%=t('close')%></button>
@ -172,9 +177,16 @@
return false; return false;
}); });
$(document).on('click',".select_member_modal",function () { $(document).on('click',".select_member_modal",function () {
if(window.still_processing){
return;
}
window.still_processing = true;
$.get("<%= admin_e_paper_subscribers_get_subscribers_modal_path %>").done(function(data){ $.get("<%= admin_e_paper_subscribers_get_subscribers_modal_path %>").done(function(data){
$("#select_member_modal").html(data); $("#select_member_modal").html(data);
$("#member-filter").modal('show'); $("#member-filter").modal('show');
window.still_processing = false;
}).fail(function(){
window.still_processing = false;
}); });
return false; return false;
}); });
@ -236,15 +248,29 @@
$(this).parent().addClass("open"); $(this).parent().addClass("open");
}) })
$('#remove_subscribers_forever').off('click').on('click',function(){ $('#remove_subscribers_forever').off('click').on('click',function(){
var member_cards = '<ul id="card-list-managers" class="checkbox-card clearfix" style="clear: left;">'+$.map($('#members_field .check-item'),function(member_card,i){ if(window.still_processing){
return member_card.outerHTML; return;
}).join('')+'</ul>'; }
window.still_processing = true;
var member_cards;
var check_items = $('#members_field #card-list-managers .check-item');
if(check_items.length > 50){
member_cards = '<ul id="card-list-managers" class="checkbox-card clearfix" style="clear: left;">'+check_items.slice(0,50).map(function(i,v){ return $(v).prop('outerHTML')}).toArray().join('')+'<li style="background: transparent;color: black;">... etc</li>'+'</ul>';
}else{
member_cards = '<ul id="card-list-managers" class="checkbox-card clearfix" style="clear: left;">'+$('#members_field #card-list-managers').html()+'</ul>';
}
window.still_processing = false;
if(double_confirm_message('<%= t('e_paper.delete_subscribers_hint') %>')){ if(double_confirm_message('<%= t('e_paper.delete_subscribers_hint') %>')){
$("#members_form").before("<div id='dialog-confirm' title='"+"<%= t('site.edit_members.delete_hint1') %>'>"+ if($('#dialog-confirm').length == 0){
$("#members_form").before("<div id='dialog-confirm' title='"+"<%= t('site.edit_members.delete_hint1') %>'>"+
"<div style='clear:both;'></div><div><span class='ui-icon ui-icon-alert' style='float:left; margin:0 7px 20px 0;'></span>"+ "<div style='clear:both;'></div><div><span class='ui-icon ui-icon-alert' style='float:left; margin:0 7px 20px 0;'></span>"+
"<%= t('e_paper.delete_subscribers_hint2') %>"+member_cards+"</div>"+ "<%= t('e_paper.delete_subscribers_hint2') %>"+member_cards+"</div>"+
"</div>"); "</div>");
$( "#dialog-confirm" ).dialog({ }else{
$('#dialog-confirm').html("<div style='clear:both;'></div><div><span class='ui-icon ui-icon-alert' style='float:left; margin:0 7px 20px 0;'></span>"+
"<%= t('e_paper.delete_subscribers_hint2') %>"+member_cards+"</div>");
}
$( "#dialog-confirm" ).dialog({
resizable: true, resizable: true,
minHeight: 100, minHeight: 100,
maxHeight: 400, maxHeight: 400,
@ -267,9 +293,16 @@
function update_thread(){ function update_thread(){
$.post("<%=admin_threads_get_status_path%>",{"id": "<%=params[:thread_id]%>"}).done(function(data){ $.post("<%=admin_threads_get_status_path%>",{"id": "<%=params[:thread_id]%>"}).done(function(data){
var finish_percent = data["finish_percent"]; var finish_percent = data["finish_percent"];
var is_finish = (data["status"] == "finish" || data["status"] == "error"); var current_count = data["current_count"];
var all_count = data["all_count"];
var is_finish = (data["status"] == "finish");
if(finish_percent){ if(finish_percent){
$("#threadModal .modal-body").text(finish_percent + " % finished") $("#threadModal .modal-body .thread-status").text(data["status"]);
if(data["status"] != 'Processing'){
$("#threadModal .modal-body .thread-current-count").text(current_count);
$("#threadModal .modal-body .thread-all-count").text(all_count);
}
$("#threadModal .modal-body .thread-finish_percent").text(finish_percent)
} }
if(!is_finish){ if(!is_finish){
window.time_out_id = window.setTimeout(update_thread, 1000); window.time_out_id = window.setTimeout(update_thread, 1000);
@ -285,8 +318,16 @@
}); });
} }
if($("#threadModal").length != 0){ if($("#threadModal").length != 0){
$("#threadModal").on('hidden.bs.modal',function(){
window.clearTimeout(window.time_out_id);
})
$("#threadModal").on('shown.bs.modal',function(){
window.time_out_id = window.setTimeout(update_thread, 1000);
})
$("#threadModal").modal("show"); $("#threadModal").modal("show");
window.time_out_id = window.setTimeout(update_thread, 1000); $(".show_progress").click(function(){
$("#threadModal").modal("show");
})
} }
$(document).on('click','.modal-backdrop',function(){ $(document).on('click','.modal-backdrop',function(){
$('.modal').modal('hide'); $('.modal').modal('hide');

View File

@ -4,6 +4,7 @@ en:
restful_actions: restful_actions:
batch_delete_subscribers: "Batch Delete Subscribers" batch_delete_subscribers: "Batch Delete Subscribers"
e_paper: e_paper:
show_progress: "Show Progress"
delete_subscribers_hint2: "Delete Subscribers below forever." delete_subscribers_hint2: "Delete Subscribers below forever."
delete_subscribers_hint1: "Do you realy want to delete Subscribers you added forever?" delete_subscribers_hint1: "Do you realy want to delete Subscribers you added forever?"
delete_subscribers_hint: "Click 『Add』 button to select Subscribers" delete_subscribers_hint: "Click 『Add』 button to select Subscribers"

View File

@ -4,6 +4,7 @@ zh_tw:
restful_actions: restful_actions:
batch_delete_subscribers: "批次刪除訂閱者" batch_delete_subscribers: "批次刪除訂閱者"
e_paper: e_paper:
show_progress: "顯示進度"
delete_subscribers_hint2: "永久刪除以下訂閱者" delete_subscribers_hint2: "永久刪除以下訂閱者"
delete_subscribers_hint1: "您確定真的要永久刪除所選的訂閱者嗎?" delete_subscribers_hint1: "您確定真的要永久刪除所選的訂閱者嗎?"
delete_subscribers_hint: "點選『新增』按鈕選擇訂閱者" delete_subscribers_hint: "點選『新增』按鈕選擇訂閱者"