From ad003ea4657959553f2c7b6901649d193c11f7c6 Mon Sep 17 00:00:00 2001 From: BoHung Chiu Date: Sun, 24 Sep 2023 15:20:39 +0800 Subject: [PATCH] Add import and export feature. --- app/controllers/admin/news_controller.rb | 135 ++++++++++ app/helpers/admin/news_helper.rb | 235 ++++++++++++++++++ app/views/admin/news/_export_excel.xlsx.axlsx | 233 +++++++++++++++++ app/views/admin/news/excel_format.xlsx.axlsx | 132 ++++++++++ app/views/admin/news/import_export.html.erb | 127 ++++++++++ config/locales/en.yml | 7 + config/locales/zh_tw.yml | 7 + config/routes.rb | 5 + lib/news/engine.rb | 5 + 9 files changed, 886 insertions(+) create mode 100644 app/views/admin/news/_export_excel.xlsx.axlsx create mode 100644 app/views/admin/news/excel_format.xlsx.axlsx create mode 100644 app/views/admin/news/import_export.html.erb diff --git a/app/controllers/admin/news_controller.rb b/app/controllers/admin/news_controller.rb index 32e8d35..46f2da6 100644 --- a/app/controllers/admin/news_controller.rb +++ b/app/controllers/admin/news_controller.rb @@ -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 diff --git a/app/helpers/admin/news_helper.rb b/app/helpers/admin/news_helper.rb index 1460b5c..67e777f 100644 --- a/app/helpers/admin/news_helper.rb +++ b/app/helpers/admin/news_helper.rb @@ -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 diff --git a/app/views/admin/news/_export_excel.xlsx.axlsx b/app/views/admin/news/_export_excel.xlsx.axlsx new file mode 100644 index 0000000..381ed5b --- /dev/null +++ b/app/views/admin/news/_export_excel.xlsx.axlsx @@ -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 \ No newline at end of file diff --git a/app/views/admin/news/excel_format.xlsx.axlsx b/app/views/admin/news/excel_format.xlsx.axlsx new file mode 100644 index 0000000..2c89cfa --- /dev/null +++ b/app/views/admin/news/excel_format.xlsx.axlsx @@ -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 \ No newline at end of file diff --git a/app/views/admin/news/import_export.html.erb b/app/views/admin/news/import_export.html.erb new file mode 100644 index 0000000..7efb664 --- /dev/null +++ b/app/views/admin/news/import_export.html.erb @@ -0,0 +1,127 @@ +<% content_for :page_specific_javascript do %> + +<% end %> +<% if @thread %> + +<% end %> +
+

<%= t("news.export_to_excel") %>

+ +

<%= t("news.import_from_excel") %>

+ <%= hidden_field_tag :authenticity_token, form_authenticity_token %> +
+ +
+ +
+ +
+
+
+
+ " class="btn btn-primary"> +
+
+ + \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 116034b..63aa8db 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -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 diff --git a/config/locales/zh_tw.yml b/config/locales/zh_tw.yml index d8f82b2..266f37f 100644 --- a/config/locales/zh_tw.yml +++ b/config/locales/zh_tw.yml @@ -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: 系所 diff --git a/config/routes.rb b/config/routes.rb index bc3da5f..dd1704f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 diff --git a/lib/news/engine.rb b/lib/news/engine.rb index 6acb28f..0af7e71 100644 --- a/lib/news/engine.rb +++ b/lib/news/engine.rb @@ -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,