Add MD5 of each revision in the detail view of documents #527

This commit is contained in:
Karel Picman 2016-04-22 12:46:30 +02:00
parent 8507ee9b09
commit 52f245e913
8 changed files with 170 additions and 62 deletions

View File

@ -139,10 +139,16 @@ class DmsfFilesController < ApplicationController
revision.size = last_revision.size
revision.disk_filename = last_revision.disk_filename
revision.mime_type = last_revision.mime_type
if last_revision.digest.blank?
revision.digest = DmsfFileRevision.create_digest last_revision.disk_file
else
revision.digest = last_revision.digest
end
else
revision.size = file_upload.size
revision.disk_filename = revision.new_storage_filename
revision.mime_type = Redmine::MimeType.of(file_upload.original_filename)
revision.digest = DmsfFileRevision.create_digest file_upload.path
end
# Custom fields

View File

@ -187,6 +187,7 @@ class DmsfUploadController < ApplicationController
end
new_revision.mime_type = Redmine::MimeType.of(new_revision.name)
new_revision.size = File.size(commited_disk_filepath)
new_revision.digest = DmsfFileRevision.create_digest commited_disk_filepath
# Need to save file first to generate id for it in case of creation.
# File id is needed to properly generate revision disk filename

View File

@ -67,17 +67,6 @@ module DmsfHelper
return "#{Redmine::Utils.relative_url_root}/plugin_assets/#{plugin}/#{asset_type}/#{source}"
end
def self.to_time(obj)
#Right, enough of bugs, let's try a better approach here.
return unless obj
return obj.to_time(ActiveRecord::Base.default_timezone) if obj.is_a?(String)
# Why can't Mysql::Time conform to time object? - without a utc? method it breaks redmine's
# rendering method, so we convert it to string, and back into time - not the most efficient
# of methods - however seems functional. Not sure if MySQL
(obj.class.name == 'Mysql::Time') ? obj.to_s.to_time(ActiveRecord::Base.default_timezone) : obj
end
def self.dmsf_tree(parent, obj, tree = nil)
tree ||= []
# Folders && files && links

View File

@ -19,6 +19,8 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'digest/md5'
class DmsfFileRevision < ActiveRecord::Base
unloadable
belongs_to :dmsf_file
@ -159,6 +161,7 @@ class DmsfFileRevision < ActiveRecord::Base
new_revision.source_revision = self
new_revision.user = User.current
new_revision.name = self.name
new_revision.digest = self.digest
new_revision
end
@ -262,4 +265,23 @@ class DmsfFileRevision < ActiveRecord::Base
format + ext
end
def self.create_digest(path)
begin
Digest::MD5.file(path).hexdigest
rescue Exception => e
Rails.logger.error e.message
nil
end
end
def create_digest
begin
self.digest = Digest::MD5.file(self.disk_file).hexdigest
true
rescue Exception => e
Rails.logger.error e.message
false
end
end
end

View File

@ -22,22 +22,22 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<table class="display access-table list">
<table class="display list dmsf_list">
<thead>
<tr>
<th><%= l(:field_user) %></th>
<th><%= l(:heading_access_downloads_emails) %></th>
<th><%= l(:heading_access_first) %></th>
<th><%= l(:heading_access_last) %></th>
<th class="dmsf_th"><%= l(:field_user) %></th>
<th class="dmsf_th"><%= l(:heading_access_downloads_emails) %></th>
<th class="dmsf_th"><%= l(:heading_access_first) %></th>
<th class="dmsf_th"><%= l(:heading_access_last) %></th>
</tr>
</thead>
<tbody>
<% revision.access_grouped.each do |access| %>
<tr>
<td><%= link_to_user(access.user) %></td>
<td class="dmsf_version"><%= access['count'] %></td>
<td class="dmsf_modified"><%= format_time(DmsfHelper::to_time(access.first_at)) %></td>
<td class="dmsf_modified"><%= format_time(DmsfHelper::to_time(access.last_at)) %></td>
<td class="dmsf_author"><%= link_to_user(access.user) %></td>
<td class="dmsf_version"><%= access.count %></td>
<td class="dmsf_modified"><%= format_time(access.first_at) %></td>
<td class="dmsf_modified"><%= format_time(access.last_at) %></td>
</tr>
<% end %>
</tbody>

View File

