diff --git a/Gemfile b/Gemfile index 045642faf..98d81ca70 100644 --- a/Gemfile +++ b/Gemfile @@ -4,10 +4,9 @@ source 'http://ruby.taobao.org' unless RUBY_PLATFORM =~ /w32/ # unix-like only gem 'iconv' - gem 'rubyzip' - gem 'zip-zip' end +gem 'zipruby', '~> 0.3.6' #performance gem 'delayed_job_active_record'#, :group => :production gem 'daemons' gem 'grape', '~> 0.9.0' diff --git a/app/controllers/zipdown_controller.rb b/app/controllers/zipdown_controller.rb index 9880a6382..80e7c1c06 100644 --- a/app/controllers/zipdown_controller.rb +++ b/app/controllers/zipdown_controller.rb @@ -1,4 +1,3 @@ -require 'zip' class ZipdownController < ApplicationController #查找项目(课程) before_filter :find_project_by_bid_id, :only => [:assort] @@ -56,9 +55,9 @@ class ZipdownController < ApplicationController if homework != nil unless homework.attachments.empty? zipfile = zip_homework_by_user homework - send_file zipfile, :filename => ((homework.user.user_extensions.nil? || homework.user.user_extensions.student_id.nil?) ? "" : homework.user.user_extensions.student_id) + + send_file zipfile.file_path, :filename => ((homework.user.user_extensions.nil? || homework.user.user_extensions.student_id.nil?) ? "" : homework.user.user_extensions.student_id) + "_" + (homework.user.lastname.nil? ? "" : homework.user.lastname) + (homework.user.firstname.nil? ? "" : homework.user.firstname) + - "_" + homework.name + ".zip", :type => detect_content_type(zipfile) if(zipfile) + "_" + homework.name + ".zip", :type => detect_content_type(zipfile.file_path) if(zipfile) else render file: 'public/no_file_found.html' end @@ -88,85 +87,120 @@ class ZipdownController < ApplicationController def zip_bid(bid) # Todo: User Access Controll bid_homework_path = [] + digests = [] bid.homeworks.each do |homeattach| unless homeattach.attachments.empty? - bid_homework_path << zip_homework_by_user(homeattach) + out_file = zip_homework_by_user(homeattach) + bid_homework_path << out_file.file_path + digests << out_file.file_digest end end - zips = split_pack_files(bid_homework_path, Setting.pack_attachment_max_size.to_i*1024) - x = 0 + homework_id = bid.id + user_id = bid.author_id - zips.each { |o| - x += 1 - file = zipping "#{Time.now.to_i}_#{bid.name}_#{x}.zip", o[:files], OUTPUT_FOLDER - o[:real_file] = file - o[:file] = File.basename(file) - o[:size] = (File.size(file) / 1024.0 / 1024.0).round(2) + out_file = find_or_pack(homework_id, user_id, digests.sort){ + zipping("#{Time.now.to_i}_#{bid.name}.zip", + bid_homework_path, OUTPUT_FOLDER) } + + # zips = split_pack_files(bid_homework_path, Setting.pack_attachment_max_size.to_i*1024) + # x = 0 + # + # + # zips.each { |o| + # x += 1 + # file = zipping "#{Time.now.to_i}_#{bid.name}_#{x}.zip", o[:files], OUTPUT_FOLDER + # o[:real_file] = file + # o[:file] = File.basename(file) + # o[:size] = (File.size(file) / 1024.0 / 1024.0).round(2) + # } + + [{files:[out_file.file_path], count: 1, index: 1, + real_file: out_file.file_path, file: File.basename(out_file.file_path), + size:(out_file.pack_size / 1024.0 / 1024.0).round(2) + }] end - def zip_homework_by_user(homeattach) + def zip_homework_by_user(homework_attach) homeworks_attach_path = [] not_exist_file = [] # 需要将所有homework.attachments遍历加入zip - # 并且返回zip路径 - homeattach.attachments.each do |attach| + + + 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 - zipping("#{homeattach.user.lastname}#{homeattach.user.firstname}_#{((homeattach.user.user_extensions.nil? || homeattach.user.user_extensions.student_id.nil?) ? "" : homeattach.user.user_extensions.student_id)}_#{Time.now.to_i.to_s}.zip", homeworks_attach_path, OUTPUT_FOLDER, true, not_exist_file) + + out_file = find_or_pack(homework_attach.bid_id, homework_attach.user_id, digests.sort){ + zipping("#{homework_attach.user.lastname}#{homework_attach.user.firstname}_#{((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 zipping(zip_name_refer, files_paths, output_path, is_attachment=false, not_exist_file=[]) - # 输入待打包的文件列表,已经打包文件定位到ouput_path - ic = Iconv.new('GBK//IGNORE', 'UTF-8//IGNORE') + def find_or_pack(homework_id, user_id, digests) + raise "please given a pack block" unless block_given? - rename_zipfile = zip_name_refer ||= "#{Time.now.to_i.to_s}.zip" - zipfile_name = "#{output_path}/#{rename_zipfile}" + out_file = ZipPack.packed?(homework_id, user_id, digests.sort) - Dir.mkdir(File.dirname(zipfile_name)) unless File.exist?(File.dirname(zipfile_name)) + unless out_file && out_file.file_valid? + file = yield - unless is_attachment - #都是zip合并,没必要再费力压缩了 - Zip.default_compression = Zlib::NO_COMPRESSION + 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 - Zip.default_compression = Zlib::DEFAULT_COMPRESSION + out_file.pack_times = out_file.pack_times + 1 + out_file.save end - Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile| + 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" + zipfile_name = "#{output_path}/#{rename_zipfile}" + + Dir.mkdir(File.dirname(zipfile_name)) unless File.exist?(File.dirname(zipfile_name)) + Zip::Archive.open(zipfile_name, Zip::CREATE) do |zipfile| files_paths.each do |filename| flag = true index = 1 - rename_file = ic.iconv( (File.basename(filename)) ).to_s - rename_file = ic.iconv( filename_to_real( File.basename(filename))).to_s if is_attachment + rename_file = File.basename(filename) + rename_file = filename_to_real( File.basename(filename)) if is_attachment begin - zipfile.add(rename_file, filename) + zipfile.add_file(rename_file, filename) flag = false rescue Exception => e - zipfile.get_output_stream('FILE_NOTICE.txt') do |os| - os.write l(:label_file_exist) - end + zipfile.add_buffer('FILE_NOTICE.txt', l(:label_file_exist)) next end end unless not_exist_file.empty? - zipfile.get_output_stream('FILE_LOST.txt') do |os| - os.write l(:label_file_lost) + not_exist_file.join(',').to_s - end + zipfile.add_buffer('FILE_LOST.txt', l(:label_file_lost) + not_exist_file.join(',').to_s) end end zipfile_name - #rescue Errno => e - # logger.error "[zipdown#zipping] ===> #{e}" - # @error = e end # 合理分配文件打包 diff --git a/app/models/zip_pack.rb b/app/models/zip_pack.rb new file mode 100644 index 000000000..e2d03f363 --- /dev/null +++ b/app/models/zip_pack.rb @@ -0,0 +1,18 @@ +class ZipPack < ActiveRecord::Base + # attr_accessible :title, :body + + def self.packed?(bid_id, user_id, digests) + zip_pack = ZipPack.where(homework_id: bid_id, user_id: user_id).first + return false unless zip_pack && zip_pack.digests == digests + zip_pack + end + + def file_valid? + return false unless File.exist?(self.file_path) + Trustie::Utils.digest(self.file_path) == self.file_digest + end + + def digests + self.file_digests.split(',').sort + end +end diff --git a/app/views/bids/_homework_list.html.erb b/app/views/bids/_homework_list.html.erb index a59997a62..577cd280f 100644 --- a/app/views/bids/_homework_list.html.erb +++ b/app/views/bids/_homework_list.html.erb @@ -22,8 +22,8 @@ <%= link_to "留言", get_homework_jours_homework_attach_index_path(:bid_id => @bid.id), {:remote => true}%> (<%= @jours_count %>) -
  • - <%#= link_to "作品打包下载", zipdown_assort_path(obj_class: @bid.class, obj_id: @bid), class: "tb_all" unless @bid.homeworks.empty? %> +
  • <%= link_to "作品打包下载", zipdown_assort_path(obj_class: @bid.class, obj_id: @bid, format: :json), + remote: true, class: "tb_all" unless @bid.homeworks.empty? %>
  • <% else %> diff --git a/config/initializers/30-redmine.rb b/config/initializers/30-redmine.rb index 1018ca18c..769039f4b 100644 --- a/config/initializers/30-redmine.rb +++ b/config/initializers/30-redmine.rb @@ -2,6 +2,7 @@ I18n.default_locale = 'en' I18n.backend = Redmine::I18n::Backend.new require 'redmine' +require 'trustie' # Load the secret token from the Redmine configuration file secret = Redmine::Configuration['secret_token'] diff --git a/config/routes.rb b/config/routes.rb index 6ca3edd67..d702ba24c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -102,11 +102,11 @@ RedmineApp::Application.routes.draw do mount SeemsRateable::Engine => '/rateable', :as => :rateable - # namespace :zipdown do - # match 'assort' - # match 'download_user_homework', :as => :download_user_homework - # match 'download' - # end + namespace :zipdown do + match 'assort' + match 'download_user_homework', :as => :download_user_homework + match 'download' + end namespace :test do match 'courselist' match 'zip' diff --git a/db/migrate/20150402015402_create_zip_packs.rb b/db/migrate/20150402015402_create_zip_packs.rb new file mode 100644 index 000000000..8ba268e24 --- /dev/null +++ b/db/migrate/20150402015402_create_zip_packs.rb @@ -0,0 +1,14 @@ +class CreateZipPacks < ActiveRecord::Migration + def change + create_table :zip_packs do |t| + t.integer :user_id + t.integer :homework_id + t.string :file_digest + t.string :file_path + t.integer :pack_times, default: 1 + t.integer :pack_size, default: 0 + t.string :file_digests + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 6f215e48f..a8ade8ed0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20150331032810) do +ActiveRecord::Schema.define(:version => 20150402015402) do create_table "activities", :force => true do |t| t.integer "act_id", :null => false @@ -1451,4 +1451,16 @@ ActiveRecord::Schema.define(:version => 20150331032810) do t.datetime "updated_at", :null => false end + create_table "zip_packs", :force => true do |t| + t.integer "user_id" + t.integer "homework_id" + t.string "file_digest" + t.string "file_path" + t.integer "pack_times", :default => 1 + t.integer "pack_size", :default => 0 + t.string "file_digests" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + end diff --git a/lib/trustie.rb b/lib/trustie.rb new file mode 100644 index 000000000..ff70d118c --- /dev/null +++ b/lib/trustie.rb @@ -0,0 +1 @@ +require 'trustie/utils' \ No newline at end of file diff --git a/lib/trustie/utils.rb b/lib/trustie/utils.rb new file mode 100644 index 000000000..a152a869a --- /dev/null +++ b/lib/trustie/utils.rb @@ -0,0 +1,20 @@ +#coding=utf-8 + +module Trustie + module Utils + def self.digest(diskfile) + md5 = Digest::MD5.new + File.open(diskfile, "rb") do |f| + buffer = "" + while (buffer = f.read(8192)) + md5.update(buffer) + end + end + md5.hexdigest + end + end +end + +if __FILE__ == $0 + puts Trustie::Utils.digest('/Users/guange/Downloads/QQ_V4.0.2.dmg') +end \ No newline at end of file