Public URLs in email entries #626

This commit is contained in:
Karel Picman 2017-01-02 08:12:43 +01:00
parent 305fd70193
commit e9385da7fa
18 changed files with 331 additions and 21 deletions

View File

@ -443,7 +443,7 @@ class DmsfController < ApplicationController
end
max_files = Setting.plugin_redmine_dmsf['dmsf_max_file_download'].to_i
if max_files > 0 && zip.files.length > max_files
raise ZipMaxFilesError#, zip.files.length
raise ZipMaxFilesError
end
zip
end

View File

@ -0,0 +1,46 @@
# 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 DmsfPublicUrlsController < ApplicationController
unloadable
model_object DmsfPublicUrl
before_filter :authorize, :only => [:create]
skip_before_filter :check_if_login_required, :only => [:show]
def show
dmsf_public_url = DmsfPublicUrl.where('token = ? AND expire_at >= now()', params[:token]).first
if dmsf_public_url
revision = dmsf_public_url.dmsf_file.last_revision
begin
send_file(revision.disk_file,
:filename => filename_for_content_disposition(revision.name),
:type => revision.detect_content_type,
:disposition => dmsf_public_url.dmsf_file.disposition)
rescue Exception => e
Rails.logger.error e.message
render_404
end
else
render_404
end
end
end

View File

@ -42,6 +42,7 @@ class DmsfFile < ActiveRecord::Base
:class_name => 'DmsfLock', :foreign_key => 'entity_id', :dependent => :destroy
has_many :referenced_links, -> { where target_type: DmsfFile.model_name.to_s},
:class_name => 'DmsfLink', :foreign_key => 'target_id', :dependent => :destroy
has_many :dmsf_public_urls, :dependent => :destroy
STATUS_DELETED = 1
STATUS_ACTIVE = 0

View File

@ -54,10 +54,13 @@ class DmsfMailer < Mailer
zipped_content_data = open(email_params[:zipped_content], 'rb') { |io| io.read }
redmine_headers 'Project' => project.identifier if project
@body = email_params[:body]
@links_only = email_params[:links_only]
@links_only = email_params[:links_only] == '1'
@public_url = email_params[:public_urls] == '1'
@expired_at = email_params[:expired_at]
@folders = email_params[:folders]
@files = email_params[:files]
unless @links_only == '1'
unless @links_only
attachments['Documents.zip'] = { :content_type => 'application/zip', :content => zipped_content_data }
end
mail :to => email_params[:to], :cc => email_params[:cc],

View File

@ -0,0 +1,36 @@
# encode: 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 DmsfPublicUrl < ActiveRecord::Base
unloadable
include ActiveModel::Validations
belongs_to :dmsf_file
belongs_to :user
before_save :generate_unique_token
private
def generate_unique_token
self.token ||= SecureRandom.hex(16)
end
end

View File

