|
- #coding=utf-8
-
- require "base64"
- require 'zip'
-
- class ZipdownController < ApplicationController
- #查找项目(课程)
- before_filter :find_project_by_bid_id, :only => [:assort]
- #检查权限
- #勿删 before_filter :authorize, :only => [:assort,:download_user_homework]
- SAVE_FOLDER = "#{Rails.root}/files"
- OUTPUT_FOLDER = "#{Rails.root}/files/archiveZip"
- MAX_PATH = 50
-
- #统一下载功能
- def download
- if User.current.logged?
- begin
- if params[:base64file]
- file = decode64(params[:base64file])
- send_file "#{OUTPUT_FOLDER}/#{file}", :filename => filename_for_content_disposition(file), :type => detect_content_type(file)
- else
- send_file "#{OUTPUT_FOLDER}/#{params[:file]}", :filename => filename_for_content_disposition(params[:filename]), :type => detect_content_type(params[:file])
- end
- rescue => e
- render file: 'public/no_file_found.html'
- end
- else
- render_403
- end
- end
-
- #一个作业下所有文件打包下载,只有admin和课程老师有权限
- def assort
- if params[:obj_class] == "Bid"
- bid = Bid.find params[:obj_id]
- render_403 if User.current.allowed_to?(:as_teacher,bid.courses.first)
- file_count = 0
- bid.homeworks.map { |homework| file_count += homework.attachments.count}
- if file_count > 0
- zipfile = zip_bid bid
- else
- zipfile = {:message => "no file"}
- end
- elsif params[:obj_class] == "HomeworkCommon"
- homework = HomeworkCommon.find params[:obj_id]
- render_403 if User.current.allowed_to?(:as_teacher,homework.course)
- file_count = 0
- homework.student_works.map { |work| file_count += work.attachments.count}
- if file_count > 0
- zipfile = zip_homework_common homework
- else
- zipfile = {:message => "no file"}
- end
- else
- logger.error "[ZipDown#assort] ===> #{params[:obj_class]} unKown !!"
- end
- respond_to do |format|
- format.json {
- render json: zipfile.to_json
- }
- end
- end
-
- #下载某一学生的作业的所有文件
- def download_user_homework
- homework = HomeworkAttach.find params[:homework]
- if User.current.admin? || User.current.member_of_course?(homework.bid.courses.first)
- if homework != nil
- unless homework.attachments.empty?
- zipfile = zip_homework_by_user homework
- filename = ((homework.user.user_extensions.nil? || homework.user.user_extensions.student_id.nil?) ? "" : homework.user.user_extensions.student_id) +
- "_" + homework.user.show_name +
- "_" + homework.name + ".zip"
- send_file zipfile.file_path, :filename => filename_for_content_disposition(filename), :type => detect_content_type(zipfile.file_path) if(zipfile)
- else
- render file: 'public/no_file_found.html'
- end
- else
- render file: 'public/file_not_found.html'
- end
- else
- render_403
- end
- #rescue => e
- # render file: 'public/file_not_found.html'
- end
-
- private
-
- #通过作业Id找到项目(课程)
- def find_project_by_bid_id
- obj_class = params[:obj_class]
- obj_id = params[:obj_id]
- obj = obj_class.constantize.find(obj_id)
- case obj.class.to_s.to_sym
- when :Bid
- @project = obj.courses[0]
- end
- end
-
- 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_homework_common homework_common
- bid_homework_path = []
- digests = []
- homework_common.student_works.each do |work|
- unless work.attachments.empty?
- out_file = zip_student_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)
- "#{work.user.show_name}_#{((work.user.user_extensions.nil? || work.user.user_extensions.student_id.nil?) ? "" : work.user.user_extensions.student_id)}_#{Time.now.to_i.to_s}"
- end
-
- def zip_student_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.homework_common_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.homework_common_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
|