Add import and export feature.

This commit is contained in:
BoHung Chiu 2023-09-24 15:20:39 +08:00
parent a810260e14
commit ad003ea465
9 changed files with 886 additions and 0 deletions

View File

@ -1,5 +1,6 @@
# encoding: utf-8
class Admin::NewsController < OrbitAdminController
require 'rubyXL'
include Admin::NewsHelper
before_action ->(module_app = @app_title) { set_variables module_app }
before_action :set_news_bulletin, only: [:edit, :destroy]
@ -155,6 +156,140 @@ class Admin::NewsController < OrbitAdminController
redirect_to "/admin/news"
end
def render_404
render :file => "#{Rails.root}/app/views/errors/404.html", :layout => false, :status => 404, :formats => [:html]
end
def import_export
@thread = Multithread.where(:id=>params[:thread_id]).first if params[:thread_id].present?
end
def download_file_from_thread
@thread = Multithread.where(:id=>params[:id]).first if params[:id].present?
if @thread && @thread.status[:file]
send_file(@thread.status[:file],:filename=>@thread.status[:filename])
else
render_404
end
end
def excel_format
respond_to do |format|
format.xlsx {
response.headers['Content-Disposition'] = 'attachment; filename="news_import_format.xlsx"'
}
end
end
def export_excel
@thread = Multithread.where(:key=>'export_news').first
update_flag = true
if @thread.nil?
@thread = Multithread.create(:key=>'export_news',:status=>{:status=>'Processing'})
else
update_flag = false if @thread.status[:status] == 'Processing' && @thread.respond_to?(:updated_at) && (@thread.updated_at > DateTime.now - 1.minute rescue false)
if update_flag
@thread.update(:status=>{:status=>'Processing'})
end
end
if update_flag
@host = Site.first.root_url
if @host == "http"
@host = request.protocol + request.host_with_port
end
Thread.new do
begin
@news = NewsBulletin.where(:is_preview.ne=>true).desc(:id)
last_updated = [NewsBulletin.max(:updated_at).to_i, Unit.max(:updated_at).to_i, Department.max(:updated_at).to_i].max
filename = "public/news_export_#{last_updated}.xlsx"
if File.exist?(filename)
@thread.update(:status=>{:status=>'finish','finish_percent'=>100,'info'=>I18n.t('announcement.read_from_cache')})
else
excel_contents = render_to_string( handlers: [:axlsx], formats: [:xlsx] ,partial: 'export_excel.xlsx' )
File.open(filename, 'w') do |f|
f.write excel_contents
end
end
@thread.status[:file] = filename
@thread.status[:filename] = "news_export_#{DateTime.now.in_time_zone(Time.zone.utc_offset / 3600).strftime('%Y_%m_%d_%H%M')}.xlsx"
@thread.save
rescue => e
@thread.status[:status] = 'error'
# @thread.status[:info] = [e.to_s, e.backtrace]
puts [e.to_s, e.backtrace]
@thread.save
end
end
end
redirect_to admin_news_import_export_path(:thread_id=>@thread.id.to_s)
end
def importnews
workbook = RubyXL::Parser.parse(params["import_file"].tempfile)
raw_categories = @module_app.categories.asc(:created_at).to_a.map.with_index{|v, k| [k.to_s,v]}.to_h
raw_tags = @module_app.tags.asc(:created_at).to_a.map.with_index{|v, k| [k.to_s,v]}.to_h
categories = raw_categories.clone
tags = raw_tags.clone
sheet = workbook[0]
if sheet.count <= 503
sheet.each_with_index do |row, i|
if i == 2
begin
cats_text = row.cells[0].value.to_s.sub(/(^|,)\s*Example\s*:.*$/,'')
cats_keys = cats_text.split('->').map{|s| s.split(',')[-1].strip}[0...-1]
cats_values = cats_text.split('->')[1..-1].to_a.map{|s| s.strip.sub(/,\s*\d+$/,'')}
categories_relations = cats_keys.zip(cats_values).to_h
rescue => e
categories_relations = {}
end
begin
tags_text = row.cells[1].value.to_s.sub(/(^|,)\s*Example\s*:.*$/,'')
tags_keys = tags_text.split('->').map{|s| s.split(',')[-1].strip}[0...-1]
tags_values = tags_text.split('->')[1..-1].to_a.map{|s| s.strip.sub(/,\s*\d+$/,'')}
tags_relations = tags_keys.zip(tags_values).to_h
rescue => e
tags_relations = {}
end
if categories_relations.present?
categories = categories_relations.map do |k, v|
tmp = raw_categories[k]
if tmp && tmp.title.strip == v
[k, tmp]
else
tmp = raw_categories.detect{|kk, vv| vv.title.strip == v}
if tmp.nil?
tmp = @module_app.categories.create(:title_translations=> localize_data(v))
end
[k, tmp]
end
end.to_h
end
if tags_relations.present?
tags = tags_relations.map do |k, v|
tmp = raw_tags[k]
if tmp && tmp.name.strip == v
[k, tmp]
else
tmp = raw_tags.detect{|kk, vv| vv.name.strip == v}
if tmp.nil?
tmp = @module_app.tags.create(:name_translations=> localize_data(v))
end
[k, tmp]
end
end.to_h
end
end
next if i < 3
v = row.cells.first.value rescue nil
next if v.blank? #類別為空
import_this_news(row, categories, tags)
end
redirect_to admin_news_index_path
else
redirect_to admin_news_index_path(:error => "1")
end
end
def preview
if params['preview_type'].eql?('edit')
news_bulletin_data = news_bulletin_params