@ -98,21 +98,13 @@
<%= link_to(revision.user.name, user_path(revision.user)) if revision.user %>
</div>
</div>
<div class="dmsf_revision_inner_box">
<div class="clear">
<div class="attributes dmsf_revision_inner_box">
<div class="splitcontent">
<div class="splitcontentleft">
<p>
<%= label_tag('', l(:label_title)) %>
<%= h(revision.title) %>
</p>
</div>
<div class="splitcontentright">
<p>
<%= label_tag('', l(:label_file)) %>
<%= ("#{h(revision.dmsf_file.dmsf_folder.dmsf_path_str)}/") if revision.dmsf_file.dmsf_folder %><%= h(revision.name) %>
</p>
</div>
</div>
<% if revision.description.present? %>
<p>
<%= label_tag('', l(:label_description)) %>
@ -121,39 +113,26 @@
</div>
</p>
<% end %>
<div class="clear">
<div class="splitcontentleft">
<p>
<%= label_tag('', l(:label_version)) %>
<%= revision.major_version %>.<%= revision.minor_version %>
</p>
<p>
<%= label_tag('', l(:link_workflow)) %>
<%= label_tag('', l(:label_size)) %>
<%= number_to_human_size(revision.size) %>
</p>
<% wf = DmsfWorkflow.find_by_id(revision.dmsf_workflow_id) %>
<% if wf %>
<p>
<%= label_tag('', l(:link_workflow)) %>
<%= "#{wf.name} - " %>
<%= link_to(revision.workflow_str(false),
log_dmsf_workflow_path(:project_id => @project.id,
:id => wf.id, :dmsf_file_revision_id => revision.id),
:title => DmsfWorkflow.assignments_to_users_str(wf.next_assignments(revision.id)),
:remote => true) %>
<% else %>
<%= revision.workflow_str(true) %>
</p>
<% end %>
</p>
</div>
<div class="splitcontentright">
<p>
<%= label_tag('', l(:label_mime)) %>
<%= h(revision.mime_type) %>
</p>
<p>
<%= label_tag('', l(:label_size)) %>
<%= number_to_human_size(revision.size) %>
</p>
</div>
</div>
<%= render 'dmsf/custom_fields', :object => revision %>
<% if revision.comment.present? %>
<p>
<%= label_tag('', l(:label_comment)) %>
@ -162,6 +141,25 @@
</div>
</p>
<% end %>
</div>
<div class="splitcontentright">
<p>
<%= label_tag('', l(:label_file)) %>
<%= ("#{h(revision.dmsf_file.dmsf_folder.dmsf_path_str)}/") if revision.dmsf_file.dmsf_folder %><%= h(revision.name) %>
</p>
<p>
<%= label_tag('', l(:label_mime)) %>
<%= h(revision.mime_type) %>
</p>
<% if revision.digest.present? %>
<p>
<%= label_tag('', 'MD5') %>
<%= revision.digest %>
</p>
<% end %>
<%= render 'dmsf/custom_fields', :object => revision %>
</div>
</div>
<div id="<%= "revision_access-#{revision.id}" %>" style="display:none">
<%= render(:partial => 'revision_access', :locals => {:revision => revision}) if User.current.allowed_to?(:file_manipulation, @file.project) %>
</div>
@ -208,7 +206,7 @@
}
});
$('.access-table').dataTable({
$('.dmsf_list').dataTable({
'bJQueryUI': true,
'oLanguage': {
'sUrl': '/plugin_assets/<%= :redmine_dmsf %>/javascripts/<%= url %>'

View File

@ -0,0 +1,29 @@
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-16 Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class AddDigestToRevision < ActiveRecord::Migration
def up
add_column :dmsf_file_revisions, :digest, :string, :limit => 40, :default => '', :null => false
end
def down
remove_column :dmsf_file_revisions, :digest
end
end

View File

@ -0,0 +1,63 @@
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-16 Karel Pičman <karel.picman@kontron.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
desc <<-END_DESC
DMSF maintenance task
* Create missing MD5 digest for all file revisions
Available options:
*dry_run - test, no changes to he database
Example:
bundle exec rake redmine:dmsf_create_digests RAILS_ENV="production"
bundle exec rake redmine:dmsf_create_digests dry_run=1 RAILS_ENV="production"
END_DESC
namespace :redmine do
task :dmsf_create_digests => :environment do
m = DmsfDigest.new
m.create_digests
end
end
class DmsfDigest
def initialize
@dry_run = ENV['dry_run']
end
def create_digests
revisions = DmsfFileRevision.where("digest IS NULL OR digest = ''").all
count = revisions.count
n = 0
revisions.each_with_index do |rev, i|
if rev.create_digest
rev.save unless @dry_run
n += 1
end
# Progress bar
print "\r#{i * 100 / count}%"
end
print "\r100%\n"
# Result
puts "#{n}/#{DmsfFileRevision.count} revisions updated."
end
end