You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
374 lines
14 KiB
374 lines
14 KiB
#coding=utf-8
|
|
require "base64"
|
|
require 'zip'
|
|
|
|
if RUBY_PLATFORM =~ /linux|darwin/
|
|
require 'pdfkit'
|
|
end
|
|
|
|
module ZipService
|
|
|
|
SAVE_FOLDER = "#{Rails.root}/files"
|
|
OUTPUT_FOLDER = "#{Rails.root}/files/archiveZip"
|
|
SHIXUN_FOLDER = "#{Rails.root}/shixunfiles"
|
|
MAX_PATH = 50
|
|
|
|
def zip_bid(bid)
|
|
# Todo: User Access Controll
|
|
bid_homework_path = []
|
|
digests = []
|
|
bid.homeworks.each do |homeattach|
|
|
unless homeattach.attachments.empty?
|
|
out_file = zip_homework_by_user(homeattach)
|
|
bid_homework_path << out_file.file_path
|
|
digests << out_file.file_digest
|
|
end
|
|
end
|
|
homework_id = bid.id
|
|
user_id = bid.author_id
|
|
out_file = find_or_pack(homework_id, user_id, digests.sort){
|
|
zipping("#{Time.now.to_i}_#{bid.name}.zip",
|
|
bid_homework_path, OUTPUT_FOLDER)
|
|
}
|
|
[{files:[out_file.file_path], count: 1, index: 1,
|
|
real_file: out_file.file_path,
|
|
file: File.basename(out_file.file_path),
|
|
base64file: encode64(File.basename(out_file.file_path)),
|
|
size:(out_file.pack_size / 1024.0 / 1024.0).round(2)
|
|
}]
|
|
end
|
|
|
|
def encode64(str)
|
|
Base64.urlsafe_encode64(str)
|
|
end
|
|
|
|
def decode64(str)
|
|
Base64.urlsafe_decode64(str)
|
|
end
|
|
|
|
def zip_user_exercise exercise, exercise_users
|
|
bid_homework_path = []
|
|
digests = []
|
|
members = exercise.course.members
|
|
exercise_users.each do |exercise_user|
|
|
member = members.where(:user_id => exercise_user.user_id).first
|
|
group_name = member.try(:course_group_id).to_i == 0 ? '未分班' : member.course_group.name
|
|
export_file_name = "#{group_name}-#{exercise.course_id}-#{exercise.exercise_name}-#{exercise_user.user.user_extensions.student_id}-#{exercise_user.user.show_real_name}" + ".pdf"
|
|
out_file = export_user_exercise(exercise, exercise_user, export_file_name)
|
|
file_name = File::expand_path(out_file)
|
|
|
|
bid_homework_path << file_name
|
|
digests << Trustie::Utils.digest(file_name)
|
|
end
|
|
# file_name = "#{Time.now.strftime("%Y%m%d%H:%M:%S").to_s}-#{exercise.course_id}-#{exercise.exercise_name}-#{exercise_user.user.user_extensions.student_id}-#{exercise_user.user.show_name}" + ".pdf"
|
|
out_file = find_or_pack(exercise.id, exercise.user_id, digests.sort){
|
|
zipping("#{Time.now.strftime("%Y%m%d%H%M%S").to_s}-#{exercise.course_id}-#{exercise.exercise_name}.zip",
|
|
bid_homework_path, OUTPUT_FOLDER)
|
|
}
|
|
[{files:[out_file.file_path], count: 1, index: 1,
|
|
real_file: out_file.file_path,
|
|
file: File.basename(out_file.file_path),
|
|
base64file: encode64(File.basename(out_file.file_path)),
|
|
size:(out_file.pack_size / 1024.0 / 1024.0).round(2)
|
|
}]
|
|
end
|
|
|
|
def zip_shixun_work homework_common, student_works
|
|
bid_homework_path = []
|
|
digests = []
|
|
members = homework_common.course.members
|
|
student_works.each do |work|
|
|
unless work.work_status == 0
|
|
member = members.where(:user_id => work.user_id).first
|
|
group_id = member.try(:course_group_id).to_i == 0 ? '未分班' : member.course_group.name
|
|
export_file_name = "#{group_id}-#{homework_common.course_id}-#{homework_common.name}-#{work.user.user_extensions.student_id}-#{work.user.show_real_name}" + ".pdf"
|
|
out_file = export_user_shixun_work(homework_common, work, export_file_name)
|
|
file_name = File::expand_path(out_file)
|
|
|
|
bid_homework_path << file_name
|
|
digests << Trustie::Utils.digest(file_name)
|
|
end
|
|
end
|
|
out_file = find_or_pack(homework_common.id, homework_common.user_id, digests.sort){
|
|
zipping("#{Time.now.strftime("%Y%m%d%H%M%S").to_s}-#{homework_common.course_id}-#{homework_common.name}.zip",
|
|
bid_homework_path, OUTPUT_FOLDER)
|
|
}
|
|
[{files:[out_file.file_path], count: 1, index: 1,
|
|
real_file: out_file.file_path,
|
|
file: File.basename(out_file.file_path),
|
|
base64file: encode64(File.basename(out_file.file_path)),
|
|
size:(out_file.pack_size / 1024.0 / 1024.0).round(2)
|
|
}]
|
|
end
|
|
|
|
def zip_homework_common homework_common, student_works
|
|
bid_homework_path = []
|
|
digests = []
|
|
student_works.each do |work|
|
|
unless work.attachments.empty?
|
|
out_file = zip_student_work_by_user(work, homework_common.id)
|
|
|
|
bid_homework_path << out_file.file_path
|
|
digests << out_file.file_digest
|
|
|
|
|
|
end
|
|
end
|
|
homework_id = homework_common.id
|
|
user_id = homework_common.user_id
|
|
out_file = find_or_pack(homework_id, user_id, digests.sort){
|
|
zipping("#{Time.now.to_i}_#{homework_common.name}.zip",
|
|
bid_homework_path, OUTPUT_FOLDER)
|
|
}
|
|
[{files:[out_file.file_path], count: 1, index: 1,
|
|
real_file: out_file.file_path,
|
|
file: File.basename(out_file.file_path),
|
|
base64file: encode64(File.basename(out_file.file_path)),
|
|
size:(out_file.pack_size / 1024.0 / 1024.0).round(2)
|
|
}]
|
|
end
|
|
|
|
def zip_contest_work homework_common
|
|
bid_homework_path = []
|
|
digests = []
|
|
homework_common.contestant_works.each do |work|
|
|
unless work.attachments.empty?
|
|
out_file = zip_contestant_work_by_user(work)
|
|
|
|
bid_homework_path << out_file.file_path
|
|
digests << out_file.file_digest
|
|
|
|
|
|
end
|
|
end
|
|
homework_id = homework_common.id
|
|
user_id = homework_common.user_id
|
|
out_file = find_or_pack(homework_id, user_id, digests.sort){
|
|
zipping("#{Time.now.to_i}_#{homework_common.name}.zip",
|
|
bid_homework_path, OUTPUT_FOLDER)
|
|
}
|
|
[{files:[out_file.file_path], count: 1, index: 1,
|
|
real_file: out_file.file_path,
|
|
file: File.basename(out_file.file_path),
|
|
base64file: encode64(File.basename(out_file.file_path)),
|
|
size:(out_file.pack_size / 1024.0 / 1024.0).round(2)
|
|
}]
|
|
end
|
|
|
|
def zip_homework_by_user(homework_attach)
|
|
homeworks_attach_path = []
|
|
not_exist_file = []
|
|
# 需要将所有homework.attachments遍历加入zip
|
|
digests = []
|
|
homework_attach.attachments.each do |attach|
|
|
if File.exist?(attach.diskfile)
|
|
homeworks_attach_path << attach.diskfile
|
|
digests << attach.digest
|
|
else
|
|
not_exist_file << attach.filename
|
|
digests << 'not_exist_file'
|
|
end
|
|
end
|
|
out_file = find_or_pack(homework_attach.bid_id, homework_attach.user_id, digests.sort){
|
|
zipping("#{homework_attach.user.show_name}_#{((homework_attach.user.user_extensions.nil? || homework_attach.user.user_extensions.student_id.nil?) ? "" : homework_attach.user.user_extensions.student_id)}_#{Time.now.to_i.to_s}.zip",
|
|
homeworks_attach_path, OUTPUT_FOLDER, true, not_exist_file)
|
|
}
|
|
end
|
|
|
|
def make_zip_name(work, file_name="")
|
|
Rails.logger.info("######################file_name: #{file_name}")
|
|
name = file_name === "" ? "" : (file_name[0, file_name.rindex('.')]+"_")
|
|
"#{name}#{work.user.show_real_name}_#{((work.user.user_extensions.nil? || work.user.user_extensions.student_id.nil?) ? "" : work.user.user_extensions.student_id)}"
|
|
end
|
|
|
|
def export_user_exercise exercise, exercise_user, file_name
|
|
url = Setting.protocol + "://" + Setting.host_name + "/exercise/" + exercise.id.to_s + "/show_student_result?user_id=#{exercise_user.user_id}&pdf=1"
|
|
kit = PDFKit.new(url, :page_size => "A4")
|
|
# kit.to_pdf # inline PDF
|
|
# file_name = "#{exercise.course_id}-#{exercise.exercise_name}-#{exercise_user.user.user_extensions.student_id}-#{exercise_user.user.show_real_name}" + ".pdf"
|
|
# file_name = "#{Time.now.strftime("%Y%m%d%H%M%S").to_s}-#{exercise.course_id}-#{exercise.id}-#{exercise_user.user.user_extensions.student_id}" + ".pdf"
|
|
file_name.gsub!(" ", "-")
|
|
file_name.gsub!("/", "_")
|
|
kit.to_file("#{OUTPUT_FOLDER}/#{file_name}")
|
|
out_file = "#{OUTPUT_FOLDER}/#{file_name}"
|
|
out_file
|
|
end
|
|
|
|
def export_user_shixun_work homework, student_work, file_name
|
|
url = Setting.protocol + "://" + Setting.host_name + "/student_work/" + student_work.id.to_s + "/shixun_work_report?pdf=1"
|
|
kit = PDFKit.new(url, :page_size => "A4")
|
|
# kit.to_pdf # inline PDF
|
|
# file_name = "#{homework.course_id}-#{homework.name}-#{student_work.user.user_extensions.student_id}-#{student_work.user.show_real_name}" + ".pdf"
|
|
# file_name = "#{Time.now.strftime("%Y%m%d%H%M%S").to_s}-#{homework.course_id}-#{homework.id}-#{student_work.user.user_extensions.student_id}" + ".pdf"
|
|
file_name.gsub!(" ", "-")
|
|
file_name.gsub!("/", "_")
|
|
kit.to_file("#{OUTPUT_FOLDER}/#{file_name}")
|
|
out_file = "#{OUTPUT_FOLDER}/#{file_name}"
|
|
out_file
|
|
end
|
|
|
|
|
|
def zip_student_work_by_user(work, object_id)
|
|
homeworks_attach_path = []
|
|
not_exist_file = []
|
|
filename = []
|
|
# 需要将所有homework.attachments遍历加入zip
|
|
digests = []
|
|
work.attachments.each do |attach|
|
|
if File.exist?(attach.diskfile)
|
|
homeworks_attach_path << attach.diskfile
|
|
digests << attach.digest
|
|
filename << attach.filename
|
|
else
|
|
not_exist_file << attach.filename
|
|
digests << 'not_exist_file'
|
|
filename << attach.filename
|
|
end
|
|
end
|
|
|
|
#单个文件的话,不需要压缩,只改名
|
|
out_file = nil
|
|
if homeworks_attach_path.size == 1
|
|
out_file = find_or_pack(object_id, work.user_id, digests.sort){
|
|
des_path = "#{OUTPUT_FOLDER}/#{make_zip_name(work, filename.first)}_#{File.basename(homeworks_attach_path.first)}"
|
|
FileUtils.cp homeworks_attach_path.first, des_path
|
|
des_path
|
|
}
|
|
else
|
|
out_file = find_or_pack(object_id, work.user_id, digests.sort){
|
|
zipping("#{make_zip_name(work)}.zip",
|
|
homeworks_attach_path, OUTPUT_FOLDER, true, not_exist_file)
|
|
}
|
|
end
|
|
out_file
|
|
|
|
end
|
|
|
|
def zip_contestant_work_by_user(work)
|
|
homeworks_attach_path = []
|
|
not_exist_file = []
|
|
# 需要将所有homework.attachments遍历加入zip
|
|
digests = []
|
|
work.attachments.each do |attach|
|
|
if File.exist?(attach.diskfile)
|
|
homeworks_attach_path << attach.diskfile
|
|
digests << attach.digest
|
|
else
|
|
not_exist_file << attach.filename
|
|
digests << 'not_exist_file'
|
|
end
|
|
end
|
|
|
|
#单个文件的话,不需要压缩,只改名
|
|
out_file = nil
|
|
if homeworks_attach_path.size == 1
|
|
out_file = find_or_pack(work.work_id, work.user_id, digests.sort){
|
|
des_path = "#{OUTPUT_FOLDER}/#{make_zip_name(work)}_#{File.basename(homeworks_attach_path.first)}"
|
|
FileUtils.cp homeworks_attach_path.first, des_path
|
|
des_path
|
|
}
|
|
else
|
|
out_file = find_or_pack(work.work_id, work.user_id, digests.sort){
|
|
zipping("#{make_zip_name(work)}.zip",
|
|
homeworks_attach_path, OUTPUT_FOLDER, true, not_exist_file)
|
|
}
|
|
end
|
|
out_file
|
|
|
|
end
|
|
|
|
|
|
def find_or_pack(homework_id, user_id, digests)
|
|
raise "please given a pack block" unless block_given?
|
|
|
|
out_file = ZipPack.packed?(homework_id, user_id, digests.sort)
|
|
|
|
unless out_file && out_file.file_valid?
|
|
file = yield
|
|
|
|
ZipPack.where(homework_id: homework_id,
|
|
user_id: user_id).delete_all
|
|
|
|
out_file = ZipPack.create(homework_id: homework_id,
|
|
user_id: user_id,
|
|
file_digest: Trustie::Utils.digest(file),
|
|
file_path: file,
|
|
pack_size: File.size(file),
|
|
file_digests: digests.join(',')
|
|
)
|
|
else
|
|
out_file.pack_times = out_file.pack_times + 1
|
|
out_file.save
|
|
end
|
|
|
|
out_file
|
|
end
|
|
|
|
|
|
def zipping(zip_name_refer, files_paths, output_path, is_attachment=false, not_exist_file=[])
|
|
rename_zipfile = zip_name_refer ||= "#{Time.now.to_i.to_s}.zip"
|
|
# 文件名过长
|
|
|
|
if rename_zipfile.size > MAX_PATH
|
|
rename_zipfile = rename_zipfile[0,rename_zipfile.size-4][0,MAX_PATH-4] + rename_zipfile[-4,4]
|
|
end
|
|
|
|
zipfile_name = "#{output_path}/#{rename_zipfile}"
|
|
|
|
Dir.mkdir(File.dirname(zipfile_name)) unless File.exist?(File.dirname(zipfile_name))
|
|
Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
|
|
files_paths.each do |filename|
|
|
rename_file = File.basename(filename)
|
|
rename_file = filename_to_real( File.basename(filename)) if is_attachment
|
|
|
|
begin
|
|
zipfile.add(rename_file, filename)
|
|
rescue Exception => e
|
|
zipfile.get_output_stream('FILE_NOTICE.txt'){|os| os.write l(:label_file_exist)}
|
|
next
|
|
end
|
|
end
|
|
unless not_exist_file.empty?
|
|
zipfile.get_output_stream('FILE_LOST.txt'){|os| os.write l(:label_file_lost) + not_exist_file.join(',').to_s}
|
|
end
|
|
end
|
|
zipfile_name
|
|
end
|
|
|
|
# 合理分配文件打包
|
|
# 如果小于 pack_attachment_max_size, 则返回单个文件
|
|
# 反之则切分为多个文件组返回
|
|
def split_pack_files(files, pack_attachment_max_size)
|
|
max_size = 0
|
|
last_files = []
|
|
ret_files = []
|
|
files.each_with_index do |f,i|
|
|
if (max_size += File.size(f)) > pack_attachment_max_size
|
|
max_size = 0
|
|
if last_files.empty? #如果单个文件超过大小,也将此文件作为一组
|
|
ret_files << {files: [f], count: 1, index: ret_files.count+1}
|
|
last_files.clear
|
|
else
|
|
ret_files << {files:last_files, count: last_files.count, index: ret_files.count+1}
|
|
last_files.clear
|
|
redo
|
|
end
|
|
else
|
|
last_files << f
|
|
end
|
|
end
|
|
|
|
ret_files << {files:last_files, count: last_files.count, index: ret_files.count+1} unless last_files.empty?
|
|
ret_files
|
|
end
|
|
|
|
def detect_content_type(name)
|
|
content_type = Redmine::MimeType.of(name)
|
|
content_type.to_s
|
|
end
|
|
|
|
def filename_to_real(name)
|
|
attach = Attachment.find_by_disk_filename(name)
|
|
attach.filename
|
|
end
|
|
end |