@ -27,7 +27,7 @@
<%= render(:partial => 'path',
:locals => {:folder => @folder, :filename => nil, :title => l(:heading_send_documents_by_email)}) %>
<%= form_tag({ :action => 'entries_email', :id => @project, :folder_id => @folder },
<%= form_tag(email_entries_path(:id => @project, :folder_id => @folder),
{ :method => :post }) do %>
<%= hidden_field_tag('email[zipped_content]', @email_params[:zipped_content]) %>
<%= hidden_field_tag('email[folders]', @email_params[:folders].to_json) %>
@ -55,7 +55,8 @@
<span>
<%= link_to 'Documents.zip', download_email_entries_path(:id => @project, :folder_id => @folder, :path => @email_params[:zipped_content]) %>
<%= l(:label_or) %>
<%= check_box_tag('email[links_only]') %> <%= l(:label_links_only) %>
<%= check_box_tag('email[links_only]', 1, false, :onchange => "$('#public_url').toggle()") %> <%= l(:label_links_only) %>
<%= render(:partial => 'dmsf_public_urls/new') %>
</span>
</p>
<p>

View File

@ -23,7 +23,7 @@
<%= textilizable(@body) %>
<% if @links_only == '1' %>
<% if @links_only %>
<% folders = [] %>
<% files = [] %>
<% if @folders.present? %>
@ -38,8 +38,18 @@
<br/><br/>
<% dir.dmsf_files.each do |file| %>
<% unless files.include?(file) %>
<%= link_to(h(file.title), dmsf_file_url(file)) %>
&nbsp;(<%= link_to(h(file.name), dmsf_file_url(file, :download => '')) %>)
<% if @public_urls %>
<% dmsf_public_url = DmsfPublicUrl.new %>
<% dmsf_public_url.dmsf_file = file %>
<% dmsf_public_url.user = User.current %>
<% dmsf_public_url.expire_at = @expired_at %>
<% dmsf_public_url.save %>
<%= link_to(h(file.title), dmsf_public_urls_url(:token => dmsf_public_url.token)) %>
(<%= link_to(h(file.name), dmsf_public_urls_url(:token => dmsf_public_url.token)) %>)
<% else %>
<%= link_to(h(file.title), dmsf_file_url(file)) %>
&nbsp;(<%= link_to(h(file.name), dmsf_file_url(file)) %>)
<% end %>
<br/>
<% files << file %>
<% end %>
@ -55,8 +65,18 @@
<% JSON.parse(@files).each do |id| %>
<% file = DmsfFile.find_by_id id %>
<% if file && !files.include?(file) %>
<%= link_to(h(file.title), dmsf_file_url(file)) %>
&nbsp;(<%= link_to(h(file.name), dmsf_file_url(file, :download => '')) %>)
<% if @public_url %>
<% dmsf_public_url = DmsfPublicUrl.new %>
<% dmsf_public_url.dmsf_file = file %>
<% dmsf_public_url.user = User.current %>
<% dmsf_public_url.expire_at = @expired_at %>
<% dmsf_public_url.save %>
<%= link_to(h(file.title), dmsf_public_urls_url(:token => dmsf_public_url.token)) %>
&nbsp;(<%= link_to(h(file.name), dmsf_public_urls_url(:token => dmsf_public_url.token)) %>)
<% else %>
<%= link_to(h(file.title), dmsf_file_url(file)) %>
&nbsp;(<%= link_to(h(file.name), dmsf_file_url(file)) %>)
<% end %>
<br/>
<% files << file %>
<% end %>

View File

@ -23,7 +23,7 @@
<%= @body %>
<% if @links_only == '1' %>
<% if @links_only %>
<% folders = [] %>
<% files = [] %>
<% if @folders.present? %>
@ -36,7 +36,16 @@
<%= dir.dmsf_path_str %>
<% dir.dmsf_files.each do |file| %>
<% unless files.include?(file) %>
<%= dmsf_file_url(file, :download => '') %>
<% if @public_urls %>
<% dmsf_public_url = DmsfPublicUrl.new %>
<% dmsf_public_url.dmsf_file = file %>
<% dmsf_public_url.user = User.current %>
<% dmsf_public_url.expire_at = @expired_at %>
<% dmsf_public_url.save %>
<%= dmsf_public_urls_url(:token => dmsf_public_url.token) %>
<% else %>
<%= dmsf_file_url(file) %>
<% end %>
<% files << file %>
<% end %>
<% end %>
@ -49,7 +58,16 @@
<% JSON.parse(@files).each do |id| %>
<% file = DmsfFile.find_by_id id %>
<% if file && !files.include?(file) %>
<%= dmsf_file_url(file, :download => '') %>
<% if @public_urls %>
<% dmsf_public_url = DmsfPublicUrl.new %>
<% dmsf_public_url.dmsf_file = file %>
<% dmsf_public_url.user = User.current %>
<% dmsf_public_url.expire_at = @expired_at %>
<% dmsf_public_url.save %>
<%= dmsf_public_urls_url(:token => dmsf_public_url.token) %>
<% else %>
<%= dmsf_file_url(file) %>
<% end %>
<% files << file %>
<% end %>
<% end %>

View File

@ -0,0 +1,28 @@
<%
# 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.
%>
<span id="public_url" class="dmsf_invisible">
<%= check_box_tag('email[public_urls]', 1, false) %> <%= l(:label_public_urls) %>
<%= date_field_tag('email[expired_at]', '', :value => (DateTime.now + 3.days).to_date, :size => 10,
:readonly => true) + calendar_for('email_expired_at') %>
</span>

View File

@ -333,3 +333,5 @@ en:
label_drag_drop: Modern
error_maximum_upload_filecount: "No more than %{filecount} file(s) can be uploaded."
label_public_urls: Public URLs valid to

View File

@ -36,7 +36,7 @@ RedmineApp::Application.routes.draw do
post '/projects/:id/dmsf/entries', :controller => 'dmsf', :action => 'entries_operation'
post '/projects/:id/dmsf/tag_changed', :controller => 'dmsf', :action => 'tag_changed', :as => 'tag_changed'
post '/projects/:id/dmsf/entries/delete', :controller => 'dmsf', :action => 'delete_entries', :as => 'delete_entries'
post '/projects/:id/dmsf/entries/email', :controller => 'dmsf', :action => 'entries_email'
post '/projects/:id/dmsf/entries/email', :to => 'dmsf#entries_email', :as => 'email_entries'
get '/projects/:id/dmsf/entries/download_email_entries', :controller => 'dmsf', :action => 'download_email_entries', :as => 'download_email_entries'
get '/projects/:id/dmsf/lock', :controller => 'dmsf', :action => 'lock', :as => 'lock_dmsf'
get '/projects/:id/dmsf/unlock', :controller => 'dmsf', :action => 'unlock', :as => 'unlock_dmsf'
@ -147,4 +147,7 @@ RedmineApp::Application.routes.draw do
end
end
# Public URLs
resource :dmsf_public_urls
end

View File

@ -0,0 +1,36 @@
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-15 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 CreateDmsfPublicUrls < ActiveRecord::Migration
def change
create_table :dmsf_public_urls do |t|
t.string :token, :null => false, :limit => 32
t.references :dmsf_file, :null => false
t.references :user, :null => false
t.datetime :expire_at, :null => false
t.timestamps
end
add_index :dmsf_public_urls, :token
end
def self.down
drop_table :dmsf_public_urls
end
end

View File

@ -74,7 +74,8 @@ Redmine::Plugin.register :redmine_dmsf do
:dmsf_files_copy => [:new, :create, :move],
:dmsf_workflows => [:log]},
:read => true
permission :email_documents, {}
permission :email_documents,
{:dmsf_public_urls => [:create]}
permission :folder_manipulation,
{:dmsf => [:new, :create, :delete, :edit, :save, :edit_root, :save_root, :lock, :unlock, :notify_activate, :notify_deactivate, :restore]}
permission :file_manipulation,

