diff --git a/app/controllers/dmsf_controller.rb b/app/controllers/dmsf_controller.rb index 65e355fe..59a45a57 100644 --- a/app/controllers/dmsf_controller.rb +++ b/app/controllers/dmsf_controller.rb @@ -31,6 +31,8 @@ class DmsfController < ApplicationController before_filter :authorize before_filter :find_folder, :except => [:new, :create, :edit_root, :save_root] before_filter :find_parent, :only => [:new, :create] + + accept_api_auth :show, :create helper :all @@ -134,7 +136,14 @@ class DmsfController < ApplicationController @trash_enabled = DmsfFolder.deleted.where(:project_id => @project.id).any? || DmsfFile.deleted.where(:project_id => @project.id).any? || DmsfLink.deleted.where(:project_id => @project.id).any? - end + + respond_to do |format| + format.html { + render :layout => !request.xhr? + } + format.api + end + end def trash @folder_manipulation_allowed = User.current.allowed_to? :folder_manipulation, @project @@ -249,13 +258,11 @@ class DmsfController < ApplicationController render :action => 'edit' end - def create - if (Rails::VERSION::MAJOR > 3) - @folder = DmsfFolder.new( - params.require(:dmsf_folder).permit(:title, :description, :dmsf_folder_id)) - else - @folder = DmsfFolder.new(params[:dmsf_folder]) - end + def create + @folder = DmsfFolder.new + @folder.title = params[:dmsf_folder][:title] + @folder.description = params[:dmsf_folder][:description] + @folder.dmsf_folder_id = params[:dmsf_folder][:dmsf_folder_id] @folder.project = @project @folder.user = User.current diff --git a/app/controllers/dmsf_upload_controller.rb b/app/controllers/dmsf_upload_controller.rb index 0c531d1e..1371bbf7 100644 --- a/app/controllers/dmsf_upload_controller.rb +++ b/app/controllers/dmsf_upload_controller.rb @@ -26,10 +26,12 @@ class DmsfUploadController < ApplicationController before_filter :find_project before_filter :authorize - before_filter :find_folder, :except => [:upload_file] + before_filter :find_folder, :except => [:upload_file, :upload] helper :all helper :dmsf_workflows + + accept_api_auth :upload, :commit def upload_files uploaded_files = params[:attachments] @@ -62,11 +64,7 @@ class DmsfUploadController < ApplicationController return end @disk_filename = DmsfHelper.temp_filename(@tempfile.original_filename) - File.open("#{DmsfHelper.temp_dir}/#{@disk_filename}", 'wb') do |f| - while (buffer = @tempfile.read(8192)) - f.write(buffer) - end - end + FileUtils.mv(@tempfile.path, "#{DmsfHelper.temp_dir}/#{@disk_filename}") if File.size("#{DmsfHelper.temp_dir}/#{@disk_filename}") <= 0 begin File.delete("#{DmsfHelper.temp_dir}/#{@disk_filename}") @@ -85,12 +83,55 @@ class DmsfUploadController < ApplicationController end end + # REST API document upload + def upload + unless request.content_type == 'application/octet-stream' + render :nothing => true, :status => 406 + return + end + + @attachment = Attachment.new(:file => request.raw_post) + @attachment.author = User.current + @attachment.filename = params[:filename].presence || Redmine::Utils.random_hex(16) + saved = @attachment.save + + respond_to do |format| + format.js + format.api { + if saved + render :action => 'upload', :status => :created + else + render_validation_errors(@attachment) + end + } + end + end + def commit_files if (Rails::VERSION::MAJOR > 3) commited_files = params.require(:commited_files) else commited_files = params[:commited_files] end + commit_files_internal commited_files + end + + # REST API file commit + def commit + uploaded_files = params[:attachments] + if uploaded_files && uploaded_files.is_a?(Hash) + # standard file input uploads + uploaded_files.each_value do |uploaded_file| + upload = DmsfUpload.create_from_uploaded_attachment(@project, @folder, uploaded_file) + uploaded_file[:disk_filename] = upload.disk_filename + end + end + commit_files_internal uploaded_files + end + + private + + def commit_files_internal(commited_files) if commited_files && commited_files.is_a?(Hash) files = [] failed_uploads = [] @@ -146,12 +187,12 @@ class DmsfUploadController < ApplicationController new_revision.mime_type = Redmine::MimeType.of(new_revision.name) new_revision.size = File.size(commited_disk_filepath) - file_upload = File.new(commited_disk_filepath, 'rb') - unless file_upload - failed_uploads.push(commited_file) - flash[:error] = l(:error_file_commit_require_uploaded_file) - next - end +# file_upload = File.new(commited_disk_filepath, 'rb') +# unless file_upload +# failed_uploads.push(commited_file) +# flash[:error] = l(:error_file_commit_require_uploaded_file) +# next +# end if file.locked? begin @@ -180,9 +221,10 @@ class DmsfUploadController < ApplicationController if new_revision.save new_revision.assign_workflow(commited_file[:dmsf_workflow_id]) - new_revision.copy_file_content(file_upload) - file_upload.close - File.delete(commited_disk_filepath) + #new_revision.copy_file_content(file_upload) + #file_upload.close + #File.delete(commited_disk_filepath) + FileUtils.mv(commited_disk_filepath, new_revision.disk_file) file.set_last_revision new_revision files.push(file) else @@ -213,10 +255,13 @@ class DmsfUploadController < ApplicationController flash[:warning] = l(:warning_some_files_were_not_commited, :files => failed_uploads.map{|u| u['name']}.join(', ')) end end - redirect_to dmsf_folder_path(:id => @project, :folder_id => @folder) + respond_to do |format| + format.js + format.api { render_validation_errors(failed_uploads) } + format.html { redirect_to dmsf_folder_path(:id => @project, :folder_id => @folder) } + end + end - - private def log_activity(file, action) Rails.logger.info "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} #{User.current.login}@#{request.remote_ip}/#{request.env['HTTP_X_FORWARDED_FOR']}: #{action} dmsf://#{file.project.identifier}/#{file.id}/#{file.last_revision.id}" diff --git a/app/models/dmsf_upload.rb b/app/models/dmsf_upload.rb index 41fc5145..31ae5566 100644 --- a/app/models/dmsf_upload.rb +++ b/app/models/dmsf_upload.rb @@ -45,13 +45,7 @@ class DmsfUpload :original_filename => a.filename, :comment => uploaded_file[:description] } - File.open(a.diskfile, 'rb') do |fr| - File.open("#{DmsfHelper.temp_dir}/#{uploaded[:disk_filename]}", 'wb') do |fw| - while (buffer = fr.read(8192)) - fw.write(buffer) - end - end - end + FileUtils.mv(a.diskfile, "#{DmsfHelper.temp_dir}/#{uploaded[:disk_filename]}") a.destroy DmsfUpload.new(project, folder, uploaded) end diff --git a/app/views/dmsf/show.api.rsb b/app/views/dmsf/show.api.rsb new file mode 100644 index 00000000..a1d33e73 --- /dev/null +++ b/app/views/dmsf/show.api.rsb @@ -0,0 +1,30 @@ +api.array :dmsf_folders, api_meta(:total_count => @subfolders.size) do + @subfolders.each do |folder| + api.folder do + api.id folder.id + api.title folder.title + end + end +end + +api.array :dmsf_files, api_meta(:total_count => @files.size) do + @files.each do |file| + api.file do + api.id file.id + api.name file.name + end + end +end + +api.array :dmsf_links, api_meta(:total_count => @dir_links.size + @file_links.size + @url_links.size) do + (@dir_links + @file_links + @url_links).each do |link| + api.link do + api.id link.id + api.name link.name + api.target_type link.target_type + api.target_id link.target_id + api.target_project_id link.target_project_id + api.external_url link.external_url if link.external_url.present? + end + end +end \ No newline at end of file diff --git a/app/views/dmsf_files/show.api.rsb b/app/views/dmsf_files/show.api.rsb index 8a66d0f3..4f265db2 100644 --- a/app/views/dmsf_files/show.api.rsb +++ b/app/views/dmsf_files/show.api.rsb @@ -1,8 +1,8 @@ api.file do api.id @file.id - api.name @file.name + api.name @file.name api.project_id @file.project_id - api.dmsf_folder_id @file.folder ? @file.dmsf_folder_id : -1 - api.version "#{@file.last_revision.major_version}.#{@file.last_revision.minor_version}" + api.dmsf_folder_id @file.folder if @file.dmsf_folder_id + api.version "#{@file.last_revision.major_version}.#{@file.last_revision.minor_version}" if @file.last_revision api.content_url url_for(:controller => :dmsf_files, :action => 'show', :download => '', :id => @file, :only_path => false) end \ No newline at end of file diff --git a/app/views/dmsf_upload/commit.api.rsb b/app/views/dmsf_upload/commit.api.rsb new file mode 100644 index 00000000..f1481c7d --- /dev/null +++ b/app/views/dmsf_upload/commit.api.rsb @@ -0,0 +1,3 @@ +api.commit do + puts 'OK' +end diff --git a/app/views/dmsf_upload/upload.api.rsb b/app/views/dmsf_upload/upload.api.rsb new file mode 100644 index 00000000..0a399ec1 --- /dev/null +++ b/app/views/dmsf_upload/upload.api.rsb @@ -0,0 +1,3 @@ +api.upload do + api.token @attachment.token +end diff --git a/config/routes.rb b/config/routes.rb index 0852c9ab..9569f325 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -58,7 +58,9 @@ RedmineApp::Application.routes.draw do post '/projects/:id/dmsf/upload/files', :controller => 'dmsf_upload', :action => 'upload_files' post '/projects/:id/dmsf/upload/file', :controller => 'dmsf_upload', :action => 'upload_file' + post '/projects/:id/dmsf/upload', :controller => 'dmsf_upload', :action => 'upload' post '/projects/:id/dmsf/upload/commit', :controller => 'dmsf_upload', :action => 'commit_files' + post '/projects/:id/dmsf/commit', :controller => 'dmsf_upload', :action => 'commit' # # dmsf_files controller diff --git a/extra/api_client.rb b/extra/api/api_client.rb similarity index 79% rename from extra/api_client.rb rename to extra/api/api_client.rb index 98de7da1..cb9554b9 100644 --- a/extra/api_client.rb +++ b/extra/api/api_client.rb @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Redmine plugin for Document Management System "Features" # # Copyright (C) 2011-15 Karel Pičman @@ -19,22 +21,25 @@ require 'rubygems' require 'active_resource' +# Simple REST API client in Ruby +# usage: ruby api_client.rb [login] [password] + # Dmsf file class DmsfFile < ActiveResource::Base self.site = 'http://localhost:3000/' - self.user = 'kpicman' - self.password = 'Kontron2014+' + self.user = ARGV[0] + self.password = ARGV[1] end -# Retrieving a file -file = DmsfFile.find 17200 +# 2. Get a document +FILE_ID = 17216 +file = DmsfFile.find FILE_ID if file puts file.id puts file.name puts file.version - puts file.project_id - puts file.dmsf_folder_id + puts file.project_id puts file.content_url else - puts 'No file with id = 1 found' + puts "No file with id = #{FILE_ID} found" end \ No newline at end of file diff --git a/extra/api/api_client.sh b/extra/api/api_client.sh new file mode 100644 index 00000000..43e5f79b --- /dev/null +++ b/extra/api/api_client.sh @@ -0,0 +1,42 @@ +# 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. + +#!/bin/bash + +# Authentication as input parameters either as login + password or the API key +# -u ${1}:${2} +# -H "X-Redmine-API-Key: ${1}" + +# BOTH XML and JSON formats are supported. +# Just replace .xml with .json + +# 1. List of documents in a given folder or the root folder +curl -v -H "Content-Type: application/xml" -X GET -u ${1}:${2} http://localhost:3000//projects/12/dmsf.xml +#curl -v -H "Content-Type: application/xml" -X GET -u ${1}:${2} http://localhost:3000//projects/12/dmsf.xml?folder_id=5155 + +# 2. Get a document +#curl -v -H "Content-Type: application/xml" -X GET -u ${1}:${2} http://localhost:3000/dmsf/files/17216.xml + +# 3. Create a folder +#curl -v -H "Content-Type: application/xml" -X POST --data "@folder.xml" -u ${1}:${2} http://localhost:3000//projects/12/dmsf/create.xml + +# 4. Upload a document into a given folder or the root folder +#curl --data-binary "@cat.gif" -H "Content-Type: application/octet-stream" -X POST -u ${1}:${2} http://localhost:3000//projects/12/dmsf/upload.xml?filename=cat.gif +#curl -v -H "Content-Type: application/xml" -X POST --data "@file.xml" -u ${1}:${2} http://localhost:3000//projects/12/dmsf/commit.xml \ No newline at end of file diff --git a/extra/api/cat.gif b/extra/api/cat.gif new file mode 100644 index 00000000..0329e659 Binary files /dev/null and b/extra/api/cat.gif differ diff --git a/extra/api/file.xml b/extra/api/file.xml new file mode 100644 index 00000000..289c3586 --- /dev/null +++ b/extra/api/file.xml @@ -0,0 +1,12 @@ + + + + cat.gif + cat.gif + cat.gif + REST API + From API + + 15843.c49f68ff81b552d315927df2e27df506 + + diff --git a/extra/api/folder.xml b/extra/api/folder.xml new file mode 100644 index 00000000..fd0bef9c --- /dev/null +++ b/extra/api/folder.xml @@ -0,0 +1,6 @@ + + + rest_api + A folder created via REST API + + diff --git a/init.rb b/init.rb index eb332460..5097a868 100644 --- a/init.rb +++ b/init.rb @@ -28,7 +28,7 @@ Redmine::Plugin.register :redmine_dmsf do name 'DMSF' author 'Vit Jonas / Daniel Munn / Karel Picman' description 'Document Management System Features' - version '1.5.1 stable' + version '1.5.2 devel' url 'http://www.redmine.org/plugins/dmsf' author_url 'https://github.com/danmunn/redmine_dmsf/graphs/contributors' @@ -74,7 +74,7 @@ Redmine::Plugin.register :redmine_dmsf do {:dmsf => [:new, :create, :delete, :edit, :save, :edit_root, :save_root, :lock, :unlock, :notify_activate, :notify_deactivate, :restore]} permission :file_manipulation, {:dmsf_files => [:create_revision, :lock, :unlock, :delete_revision, :notify_activate, :notify_deactivate, :restore], - :dmsf_upload => [:upload_files, :upload_file, :commit_files], + :dmsf_upload => [:upload_files, :upload_file, :upload, :commit_files, :commit], :dmsf_links => [:new, :create, :destroy, :restore] } permission :file_delete, diff --git a/lib/redmine_dmsf/webdav/base_resource.rb b/lib/redmine_dmsf/webdav/base_resource.rb index 7b5bf7ae..b91a9786 100644 --- a/lib/redmine_dmsf/webdav/base_resource.rb +++ b/lib/redmine_dmsf/webdav/base_resource.rb @@ -78,7 +78,7 @@ module RedmineDmsf '-', '', '', - ] + entities if parent? + ] + entities if parent @response.body << index_page % [ path.empty? ? '/' : path, path.empty? ? '/' : path , entities ] end diff --git a/lib/tasks/dmsf_convert_documents.rake b/lib/tasks/dmsf_convert_documents.rake index 82e0321f..7df67efd 100644 --- a/lib/tasks/dmsf_convert_documents.rake +++ b/lib/tasks/dmsf_convert_documents.rake @@ -141,19 +141,12 @@ class DmsfConvertDocuments revision.comment = 'Converted from documents' revision.mime_type = attachment.content_type - revision.disk_filename = revision.new_storage_filename - attachment_file = File.open(attachment.diskfile, 'rb') + revision.disk_filename = revision.new_storage_filename unless dry - File.open(revision.disk_file, 'wb') do |f| - while (buffer = attachment_file.read(8192)) - f.write(buffer) - end - end + FileUtils.cp(attachment.diskfile, revision.disk_file) revision.size = File.size(revision.disk_file) - end - - attachment_file.close + end if dry puts "Dry check revision: #{revision.title}"