View File

@ -1,4 +1,5 @@
module Admin::NewsHelper
InUseLocales = (Site.first.in_use_locales rescue [:en,:zh_tw])
def page_for_news_bulletin(news_bulletin)
ann_page = nil
pages = Page.where(:module=>'news')
@ -25,6 +26,240 @@ module Admin::NewsHelper
request.protocol+(request.host_with_port+ann_page.url+'/'+news_bulletin.to_param).gsub('//','/') rescue "/"
end
def get_response(uri)
http = Net::HTTP.new(uri.host, uri.port)
if uri.scheme == 'https'
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
timeout = 5
http.open_timeout = timeout #set read_timeout to avoid web die caused by no response
http.ssl_timeout = timeout
http.read_timeout = 1
req = Net::HTTP::Get.new(uri.request_uri)
res = http.request(req)
if res.code == "301" || res.code == "302"
location = res['Location']
cookie = res['Set-Cookie']
headers = {
'Cookie' => cookie,
}
if location[0] == "/"
uri = URI.parse("#{uri.scheme}://#{uri.host}#{location}")
else
uri = URI.parse(location)
end
res = Net::HTTP.get_response(uri,nil,headers)
end
return res
end
def restore_remote_file(uri,save_path)
response = get_response(uri)
uri_params = CGI.parse(response['Content-Disposition']) rescue {}
if save_path[-1] == "/"
filename = ""
if uri_params["filename*"].present?
filename = uri_params["filename*"][0].split("'").last rescue ""
end
if uri_params["filename"].present? && filename.blank?
filename = uri_params["filename"][0].to_s.gsub(/[\'\"]/,'') rescue ""
end
if filename.blank?
filename = response.uri.to_s.split('/').last.split('?').first
end
save_path = save_path + filename
end
if File.exist?(save_path)
File.open(save_path,"w+b"){|f| f.write(response.body)}
else
FileUtils.mkdir_p(File.dirname(save_path))
File.open(save_path,"w+b"){|f| f.write(response.body)}
end
return save_path
end
def localize_data(data)
return InUseLocales.map{|locale| [locale, data] }.to_h
end
def import_this_news(row,categories,tags)
value = {}
anns = NewsBulletin.new
row.cells.each_with_index do |cell,index|
val = cell.nil? ? nil : cell.value rescue nil
case index
when 0
anns.category = categories[val.to_s.strip]
when 1
val = val.to_s
new_tags = []
if (val.include?(",") rescue false)
ts = val.split(",")
ts.each do |t|
new_tags << tags[t.strip]
end
else
new_tags << tags[val.strip]
end
anns.tags=new_tags
when 2
anns.postdate = val
when 3
anns.deadline = val
when 4
anns.is_top = (val.to_i == 1 ? true : false)
when 5
anns.is_hot = (val.to_i == 1 ? true : false)
when 6
anns.is_hidden = (val.to_i == 1 ? true : false)
when 7
anns.remote_image_url = val
when 8
value["en"] = val if val.present?
anns.image_description_translations = value.clone
when 9
value["zh_tw"] = val if val.present?
anns.image_description_translations = value.clone
value = {}
when 10
value["en"] = val if val.present?
anns.title_translations = value.clone
when 11
value["zh_tw"] = val if val.present?
anns.title_translations = value.clone
value = {}
when 12
value["en"] = val if val.present?
anns.subtitle_translations = value.clone
when 13
value["zh_tw"] = val if val.present?
anns.subtitle_translations = value.clone
value = {}
when 14, 15
if index == 14
tmp_locale = 'en'
else
tmp_locale = 'zh_tw'
end
if val.present?
doc = Nokogiri::HTML.fragment(val)
doc.css('[src]').each do |el|
src = el.attributes['src'].value.to_s rescue ""
if src.present?
a = Asset.new
uri = URI.parse(URI.encode(src))
uri_params = CGI::parse(uri.query) rescue {}
if uri.query.present?
filename = uri_params["title"][0] + (File.extname(uri_params["filename"][0])) rescue ""
else
filename = src.split("/").last
end
save_path = "public/" + a.data.store_path + filename
begin
save_path = restore_remote_file(uri,save_path)
rescue
next
end
filename = File.basename(save_path)
a["data"] = URI.decode(filename)
a.title_translations = localize_data(filename)
if (a.save! rescue false)
el.attributes['src'].value = URI.decode(a.data.url)
end
end
end
doc.css('[href]').each do |el|
href = el.attributes['href'].value.to_s rescue ""
if href.present?
a = Asset.new
uri = URI.parse(URI.encode(href))
uri_params = CGI::parse(uri.query) rescue {}
if uri.query.present?
filename = uri_params["title"][0] + (File.extname(uri_params["filename"][0])) rescue ""
else
filename = href.split("/").last
end
save_path = "public/" + a.data.store_path + filename
begin
save_path = restore_remote_file(uri,save_path)
rescue => e
puts [e.to_s, e.backtrace[0..10].to_s]
next
end
filename = File.basename(save_path)
a["data"] = URI.decode(filename)
a.title_translations = localize_data(filename)
if (a.save! rescue false)
el.attributes['href'].value = URI.decode(a.data.url)
end
end
end
value[tmp_locale] = doc.to_s
end
anns.text_translations = value.clone
if index == 15
value = {}
end
when 16
links = val.split(";") rescue []
desc_en = row.cells[17].value.split(";") rescue []
desc_zh_tw = row.cells[18].value.split(";") rescue []
links.each_with_index do |link,i|
bl = NewsBulletinLink.new
bl.url = link.strip
bl.title_translations = {"en" => desc_en[i], "zh_tw" => desc_zh_tw[i]}
bl.news_bulletin_id = anns.id
bl.save
end
when 19
files = val.split(";") rescue []
desc_en = row.cells[20].value.split(";") rescue []
desc_zh_tw = row.cells[21].value.split(";") rescue []
alt_en = row.cells[22].value.split(";") rescue []
alt_zh_tw = row.cells[23].value.split(";") rescue []
files.each_with_index do |file, i|
bf = NewsBulletinFile.new
bf.remote_file_url = file.strip rescue nil
bf.title_translations = {"en" => (alt_en[i] rescue ""), "zh_tw" => (alt_zh_tw[i] rescue "")}
bf.description_translations = {"en" => (desc_en[i] rescue ""), "zh_tw" => (desc_zh_tw[i] rescue "")}
bf.news_bulletin_id = anns.id
bf.save
end
when 24
if val.present?
tmp = val.split("-", 2).map{|v| v.strip}
unit_text = tmp[0]
dept_text = tmp[1]
if unit_text
unit = Unit.where(:name=>/\s*#{unit_text}\s*/).first
if unit.nil?
unit = Unit.create(:name_translations=>localize_data(unit_text))
end
else
unit = nil
end
if unit && dept_text
dept = unit.departments.where(:name=>/\s*#{dept_text}\s*/).first
if dept.nil?
dept = unit.departments.create(:name_translations=>localize_data(dept_text))
end
else
dept = nil
end
anns.unit = unit
anns.department = dept
end
when 25
anns.view_count = (val.to_i rescue 0)
end
end
current_user_id = current_user.id
anns.create_user_id = current_user_id
anns.update_user_id = current_user_id
anns.approved = true
anns.save
end
def send_rejection_email(news)
user = User.find(news.create_user_id) rescue nil

View File

@ -0,0 +1,233 @@
# encoding: utf-8
require 'nokogiri'
wb = xlsx_package.workbook
wb.add_worksheet(name: "News") do |sheet|
heading = sheet.styles.add_style(:b => true, :locked => true)
example = sheet.styles.add_style(:i => true)
row = []
row1 = []
row2 = []
row << t("category")
row1 << "select"
t = ""
categories = @module_app.categories.asc(:created_at)
categories.each_with_index do |cat,i|
t = t + "#{i}" + " -> " + cat.title + ", "
end
if categories.count > 0
t = t + " Example : 0"
else
t = "Leave this field blank"
end
row2 << t
row << t("tags")
row1 << "select"
t = ""
tags = @module_app.tags.asc(:created_at)
tags.each_with_index do |tag,i|
t = t + "#{i}" + " -> " + tag.name + ", "
end
if tags.count > 0
t = t + " Example : 0,1,2"
else
t = "Leave this field blank"
end
row2 << t
row << t("start_date")
row1 << "datetime"
row2 << "Format: YYYY/MM/DD hh:mm, Example: 2015/12/10 00:00"
row << t("end_date")
row1 << "datetime"
row2 << "Format: YYYY/MM/DD hh:mm, Example: 2015/12/12 00:00"
row << t("top")
row1 << "boolean"
row2 << "0 for false, 1 for true"
row << t("hot")
row1 << "boolean"
row2 << "0 for false, 1 for true"
row << t("hide")
row1 << "boolean"
row2 << "0 for false, 1 for true "
row << t("image")
row1 << "url"
row2 << "http://www.example.com/images/example.png"
row << t("image") + " " + t("description") + " - " + t("en")
row1 << "textfield"
row2 << ""
row << t("image") + " " + t("description") + " - " + t("zh_tw")
row1 << "textfield"
row2 << ""
row << t("title") + " - " + t("en")
row1 << "textfield"
row2 << ""
row << t("title") + " - " + t("zh_tw")
row1 << "textfield"
row2 << ""
row << t("subtitle") + " - " + t("en")
row1 << "textarea"
row2 << ""
row << t("subtitle") + " - " + t("zh_tw")
row1 << "textarea"
row2 << ""
row << t("content") + " - " + t("en")
row1 << "editor"
row2 << ""
row << t("content") + " - " + t("zh_tw")
row1 << "editor"
row2 << ""
row << t("link")
row1 << "textfield"
row2 << "Seperate with ';'. Example: http://rulingcom.com; http://google.com"
row << t("link") + " " + t("url_alt") + " - " + t("en")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : Rulingcom official site; Google search engine"
row << t("link") + " " + t("url_alt") + " - " + t("zh_tw")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : Rulingcom official site; Google search engine"
row << t("file_")
row1 << "textfield"
row2 << "Seperate with ';'. Example: http://www.example.com/images/example.png; http://www.example.com/images/example2.png"
row << t("file_") + " " + t("description") + " - " + t("en")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : Great view; Nice potrait"
row << t("file_") + " " + t("description") + " - " + t("zh_tw")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : Great view; Nice potrait"
row << t("file_") + " " + t("alternative") + " - " + t("en")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : example1; example2"
row << t("file_") + " " + t("alternative") + " - " + t("zh_tw")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : example1; example2"
row << t("news.unit")
row1 << "textfield"
row2 << "Unit - Department"
row << t("view_count")
row1 << "integer"
row2 << ""
sheet.add_row row, :style => heading
sheet.add_row row1
sheet.add_row row2, :style => example
if @thread
all_count = @news.count
puts_every_count = [all_count * 3 / 100, 1].max
current_count = 0
finish_percent = 0
@thread.update(:status=>{:status=>'Processing','all_count'=>all_count,'current_count'=>current_count,'finish_percent'=>finish_percent})
end
@news.each do |anns|
row = []
row << categories.to_a.index(anns.category)
t = []
anns.tags.each do |tag|
t << tags.to_a.index(tag)
end
row << t.join(",")
row << (anns.postdate.strftime("%Y/%m/%d %H:%M") rescue "")
row << (anns.deadline.strftime("%Y/%m/%d %H:%M") rescue "")
row << (anns.is_top? ? 1 : 0)
row << (anns.is_hot? ? 1 : 0)
row << (anns.is_hidden? ? 1 : 0)
image_url = anns.image.url rescue ""
row << (image_url.blank? ? "" : (@host + image_url))
row << anns.image_description_translations["en"]
row << anns.image_description_translations["zh_tw"]
row << anns.title_translations["en"]
row << anns.title_translations["zh_tw"]
row << anns.subtitle_translations["en"]
row << anns.subtitle_translations["zh_tw"]
["en", "zh_tw"].each do |l|
text = anns.text_translations[l]
doc = Nokogiri::HTML.fragment(text)
doc.css('[src]').each do |el|
src = el.attributes['src'].value.to_s rescue ""
if src.match(/^\/([^\/]|$)/)
src = @host + src
el.attributes['src'].value = src
end
end
doc.css('[href]').each do |el|
href = el.attributes['href'].value.to_s rescue ""
if href.match(/^\/([^\/]|$)/)
href = @host + href
el.attributes['href'].value = href
end
end
row << doc.to_s
end
links = anns.news_bulletin_links.asc(:created_at)
t = links.collect{|l|l.url}
row << t.join(";")
t = links.collect{|l|l.title_translations["en"]}
row << t.join(";")
t = links.collect{|l|l.title_translations["zh_tw"]}
row << t.join(";")
files = anns.news_bulletin_files.asc(:created_at)
t = files.collect{|f|(@host + f.file.url rescue nil)}
t.delete(nil)
row << t.join(";")
t = files.collect{|l|l.description_translations["en"]}
row << t.join(";")
t = files.collect{|l|l.description_translations["zh_tw"]}
row << t.join(";")
t = files.collect{|l|l.title_translations["en"]}
row << t.join(";")
t = files.collect{|l|l.title_translations["zh_tw"]}
row << t.join(";")
tmp_unit = ""
Unit.where({:id => anns.unit_id}).each do |u|
tmp_unit += u.name
end
Department.where({:id => anns.department_id}).each do |d|
tmp_unit += "-#{d.name}"
end
row << tmp_unit
row << anns.view_count.to_s
sheet.add_row row
if @thread
current_count += 1
if current_count % puts_every_count == 0
finish_percent = (current_count * 100.0 / all_count).round(1)
@thread.update(:status=>{:status=>'Processing','all_count'=>all_count,'current_count'=>current_count,'finish_percent'=>finish_percent})
end
end
end
if @thread
finish_percent = 100
@thread.update(:status=>{:status=>'finish','all_count'=>all_count,'current_count'=>current_count,'finish_percent'=>finish_percent})
end
end

View File

@ -0,0 +1,132 @@
# encoding: utf-8
wb = xlsx_package.workbook
wb.add_worksheet(name: "News") do |sheet|
heading = sheet.styles.add_style(:b => true, :locked => true)
example = sheet.styles.add_style(:i => true)
row = []
row1 = []
row2 = []
row << t("category")
row1 << "select"
t = ""
@module_app.categories.asc(:created_at).each_with_index do |cat,i|
t = t + "#{i}" + " -> " + cat.title + ", "
end
if @module_app.categories.count > 0
t = t + " Example : 0"
else
t = "Leave this field blank"
end
row2 << t
row << t("tags")
row1 << "select"
t = ""
@module_app.tags.asc(:created_at).each_with_index do |tag,i|
t = t + "#{i}" + " -> " + tag.name + ", "
end
if @module_app.tags.count > 0
t = t + " Example : 0,1,2"
else
t = "Leave this field blank"
end
row2 << t
row << t("start_date")
row1 << "datetime"
row2 << "Format: YYYY/MM/DD hh:mm, Example: 2015/12/10 00:00"
row << t("end_date")
row1 << "datetime"
row2 << "Format: YYYY/MM/DD hh:mm, Example: 2015/12/12 00:00"
row << t("top")
row1 << "boolean"
row2 << "0 for false, 1 for true"
row << t("hot")
row1 << "boolean"
row2 << "0 for false, 1 for true"
row << t("hide")
row1 << "boolean"
row2 << "0 for false, 1 for true "
row << t("image")
row1 << "url"
row2 << "http://www.example.com/images/example.png"
row << t("image") + " " + t("description") + " - " + t("en")
row1 << "textfield"
row2 << ""
row << t("image") + " " + t("description") + " - " + t("zh_tw")
row1 << "textfield"
row2 << ""
row << t("title") + " - " + t("en")
row1 << "textfield"
row2 << ""
row << t("title") + " - " + t("zh_tw")
row1 << "textfield"
row2 << ""
row << t("subtitle") + " - " + t("en")
row1 << "textarea"
row2 << ""
row << t("subtitle") + " - " + t("zh_tw")
row1 << "textarea"
row2 << ""
row << t("content") + " - " + t("en")
row1 << "editor"
row2 << ""
row << t("content") + " - " + t("zh_tw")
row1 << "editor"
row2 << ""
row << t("link")
row1 << "textfield"
row2 << "Seperate with ';'. Example: http://rulingcom.com; http://google.com"
row << t("link") + " " + t("url_alt") + " - " + t("en")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : Rulingcom official site; Google search engine"
row << t("link") + " " + t("url_alt") + " - " + t("zh_tw")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : Rulingcom official site; Google search engine"
row << t("file_")
row1 << "textfield"
row2 << "Seperate with ';'. Example: http://www.example.com/images/example.png; http://www.example.com/images/example2.png"
row << t("file_") + " " + t("description") + " - " + t("en")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : Great view; Nice potrait"
row << t("file_") + " " + t("description") + " - " + t("zh_tw")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : Great view; Nice potrait"
row << t("file_") + " " + t("alternative") + " - " + t("en")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : example1; example2"
row << t("file_") + " " + t("alternative") + " - " + t("zh_tw")
row1 << "textfield"
row2 << "Seperate with ';' with respective to the links in the link columns. Example : example1; example2"
row << t("news.unit")
row1 << "textfield"
row2 << "Unit - Department"
row << t("view_count")
row1 << "integer"
row2 << ""
sheet.add_row row, :style => heading
sheet.add_row row1
sheet.add_row row2, :style => example
end

View File

@ -0,0 +1,127 @@
<% content_for :page_specific_javascript do %>
<script type="text/javascript" src="/assets/validator.js"></script>
<% end %>
<% 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 class="thread-count-zone <%= 'hide' unless @thread.status[:current_count]%>">
<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
<br>
<span class="thread-info"><%= @thread.status[:info].to_s.html_safe %></span>
<br>
<span class="thread-file">
<% if @thread.status[:filename] %>
<a href="<%=admin_news_download_file_from_thread_path(:id=>@thread.id.to_s) %>" title="<%= @thread.status[:filename] %>"><%= @thread.status[:filename] %></a>
<% end %>
</span>
</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 %>
<form action="<%= admin_news_importnews_path %>" method="post" class="form-horizontal main-forms" id="import-news-xls" enctype="multipart/form-data">
<h3 style="padding-left: 30px;"><%= t("news.export_to_excel") %></h3>
<div class="control-group">
<div class="controls">
<a href="<%= admin_news_export_excel_path %>"><%= t("news.export_all_news") %></a>
</div>
</div>
<h3 style="padding-left: 30px;"><%= t("news.import_from_excel") %></h3>
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
<div class="input-area">
<div class="control-group">
<div class="controls">
<a href="<%= admin_news_excel_format_path(:format => "xlsx") %>"><%= t("news.download_example_sheet_here") %></a>
</div>
</div>
<div class="control-group">
<label for="import-news" class="control-label muted"><%= t("upload") %></label>
<div class="controls">
<input type="file" id="import-news" name="import_file" data-fv-validation="required;mustbexls;" data-fv-messages="Cannot be empty; Must be an excel file.;" />
</div>
</div>
</div>
<div class="form-actions">
<input type="submit" value="<%= t("restful_actions.import") %>" class="btn btn-primary">
</div>
</form>
<script type="text/javascript">
var form = new FormValidator($("#import-news-xls"));
form.validate_functions.mustbexls = function(val){
var t = val.split("."),
ext = t[t.length - 1];
return (ext == "xls" || ext == "xlsx")
}
var form = new FormValidator($("#import-news-wp-xml"));
form.validate_functions.mustbexml = function(val){
var t = val.split("."),
ext = t[t.length - 1];
return (ext == "xml")
}
$(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" && data["filename"]) || data["status"] == "error");
var info = data["info"]
if(finish_percent){
$("#threadModal .modal-body .thread-status").text(data["status"]);
if(data["current_count"]){
$("#threadModal .modal-body .thread-count-zone").removeClass('hide');
$("#threadModal .modal-body .thread-current-count").text(current_count);
$("#threadModal .modal-body .thread-all-count").text(all_count);
}else{
$("#threadModal .modal-body .thread-count-zone").addClass('hide');
}
$("#threadModal .modal-body .thread-finish_percent").text(finish_percent);
if(info){
$("#threadModal .modal-body .thread-info").text(info);
}
}
if(!is_finish){
window.time_out_id = window.setTimeout(update_thread, 1000);
}else{
var id = "<%=@thread.id if @thread%>";
var filename = data["filename"];
if(filename){
$("#threadModal .modal-body .thread-file").html(`<a href="<%=admin_news_download_file_from_thread_path%>?id=${id}" title="${filename}">${filename}</a>`);
}
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);
window.history.replaceState(null,$('title').text(),window.location.pathname);
})
$("#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

@ -22,6 +22,13 @@ en:
ut_prompt: Please choose department
news:
cover_image_not_yet_upload: The cover image has not been uploaded yet.
import_export: Import / Export
import: Import
export_news: Export News
export_to_excel: Export to Excel
export_all_news: Export all News
import_from_excel: Import from Excel
download_example_sheet_here: Download example sheet here
admins: Unit Setting
unit: Department
category: Category

View File

@ -22,6 +22,13 @@ zh_tw:
ut_prompt: 請選擇單位
news:
cover_image_not_yet_upload: 您還沒有上傳封面圖片
import_export: 匯入 / 匯出
import: 匯入
export_news: 匯出新聞
export_to_excel: 匯出至Excel檔
export_all_news: 匯出所有新聞
import_from_excel: 從Excel檔匯入
download_example_sheet_here: 在此下載範例
unit: 單位
category: 分類
department: 系所

View File

@ -10,6 +10,11 @@ Rails.application.routes.draw do
get 'newsbulletins.json', to: 'newsbulletins#get_bulletins'
post 'news/approve_news_bulletin', to: 'news#approve_news_bulletin'
get 'news_admins/get_departments' => "news_admins#get_departments"
get 'news/import_export', to: 'news#import_export'
get 'news/download_file_from_thread', to: 'news#download_file_from_thread'
post 'news/importnews', to: 'news#importnews'
get 'news/excel_format', to: 'news#excel_format'
get 'news/export_excel', to: 'news#export_excel'
resources :news
resources :news_admins
end

View File

@ -44,6 +44,11 @@ module News
:active_for_action=>{'admin/news'=>'tags'},
:active_for_tag => 'News',
:available_for => 'managers'
context_link 'news.import_export',
:link_path=>"admin_news_import_export_path" ,
:priority=>5,
:active_for_action=>{'admin/news'=>'import_export'},
:available_for => 'managers'
context_link 'news.admins',
:link_path=>"admin_news_admins_path" ,
:priority=>6,