diff --git a/app/controllers/dmsf_controller.rb b/app/controllers/dmsf_controller.rb index 6833877a..175b32f8 100644 --- a/app/controllers/dmsf_controller.rb +++ b/app/controllers/dmsf_controller.rb @@ -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 diff --git a/app/controllers/dmsf_public_urls_controller.rb b/app/controllers/dmsf_public_urls_controller.rb new file mode 100644 index 00000000..f9db08c7 --- /dev/null +++ b/app/controllers/dmsf_public_urls_controller.rb @@ -0,0 +1,46 @@ +# encoding: utf-8 +# +# Redmine plugin for Document Management System "Features" +# +# Copyright (C) 2011-16 Karel Pičman +# +# 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 diff --git a/app/models/dmsf_file.rb b/app/models/dmsf_file.rb index 82cba93b..d0bc697f 100644 --- a/app/models/dmsf_file.rb +++ b/app/models/dmsf_file.rb @@ -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 diff --git a/app/models/dmsf_mailer.rb b/app/models/dmsf_mailer.rb index 1f729091..9fefa497 100644 --- a/app/models/dmsf_mailer.rb +++ b/app/models/dmsf_mailer.rb @@ -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], diff --git a/app/models/dmsf_public_url.rb b/app/models/dmsf_public_url.rb new file mode 100644 index 00000000..4a908d2b --- /dev/null +++ b/app/models/dmsf_public_url.rb @@ -0,0 +1,36 @@ +# encode: utf-8 +# +# Redmine plugin for Document Management System "Features" +# +# Copyright (C) 2011-16 Karel Pičman +# +# 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 diff --git a/app/views/dmsf/email_entries.html.erb b/app/views/dmsf/email_entries.html.erb index 010baf4b..0cf7edcb 100644 --- a/app/views/dmsf/email_entries.html.erb +++ b/app/views/dmsf/email_entries.html.erb @@ -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 @@ <%= 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') %>

diff --git a/app/views/dmsf_mailer/send_documents.html.erb b/app/views/dmsf_mailer/send_documents.html.erb index ac8f1eeb..275ae28f 100644 --- a/app/views/dmsf_mailer/send_documents.html.erb +++ b/app/views/dmsf_mailer/send_documents.html.erb @@ -23,7 +23,7 @@ <%= textilizable(@body) %> -<% if @links_only == '1' %> +<% if @links_only %> <% folders = [] %> <% files = [] %> <% if @folders.present? %> @@ -38,8 +38,18 @@

<% dir.dmsf_files.each do |file| %> <% unless files.include?(file) %> - <%= link_to(h(file.title), dmsf_file_url(file)) %> -  (<%= 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)) %> +  (<%= link_to(h(file.name), dmsf_file_url(file)) %>) + <% end %>
<% 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)) %> -  (<%= 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)) %> +  (<%= link_to(h(file.name), dmsf_public_urls_url(:token => dmsf_public_url.token)) %>) + <% else %> + <%= link_to(h(file.title), dmsf_file_url(file)) %> +  (<%= link_to(h(file.name), dmsf_file_url(file)) %>) + <% end %>
<% files << file %> <% end %> diff --git a/app/views/dmsf_mailer/send_documents.text.erb b/app/views/dmsf_mailer/send_documents.text.erb index b4f4f23d..fffdced5 100644 --- a/app/views/dmsf_mailer/send_documents.text.erb +++ b/app/views/dmsf_mailer/send_documents.text.erb @@ -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 %> diff --git a/app/views/dmsf_public_urls/_new.html.erb b/app/views/dmsf_public_urls/_new.html.erb new file mode 100644 index 00000000..4db369a4 --- /dev/null +++ b/app/views/dmsf_public_urls/_new.html.erb @@ -0,0 +1,28 @@ +<% +# encoding: utf-8 +# +# Redmine plugin for Document Management System "Features" +# +# +# Copyright (C) 2011-16 Karel Pičman +# +# 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. +%> + + + <%= 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') %> + diff --git a/config/locales/en.yml b/config/locales/en.yml index 3979ce52..418ed7c3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -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 diff --git a/config/routes.rb b/config/routes.rb index 166e836d..f8e3d1f2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 \ No newline at end of file diff --git a/db/migrate/201500910153701_title_not_null.rb b/db/migrate/20150910153701_title_not_null.rb similarity index 100% rename from db/migrate/201500910153701_title_not_null.rb rename to db/migrate/20150910153701_title_not_null.rb diff --git a/db/migrate/20161223133200_create_dmsf_public_urls.rb b/db/migrate/20161223133200_create_dmsf_public_urls.rb new file mode 100644 index 00000000..db90d10f --- /dev/null +++ b/db/migrate/20161223133200_create_dmsf_public_urls.rb @@ -0,0 +1,36 @@ +# encoding: utf-8 +# +# Redmine plugin for Document Management System "Features" +# +# Copyright (C) 2011-15 Karel Pičman +# +# 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 diff --git a/init.rb b/init.rb index d3b6336e..f970e137 100644 --- a/init.rb +++ b/init.rb @@ -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, diff --git a/test/fixtures/dmsf_public_urls.yml b/test/fixtures/dmsf_public_urls.yml new file mode 100644 index 00000000..4d0a70a2 --- /dev/null +++ b/test/fixtures/dmsf_public_urls.yml @@ -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() %> diff --git a/test/functional/dmsf_public_urls_controller_test.rb b/test/functional/dmsf_public_urls_controller_test.rb new file mode 100644 index 00000000..bd75d6eb --- /dev/null +++ b/test/functional/dmsf_public_urls_controller_test.rb @@ -0,0 +1,46 @@ +# encoding: utf-8 +# +# Redmine plugin for Document Management System "Features" +# +# Copyright (C) 2011-16 Karel Pičman +# +# 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 diff --git a/test/integration/dmsf_webdav_get_test.rb b/test/integration/dmsf_webdav_get_test.rb index 20295236..f06efdb9 100644 --- a/test/integration/dmsf_webdav_get_test.rb +++ b/test/integration/dmsf_webdav_get_test.rb @@ -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 \ No newline at end of file +end diff --git a/test/unit/dmsf_public_url_test.rb b/test/unit/dmsf_public_url_test.rb new file mode 100644 index 00000000..aab0b3e9 --- /dev/null +++ b/test/unit/dmsf_public_url_test.rb @@ -0,0 +1,56 @@ +# encoding: utf-8 +# +# Redmine plugin for Document Management System "Features" +# +# Copyright (C) 2011-16 Karel Pičman +# +# 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