18
test/fixtures/dmsf_public_urls.yml vendored Normal file
View File

@ -0,0 +1,18 @@
---
public_url_1:
id: 1
dmsf_file_id: 1
user_id: 1
token: 'd8d33e21914a433b280fdc94450ee212'
expire_at: <%= (Time.now + 1.day).to_date %>
created_at: <%= DateTime.now() %>
updated_at: <%= DateTime.now() %>
public_url_2:
id: 2
dmsf_file_id: 1
user_id: 1
token: 'e8d33e21914a433b280fdc94450ee212'
expire_at: <%= (Time.now - 1.day).to_date %>
created_at: <%= DateTime.now() %>
updated_at: <%= DateTime.now() %>

View File

@ -0,0 +1,46 @@
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-16 Karel Pičman <karel.picman@lbcfree.net>
#
# 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.
require File.expand_path('../../test_helper', __FILE__)
class DmsfPublicUrlsControllerTest < RedmineDmsf::Test::TestCase
fixtures :dmsf_files, :dmsf_file_revisions, :dmsf_public_urls
def setup
DmsfFile.storage_path = File.expand_path '../../fixtures/files', __FILE__
end
def test_show_valid_url
get :show, :token => 'd8d33e21914a433b280fdc94450ee212'
assert_response :success
end
def test_show_url_width_invalid_token
get :show, :token => 'f8d33e21914a433b280fdc94450ee212'
assert_response :missing
end
def test_show_url_that_has_expired
get :show, :token => 'e8d33e21914a433b280fdc94450ee212'
assert_response :missing
end
end

View File

@ -83,11 +83,8 @@ class DmsfWebdavGetTest < RedmineDmsf::Test::IntegrationTest
end
def test_download_file_from_dmsf_enabled_project
#@project1.enable_module! :dmsf # Flag module enabled
get "/dmsf/webdav/#{@project1.identifier}/test.txt", nil, @admin
assert_response :success
assert_equal response.body, '1234',
"File downloaded with unexpected contents: '#{response.body}'"
end
def test_should_list_dmsf_contents_within_project
@ -135,8 +132,6 @@ class DmsfWebdavGetTest < RedmineDmsf::Test::IntegrationTest
@role.add_permission! :view_dmsf_files
get "/dmsf/webdav/#{@project1.identifier}/test.txt", nil, @jsmith
assert_response :success
assert_equal response.body, '1234',
"File downloaded with unexpected contents: '#{response.body}'"
end
end
end

View File

@ -0,0 +1,56 @@
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-16 Karel Pičman <karel.picman@lbcfree.net>
#
# 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.
require File.expand_path('../../test_helper', __FILE__)
class DmsfPublicUrlsTest < RedmineDmsf::Test::UnitTest
fixtures :dmsf_files, :dmsf_file_revisions, :dmsf_public_urls, :users
def setup
@file1 = DmsfFile.find_by_id 1
assert_not_nil @file1
@dmsf_public_url1 = DmsfPublicUrl.find_by_id 1
assert_not_nil @dmsf_public_url1
@user2 = User.find_by_id 2
assert_not_nil @user2
end
def test_truth
assert_kind_of DmsfFile, @file1
assert_kind_of DmsfPublicUrl, @dmsf_public_url1
assert_kind_of User, @user2
end
def test_create
url = DmsfPublicUrl.new
url.dmsf_file = @file1
url.user = @user2
url.expire_at = DateTime.now() + 1.day
assert url.save, url.errors.full_messages.to_sentence
assert_not_nil url.token
end
def test_belongs_to_file
@file1.destroy
assert_nil DmsfPublicUrl.find_by_id 1
end
end