Merged with devel-1.6.0

This commit is contained in:
Karel Picman 2017-09-12 12:56:47 +02:00
commit 23664570df
211 changed files with 8901 additions and 5401 deletions

View File

@ -3,9 +3,9 @@ language: ruby
sudo: false sudo: false
rvm: rvm:
- 2.0.0 - 2.3
install: "echo skip bundle install" install: 'echo skip bundle install'
script: script:
- export WORKSPACE=`pwd`/workspace - export WORKSPACE=`pwd`/workspace

View File

@ -1,6 +1,62 @@
Changelog for Redmine DMSF Changelog for Redmine DMSF
========================== ==========================
1.6.0 *2017-09-12*
------------------
Folder permissions
Documents attachable to issues
Hungarian localisation
Fulltext search in *.eml and *.msg
IMPORTANT
1. Files in the filesystem are re-organized by a new system based on dates. So, documents are not stored in folders named
by the project's identifier but by the data of uploading, e.g. 2017/09. It's the same system used by Redmine for
attachments.
2. DMS storage directory plugin option is related to the rails root directory.
3. The plugin is independent of the gem xapian-full-alaveteli which has been replaced with ruby-xapian package. Therefore
is recommended to uninstall xapian-full-alaveteli gem and install ruby-xapian package in order the full-text search
is working.
* Bug: #758 - Error in template when retrieving details of a file in a subfolder
* New: #755 - Ability to retrieve the MD5 value of a Document type
* Bug: #749 - REST API - List of documents in folder fails when using folder_title
* Bug: #747 - Background icon repeating in admin panel (Redmine 3.4.2)
* Bug: #746 - Thumbnail macro: size paramter not respected
* Bug: #744 - Full stops within filename lead to false extensions
* New: #742 - WebDAV PROPSTATS and PROPFIND caching change
* Bug: #738 - Upload failure
* Bug: #734 - DMSF uploader seems to override built in uploader
* New: #733 - Make the storage path Rails.root related
* Bug: #732 - Buggy tree view
* Bug: #731 - Add users for new step in Worflow Dialogue
* Bug: #730 - Workflow "New Step" dialog not appearing
* Bug: #728 - Internal error 500 when uploading document via Edit issue
* New: #727 - Ability to disable document upload in issues
* Bug: #725 - Can't uninstall redmine dmsf in Bitnami
* New: #717 - Enhacement: Xapian parse eml and msg files in same way as word, excel...
* Bug: #714 - The full text search does not work
* New: #713 - Hungarian localisation
* New: #712 - Notifications ON/OFF are confusing
* Bug: #710 - Can't delete locked documents from the trash
* Bug: #701 - How tagging with multiple values works?
* Bug: #700 - 'Save as' from Excel does not work when using project names
* New: #699 - Speed up the main view
* New: #697 - Email notifications from WebDAV interface
* Bug: #694 - redmine:dmsf_convert_documents
* Bug: #693 - redmine:dmsf_convert_documents
* Bug: #692 - Error migrate plugin v1.5.9
* New: #691 - The last approver in the CSV export
* Bug: #685 - Problem deleting plugin
* Bug: #683 - Approval reminder problem
* New: #667 - A better navigation in found results
* New: #651 - Incomplete copy of a file to another project
* Bug: #623 - Option "Navigate folders in a tree" seems not to be saved
* New: #543 - Feature Request: Document Location - Folder Structure
* New: #170 - Document and Folder Access Control. This issue may be duplicated as I saw it on google code some time ago.
* New: #48 - Linking Issues and DMSF Documents
1.5.9 *2016-03-01* 1.5.9 *2016-03-01*
------------------ ------------------

View File

@ -28,7 +28,4 @@ gem 'simple_enum'
gem 'uuidtools' gem 'uuidtools'
gem 'dav4rack' gem 'dav4rack'
gem 'dalli' gem 'dalli'
gem 'redmine_extensions' unless Dir.exist?(File.expand_path('../../easyproject', __FILE__))
group :xapian do
gem 'xapian-full-alaveteli', :require => false
end

136
README.md
View File

@ -1,7 +1,7 @@
Redmine DMSF Plugin Redmine DMSF Plugin
=================== ===================
The current version of Redmine DMSF is **1.5.9** [![Build Status](https://api.travis-ci.org/danmunn/redmine_dmsf.png)](https://travis-ci.org/danmunn/redmine_dmsf) The current version of Redmine DMSF is **1.6.0** [![Build Status](https://api.travis-ci.org/danmunn/redmine_dmsf.png)](https://travis-ci.org/danmunn/redmine_dmsf)
Redmine DMSF is Document Management System Features plugin for Redmine issue tracking system; It is aimed to replace current Redmine's Documents module. Redmine DMSF is Document Management System Features plugin for Redmine issue tracking system; It is aimed to replace current Redmine's Documents module.
@ -37,7 +37,8 @@ Features
* Documents and folders symbolic links * Documents and folders symbolic links
* Document tagging * Document tagging
* Trash bin * Trash bin
* Compatible with Redmine 3.3.x * Documents attachable to issues
* Compatible with Redmine 3.4.x
Dependencies Dependencies
------------ ------------
@ -46,51 +47,76 @@ Dependencies
### Full-text search (optional) ### Full-text search (optional)
If you want to use fulltext search abilities: If you want to use fulltext search abilities, install xapian-omega and ruby-xapian packages. See https://xapian.org
for details.
* Xapian (<http://www.xapian.org>) search engine
* Xapian Omega indexing tool ```
* Xapian ruby bindings - xapian or xapian-full gem sudo apt-get install xapian-omega ruby-xapian
```
To index some files with omega you may have to install some other packages like To index some files with omega you may have to install some other packages like
xpdf, antiword, ... xpdf, antiword, ...
From Omega documentation: From Omega documentation:
* PDF (.pdf) if pdftotext is available (comes with xpdf) * HTML (.html, .htm, .shtml, .shtm, .xhtml, .xhtm)
* PostScript (.ps, .eps, .ai) if ps2pdf (from ghostscript) and pdftotext (comes with xpdf) are available * PHP (.php) - our HTML parser knows to ignore PHP code
* OpenOffice/StarOffice documents (.sxc, .stc, .sxd, .std, .sxi, .sti, .sxm, .sxw, .sxg, .stw) if unzip is available. * text files (.txt, .text)
* OpenDocument format documents (.odt, .ods, .odp, .odg, .odc, .odf, .odb, .odi, .odm, .ott, .ots, .otp, .otg, .otc, .otf, .oti, .oth) if unzip is available * SVG (.svg)
* MS Word documents (.doc, .dot) if antiword is available * CSV (Comma-Separated Values) files (.csv)
* MS Excel documents (.xls, .xlb, .xlt) if xls2csv is available (comes with catdoc) * PDF (.pdf) if pdftotext is available (comes with poppler or xpdf)
* MS Powerpoint documents (.ppt, .pps) if catppt is available (comes with catdoc) * PostScript (.ps, .eps, .ai) if ps2pdf (from ghostscript) and pdftotext (comes with poppler or xpdf) are available
* MS Office 2007 documents (.docx, .dotx, .xlsx, .xlst, .pptx, .potx, .ppsx) if unzip is available * OpenOffice/StarOffice documents (.sxc, .stc, .sxd, .std, .sxi, .sti, .sxm, .sxw, .sxg, .stw) if unzip is available
* Wordperfect documents (.wpd) if wpd2text is available (comes with libwpd) * OpenDocument format documents (.odt, .ods, .odp, .odg, .odc, .odf, .odb, .odi, .odm, .ott, .ots, .otp, .otg, .otc, .otf, .oti, .oth) if unzip is available
* MS Works documents (.wps, .wpt) if wps2text is available (comes with libwps) * MS Word documents (.dot) if antiword is available (.doc files are left to libmagic, as they may actually be RTF (AbiWord saves RTF when asked to save as .doc, and Microsoft Word quietly loads RTF files with a .doc extension), or plain-text).
* AbiWord documents (.abw) * MS Excel documents (.xls, .xlb, .xlt, .xlr, .xla) if xls2csv is available (comes with catdoc)
* Compressed AbiWord documents (.zabw) if gzip is available * MS Powerpoint documents (.ppt, .pps) if catppt is available (comes with catdoc)
* Rich Text Format documents (.rtf) if unrtf is available * MS Office 2007 documents (.docx, .docm, .dotx, .dotm, .xlsx, .xlsm, .xltx, .xltm, .pptx, .pptm, .potx, .potm, .ppsx, .ppsm) if unzip is available
* Perl POD documentation (.pl, .pm, .pod) if pod2text is available * Wordperfect documents (.wpd) if wpd2text is available (comes with libwpd)
* TeX DVI files (.dvi) if catdvi is available * MS Works documents (.wps, .wpt) if wps2text is available (comes with libwps)
* DjVu files (.djv, .djvu) if djvutxt is available * MS Outlook message (.msg) if perl with Email::Outlook::Message and HTML::Parser modules is available
* XPS files (.xps) if unzip is available * MS Publisher documents (.pub) if pub2xhtml is available (comes with libmspub)
* AbiWord documents (.abw)
* Compressed AbiWord documents (.zabw)
* Rich Text Format documents (.rtf) if unrtf is available
* Perl POD documentation (.pl, .pm, .pod) if pod2text is available
* reStructured text (.rst, .rest) if rst2html is available (comes with docutils)
* Markdown (.md, .markdown) if markdown is available
* TeX DVI files (.dvi) if catdvi is available
* DjVu files (.djv, .djvu) if djvutxt is available
* XPS files (.xps) if unzip is available
* Debian packages (.deb, .udeb) if dpkg-deb is available
* RPM packages (.rpm) if rpm is available
* Atom feeds (.atom)
* MAFF (.maff) if unzip is available
* MHTML (.mhtml, .mht) if perl with MIME::Tools is available
* MIME email messages (.eml) and USENET articles if perl with MIME::Tools and HTML::Parser is available
* vCard files (.vcf, .vcard) if perl with Text::vCard is available
You can use following commands to install some of the required indexing tools:
On Debian use: On Debian use:
```sudo apt-get install xapian-omega libxapian-dev xpdf poppler-utils \ ```
sudo apt-get install xapian-omega libxapian-dev xpdf poppler-utils \
antiword unzip catdoc libwpd-tools libwps-tools gzip unrtf catdvi \ antiword unzip catdoc libwpd-tools libwps-tools gzip unrtf catdvi \
djview djview3 uuid uuid-dev xz-utils``` djview djview3 uuid uuid-dev xz-utils libemail-outlook-message-perl
```
On Ubuntu use: On Ubuntu use:
```sudo apt-get install xapian-omega libxapian-dev xpdf poppler-utils antiword \ ```
sudo apt-get install xapian-omega libxapian-dev xpdf poppler-utils antiword \
unzip catdoc libwpd-tools libwps-tools gzip unrtf catdvi djview djview3 \ unzip catdoc libwpd-tools libwps-tools gzip unrtf catdvi djview djview3 \
uuid uuid-dev xz-utils``` uuid uuid-dev xz-utils libemail-outlook-message-perl
```
On CentOS user: On CentOS use:
```sudo yum install xapian-omega libxapian-dev xpdf poppler-utils antiword \ ```
sudo yum install xapian-omega libxapian-dev xpdf poppler-utils antiword \
unzip catdoc libwpd-tools libwps-tools gzip unrtf catdvi djview djview3 \ unzip catdoc libwpd-tools libwps-tools gzip unrtf catdvi djview djview3 \
uuid uuid-dev xz``` uuid uuid-dev xz libemail-outlook-message-perl
```
Usage Usage
----- -----
@ -190,7 +216,7 @@ In the file <redmine_root>/public/help/<language>/wiki_syntax.html, at the end o
<tr><th></th><td>{{dmsf(83)}}</td><td>Document <a href="#">#83</a></td></tr> <tr><th></th><td>{{dmsf(83)}}</td><td>Document <a href="#">#83</a></td></tr>
There's a patch that helps you to modify all help files at once. In your Redmine folder: There's a patch (tested with Redmine 3.4.2) that helps you to modify all help files at once. In your Redmine folder:
`cd redmine` `cd redmine`
@ -211,9 +237,9 @@ Before installing ensure that the Redmine instance is stopped.
6. Restart the web server. 6. Restart the web server.
7. You should configure the plugin via Redmine interface: Administration -> Plugins -> DMSF -> Configure. 7. You should configure the plugin via Redmine interface: Administration -> Plugins -> DMSF -> Configure.
8. Assign DMSF permissions to appropriate roles. 8. Assign DMSF permissions to appropriate roles.
9. There are two rake tasks: 9. There are a few rake tasks:
a) To convert documents from the standard Redmine document module I) To convert documents from the standard Redmine document module
Available options: Available options:
@ -229,21 +255,53 @@ Before installing ensure that the Redmine instance is stopped.
chown -R www-data:www-data /redmine/files/dmsf chown -R www-data:www-data /redmine/files/dmsf
afterwards) afterwards)
b) To alert all users who are expected to do an approval in the current approval steps II) To alert all users who are expected to do an approval in the current approval steps
Example: Example:
rake redmine:dmsf_alert_approvals RAILS_ENV="production" rake redmine:dmsf_alert_approvals RAILS_ENV="production"
III) To clears the Webdav Cache
Example:
rake redmine:dmsf_clear_webdav_cache RAILS_ENV="production"
IV) To create missing MD5 digest for all file revisions
Available options:
*dry_run - test, no changes to the 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"
V) To maintain DMSF
* Remove all files with no database record from the document directory
* Remove all links project_id = -1 (added links to an issue which hasn't been created)
Available options:
*dry_run - No physical deletion but to list of all unused files only
Example:
rake redmine:dmsf_maintenance RAILS_ENV="production"
rake redmine:dmsf_maintenance dry_run=1 RAILS_ENV="production"
### Fulltext search (optional) ### Fulltext search (optional)
If you want to use full-text search features, you must setup file content indexing. If you want to use full-text search features, you must setup file content indexing.
It is necessary to index DMSF files with omega before searching attempts to receive some output: It is necessary to index DMSF files with omindex before searching attempts to receive some output:
1. Change the configuration part of redmine_dmsf/extra/xapian_indexer.rb file according to your environment. 1. Change the configuration part of redmine_dmsf/extra/xapian_indexer.rb file according to your environment.
2. Run `ruby redmine_dmsf/extra/xapian_indexer.rb -f` (The path to the index database set in xapian_indexer.rb must corresponds to the path set in the plugin's settings.)
2. Run `ruby redmine_dmsf/extra/xapian_indexer.rb -vf`
This command must be run on regular basis (e.g. from cron) This command should be run on regular basis (e.g. from cron)
Example of cron job (once per hour at 8th minute): Example of cron job (once per hour at 8th minute):

83
after_init.rb Normal file
View File

@ -0,0 +1,83 @@
require_dependency 'zip'
require_dependency File.dirname(__FILE__) + '/lib/redmine_dmsf.rb'
def init
# Administration menu extension
Redmine::MenuManager.map :admin_menu do |menu|
menu.push :dmsf_approvalworkflows, :dmsf_workflows_path, :caption => :label_dmsf_workflow_plural,
:html => { :class => 'icon icon-approvalworkflows' }, :if => Proc.new { |_| User.current.admin? }
end
Redmine::MenuManager.map :project_menu do |menu|
menu.push :dmsf, { :controller => 'dmsf', :action => 'show' }, :caption => :menu_dmsf, :before => :documents,
:param => :id
end
# Permissions
Redmine::AccessControl.map do |map|
map.project_module :dmsf do |pmap|
pmap.permission :view_dmsf_file_revision_accesses,
:read => true
pmap.permission :view_dmsf_file_revisions,
:read => true
pmap.permission :view_dmsf_folders,
{:dmsf => [:show],
:dmsf_folders_copy => [:new, :copy_to, :move_to]},
:read => true
pmap.permission :user_preferences,
{:dmsf_state => [:user_pref_save]}
pmap.permission :view_dmsf_files,
{:dmsf => [:entries_operation, :entries_email, :download_email_entries, :tag_changed],
:dmsf_files => [:show, :view, :thumbnail],
:dmsf_files_copy => [:new, :create, :move],
:dmsf_workflows => [:log]},
:read => true
pmap.permission :email_documents,
{:dmsf_public_urls => [:create]}
pmap.permission :folder_manipulation,
{:dmsf => [:new, :create, :delete, :edit, :save, :edit_root, :save_root, :lock, :unlock,
:notify_activate, :notify_deactivate, :restore],
:dmsf_folder_permissions => [:new, :append, :autocomplete_for_user]}
pmap.permission :file_manipulation,
{:dmsf_files => [:create_revision, :lock, :unlock, :delete_revision, :notify_activate,
:notify_deactivate, :restore],
:dmsf_upload => [:upload_files, :upload_file, :upload, :commit_files, :commit,
:delete_dmsf_attachment, :delete_dmsf_link_attachment],
:dmsf_links => [:new, :create, :destroy, :restore, :autocomplete_for_project,
:autocomplete_for_folder]
}
pmap.permission :file_delete,
{ :dmsf => [:trash, :delete_entries],
:dmsf_files => [:delete]}
pmap.permission :force_file_unlock, {}
pmap.permission :file_approval,
{:dmsf_workflows => [:action, :new_action, :autocomplete_for_user, :start, :assign, :assignment]}
pmap.permission :manage_workflows,
{:dmsf_workflows => [:index, :new, :create, :destroy, :show, :new_step, :add_step, :remove_step,
:reorder_steps, :update, :update_step, :delete_step, :edit]}
pmap.permission :display_system_folders,
:read => true
end
end
end
unless Redmine::Plugin.installed?(:easy_extensions)
init
else
ActiveSupport.on_load(:easyproject, yield: true) do
init
end
end
ActionDispatch::Reloader.to_prepare do
# Rubyzip configuration
Zip.unicode_names = true
Redmine::Search.map do |search|
search.register :dmsf_files
search.register :dmsf_folders
end
Redmine::Activity.register :dmsf_file_revision_accesses, :default => false
Redmine::Activity.register :dmsf_file_revisions
end

View File

@ -1,4 +1,5 @@
# encoding: utf-8 # encoding: utf-8
# encoding: utf-8
# #
# Redmine plugin for Document Management System "Features" # Redmine plugin for Document Management System "Features"
# #
@ -23,17 +24,24 @@
class DmsfController < ApplicationController class DmsfController < ApplicationController
unloadable unloadable
before_filter :find_project before_action :find_project
before_filter :authorize, :except => [:expand_folder] before_action :authorize, :except => [:expand_folder]
before_filter :find_folder, :except => [:new, :create, :edit_root, :save_root] before_action :find_folder, :except => [:new, :create, :edit_root, :save_root]
before_filter :find_parent, :only => [:new, :create] before_action :find_parent, :only => [:new, :create]
before_filter :tree_view, :only => [:delete, :show] before_action :tree_view, :only => [:delete, :show]
before_action :permissions
accept_api_auth :show, :create, :save accept_api_auth :show, :create, :save
skip_before_action :verify_authenticity_token, if: -> { request.headers['HTTP_X_REDMINE_API_KEY'].present? } skip_before_action :verify_authenticity_token, if: -> { request.headers['HTTP_X_REDMINE_API_KEY'].present? }
helper :all helper :all
helper :dmsf_folder_permissions
def permissions
render_403 unless DmsfFolder.permissions?(@folder)
true
end
def expand_folder def expand_folder
@tree_view = true @tree_view = true
@ -73,13 +81,15 @@ class DmsfController < ApplicationController
@file_manipulation_allowed = User.current.allowed_to? :file_manipulation, @project @file_manipulation_allowed = User.current.allowed_to? :file_manipulation, @project
@file_delete_allowed = User.current.allowed_to? :file_delete, @project @file_delete_allowed = User.current.allowed_to? :file_delete, @project
@subfolders = DmsfFolder.deleted.where(:project_id => @project.id) @subfolders = DmsfFolder.deleted.where(:project_id => @project.id)
@files = DmsfFile.deleted.where(:container_id => @project.id, :container_type => 'Project') @files = DmsfFile.deleted.where(:project_id => @project.id)
@dir_links = DmsfLink.deleted.where(:project_id => @project.id, :target_type => DmsfFolder.model_name.to_s) @dir_links = DmsfLink.deleted.where(:project_id => @project.id, :target_type => DmsfFolder.model_name.to_s)
@file_links = DmsfLink.deleted.where(:project_id => @project.id, :target_type => DmsfFile.model_name.to_s) @file_links = DmsfLink.deleted.where(:project_id => @project.id, :target_type => DmsfFile.model_name.to_s)
@url_links = DmsfLink.deleted.where(:project_id => @project.id, :target_type => 'DmsfUrl') @url_links = DmsfLink.deleted.where(:project_id => @project.id, :target_type => 'DmsfUrl')
end end
def download_email_entries def download_email_entries
# IE has got a tendency to cache files
expires_in(0.year, "must-revalidate" => true)
send_file( send_file(
params[:path], params[:path],
:filename => 'Documents.zip', :filename => 'Documents.zip',
@ -150,6 +160,7 @@ class DmsfController < ApplicationController
if params[:dmsf_folder] && params[:dmsf_folder][:custom_field_values].present? if params[:dmsf_folder] && params[:dmsf_folder][:custom_field_values].present?
redirect_to dmsf_folder_path( redirect_to dmsf_folder_path(
:id => @project, :id => @project,
:folder_id => @folder,
:custom_field_id => params[:dmsf_folder][:custom_field_values].first[0], :custom_field_id => params[:dmsf_folder][:custom_field_values].first[0],
:custom_value => params[:dmsf_folder][:custom_field_values].first[1]) :custom_value => params[:dmsf_folder][:custom_field_values].first[1])
else else
@ -174,25 +185,18 @@ class DmsfController < ApplicationController
render :action => 'edit' render :action => 'edit'
end end
def edit
@parent = @folder.dmsf_folder
@pathfolder = copy_folder(@folder)
@force_file_unlock_allowed = User.current.allowed_to?(:force_file_unlock, @project)
@users = Principal.active.where(:id => @folder.dmsf_folder_permissions.users.map{ |p| p.object_id })
end
def create def create
@folder = DmsfFolder.new @folder = DmsfFolder.new
@folder.title = params[:dmsf_folder][:title].strip
@folder.description = params[:dmsf_folder][:description].strip
@folder.dmsf_folder_id = params[:dmsf_folder][:dmsf_folder_id]
@folder.project = @project @folder.project = @project
@folder.user = User.current @folder.user = User.current
saved = @folder.update_from_params(params)
# Custom fields
if params[:dmsf_folder][:custom_field_values].present?
params[:dmsf_folder][:custom_field_values].each_with_index do |v, i|
@folder.custom_field_values[i].value = v[1]
end
end
saved = @folder.save
respond_to do |format| respond_to do |format|
format.js format.js
format.api { format.api {
@ -203,7 +207,7 @@ class DmsfController < ApplicationController
format.html { format.html {
if saved if saved
flash[:notice] = l(:notice_folder_created) flash[:notice] = l(:notice_folder_created)
redirect_to dmsf_folder_path(:id => @project, :folder_id => @folder) redirect_to dmsf_folder_path(:id => @project, :folder_id => @folder.dmsf_folder)
else else
@pathfolder = @parent @pathfolder = @parent
render :action => 'edit' render :action => 'edit'
@ -213,30 +217,13 @@ class DmsfController < ApplicationController
end end
def edit
@parent = @folder.dmsf_folder
@pathfolder = copy_folder(@folder)
@force_file_unlock_allowed = User.current.allowed_to?(:force_file_unlock, @project)
end
def save def save
unless params[:dmsf_folder] unless params[:dmsf_folder]
redirect_to dmsf_folder_path(:id => @project, :folder_id => @folder) redirect_to dmsf_folder_path(:id => @project, :folder_id => @folder)
return return
end end
@pathfolder = copy_folder(@folder) @pathfolder = copy_folder(@folder)
@folder.title = params[:dmsf_folder][:title].strip saved = @folder.update_from_params(params)
@folder.description = params[:dmsf_folder][:description].strip
@folder.dmsf_folder_id = params[:dmsf_folder][:dmsf_folder_id]
# Custom fields
if params[:dmsf_folder][:custom_field_values].present?
params[:dmsf_folder][:custom_field_values].each_with_index do |v, i|
@folder.custom_field_values[i].value = v[1]
end
end
saved = @folder.save
respond_to do |format| respond_to do |format|
format.api { format.api {
unless saved unless saved
@ -246,7 +233,7 @@ class DmsfController < ApplicationController
format.html { format.html {
if saved if saved
flash[:notice] = l(:notice_folder_details_were_saved) flash[:notice] = l(:notice_folder_details_were_saved)
redirect_to dmsf_folder_path(:id => @project, :folder_id => @folder) redirect_to dmsf_folder_path(:id => @project, :folder_id => @folder.dmsf_folder)
else else
render :action => 'edit' render :action => 'edit'
end end
@ -529,7 +516,7 @@ class DmsfController < ApplicationController
recipients.each do |u| recipients.each do |u|
DmsfMailer.files_deleted(u, @project, deleted_files).deliver DmsfMailer.files_deleted(u, @project, deleted_files).deliver
end end
if Setting.plugin_redmine_dmsf[:dmsf_display_notified_recipients] == '1' if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] == '1'
unless recipients.empty? unless recipients.empty?
to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ')
to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.') to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.')
@ -563,7 +550,8 @@ class DmsfController < ApplicationController
def find_folder_by_title def find_folder_by_title
# find by title has to be scoped to project # find by title has to be scoped to project
@folder = DmsfFolder.find_by(title: params[:folder_title], project_id: params[:id]) if params[:folder_title].present? project = Project.find(params[:id])
@folder = DmsfFolder.find_by(title: params[:folder_title], project_id: project.id) if params[:folder_title].present?
rescue DmsfAccessError rescue DmsfAccessError
render_403 render_403
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
@ -592,6 +580,7 @@ class DmsfController < ApplicationController
private private
def get_display_params def get_display_params
@system_folder = @folder && @folder.system
@folder_manipulation_allowed = User.current.allowed_to?(:folder_manipulation, @project) @folder_manipulation_allowed = User.current.allowed_to?(:folder_manipulation, @project)
@file_manipulation_allowed = User.current.allowed_to?(:file_manipulation, @project) @file_manipulation_allowed = User.current.allowed_to?(:file_manipulation, @project)
@file_delete_allowed = User.current.allowed_to?(:file_delete, @project) @file_delete_allowed = User.current.allowed_to?(:file_delete, @project)
@ -600,93 +589,82 @@ class DmsfController < ApplicationController
@workflows_available = DmsfWorkflow.where(['project_id = ? OR project_id IS NULL', @project.id]).exists? @workflows_available = DmsfWorkflow.where(['project_id = ? OR project_id IS NULL', @project.id]).exists?
@file_approval_allowed = User.current.allowed_to?(:file_approval, @project) @file_approval_allowed = User.current.allowed_to?(:file_approval, @project)
tag = params[:custom_field_id].present? && params[:custom_value].present? tag = params[:custom_field_id].present? && params[:custom_value].present?
@folder = nil if tag @extra_columns = [l(:label_last_approver), l(:field_project), l(:label_document_url), l(:label_last_revision_id)]
@extra_columns = [l(:field_project), l(:label_document_url), l(:label_last_revision_id)]
if @tree_view if @tree_view
@locked_for_user = false @locked_for_user = false
else else
unless @folder if tag
if tag @subfolders = []
@subfolders = [] folder_id = @folder.id if @folder
DmsfFolder.where(:project_id => @project.id).visible.each do |f| DmsfFolder.where(:project_id => @project.id, :dmsf_folder_id => folder_id, :system => false).visible.each do |f|
f.custom_field_values.each do |v| f.custom_field_values.each do |v|
if v.custom_field_id == params[:custom_field_id].to_i
if v.custom_field.compare_values?(v.value, params[:custom_value])
@subfolders << f
break
end
end
end
end
@files = []
DmsfFile.where(:project_id => @project.id, :dmsf_folder_id => folder_id).visible.each do |f|
r = f.last_revision
if r
r.custom_field_values.each do |v|
if v.custom_field_id == params[:custom_field_id].to_i if v.custom_field_id == params[:custom_field_id].to_i
if v.custom_field.compare_values?(v.value, params[:custom_value]) if v.custom_field.compare_values?(v.value, params[:custom_value])
@subfolders << f @files << f
break break
end end
end end
end end
end end
@files = [] end
DmsfFile.where(:container_id => @project.id, :container_type => 'Project').visible.each do |f| @dir_links = []
r = f.last_revision DmsfLink.where(:project_id => @project.id, :target_type => DmsfFolder.model_name.to_s, :dmsf_folder_id => folder_id).where('target_id IS NOT NULL').visible.each do |l|
if r l.target_folder.custom_field_values.each do |v|
r.custom_field_values.each do |v| if v.custom_field_id == params[:custom_field_id].to_i
if v.custom_field_id == params[:custom_field_id].to_i if v.custom_field.compare_values?(v.value, params[:custom_value])
if v.custom_field.compare_values?(v.value, params[:custom_value]) @dir_links << l
@files << f break
break
end
end
end end
end end
end end
@dir_links = [] end
DmsfLink.where(:project_id => @project.id, :target_type => DmsfFolder.model_name.to_s).visible.each do |l| @file_links = []
l.target_folder.custom_field_values.each do |v| DmsfLink.where(:project_id => @project.id, :target_type => DmsfFile.model_name.to_s, :dmsf_folder_id => folder_id).visible.each do |l|
r = l.target_file.last_revision if l.target_file
if r
r.custom_field_values.each do |v|
if v.custom_field_id == params[:custom_field_id].to_i if v.custom_field_id == params[:custom_field_id].to_i
if v.custom_field.compare_values?(v.value, params[:custom_value]) if v.custom_field.compare_values?(v.value, params[:custom_value])
@dir_links << l @file_links << l
break break
end end
end end
end end
end end
@file_links = [] end
DmsfLink.where(:project_id => @project.id, :target_type => DmsfFile.model_name.to_s).visible.each do |l| @url_links = []
r = l.target_file.last_revision if l.target_file else
if r if @folder
r.custom_field_values.each do |v| @subfolders = @folder.dmsf_folders.visible.to_a
if v.custom_field_id == params[:custom_field_id].to_i @files = @folder.dmsf_files.visible
if v.custom_field.compare_values?(v.value, params[:custom_value]) @dir_links = @folder.folder_links.visible
@file_links << l @file_links = @folder.file_links.visible
break @url_links = @folder.url_links.visible
end @locked_for_user = @folder.locked_for_user?
end
end
end
end
@url_links = []
DmsfLink.where(:project_id => @project.id, :target_type => 'DmsfUrl').visible.each do |l|
r = l.target_file.last_revision if l.target_file
if r
r.custom_field_values.each do |v|
if v.custom_field_id == params[:custom_field_id].to_i
if v.custom_field.compare_values?(v.value, params[:custom_value])
@file_links << l
break
end
end
end
end
end
else else
@subfolders = @project.dmsf_folders.visible @subfolders = @project.dmsf_folders.visible.to_a
@files = @project.dmsf_files.visible @files = @project.dmsf_files.visible
@dir_links = @project.folder_links.visible @dir_links = @project.folder_links.visible
@file_links = @project.file_links.visible @file_links = @project.file_links.visible
@url_links = @project.url_links.visible @url_links = @project.url_links.visible
@locked_for_user = false
end end
@locked_for_user = false
else
@subfolders = @folder.dmsf_folders.visible
@files = @folder.dmsf_files.visible
@dir_links = @folder.folder_links.visible
@file_links = @folder.file_links.visible
@url_links = @folder.url_links.visible
@locked_for_user = @folder.locked_for_user?
end end
# Remove system folders you are not allowed to see because you are not allowed to see the issue
@subfolders = DmsfHelper.visible_folders(@subfolders, @project)
end end
@ajax_upload_size = Setting.plugin_redmine_dmsf['dmsf_max_ajax_upload_filesize'].present? ? Setting.plugin_redmine_dmsf['dmsf_max_ajax_upload_filesize'] : 100 @ajax_upload_size = Setting.plugin_redmine_dmsf['dmsf_max_ajax_upload_filesize'].present? ? Setting.plugin_redmine_dmsf['dmsf_max_ajax_upload_filesize'] : 100
@ -695,7 +673,7 @@ class DmsfController < ApplicationController
@trash_visible = @folder_manipulation_allowed && @file_manipulation_allowed && @trash_visible = @folder_manipulation_allowed && @file_manipulation_allowed &&
@file_delete_allowed && !@locked_for_user && !@folder @file_delete_allowed && !@locked_for_user && !@folder
@trash_enabled = DmsfFolder.deleted.where(:project_id => @project.id).any? || @trash_enabled = DmsfFolder.deleted.where(:project_id => @project.id).any? ||
DmsfFile.deleted.where(:container_id => @project.id, :container_type => 'Project').any? || DmsfFile.deleted.where(:project_id => @project.id).any? ||
DmsfLink.deleted.where(:project_id => @project.id).any? DmsfLink.deleted.where(:project_id => @project.id).any?
end end

View File

@ -24,10 +24,11 @@ class DmsfFilesController < ApplicationController
menu_item :dmsf menu_item :dmsf
before_filter :find_file, :except => [:delete_revision] before_action :find_file, :except => [:delete_revision]
before_filter :find_revision, :only => [:delete_revision] before_action :find_revision, :only => [:delete_revision]
before_filter :authorize before_action :authorize
before_filter :tree_view, :only => [:delete] before_action :tree_view, :only => [:delete]
before_action :permissions
accept_api_auth :show accept_api_auth :show
@ -35,6 +36,13 @@ class DmsfFilesController < ApplicationController
helper :dmsf_workflows helper :dmsf_workflows
helper :dmsf helper :dmsf
def permissions
if @file
render_403 unless DmsfFolder.permissions?(@file.dmsf_folder)
end
true
end
def view def view
begin begin
if params[:download].blank? if params[:download].blank?
@ -57,6 +65,8 @@ class DmsfFilesController < ApplicationController
else else
title_format = Setting.plugin_redmine_dmsf['dmsf_global_title_format'] title_format = Setting.plugin_redmine_dmsf['dmsf_global_title_format']
end end
# IE has got a tendency to cache files
expires_in(0.year, "must-revalidate" => true)
send_file(@revision.disk_file, send_file(@revision.disk_file,
:filename => filename_for_content_disposition(@revision.formatted_name(title_format)), :filename => filename_for_content_disposition(@revision.formatted_name(title_format)),
:type => @revision.detect_content_type, :type => @revision.detect_content_type,
@ -121,10 +131,12 @@ class DmsfFilesController < ApplicationController
end end
else else
upload = DmsfUpload.create_from_uploaded_attachment(@project, @folder, file_upload) upload = DmsfUpload.create_from_uploaded_attachment(@project, @folder, file_upload)
revision.size = upload.size if upload
revision.disk_filename = revision.new_storage_filename revision.size = upload.size
revision.mime_type = upload.mime_type revision.disk_filename = revision.new_storage_filename
revision.digest = DmsfFileRevision.create_digest upload.disk_file revision.mime_type = upload.mime_type
revision.digest = DmsfFileRevision.create_digest upload.tempfile_path
end
end end
# Custom fields # Custom fields
@ -139,7 +151,7 @@ class DmsfFilesController < ApplicationController
if revision.save if revision.save
revision.assign_workflow(params[:dmsf_workflow_id]) revision.assign_workflow(params[:dmsf_workflow_id])
if upload if upload
FileUtils.mv(upload.disk_file, revision.disk_file) FileUtils.mv(upload.tempfile_path, revision.disk_file(false))
end end
if @file.locked? && !@file.locks.empty? if @file.locked? && !@file.locks.empty?
begin begin
@ -158,7 +170,7 @@ class DmsfFilesController < ApplicationController
recipients.each do |u| recipients.each do |u|
DmsfMailer.files_updated(u, @project, [@file]).deliver DmsfMailer.files_updated(u, @project, [@file]).deliver
end end
if Setting.plugin_redmine_dmsf[:dmsf_display_notified_recipients] == '1' if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] == '1'
unless recipients.empty? unless recipients.empty?
to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ')
to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.') to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.')
@ -184,14 +196,14 @@ class DmsfFilesController < ApplicationController
commit = params[:commit] == 'yes' commit = params[:commit] == 'yes'
if @file.delete(commit) if @file.delete(commit)
flash[:notice] = l(:notice_file_deleted) flash[:notice] = l(:notice_file_deleted)
if commit && (@file.container_type == 'Project') if commit
log_activity('deleted') log_activity('deleted')
begin begin
recipients = DmsfMailer.get_notify_users(@project, [@file]) recipients = DmsfMailer.get_notify_users(@project, [@file])
recipients.each do |u| recipients.each do |u|
DmsfMailer.files_deleted(u, @project, [@file]).deliver DmsfMailer.files_deleted(u, @project, [@file]).deliver
end end
if Setting.plugin_redmine_dmsf[:dmsf_display_notified_recipients] == '1' if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] == '1'
unless recipients.empty? unless recipients.empty?
to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ')
to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.') to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.')
@ -300,7 +312,7 @@ class DmsfFilesController < ApplicationController
:disposition => 'inline' :disposition => 'inline'
end end
else else
render :nothing => true, :status => 404 head 404
end end
end end

View File

@ -1,6 +1,7 @@
# Redmine plugin for Document Management System "Features" # Redmine plugin for Document Management System "Features"
# #
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com> # Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright (C) 2011-17 Karel Pičman <karel.picman@kontron.com>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@ -21,11 +22,19 @@ class DmsfFilesCopyController < ApplicationController
menu_item :dmsf menu_item :dmsf
before_filter :find_file before_action :find_file
before_filter :authorize before_action :authorize
before_action :permissions
helper :all helper :all
def permissions
if @file
render_403 unless DmsfFolder.permissions?(@file.dmsf_folder)
end
true
end
def new def new
@target_project = DmsfFile.allowed_target_projects_on_copy.detect {|p| p.id.to_s == params[:target_project_id]} if params[:target_project_id] @target_project = DmsfFile.allowed_target_projects_on_copy.detect {|p| p.id.to_s == params[:target_project_id]} if params[:target_project_id]
@target_project ||= @project if User.current.allowed_to?(:file_manipulation, @project) @target_project ||= @project if User.current.allowed_to?(:file_manipulation, @project)
@ -108,12 +117,15 @@ class DmsfFilesCopyController < ApplicationController
private private
def log_activity(file, action) 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}" if file && file.last_revision
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}"
end
end end
def find_file def find_file
@file = DmsfFile.visible.find(params[:id]) @file = DmsfFile.visible.find_by_id params[:id]
@project = @file.project @project = @file.project if @file
end end
end end

View File

@ -0,0 +1,68 @@
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-17 Karel Pičman <karel.picman@konton.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 DmsfFolderPermissionsController < ApplicationController
unloadable
before_action :find_folder, :only => [:destroy]
before_action :find_project
before_action :authorize
before_action :permissions
def permissions
render_403 unless DmsfFolder.permissions?(@dmsf_folder)
true
end
def new
@principals = users_for_new_users
end
def append
@principals = Principal.where(:id => params[:user_ids]).to_a
head 200 if @principals.blank?
end
def autocomplete_for_user
@principals = users_for_new_users
respond_to do |format|
format.js
end
end
private
def users_for_new_users
Principal.active.visible.member_of(@project).like(params[:q]).order(:type, :lastname).to_a
end
def find_project
if params[:project_id]
@project = Project.visible.find_by_param(params[:project_id])
end
end
def find_folder
if params[:dmsf_folder_id]
@dmsf_folder = DmsfFolder.visible.find_by_id(params[:dmsf_folder_id])
end
end
end

View File

@ -21,8 +21,14 @@ class DmsfFoldersCopyController < ApplicationController
menu_item :dmsf menu_item :dmsf
before_filter :find_folder before_action :find_folder
before_filter :authorize before_action :authorize
before_action :permissions
def permissions
render_403 unless DmsfFolder.permissions?(@folder)
true
end
def new def new
@target_project = DmsfFolder.allowed_target_projects_on_copy.detect {|p| p.id.to_s == params[:target_project_id]} if params[:target_project_id] @target_project = DmsfFolder.allowed_target_projects_on_copy.detect {|p| p.id.to_s == params[:target_project_id]} if params[:target_project_id]
@ -80,8 +86,8 @@ class DmsfFoldersCopyController < ApplicationController
end end
def find_folder def find_folder
@folder = DmsfFolder.visible.find(params[:id]) @folder = DmsfFolder.visible.find_by_id(params[:id])
@project = @folder.project @project = @folder.project if @folder
end end
end end

View File

@ -22,9 +22,18 @@ class DmsfLinksController < ApplicationController
unloadable unloadable
model_object DmsfLink model_object DmsfLink
before_filter :find_model_object, :only => [:destroy, :restore] before_action :find_model_object, :only => [:destroy, :restore]
before_filter :find_link_project before_action :find_link_project
before_filter :authorize before_action :authorize
before_action :permissions
protect_from_forgery except: :new
def permissions
if @dmsf_link
render_403 unless DmsfFolder.permissions?(@dmsf_link.dmsf_folder)
end
true
end
def initialize def initialize
@dmsf_link = nil @dmsf_link = nil
@ -35,109 +44,78 @@ class DmsfLinksController < ApplicationController
def new def new
@dmsf_link = DmsfLink.new @dmsf_link = DmsfLink.new
@dmsf_link.project_id = params[:project_id] @dmsf_link.project_id = params[:project_id]
@dmsf_link.dmsf_folder_id = params[:dmsf_folder_id]
if params[:dmsf_link].present? @dmsf_file_id = params[:dmsf_file_id]
# Reload @type = params[:type]
@dmsf_link.dmsf_folder_id = params[:dmsf_link][:dmsf_folder_id] @dmsf_link.target_project_id = params[:project_id]
@dmsf_file_id = params[:dmsf_link][:dmsf_file_id] @dmsf_link.project_id = params[:project_id]
@type = params[:dmsf_link][:type] @target_folder_id = params[:dmsf_folder_id].to_i if params[:dmsf_folder_id].present?
@link_external = (@type == 'link_from') && (params[:external_link] == 'true') if @type == 'link_to'
@dmsf_link.target_project_id = params[:dmsf_link][:target_project_id] if @dmsf_file_id
@target_folder_id = params[:dmsf_link][:target_folder_id].to_i if params[:reload].blank? && DmsfLinksHelper.is_a_number?(params[:dmsf_link][:target_folder_id]) file = DmsfFile.find_by_id @dmsf_file_id
if @type == 'link_to' @dmsf_link.name = file.title if file
if params[:dmsf_link][:dmsf_file_id].present?
file = DmsfFile.find_by_id params[:dmsf_link][:dmsf_file_id]
@dmsf_link.name = file.title if file
else
folder = DmsfFolder.find_by_id params[:dmsf_link][:dmsf_folder_id]
@dmsf_link.name = folder.title if folder
end
else else
if params[:dmsf_link][:target_file_id].present? folder = DmsfFolder.find_by_id @target_folder_id
@target_file_id = params[:dmsf_link][:target_file_id] @dmsf_link.name = folder.title if folder
file = DmsfFile.find_by_id @target_file_id
if file
folder = DmsfFolder.find_by_id params[:dmsf_link][:target_folder_id]
if (folder && (folder.project_id == @dmsf_link.target_project_id) && folder.dmsf_files.include?(file)) || folder.nil?
@dmsf_link.name = file.title
end
end
else
folder = DmsfFolder.find_by_id params[:dmsf_link][:target_folder_id]
if folder
if folder.project_id == @dmsf_link.target_project_id
@dmsf_link.name = folder.title if folder
end
end
end
end
else
# Link from/to
@dmsf_link.dmsf_folder_id = params[:dmsf_folder_id]
@dmsf_file_id = params[:dmsf_file_id]
@type = params[:type]
@link_external = false
@dmsf_link.target_project_id = params[:project_id]
@dmsf_link.project_id = params[:project_id]
@target_folder_id = params[:dmsf_folder_id].to_i if params[:dmsf_folder_id].present?
if @type == 'link_to'
if @dmsf_file_id
file = DmsfFile.find_by_id @dmsf_file_id
@dmsf_link.name = file.title if file
else
folder = DmsfFolder.find_by_id @target_folder_id
@dmsf_link.name = folder.title if folder
end
end end
end end
@container = params[:container]
respond_to do |format|
format.html
format.js
end
end
render :layout => !request.xhr? def autocomplete_for_project
respond_to do |format|
format.js
end
end
def autocomplete_for_folder
respond_to do |format|
format.js
end
end end
def create def create
@dmsf_link = DmsfLink.new @dmsf_link = DmsfLink.new
@dmsf_link.user = User.current @dmsf_link.user = User.current
if params[:dmsf_link][:type] == 'link_from' if params[:dmsf_link][:type] == 'link_from'
# Link from # Link from
@dmsf_link.project_id = params[:dmsf_link][:project_id] if params[:dmsf_link][:container].blank?
@dmsf_link.dmsf_folder_id = params[:dmsf_link][:dmsf_folder_id] @dmsf_link.project_id = params[:dmsf_link][:project_id]
@dmsf_link.dmsf_folder_id = params[:dmsf_link][:dmsf_folder_id]
else
# A container link
@dmsf_link.project_id = -1
@dmsf_link.dmsf_folder_id = nil
end
@dmsf_link.target_project_id = params[:dmsf_link][:target_project_id] @dmsf_link.target_project_id = params[:dmsf_link][:target_project_id]
@link_external = (params[:external_link] == 'true') if (params[:external_link] == 'true')
@dmsf_link.external_url = params[:dmsf_link][:external_url] @dmsf_link.external_url = params[:dmsf_link][:external_url]
if (@link_external)
@dmsf_link.target_type = 'DmsfUrl' @dmsf_link.target_type = 'DmsfUrl'
elsif params[:dmsf_link][:target_file_id].present? elsif params[:dmsf_link][:target_file_id].present?
@dmsf_link.target_id = params[:dmsf_link][:target_file_id] @dmsf_link.target_id = params[:dmsf_link][:target_file_id]
@dmsf_link.target_type = DmsfFile.model_name.to_s @dmsf_link.target_type = DmsfFile.model_name.to_s
else else
@dmsf_link.target_id = DmsfLinksHelper.is_a_number?(params[:dmsf_link][:target_folder_id]) ? params[:dmsf_link][:target_folder_id].to_i : nil @dmsf_link.target_id = DmsfLinksHelper.is_a_number?(
params[:dmsf_link][:target_folder_id]) ? params[:dmsf_link][:target_folder_id].to_i : nil
@dmsf_link.target_type = DmsfFolder.model_name.to_s @dmsf_link.target_type = DmsfFolder.model_name.to_s
end end
@dmsf_link.name = params[:dmsf_link][:name] @dmsf_link.name = params[:dmsf_link][:name]
if @dmsf_link.save if @dmsf_link.save
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
redirect_to dmsf_folder_path(:id => @project.id, :folder_id => @dmsf_link.dmsf_folder_id)
else else
@dmsf_file_id = params[:dmsf_link][:dmsf_file_id] flash[:error] = @dmsf_link.errors.full_messages.to_sentence
@type = params[:dmsf_link][:type]
@target_folder_id = params[:dmsf_link][:target_folder_id].to_i if DmsfLinksHelper.is_a_number?(params[:dmsf_link][:target_folder_id])
@target_file_id = @dmsf_link.target_id if @dmsf_link.target_type == DmsfFile.model_name.to_s
render :action => 'new'
end end
else else
# Link to # Link to
@dmsf_link.project_id = params[:dmsf_link][:target_project_id] @dmsf_link.project_id = params[:dmsf_link][:target_project_id]
@dmsf_link.dmsf_folder_id = DmsfLinksHelper.is_a_number?(params[:dmsf_link][:target_folder_id]) ? params[:dmsf_link][:target_folder_id].to_i : nil @dmsf_link.dmsf_folder_id = DmsfLinksHelper.is_a_number?(
params[:dmsf_link][:target_folder_id]) ? params[:dmsf_link][:target_folder_id].to_i : nil
@dmsf_link.target_project_id = params[:dmsf_link][:project_id] @dmsf_link.target_project_id = params[:dmsf_link][:project_id]
@link_external = (params[:external_link] == 'true') if params[:dmsf_link][:dmsf_file_id].present?
@dmsf_link.external_url = params[:dmsf_link][:external_url]
if (@link_external)
@dmsf_link.target_type = 'DmsfUrl'
elsif params[:dmsf_link][:dmsf_file_id].present?
@dmsf_link.target_id = params[:dmsf_link][:dmsf_file_id] @dmsf_link.target_id = params[:dmsf_link][:dmsf_file_id]
@dmsf_link.target_type = DmsfFile.model_name.to_s @dmsf_link.target_type = DmsfFile.model_name.to_s
else else
@ -145,24 +123,26 @@ class DmsfLinksController < ApplicationController
@dmsf_link.target_type = DmsfFolder.model_name.to_s @dmsf_link.target_type = DmsfFolder.model_name.to_s
end end
@dmsf_link.name = params[:dmsf_link][:name] @dmsf_link.name = params[:dmsf_link][:name]
if @dmsf_link.save if @dmsf_link.save
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
if params[:dmsf_link][:dmsf_file_id].present?
redirect_to dmsf_file_path(@dmsf_link.target_file)
else
redirect_to edit_dmsf_path(:id => params[:dmsf_link][:project_id], :folder_id => params[:dmsf_link][:dmsf_folder_id])
end
else else
@dmsf_file_id = params[:dmsf_link][:dmsf_file_id] flash[:error] = @dmsf_link.errors.full_messages.to_sentence
@type = params[:dmsf_link][:type]
@target_folder_id = @dmsf_link.dmsf_folder_id
@dmsf_link.target_project_id = @dmsf_link.project.id
@dmsf_link.project_id = params[:dmsf_link][:project_id]
@dmsf_link.dmsf_folder_id = params[:dmsf_link][:dmsf_folder_id]
render :action => 'new'
end end
end end
respond_to do |format|
format.html {
if params[:dmsf_link][:type] == 'link_from'
redirect_to dmsf_folder_path(:id => @project.id, :folder_id => @dmsf_link.dmsf_folder_id)
else
if params[:dmsf_link][:dmsf_file_id].present?
redirect_to dmsf_file_path(@dmsf_link.target_file)
else
redirect_to edit_dmsf_path(:id => params[:dmsf_link][:project_id], :folder_id => params[:dmsf_link][:dmsf_folder_id])
end
end
}
format.js
end
end end
def destroy def destroy

View File

@ -22,14 +22,16 @@ class DmsfPublicUrlsController < ApplicationController
unloadable unloadable
model_object DmsfPublicUrl model_object DmsfPublicUrl
before_filter :authorize, :only => [:create] before_action :authorize, :only => [:create]
skip_before_filter :check_if_login_required, :only => [:show] skip_before_action :check_if_login_required, :only => [:show]
def show def show
dmsf_public_url = DmsfPublicUrl.where('token = ? AND expire_at >= ?', params[:token], DateTime.now).first dmsf_public_url = DmsfPublicUrl.where('token = ? AND expire_at >= ?', params[:token], DateTime.now).first
if dmsf_public_url if dmsf_public_url
revision = dmsf_public_url.dmsf_file.last_revision revision = dmsf_public_url.dmsf_file.last_revision
begin begin
# IE has got a tendency to cache files
expires_in(0.year, "must-revalidate" => true)
send_file(revision.disk_file, send_file(revision.disk_file,
:filename => filename_for_content_disposition(revision.name), :filename => filename_for_content_disposition(revision.name),
:type => revision.detect_content_type, :type => revision.detect_content_type,

View File

@ -24,8 +24,8 @@ class DmsfStateController < ApplicationController
menu_item :dmsf menu_item :dmsf
before_filter :find_project before_action :find_project
before_filter :authorize before_action :authorize
def user_pref_save def user_pref_save
member = @project.members.where(:user_id => User.current.id).first member = @project.members.where(:user_id => User.current.id).first
@ -39,7 +39,10 @@ class DmsfStateController < ApplicationController
end end
else else
flash[:warning] = l(:user_is_not_project_member) flash[:warning] = l(:user_is_not_project_member)
end end
if Setting.plugin_redmine_dmsf['dmsf_act_as_attachable']
@project.update_attribute :dmsf_act_as_attachable, params[:act_as_attachable]
end
redirect_to settings_project_path(@project, :tab => 'dmsf') redirect_to settings_project_path(@project, :tab => 'dmsf')
end end

View File

@ -24,16 +24,22 @@ class DmsfUploadController < ApplicationController
menu_item :dmsf menu_item :dmsf
before_filter :find_project, :except => [:upload, :delete_dmsf_attachment] before_action :find_project, :except => [:upload, :delete_dmsf_attachment, :delete_dmsf_link_attachment]
before_filter :authorize, :except => [:upload, :delete_dmsf_attachment] before_action :authorize, :except => [:upload, :delete_dmsf_attachment, :delete_dmsf_link_attachment]
before_filter :authorize_global, :only => [:upload, :delete_dmsf_attachment] before_action :authorize_global, :only => [:upload, :delete_dmsf_attachment, :delete_dmsf_link_attachment]
before_filter :find_folder, :except => [:upload_file, :upload, :commit, :delete_dmsf_attachment] before_action :find_folder, :except => [:upload_file, :upload, :commit, :delete_dmsf_attachment, :delete_dmsf_link_attachment]
before_action :permissions, :except => [:upload_file, :upload, :commit, :delete_dmsf_attachment, :delete_dmsf_link_attachment]
helper :all helper :all
helper :dmsf_workflows helper :dmsf_workflows
accept_api_auth :upload, :commit accept_api_auth :upload, :commit
def permissions
render_403 unless DmsfFolder.permissions?(@folder)
true
end
def upload_files def upload_files
uploaded_files = params[:dmsf_attachments] uploaded_files = params[:dmsf_attachments]
@uploads = [] @uploads = []
@ -56,42 +62,23 @@ class DmsfUploadController < ApplicationController
# async single file upload handling # async single file upload handling
def upload_file def upload_file
@tempfile = params[:file]
unless @tempfile.original_filename
render_404
return
end
@disk_filename = DmsfHelper.temp_filename(@tempfile.original_filename)
target = "#{DmsfHelper.temp_dir}/#{@disk_filename}"
begin begin
FileUtils.cp @tempfile.path, target @tempfile = params[:file]
FileUtils.chmod 'u=wr,g=r', target unless @tempfile.original_filename
rescue Exception => e render_404
Rails.logger.error e.message return
end
if File.size(target) <= 0
begin
File.delete target
rescue Exception => e
Rails.logger.error e.message
end end
render :layout => nil, :json => { :jsonrpc => '2.0', @disk_filename = DmsfHelper.temp_filename(@tempfile.original_filename)
:error => {
:code => 103,
:message => l(:header_minimum_filesize),
:details => l(:error_minimum_filesize,
:file => @tempfile.original_filename.to_s)
}
}
else
render :layout => false render :layout => false
ensure
@tempfile.close false
end end
end end
# REST API document upload # REST API and Redmine attachment form
def upload def upload
unless request.content_type == 'application/octet-stream' unless request.content_type == 'application/octet-stream'
render :nothing => true, :status => 406 head 406
return return
end end
@ -127,7 +114,10 @@ class DmsfUploadController < ApplicationController
uploaded_files = attachments.select { |key, value| key == 'uploaded_file'} uploaded_files = attachments.select { |key, value| key == 'uploaded_file'}
uploaded_files.each_value do |uploaded_file| uploaded_files.each_value do |uploaded_file|
upload = DmsfUpload.create_from_uploaded_attachment(@project, @folder, uploaded_file) upload = DmsfUpload.create_from_uploaded_attachment(@project, @folder, uploaded_file)
uploaded_file[:disk_filename] = upload.disk_filename if upload
uploaded_file[:disk_filename] = upload.disk_filename
uploaded_file[:tempfile_path] = upload.tempfile_path
end
end end
commit_files_internal uploaded_files commit_files_internal uploaded_files
end end
@ -140,6 +130,13 @@ class DmsfUploadController < ApplicationController
render_404 render_404
end end
def delete_dmsf_link_attachment
link = DmsfLink.find(params[:id])
link.destroy
rescue ActiveRecord::RecordNotFound
render_404
end
private private
def commit_files_internal(commited_files) def commit_files_internal(commited_files)

View File

@ -22,12 +22,21 @@ class DmsfWorkflowsController < ApplicationController
unloadable unloadable
model_object DmsfWorkflow model_object DmsfWorkflow
before_filter :find_model_object, :except => [:create, :new, :index, :assign, :assignment] before_action :find_model_object, :except => [:create, :new, :index, :assign, :assignment]
before_filter :find_project before_action :find_project
before_filter :authorize_custom before_action :authorize_custom
before_action :permissions, :only => [:new_action, :assignment, :start]
layout :workflows_layout layout :workflows_layout
def permissions
revision = DmsfFileRevision.find_by_id params[:dmsf_file_revision_id] if params[:dmsf_file_revision_id].present?
if revision
render_403 unless revision.dmsf_file || DmsfFolder.permissions?(revision.dmsf_file.dmsf_folder)
end
true
end
def initialize def initialize
@dmsf_workflow = nil @dmsf_workflow = nil
@project = nil @project = nil
@ -72,7 +81,7 @@ class DmsfWorkflowsController < ApplicationController
:text_email_finished_approved, :text_email_finished_approved,
:text_email_to_see_history).deliver if user :text_email_to_see_history).deliver if user
end end
if Setting.plugin_redmine_dmsf[:dmsf_display_notified_recipients] == '1' if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] == '1'
unless recipients.blank? unless recipients.blank?
to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ')
to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.') to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.')
@ -95,7 +104,7 @@ class DmsfWorkflowsController < ApplicationController
:text_email_to_see_history, :text_email_to_see_history,
action.note).deliver action.note).deliver
end end
if Setting.plugin_redmine_dmsf[:dmsf_display_notified_recipients] == '1' if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] == '1'
unless recipients.blank? unless recipients.blank?
to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ')
to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.') to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.')
@ -116,7 +125,7 @@ class DmsfWorkflowsController < ApplicationController
:text_email_finished_delegated, :text_email_finished_delegated,
:text_email_to_proceed, :text_email_to_proceed,
action.note).deliver action.note).deliver
if Setting.plugin_redmine_dmsf[:dmsf_display_notified_recipients] == '1' if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] == '1'
flash[:warning] = l(:warning_email_notifications, :to => delegate.name) flash[:warning] = l(:warning_email_notifications, :to => delegate.name)
end end
end end
@ -147,7 +156,7 @@ class DmsfWorkflowsController < ApplicationController
:text_email_finished_step_short, :text_email_finished_step_short,
:text_email_to_see_status).deliver :text_email_to_see_status).deliver
end end
if Setting.plugin_redmine_dmsf[:dmsf_display_notified_recipients] == '1' if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] == '1'
recipients = assignments.collect{ |a| a.user } recipients = assignments.collect{ |a| a.user }
recipients << to if to recipients << to if to
recipients.uniq! recipients.uniq!
@ -178,31 +187,54 @@ class DmsfWorkflowsController < ApplicationController
def assignment def assignment
if (params[:commit] == l(:button_submit)) && if (params[:commit] == l(:button_submit)) &&
params[:dmsf_workflow_id].present? && (params[:dmsf_workflow_id] != '-1') params[:dmsf_workflow_id].present? && (params[:dmsf_workflow_id] != '-1')
revision = DmsfFileRevision.find_by_id params[:dmsf_file_revision_id] # DMS file
if revision if params[:dmsf_file_revision_id].present? && params[:dmsf_link_id].blank? && params[:attachment_id].blank?
revision.set_workflow(params[:dmsf_workflow_id], params[:action]) revision = DmsfFileRevision.find_by_id params[:dmsf_file_revision_id]
revision.assign_workflow(params[:dmsf_workflow_id]) if revision
if request.post? revision.set_workflow(params[:dmsf_workflow_id], params[:action])
if revision.save revision.assign_workflow(params[:dmsf_workflow_id])
file = DmsfFile.find_by_id revision.dmsf_file_id if request.post?
if file if revision.save
begin file = DmsfFile.find_by_id revision.dmsf_file_id
file.lock! if file
rescue DmsfLockError => e begin
logger.warn e.message file.lock!
rescue DmsfLockError => e
Rails.logger.warn e.message
end
flash[:notice] = l(:notice_successful_update)
end end
flash[:notice] = l(:notice_successful_update) else
flash[:error] = l(:error_workflow_assign)
end end
else
flash[:error] = l(:error_workflow_assign)
end end
end end
redirect_to :back
return
# DMS link (attached)
elsif params[:dmsf_link_id].present?
@dmsf_link_id = params[:dmsf_link_id]
@dmsf_workflow_id = params[:dmsf_workflow_id]
# Attachment (attached)
elsif params[:attachment_id].present?
@attachment_id = params[:attachment_id]
@dmsf_workflow_id = params[:dmsf_workflow_id]
end end
else
redirect_to :back
return
end
respond_to do |format|
format.html
format.js
end end
redirect_to :back
end end
def log def log
respond_to do |format|
format.html
format.js
end
end end
def edit def edit
@ -366,26 +398,7 @@ class DmsfWorkflowsController < ApplicationController
if revision if revision
revision.set_workflow(@dmsf_workflow.id, params[:action]) revision.set_workflow(@dmsf_workflow.id, params[:action])
if revision.save if revision.save
assignments = @dmsf_workflow.next_assignments revision.id @dmsf_workflow.notify_users(@project, revision, self)
recipients = assignments.collect{ |a| a.user }
recipients.uniq!
recipients = recipients & DmsfMailer.get_notify_users(@project)
recipients.each do |user|
DmsfMailer.workflow_notification(
user,
@dmsf_workflow,
revision,
:text_email_subject_started,
:text_email_started,
:text_email_to_proceed).deliver
end
if Setting.plugin_redmine_dmsf[:dmsf_display_notified_recipients] == '1'
unless recipients.blank?
to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ')
to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.')
flash[:warning] = l(:warning_email_notifications, :to => to)
end
end
flash[:notice] = l(:notice_workflow_started) flash[:notice] = l(:notice_workflow_started)
else else
flash[:error] = l(:notice_cannot_start_workflow) flash[:error] = l(:notice_cannot_start_workflow)
@ -399,22 +412,21 @@ class DmsfWorkflowsController < ApplicationController
if params[:dmsf_workflow].present? if params[:dmsf_workflow].present?
index = params[:step].to_i index = params[:step].to_i
name = params[:dmsf_workflow][:name] name = params[:dmsf_workflow][:name]
if name.present? step = @dmsf_workflow.dmsf_workflow_steps[index]
step = @dmsf_workflow.dmsf_workflow_steps[index] step.name = name
step.name = name unless step.save
unless step.save flash[:error] = step.errors.full_messages.to_sentence
flash[:error] = step.errors.full_messages.to_sentence else
else @dmsf_workflow.dmsf_workflow_steps.each do |s|
@dmsf_workflow.dmsf_workflow_steps.each do |s| if s.step == step.step
if s.step == step.step s.name = step.name
s.name = step.name s.save
s.save
end
end end
end end
end end
else end
# Operators # Operators
if params[:operator_step].present?
params[:operator_step].each do |id, operator| params[:operator_step].each do |id, operator|
step = DmsfWorkflowStep.find_by_id id step = DmsfWorkflowStep.find_by_id id
if step if step
@ -462,9 +474,11 @@ private
elsif params[:project_id] elsif params[:project_id]
@project = Project.find_by_id params[:project_id] @project = Project.find_by_id params[:project_id]
else else
@project = Project.find_by_identifier params[:id] @project = Project.find params[:id]
end end
end end
rescue ActiveRecord::RecordNotFound
@project = nil
end end
def workflows_layout def workflows_layout

View File

@ -0,0 +1,18 @@
module DmsfFolderPermissionsHelper
def users_checkboxes(users)
s = ''
if users
users.each do |user|
content = check_box_tag('permissions[user_ids][]', user.id, true, :id => nil) + user.name
s << content_tag(:label, content, :id => "user_permission_ids_#{user.id}", :class => 'inline')
end
end
s.html_safe
end
def render_principals_for_new_folder_permissions(users)
principals_check_box_tags 'user_ids[]', users
end
end

View File

@ -59,10 +59,12 @@ module DmsfHelper
extension = File.extname(filename) extension = File.extname(filename)
extension = extension[1, extension.length-1] extension = extension[1, extension.length-1]
if File.exist?("#{File.dirname(__FILE__)}/../../assets/images/filetypes/#{extension}.png") if File.exist?("#{File.dirname(__FILE__)}/../../assets/images/filetypes/#{extension}.png")
"filetype-#{extension}"; cls = "filetype-#{extension}";
else else
Redmine::MimeType.css_class_of(filename) cls = Redmine::MimeType.css_class_of(filename)
end end
cls << ' dmsf-icon-file' if cls
cls
end end
def plugin_asset_path(plugin, asset_type, source) def plugin_asset_path(plugin, asset_type, source)
@ -89,9 +91,31 @@ module DmsfHelper
'plupload/js/i18n/en.js' 'plupload/js/i18n/en.js'
end end
def self.visible_folders(folders, project)
allowed = Setting.plugin_redmine_dmsf['dmsf_act_as_attachable'] &&
(project.dmsf_act_as_attachable == Project::ATTACHABLE_DMS_AND_ATTACHMENTS)
folders.reject{ |folder|
if folder.system
unless allowed
true
else
issue_id = folder.title.to_i
if issue_id > 0
issue = Issue.find_by_id issue_id
issue && !issue.visible?(User.current)
else
false
end
end
else
false
end
}
end
def self.all_children_sorted(parent, pos, ident) def self.all_children_sorted(parent, pos, ident)
# Folders && files && links # Folders && files && links
nodes = parent.dmsf_folders.visible + parent.dmsf_links.visible + parent.dmsf_files.visible nodes = visible_folders(parent.dmsf_folders.visible.to_a, parent.is_a?(Project) ? parent : parent.project) + parent.dmsf_links.visible + parent.dmsf_files.visible
# Alphabetical and type sort # Alphabetical and type sort
nodes.sort! do |x, y| nodes.sort! do |x, y|
if ((x.is_a?(DmsfFolder) || (x.is_a?(DmsfLink) && x.is_folder?)) && if ((x.is_a?(DmsfFolder) || (x.is_a?(DmsfLink) && x.is_folder?)) &&
@ -105,7 +129,9 @@ module DmsfHelper
end end
end end
# Calculate position # Calculate position
step = 1.0 / (10 ** ident) ident = 0 unless ident
pos = (10 ** 12) unless pos
step = (10 ** 12) / (10 ** (ident * 3))
tree = [] tree = []
i = 0 i = 0
nodes.each do |x| nodes.each do |x|
@ -113,7 +139,7 @@ module DmsfHelper
i += 1 i += 1
tree << [x, pos + (step * i)] tree << [x, pos + (step * i)]
else else
tree << [x, pos + step + i] tree << [x, pos + (step * (i + 1))]
end end
end end
tree tree

View File

@ -37,6 +37,18 @@ module DmsfLinksHelper
# An integer test # An integer test
def self.is_a_number?(s) def self.is_a_number?(s)
s.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/) == nil ? false : true s.to_s.match(/\A[+-]?\d+?(\.\d+)?\Z/) == nil ? false : true
end end
def files_for_select(project_id, folder_id)
files = []
if folder_id && (folder_id != '0')
folder = DmsfFolder.find_by_id folder_id
files = folder.dmsf_files.visible.to_a if folder
elsif project_id
project = Project.find_by_id project_id
files = project.dmsf_files.visible.to_a if project
end
files
end
end end

View File

@ -21,20 +21,15 @@
module DmsfUploadHelper module DmsfUploadHelper
include Redmine::I18n include Redmine::I18n
def self.commit_files_internal(commited_files, container, folder, controller) def self.commit_files_internal(commited_files, project, folder, controller)
failed_uploads = [] failed_uploads = []
files = [] files = []
if container.is_a?(Project)
project = container
else
project = container.project
end
if commited_files && commited_files.is_a?(Hash) if commited_files && commited_files.is_a?(Hash)
failed_uploads = [] failed_uploads = []
commited_files.each_value do |commited_file| commited_files.each_value do |commited_file|
name = commited_file[:name] name = commited_file[:name]
new_revision = DmsfFileRevision.new new_revision = DmsfFileRevision.new
file = DmsfFile.visible.find_file_by_name(container, folder, name) file = DmsfFile.visible.find_file_by_name(project, folder, name)
unless file unless file
link = DmsfLink.find_link_by_file_name(project, folder, name) link = DmsfLink.find_link_by_file_name(project, folder, name)
file = link.target_file if link file = link.target_file if link
@ -42,11 +37,10 @@ module DmsfUploadHelper
unless file unless file
file = DmsfFile.new file = DmsfFile.new
file.container_type = container.class.name.demodulize file.project_id = project.id
file.container_id = container.id
file.name = name file.name = name
file.dmsf_folder = folder file.dmsf_folder = folder
file.notification = Setting.plugin_redmine_dmsf[:dmsf_default_notifications].present? file.notification = Setting.plugin_redmine_dmsf['dmsf_default_notifications'].present?
new_revision.minor_version = 0 new_revision.minor_version = 0
new_revision.major_version = 0 new_revision.major_version = 0
else else
@ -66,8 +60,6 @@ module DmsfUploadHelper
next next
end end
commited_disk_filepath = "#{DmsfHelper.temp_dir}/#{commited_file[:disk_filename].gsub(/[\/\\]/,'')}"
new_revision.dmsf_file = file new_revision.dmsf_file = file
new_revision.user = User.current new_revision.user = User.current
new_revision.name = name new_revision.name = name
@ -81,9 +73,9 @@ module DmsfUploadHelper
else else
new_revision.increase_version(version) new_revision.increase_version(version)
end end
new_revision.mime_type = Redmine::MimeType.of(new_revision.name) new_revision.mime_type = commited_file[:mime_type]
new_revision.size = File.size(commited_disk_filepath) new_revision.size = commited_file[:size]
new_revision.digest = DmsfFileRevision.create_digest commited_disk_filepath new_revision.digest = DmsfFileRevision.create_digest commited_file[:tempfile_path]
if commited_file[:custom_field_values].present? if commited_file[:custom_field_values].present?
commited_file[:custom_field_values].each_with_index do |v, i| commited_file[:custom_field_values].each_with_index do |v, i|
@ -104,7 +96,8 @@ module DmsfUploadHelper
if new_revision.save if new_revision.save
new_revision.assign_workflow(commited_file[:dmsf_workflow_id]) new_revision.assign_workflow(commited_file[:dmsf_workflow_id])
begin begin
FileUtils.mv(commited_disk_filepath, new_revision.disk_file) FileUtils.mv commited_file[:tempfile_path], new_revision.disk_file(false)
FileUtils.chmod 'u=wr,g=r', new_revision.disk_file(false)
file.set_last_revision new_revision file.set_last_revision new_revision
files.push(file) files.push(file)
if file.container.is_a?(Issue) if file.container.is_a?(Issue)
@ -118,14 +111,36 @@ module DmsfUploadHelper
else else
failed_uploads.push(commited_file) failed_uploads.push(commited_file)
end end
# Approval workflow
if commited_file[:workflow_id].present?
wf = DmsfWorkflow.find_by_id commited_file[:workflow_id]
if wf
# Assign the workflow
new_revision.set_workflow(wf.id, 'assign')
new_revision.assign_workflow(wf.id)
# Start the workflow
new_revision.set_workflow(wf.id, 'start')
if new_revision.save
wf.notify_users(project, new_revision, controller)
begin
file.lock!
rescue DmsfLockError => e
Rails.logger.warn e.message
end
else
Rails.logger.error l(:error_workflow_assign)
end
end
end
end end
if container.is_a?(Project) && ((folder && folder.notification?) || (!folder && project.dmsf_notification?)) # Notifications
if ((folder && folder.notification?) || (!folder && project.dmsf_notification?))
begin begin
recipients = DmsfMailer.get_notify_users(project, files) recipients = DmsfMailer.get_notify_users(project, files)
recipients.each do |u| recipients.each do |u|
DmsfMailer.files_updated(u, project, files).deliver DmsfMailer.files_updated(u, project, files).deliver
end end
if Setting.plugin_redmine_dmsf[:dmsf_display_notified_recipients] == '1' if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] == '1'
unless recipients.empty? unless recipients.empty?
to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ') to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ')
to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.') to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.')

View File

@ -23,7 +23,7 @@ module DmsfWorkflowsHelper
def render_principals_for_new_dmsf_workflow_users(workflow, dmsf_workflow_step_assignment_id = nil, dmsf_file_revision_id = nil) def render_principals_for_new_dmsf_workflow_users(workflow, dmsf_workflow_step_assignment_id = nil, dmsf_file_revision_id = nil)
scope = workflow.delegates(params[:q], dmsf_workflow_step_assignment_id, dmsf_file_revision_id) scope = workflow.delegates(params[:q], dmsf_workflow_step_assignment_id, dmsf_file_revision_id)
principal_count = scope.count principal_count = scope.count
principal_pages = Redmine::Pagination::Paginator.new principal_count, 10, params['page'] principal_pages = Redmine::Pagination::Paginator.new principal_count, 100, params['page']
principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).to_a principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).to_a
# Delegation # Delegation

View File

@ -23,7 +23,8 @@ begin
require 'xapian' require 'xapian'
$xapian_bindings_available = true $xapian_bindings_available = true
rescue LoadError rescue LoadError
Rails.logger.info 'REDMAIN_XAPIAN ERROR: No Ruby bindings for Xapian installed !!. PLEASE install Xapian search engine interface for Ruby.' Rails.logger.warn %{No Xapian search engine interface for Ruby installed => Full-text search won't be available.
Install a ruby-xapian package or an alternative Xapian binding (https://xapian.org).}
$xapian_bindings_available = false $xapian_bindings_available = false
end end
@ -32,6 +33,7 @@ class DmsfFile < ActiveRecord::Base
include RedmineDmsf::Lockable include RedmineDmsf::Lockable
belongs_to :project
belongs_to :dmsf_folder belongs_to :dmsf_folder
belongs_to :deleted_by_user, :class_name => 'User', :foreign_key => 'deleted_by_user_id' belongs_to :deleted_by_user, :class_name => 'User', :foreign_key => 'deleted_by_user_id'
@ -43,8 +45,8 @@ class DmsfFile < ActiveRecord::Base
:class_name => 'DmsfLink', :foreign_key => 'target_id', :dependent => :destroy :class_name => 'DmsfLink', :foreign_key => 'target_id', :dependent => :destroy
has_many :dmsf_public_urls, :dependent => :destroy has_many :dmsf_public_urls, :dependent => :destroy
STATUS_DELETED = 1 STATUS_DELETED = 1.freeze
STATUS_ACTIVE = 0 STATUS_ACTIVE = 0.freeze
scope :visible, -> { where(:deleted => STATUS_ACTIVE) } scope :visible, -> { where(:deleted => STATUS_ACTIVE) }
scope :deleted, -> { where(:deleted => STATUS_DELETED) } scope :deleted, -> { where(:deleted => STATUS_DELETED) }
@ -55,10 +57,8 @@ class DmsfFile < ActiveRecord::Base
validate :validates_name_uniqueness validate :validates_name_uniqueness
attr_accessible :project, :project_id
def validates_name_uniqueness def validates_name_uniqueness
existing_file = DmsfFile.visible.findn_file_by_name(self.container_id, self.container_type, self.dmsf_folder, self.name) existing_file = DmsfFile.visible.findn_file_by_name(self.project_id, self.dmsf_folder, self.name)
errors.add(:name, l('activerecord.errors.messages.taken')) unless (existing_file.nil? || existing_file.id == self.id) errors.add(:name, l('activerecord.errors.messages.taken')) unless (existing_file.nil? || existing_file.id == self.id)
end end
@ -69,7 +69,7 @@ class DmsfFile < ActiveRecord::Base
Redmine::Search.cache_store.delete("DmsfFile-#{o.id}") Redmine::Search.cache_store.delete("DmsfFile-#{o.id}")
else else
# Set desc to an empty string if o.description is nil # Set desc to an empty string if o.description is nil
desc = o.description.nil? ? "" : o.description desc = o.description.nil? ? '' : o.description
desc += ' / ' if o.description.present? && o.last_revision.comment.present? desc += ' / ' if o.description.present? && o.last_revision.comment.present?
desc += o.last_revision.comment if o.last_revision.comment.present? desc += o.last_revision.comment if o.last_revision.comment.present?
end end
@ -84,12 +84,10 @@ class DmsfFile < ActiveRecord::Base
:date_column => "#{table_name}.updated_at" :date_column => "#{table_name}.updated_at"
before_create :default_values before_create :default_values
def default_values def default_values
@notifications = Setting.plugin_redmine_dmsf['dmsf_default_notifications'] if (Setting.plugin_redmine_dmsf['dmsf_default_notifications'] == '1') && (!self.dmsf_folder || !self.dmsf_folder.system)
if @notifications == '1'
self.notification = true self.notification = true
else
self.notification = nil
end end
end end
@ -98,36 +96,24 @@ class DmsfFile < ActiveRecord::Base
super super
end end
@@storage_path = nil
def self.storage_path def self.storage_path
return @@storage_path if @@storage_path.present?
path = Setting.plugin_redmine_dmsf['dmsf_storage_directory'] path = Setting.plugin_redmine_dmsf['dmsf_storage_directory']
path = Pathname(Redmine::Configuration['attachments_storage_path']).join('dmsf') if path.blank? && Redmine::Configuration['attachments_storage_path'].present? if path.blank?
path = Rails.root.join('files/dmsf').to_s if path.blank? path = Pathname.new('files').join('dmsf').to_s
path.strip if path else
path pn = Pathname.new(path)
end return pn if pn.absolute?
# Lets introduce a write for storage path, that way we can also
# better interact from test-cases etc
def self.storage_path=(path)
begin
FileUtils.mkdir_p(path) unless File.exist?(path)
rescue Exception => e
Rails.logger.error e.message
end end
@@storage_path = path Rails.root.join(path)
end end
def self.find_file_by_name(container, folder, name) def self.find_file_by_name(project, folder, name)
self.findn_file_by_name(container.id, container.class.name.demodulize, folder, name) self.findn_file_by_name(project.id, folder, name)
end end
def self.findn_file_by_name(container_id, container_type, folder, name) def self.findn_file_by_name(project_id, folder, name)
where( where(
:container_id => container_id, :project_id => project_id,
:container_type => container_type,
:dmsf_folder_id => folder ? folder.id : nil, :dmsf_folder_id => folder ? folder.id : nil,
:name => name).visible.first :name => name).visible.first
end end
@ -148,9 +134,13 @@ class DmsfFile < ActiveRecord::Base
end end
def delete(commit) def delete(commit)
if locked_for_user? if locked_for_user? && (!User.current.allowed_to?(:force_file_unlock, self.project))
Rails.logger.info l(:error_file_is_locked) Rails.logger.info l(:error_file_is_locked)
errors[:base] << l(:error_file_is_locked) if self.lock.reverse[0].user
errors[:base] << l(:title_locked_by_user, :user => self.lock.reverse[0].user)
else
errors[:base] << l(:error_file_is_locked)
end
return false return false
end end
begin begin
@ -245,63 +235,43 @@ class DmsfFile < ActiveRecord::Base
projects projects
end end
def move_to(container, folder) def move_to(project, folder)
if self.locked_for_user? if self.locked_for_user?
errors[:base] << l(:error_file_is_locked) errors[:base] << l(:error_file_is_locked)
return false return false
end end
project = container.is_a?(Project) ? container : container.project
# If the target project differs from the source project we must physically move the disk files
if self.project != project
self.dmsf_file_revisions.all.each do |rev|
if File.exist? rev.disk_file(self.project)
FileUtils.mv rev.disk_file(self.project), rev.disk_file(project)
end
end
end
# Must invalidate source parent folder cache before moving # Must invalidate source parent folder cache before moving
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key) RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
self.project_id = project.id
self.container_type = self.container_type
self.container_id = container.id
self.dmsf_folder = folder self.dmsf_folder = folder
new_revision = self.last_revision.clone new_revision = self.last_revision.clone
new_revision.dmsf_file = self new_revision.dmsf_file = self
new_revision.comment = l(:comment_moved_from, :source => "#{self.project.identifier}:#{self.dmsf_path_str}") new_revision.comment = l(:comment_moved_from, :source => "#{self.project.identifier}:#{self.dmsf_path_str}")
new_revision.custom_values = [] new_revision.custom_values = []
self.last_revision.custom_values.each do |cv| self.last_revision.custom_values.each do |cv|
new_revision.custom_values << CustomValue.new({:custom_field => cv.custom_field, :value => cv.value}) new_revision.custom_values << CustomValue.new({:custom_field => cv.custom_field, :value => cv.value})
end end
self.set_last_revision(new_revision) self.set_last_revision(new_revision)
self.save && new_revision.save self.save && new_revision.save
end end
def copy_to(container, folder = nil) def copy_to(project, folder = nil)
copy_to_filename(container, folder, self.name) copy_to_filename(project, folder, self.name)
end end
def copy_to_filename(container, folder=nil, filename) def copy_to_filename(project, folder, filename)
project = container.is_a?(Project) ? container : container.project
# If the target project differs from the source project we must physically move the disk files
if (self.project != project) && self.last_revision
if File.exist? self.last_revision.disk_file(self.project)
FileUtils.cp self.last_revision.disk_file(self.project), self.last_revision.disk_file(project)
end
end
file = DmsfFile.new file = DmsfFile.new
file.dmsf_folder = folder file.dmsf_folder = folder
file.container_type = self.container_type file.project_id = project.id
file.container_id = container.id
file.name = filename file.name = filename
file.notification = Setting.plugin_redmine_dmsf['dmsf_default_notifications'].present? file.notification = Setting.plugin_redmine_dmsf['dmsf_default_notifications'].present?
if file.save && self.last_revision if file.save && self.last_revision
new_revision = self.last_revision.clone new_revision = self.last_revision.clone
new_revision.dmsf_file = file new_revision.dmsf_file = file
new_revision.disk_filename = new_revision.new_storage_filename
if File.exist? self.last_revision.disk_file
FileUtils.cp self.last_revision.disk_file, new_revision.disk_file(false)
end
new_revision.comment = l(:comment_copied_from, :source => "#{project.identifier}: #{self.dmsf_path_str}") new_revision.comment = l(:comment_copied_from, :source => "#{project.identifier}: #{self.dmsf_path_str}")
new_revision.custom_values = [] new_revision.custom_values = []
self.last_revision.custom_values.each do |cv| self.last_revision.custom_values.each do |cv|
@ -337,8 +307,7 @@ class DmsfFile < ActiveRecord::Base
project_conditions << Project.allowed_to_condition(user, :view_dmsf_files) project_conditions << Project.allowed_to_condition(user, :view_dmsf_files)
project_conditions << "#{Project.table_name}.id IN (#{project_ids.join(',')})" if project_ids.present? project_conditions << "#{Project.table_name}.id IN (#{project_ids.join(',')})" if project_ids.present?
scope = self.visible.joins(:dmsf_file_revisions).joins( scope = self.visible.joins('JOIN dmsf_file_revisions ON dmsf_file_revisions.dmsf_file_id = dmsf_files.id').joins(:project)
"JOIN #{Project.table_name} ON #{DmsfFile.table_name}.container_id = #{Project.table_name}.id AND #{DmsfFile.table_name}.container_type = 'Project'")
scope = scope.limit(options[:limit]) unless options[:limit].blank? scope = scope.limit(options[:limit]) unless options[:limit].blank?
scope = scope.where(limit_options) unless limit_options.blank? scope = scope.where(limit_options) unless limit_options.blank?
scope = scope.where(project_conditions.join(' AND ')) scope = scope.where(project_conditions.join(' AND '))
@ -352,8 +321,8 @@ class DmsfFile < ActiveRecord::Base
Setting.plugin_redmine_dmsf['dmsf_index_database'].strip, lang) Setting.plugin_redmine_dmsf['dmsf_index_database'].strip, lang)
database = Xapian::Database.new(databasepath) database = Xapian::Database.new(databasepath)
rescue Exception => e rescue Exception => e
Rails.logger.warn "REDMAIN_XAPIAN ERROR: Xapian database is not properly set, initiated or it's corrupted." Rails.logger.error "REDMINE_XAPIAN ERROR: Xapian database is not properly set, initiated or it's corrupted."
Rails.logger.warn e.message Rails.logger.error e.message
end end
if database if database
@ -401,7 +370,7 @@ class DmsfFile < ActiveRecord::Base
if dmsf_file if dmsf_file
if user.allowed_to?(:view_dmsf_files, dmsf_file.project) && if user.allowed_to?(:view_dmsf_files, dmsf_file.project) &&
(project_ids.blank? || (project_ids.include?(dmsf_file.project.id))) (project_ids.blank? || (project_ids.include?(dmsf_file.project_id)))
Redmine::Search.cache_store.write("DmsfFile-#{dmsf_file.id}", Redmine::Search.cache_store.write("DmsfFile-#{dmsf_file.id}",
dochash['sample'].force_encoding('UTF-8')) if dochash['sample'] dochash['sample'].force_encoding('UTF-8')) if dochash['sample']
break if(!options[:limit].blank? && results.count >= options[:limit]) break if(!options[:limit].blank? && results.count >= options[:limit])
@ -423,7 +392,7 @@ class DmsfFile < ActiveRecord::Base
end end
def display_name def display_name
member = Member.where(:user_id => User.current.id, :project_id => self.project.id).first member = Member.where(:user_id => User.current.id, :project_id => self.project_id).first
if member && !member.title_format.nil? && !member.title_format.empty? if member && !member.title_format.nil? && !member.title_format.empty?
title_format = member.title_format title_format = member.title_format
else else
@ -496,7 +465,13 @@ class DmsfFile < ActiveRecord::Base
def custom_value(custom_field) def custom_value(custom_field)
self.last_revision.custom_field_values.each do |cv| self.last_revision.custom_field_values.each do |cv|
return cv.value if cv.custom_field == custom_field if cv.custom_field == custom_field
if cv.value.is_a? Array
return cv.value.reject{ |x| x.empty? }.join(',')
else
return cv.value
end
end
end end
nil nil
end end
@ -522,18 +497,16 @@ class DmsfFile < ActiveRecord::Base
end end
def propfind_cache_key def propfind_cache_key
if self.container_type == 'Project' unless dmsf_folder_id
if dmsf_folder_id.nil? # File is in project root
# File is in project root return "PROPFIND/#{self.project_id}"
return "PROPFIND/#{self.container_id}" else
else return "PROPFIND/#{self.project_id}/#{self.dmsf_folder_id}"
return "PROPFIND/#{self.container_id}/#{self.dmsf_folder_id}"
end
end end
end end
def extension def extension
$1 if self.last_revision && self.last_revision.disk_filename =~ /\.(.+)$/ File.extname(self.last_revision.disk_filename).strip.downcase[1..-1] if self.last_revision
end end
include ActionView::Helpers::NumberHelper include ActionView::Helpers::NumberHelper
@ -583,6 +556,14 @@ class DmsfFile < ActiveRecord::Base
csv << '' csv << ''
end end
end end
# Last approver
if columns.include?(l(:label_last_approver))
if self.last_revision && self.last_revision.dmsf_workflow
csv << self.last_revision.workflow_tooltip
else
csv << ''
end
end
# Url # Url
if columns.include?(l(:label_document_url)) if columns.include?(l(:label_document_url))
default_url_options[:host] = Setting.host_name default_url_options[:host] = Setting.host_name
@ -604,31 +585,6 @@ class DmsfFile < ActiveRecord::Base
csv csv
end end
def project
unless @project
case self.container_type
when 'Project'
@project = Project.find_by_id(self.container_id)
when 'Issue'
issue = Issue.find_by_id(self.container_id)
@project = issue.project if issue
end
end
@project
end
def container
unless @container
case self.container_type
when 'Project'
@container = Project.find_by_id(self.container_id)
when 'Issue'
@container = Issue.find_by_id(self.container_id)
end
end
@container
end
def thumbnail(options={}) def thumbnail(options={})
if image? if image?
size = options[:size].to_i size = options[:size].to_i
@ -644,7 +600,7 @@ class DmsfFile < ActiveRecord::Base
target = File.join(Attachment.thumbnails_storage_path, "#{self.id}_#{self.last_revision.digest}_#{size}.thumb") target = File.join(Attachment.thumbnails_storage_path, "#{self.id}_#{self.last_revision.digest}_#{size}.thumb")
begin begin
Redmine::Thumbnail.generate(self.last_revision.disk_file, target, size) Redmine::Thumbnail.generate(self.last_revision.disk_file.to_s, target, size)
rescue => e rescue => e
Rails.logger.error "An error occured while generating thumbnail for #{self.last_revision.disk_file} to #{target}\nException was: #{e.message}" Rails.logger.error "An error occured while generating thumbnail for #{self.last_revision.disk_file} to #{target}\nException was: #{e.message}"
return nil return nil
@ -652,4 +608,24 @@ class DmsfFile < ActiveRecord::Base
end end
end end
def get_locked_title
if self.locked_for_user?
if self.lock.reverse[0].user
return l(:title_locked_by_user, :user => self.lock.reverse[0].user)
else
return l(:notice_account_unknown_email)
end
end
l(:title_unlock_file)
end
def container
unless @container
if self.dmsf_folder && self.dmsf_folder.system
@container = Issue.where(:id => self.dmsf_folder.title.to_i).first
end
end
@container
end
end end

View File

@ -28,6 +28,7 @@ class DmsfFileRevision < ActiveRecord::Base
belongs_to :source_revision, :class_name => 'DmsfFileRevision', :foreign_key => 'source_dmsf_file_revision_id' belongs_to :source_revision, :class_name => 'DmsfFileRevision', :foreign_key => 'source_dmsf_file_revision_id'
belongs_to :user belongs_to :user
belongs_to :deleted_by_user, :class_name => 'User', :foreign_key => 'deleted_by_user_id' belongs_to :deleted_by_user, :class_name => 'User', :foreign_key => 'deleted_by_user_id'
belongs_to :dmsf_workflow
has_many :dmsf_file_revision_access, :dependent => :destroy has_many :dmsf_file_revision_access, :dependent => :destroy
has_many :dmsf_workflow_step_assignment, :dependent => :destroy has_many :dmsf_workflow_step_assignment, :dependent => :destroy
@ -48,10 +49,8 @@ class DmsfFileRevision < ActiveRecord::Base
:timestamp => "#{DmsfFileRevision.table_name}.updated_at", :timestamp => "#{DmsfFileRevision.table_name}.updated_at",
:author_key => "#{DmsfFileRevision.table_name}.user_id", :author_key => "#{DmsfFileRevision.table_name}.user_id",
:permission => :view_dmsf_file_revisions, :permission => :view_dmsf_file_revisions,
:scope => select("#{DmsfFileRevision.table_name}.*"). :scope => DmsfFileRevision.joins(:dmsf_file).
joins(:dmsf_file).joins( joins("JOIN #{Project.table_name} ON #{Project.table_name}.id = #{DmsfFile.table_name}.project_id").visible
"LEFT JOIN #{Project.table_name} ON #{DmsfFile.table_name}.container_id = #{Project.table_name}.id").
where("#{DmsfFile.table_name}.container_type = ?", 'Project').visible
validates :title, :presence => true validates :title, :presence => true
validates_format_of :name, :with => DmsfFolder::INVALID_CHARACTERS, validates_format_of :name, :with => DmsfFolder::INVALID_CHARACTERS,
@ -72,6 +71,10 @@ class DmsfFileRevision < ActiveRecord::Base
def self.filename_to_title(filename) def self.filename_to_title(filename)
remove_extension(filename).gsub(/_+/, ' '); remove_extension(filename).gsub(/_+/, ' ');
end end
def self.easy_activity_custom_project_scope(scope, options, event_type)
scope.where(:dmsf_files => { :project_id => options[:project_ids] })
end
def delete(commit = false, force = true) def delete(commit = false, force = true)
if self.dmsf_file.locked_for_user? if self.dmsf_file.locked_for_user?
@ -105,7 +108,7 @@ class DmsfFileRevision < ActiveRecord::Base
d.save! d.save!
end end
if Setting.plugin_redmine_dmsf['dmsf_really_delete_files'] if Setting.plugin_redmine_dmsf['dmsf_really_delete_files']
dependencies = DmsfFileRevision.where(:disk_filename => self.disk_filename).all.count dependencies = DmsfFileRevision.where(:disk_filename => self.disk_filename).count
File.delete(self.disk_file) if dependencies <= 1 && File.exist?(self.disk_file) File.delete(self.disk_file) if dependencies <= 1 && File.exist?(self.disk_file)
end end
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key) RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
@ -131,20 +134,37 @@ class DmsfFileRevision < ActiveRecord::Base
"#{self.major_version}.#{self.minor_version}" "#{self.major_version}.#{self.minor_version}"
end end
def storage_base_path(project = nil) def storage_base_path
project = self.dmsf_file.project unless project time = self.created_at || DateTime.now
path = DmsfFile.storage_path.dup path = time.strftime('%Y/%m')
if self.dmsf_file && project DmsfFile.storage_path.join path
project_base = project.identifier.gsub(/[^\w\.\-]/,'_')
path << "/p_#{project_base}"
end
end end
def disk_file(project = nil) def disk_file(search_if_not_exists = true)
project = self.dmsf_file.project unless project path = self.storage_base_path
path = storage_base_path(project)
FileUtils.mkdir_p(path) unless File.exist?(path) FileUtils.mkdir_p(path) unless File.exist?(path)
"#{path}/#{self.disk_filename}" filename = path.join(self.disk_filename)
if search_if_not_exists
unless File.exist?(filename)
# Let's search for the physical file in source revisions
revisions = self.dmsf_file.dmsf_file_revisions.where(['id < ?', self.id]).order(:id => :desc)
revisions.each do |rev|
filename = rev.disk_file
break if File.exist?(filename)
end
end
end
filename
end
def new_storage_filename
raise DmsfAccessError, 'File id is not set' unless self.dmsf_file.id
filename = DmsfHelper.sanitize_filename(self.name)
timestamp = DateTime.now.strftime("%y%m%d%H%M%S")
while File.exist?(storage_base_path.join("#{timestamp}_#{self.dmsf_file.id}_#{filename}"))
timestamp.succ!
end
"#{timestamp}_#{self.dmsf_file.id}_#{filename}"
end end
def detect_content_type def detect_content_type
@ -227,16 +247,6 @@ class DmsfFileRevision < ActiveRecord::Base
end end
end end
def new_storage_filename
raise DmsfAccessError, 'File id is not set' unless self.dmsf_file.id
filename = DmsfHelper.sanitize_filename(self.name)
timestamp = DateTime.now.strftime("%y%m%d%H%M%S")
while File.exist?(File.join(storage_base_path, "#{timestamp}_#{self.dmsf_file.id}_#{filename}"))
timestamp.succ!
end
"#{timestamp}_#{self.dmsf_file.id}_#{filename}"
end
def copy_file_content(open_file) def copy_file_content(open_file)
File.open(self.disk_file, 'wb') do |f| File.open(self.disk_file, 'wb') do |f|
while (buffer = open_file.read(8192)) while (buffer = open_file.read(8192))
@ -311,4 +321,25 @@ class DmsfFileRevision < ActiveRecord::Base
dmsf_file.propfind_cache_key dmsf_file.propfind_cache_key
end end
def workflow_tooltip
tooltip = ''
if self.dmsf_workflow
case workflow
when DmsfWorkflow::STATE_WAITING_FOR_APPROVAL, DmsfWorkflow::STATE_ASSIGNED
assignments = self.dmsf_workflow.next_assignments(self.id)
if assignments
assignments.each_with_index do |assignment, index|
tooltip << ', ' if index > 0
tooltip << assignment.user.name
end
end
when DmsfWorkflow::STATE_APPROVED, DmsfWorkflow::STATE_REJECTED
action = DmsfWorkflowStepAction.joins(:dmsf_workflow_step_assignment).where(
['dmsf_workflow_step_assignments.dmsf_file_revision_id', self.id]).order('dmsf_workflow_step_actions.id').last
tooltip << action.author.name if action
end
end
tooltip
end
end end

View File

@ -40,9 +40,8 @@ class DmsfFileRevisionAccess < ActiveRecord::Base
:timestamp => "#{DmsfFileRevisionAccess.table_name}.updated_at", :timestamp => "#{DmsfFileRevisionAccess.table_name}.updated_at",
:author_key => "#{DmsfFileRevisionAccess.table_name}.user_id", :author_key => "#{DmsfFileRevisionAccess.table_name}.user_id",
:permission => :view_dmsf_file_revision_accesses, :permission => :view_dmsf_file_revision_accesses,
:scope => select("#{DmsfFileRevisionAccess.table_name}.*"). :scope => DmsfFileRevisionAccess.
joins(:dmsf_file_revision).joins( joins(:dmsf_file_revision).joins("JOIN #{DmsfFile.table_name} ON dmsf_files.id = dmsf_file_revisions.dmsf_file_id").
"LEFT JOIN #{DmsfFile.table_name} ON #{DmsfFileRevision.table_name}.dmsf_file_id = #{DmsfFile.table_name}.id " + joins("JOIN #{Project.table_name} on dmsf_files.project_id = projects.id").
"LEFT JOIN #{Project.table_name} ON #{DmsfFile.table_name}.container_id = #{Project.table_name}.id"). where(:dmsf_files => { :deleted => DmsfFile::STATUS_ACTIVE })
where("#{DmsfFile.table_name}.deleted = ? AND #{DmsfFile.table_name}.container_type = ?", DmsfFile::STATUS_ACTIVE, 'Project')
end end

View File

@ -26,8 +26,16 @@ class DmsfFileRevisionCustomField < CustomField
end end
def compare_values?(x, y) def compare_values?(x, y)
if x.is_a?(Array) && y.is_a?(Array) && !y.empty? if x.is_a?(Array) && y.is_a?(Array)
x.include? y[0] y.reject!{ |a| a.empty? }
return true if y.empty?
x.reject!{ |a| a.empty? }
y.each do |b|
if x.include?(b)
return true
end
end
return false
else else
x == y x == y
end end

View File

@ -29,7 +29,7 @@ class DmsfFolder < ActiveRecord::Base
belongs_to :deleted_by_user, :class_name => 'User', :foreign_key => 'deleted_by_user_id' belongs_to :deleted_by_user, :class_name => 'User', :foreign_key => 'deleted_by_user_id'
belongs_to :user belongs_to :user
has_many :dmsf_folders, -> { order(:title) }, :dependent => :destroy has_many :dmsf_folders, -> { order :title }, :dependent => :destroy
has_many :dmsf_files, :dependent => :destroy has_many :dmsf_files, :dependent => :destroy
has_many :folder_links, -> { where(:target_type => 'DmsfFolder').order(:name) }, has_many :folder_links, -> { where(:target_type => 'DmsfFolder').order(:name) },
:class_name => 'DmsfLink', :foreign_key => 'dmsf_folder_id', :dependent => :destroy :class_name => 'DmsfLink', :foreign_key => 'dmsf_folder_id', :dependent => :destroy
@ -42,15 +42,24 @@ class DmsfFolder < ActiveRecord::Base
:class_name => 'DmsfLink', :foreign_key => 'target_id', :dependent => :destroy :class_name => 'DmsfLink', :foreign_key => 'target_id', :dependent => :destroy
has_many :locks, -> { where(entity_type: 1).order("#{DmsfLock.table_name}.updated_at DESC") }, has_many :locks, -> { where(entity_type: 1).order("#{DmsfLock.table_name}.updated_at DESC") },
:class_name => 'DmsfLock', :foreign_key => 'entity_id', :dependent => :destroy :class_name => 'DmsfLock', :foreign_key => 'entity_id', :dependent => :destroy
has_many :dmsf_folder_permissions, :dependent => :destroy
INVALID_CHARACTERS = /\A[^\/\\\?":<>#%\*]*\z/.freeze INVALID_CHARACTERS = /\A[^\[\]\/\\\?":<>#%\*]*\z/.freeze
STATUS_DELETED = 1.freeze STATUS_DELETED = 1.freeze
STATUS_ACTIVE = 0.freeze STATUS_ACTIVE = 0.freeze
AVAILABLE_COLUMNS = %w(id title extension size modified version workflow author).freeze AVAILABLE_COLUMNS = %w(id title extension size modified version workflow author).freeze
DEFAULT_COLUMNS = %w(title size modified version workflow author).freeze DEFAULT_COLUMNS = %w(title size modified version workflow author).freeze
scope :visible, -> { where(:deleted => STATUS_ACTIVE) } scope :visible, -> (system=true) { joins(:project).joins(
scope :deleted, -> { where(:deleted => STATUS_DELETED) } "LEFT JOIN #{DmsfFolderPermission.table_name} ON #{DmsfFolder.table_name}.id = #{DmsfFolderPermission.table_name}.dmsf_folder_id").where(
:deleted => STATUS_ACTIVE).where(DmsfFolder.visible_condition(system)).distinct
}
scope :deleted, -> { joins(:project).joins(
"LEFT JOIN #{DmsfFolderPermission.table_name} ON #{DmsfFolder.table_name}.id = #{DmsfFolderPermission.table_name}.dmsf_folder_id").where(
:deleted => STATUS_DELETED).where(DmsfFolder.visible_condition).distinct
}
scope :system, -> { where(:system => true) }
scope :notsystem, -> { where(:system => false) }
acts_as_customizable acts_as_customizable
@ -72,14 +81,57 @@ class DmsfFolder < ActiveRecord::Base
validates_format_of :title, :with => INVALID_CHARACTERS, validates_format_of :title, :with => INVALID_CHARACTERS,
:message => l(:error_contains_invalid_character) :message => l(:error_contains_invalid_character)
validate :check_cycle validate :check_cycle
validates_length_of :description, :maximum => 65535
before_create :default_values before_create :default_values
def self.visible_condition(system=true)
Project.allowed_to_condition(User.current, :view_dmsf_folders) do |role, user|
if user.id && user.logged?
permissions = "#{DmsfFolderPermission.table_name}"
folders = "#{DmsfFolder.table_name}"
group_ids = user.group_ids.join(',')
group_ids = -1 if group_ids.blank?
allowed = (system && role.allowed_to?(:display_system_folders)) ? 1 : 0
%{
(#{permissions}.object_id IS NULL) OR
(#{permissions}.object_id = #{role.id} AND #{permissions}.object_type = 'Role') OR
((#{permissions}.object_id = #{user.id} OR #{permissions}.object_id IN (#{group_ids})) AND #{permissions}.object_type = 'User') AND
(#{folders}.system = #{DmsfFolder.connection.quoted_false} OR 1 = #{allowed})
}
else
'0 = 1'
end
end
end
def self.permissions?(folder, allow_system = true)
# Administrator?
return true if (User.current.admin? || folder.nil?)
# System folder?
if folder && folder.system
return false if (!allow_system || !User.current.allowed_to?(:display_system_folders, folder.project))
return false unless self.issue && self.issue.visible?(User.current)
end
# Permissions?
if !folder.dmsf_folder || permissions?(folder.dmsf_folder, allow_system)
if folder.dmsf_folder_permissions.any?
role_ids = User.current.roles_for_project(folder.project).map{ |r| r.id }
role_permission_ids = folder.dmsf_folder_permissions.roles.map{ |p| p.object_id }
return true if (role_ids & role_permission_ids).any?
principal_ids = folder.dmsf_folder_permissions.users.map{ |p| p.object_id }
return true if principal_ids.include?(User.current.id)
user_group_ids = User.current.groups.map{ |g| g.id }
return true if (principal_ids & user_group_ids).any?
return false
end
true
end
end
def default_values def default_values
@notifications = Setting.plugin_redmine_dmsf['dmsf_default_notifications'] if Setting.plugin_redmine_dmsf['dmsf_default_notifications'] == '1' && !self.system
if @notifications == '1'
self.notification = true self.notification = true
else
self.notification = nil
end end
end end
@ -108,7 +160,7 @@ class DmsfFolder < ActiveRecord::Base
if self.locked? if self.locked?
errors[:base] << l(:error_folder_is_locked) errors[:base] << l(:error_folder_is_locked)
return false return false
elsif !self.dmsf_folders.visible.empty? || !self.dmsf_files.visible.empty? elsif !self.dmsf_folders.visible.empty? || !self.dmsf_files.visible.empty? || !self.dmsf_links.visible.empty?
errors[:base] << l(:error_folder_is_not_empty) errors[:base] << l(:error_folder_is_not_empty)
return false return false
end end
@ -169,8 +221,11 @@ class DmsfFolder < ActiveRecord::Base
end end
def self.directory_tree(project, current_folder = nil) def self.directory_tree(project, current_folder = nil)
unless project.is_a? Project
project = Project.find_by_id project
end
tree = [[l(:link_documents), nil]] tree = [[l(:link_documents), nil]]
project.dmsf_folders.visible.each do |folder| project.dmsf_folders.notsystem.visible(false).each do |folder|
unless folder == current_folder unless folder == current_folder
tree.push(["...#{folder.title}", folder.id]) tree.push(["...#{folder.title}", folder.id])
directory_subtree(tree, folder, 2, current_folder) directory_subtree(tree, folder, 2, current_folder)
@ -262,6 +317,10 @@ class DmsfFolder < ActiveRecord::Base
l.copy_to project, new_folder l.copy_to project, new_folder
end end
self.dmsf_folder_permissions.each do |p|
p.copy_to new_folder
end
return new_folder return new_folder
end end
@ -272,37 +331,32 @@ class DmsfFolder < ActiveRecord::Base
def modified def modified
last_update = updated_at last_update = updated_at
dmsf_folders.each do |subfolder| time = DmsfFolder.where(
last_update = subfolder.updated_at if subfolder.updated_at > last_update ['project_id = ? AND dmsf_folder_id = ? AND updated_at > ?',
end self.project_id, self.id, last_update]).maximum(:updated_at)
dmsf_files.each do |file| last_update = time if time
last_update = file.updated_at if file.updated_at > last_update time = DmsfFile.where(
end ['project_id = ? AND dmsf_folder_id = ? AND updated_at > ?',
folder_links.each do |folder_link| self.project_id, self.id, last_update]).maximum(:updated_at)
last_update = folder_link.updated_at if folder_link.updated_at > last_update last_update = time if time
end time = DmsfLink.where(
file_links.each do |file_link| ['project_id = ? AND dmsf_folder_id = ? AND updated_at > ?',
last_update = file_link.updated_at if file_link.updated_at > last_update self.project_id, self.id, last_update]).maximum(:updated_at)
end last_update = time if time
url_links.each do |url_link|
last_update = url_link.updated_at if url_link.updated_at > last_update
end
last_update last_update
end end
# Number of items in the folder # Number of items in the folder
def items def items
dmsf_folders.visible.count + dmsf_folders.visible.where(:project_id => self.project_id).count +
dmsf_files.visible.count + dmsf_files.visible.where(:project_id => self.project_id).count +
folder_links.visible.count + dmsf_links.visible.where(:project_id => self.project_id).count
file_links.visible.count +
url_links.visible.count
end end
def self.is_column_on?(column) def self.is_column_on?(column)
columns = Setting.plugin_redmine_dmsf['dmsf_columns'] dmsf_columns = Setting.plugin_redmine_dmsf['dmsf_columns']
columns = DmsfFolder::DEFAULT_COLUMNS unless columns dmsf_columns = DmsfFolder::DEFAULT_COLUMNS unless dmsf_columns
columns.include? column dmsf_columns.include? column
end end
def custom_value(custom_field) def custom_value(custom_field)
@ -313,61 +367,61 @@ class DmsfFolder < ActiveRecord::Base
end end
def self.get_column_position(column) def self.get_column_position(column)
dmsf_columns = Setting.plugin_redmine_dmsf['dmsf_columns']
dmsf_columns = DmsfFolder::DEFAULT_COLUMNS unless dmsf_columns
pos = 0 pos = 0
columns = Setting.plugin_redmine_dmsf['dmsf_columns']
columns = DmsfFolder::DEFAULT_COLUMNS unless columns
# 0 - checkbox # 0 - checkbox
# 1 - id # 1 - id
if columns.include?('id') if dmsf_columns.include?('id')
pos += 1 pos += 1
return pos if column == 'id' return pos if column == 'id'
else else
return nil if column == 'id' return nil if column == 'id'
end end
# 2 - title # 2 - title
if columns.include?('title') if dmsf_columns.include?('title')
pos += 1 pos += 1
return pos if column == 'title' return pos if column == 'title'
else else
return nil if column == 'title' return nil if column == 'title'
end end
# 3 - extension # 3 - extension
if columns.include?('extension') if dmsf_columns.include?('extension')
pos += 1 pos += 1
return pos if column == 'extension' return pos if column == 'extension'
else else
return nil if column == 'extension' return nil if column == 'extension'
end end
# 4 - size # 4 - size
if columns.include?('size') if dmsf_columns.include?('size')
pos += 1 pos += 1
return pos if column == 'size' return pos if column == 'size'
else else
return nil if column == 'size' return nil if column == 'size'
end end
# 5 - modified # 5 - modified
if columns.include?('modified') if dmsf_columns.include?('modified')
pos += 1 pos += 1
return pos if column == 'modified' return pos if column == 'modified'
else else
return nil if column == 'modified' return nil if column == 'modified'
end end
# 6 - version # 6 - version
if columns.include?('version') if dmsf_columns.include?('version')
pos += 1 pos += 1
return pos if column == 'version' return pos if column == 'version'
else else
return nil if column == 'version' return nil if column == 'version'
end end
# 7 - workflow # 7 - workflow
if columns.include?('workflow') if dmsf_columns.include?('workflow')
pos += 1 pos += 1
return pos if column == 'workflow' return pos if column == 'workflow'
else else
return nil if column == 'workflow' return nil if column == 'workflow'
end end
# 8 - author # 8 - author
if columns.include?('author') if dmsf_columns.include?('author')
pos += 1 pos += 1
return pos if column == 'author' return pos if column == 'author'
else else
@ -399,22 +453,22 @@ class DmsfFolder < ActiveRecord::Base
end end
def save(*args) def save(*args)
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key) RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
super(*args) super(*args)
end end
def save!(*args) def save!(*args)
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key) RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
super(*args) super(*args)
end end
def destroy def destroy
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key) RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
super super
end end
def destroy! def destroy!
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key) RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
super super
end end
@ -450,6 +504,8 @@ class DmsfFolder < ActiveRecord::Base
csv << '' if columns.include?('workflow') csv << '' if columns.include?('workflow')
# Author # Author
csv << self.user.name if columns.include?('author') csv << self.user.name if columns.include?('author')
# Last approver
csv << '' if columns.include?(l(:label_last_approver))
# Url # Url
if columns.include?(l(:label_document_url)) if columns.include?(l(:label_document_url))
default_url_options[:host] = Setting.host_name default_url_options[:host] = Setting.host_name
@ -465,10 +521,66 @@ class DmsfFolder < ActiveRecord::Base
csv csv
end end
def get_locked_title
if self.locked_for_user?
if self.lock.reverse[0].user
return l(:title_locked_by_user, :user => self.lock.reverse[0].user)
else
return l(:notice_account_unknown_email)
end
end
l(:title_unlock_file)
end
def issue
unless @issue
if self.system
issue_id = self.title.to_i
@issue = Issue.find_by_id(issue_id) if issue_id > 0
end
end
@issue
end
def update_from_params(params)
# Attributes
self.title = params[:dmsf_folder][:title].strip
self.description = params[:dmsf_folder][:description].strip
self.dmsf_folder_id = params[:dmsf_folder][:dmsf_folder_id]
# Custom fields
if params[:dmsf_folder][:custom_field_values].present?
params[:dmsf_folder][:custom_field_values].each_with_index do |v, i|
self.custom_field_values[i].value = v[1]
end
end
# Permissions
self.dmsf_folder_permissions.delete_all
if params[:permissions]
if params[:permissions][:role_ids]
params[:permissions][:role_ids].each do |role_id|
permission = DmsfFolderPermission.new
permission.object_id = role_id
permission.object_type = Role.model_name.to_s
self.dmsf_folder_permissions << permission
end
end
if params[:permissions][:user_ids]
params[:permissions][:user_ids].each do |user_id|
permission = DmsfFolderPermission.new
permission.object_id = user_id
permission.object_type = User.model_name.to_s
self.dmsf_folder_permissions << permission
end
end
end
# Save
self.save
end
private private
def self.directory_subtree(tree, folder, level, current_folder) def self.directory_subtree(tree, folder, level, current_folder)
folder.dmsf_folders.visible.each do |subfolder| folder.dmsf_folders.visible(false).each do |subfolder|
unless subfolder == current_folder unless subfolder == current_folder
tree.push(["#{'...' * level}#{subfolder.title}", subfolder.id]) tree.push(["#{'...' * level}#{subfolder.title}", subfolder.id])
directory_subtree(tree, subfolder, level + 1, current_folder) directory_subtree(tree, subfolder, level + 1, current_folder)

View File

@ -0,0 +1,38 @@
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-17 Karel Pičman <karel.picman@konton.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 DmsfFolderPermission < ActiveRecord::Base
unloadable
belongs_to :dmsf_folder
scope :users, -> { where(:object_type => User.model_name.to_s) }
scope :roles, -> { where(:object_type => Role.model_name.to_s) }
def copy_to(folder)
permission = DmsfFolderPermission.new
permission.dmsf_folder_id = folder.id
permission.object_id = self.object_id
permission.object_type = self.object_type
permission.save
permission
end
end

View File

@ -62,7 +62,12 @@ class DmsfLink < ActiveRecord::Base
end end
def target_folder def target_folder
DmsfFolder.find_by_id self.target_folder_id if self.target_folder_id unless @target_folder
if self.target_folder_id
@target_folder = DmsfFolder.find_by_id self.target_folder_id
end
end
@target_folder
end end
def target_file_id def target_file_id
@ -70,15 +75,28 @@ class DmsfLink < ActiveRecord::Base
end end
def target_file def target_file
DmsfFile.find_by_id self.target_file_id if self.target_file_id unless @target_file
if self.target_file_id
@target_file = DmsfFile.find_by_id self.target_file_id
end
end
@target_file
end end
def target_project def target_project
Project.find_by_id self.target_project_id unless @target_project
@target_project = Project.find_by_id self.target_project_id
end
@target_project
end end
def folder def folder
DmsfFolder.find_by_id self.dmsf_folder_id unless @folder
if self.dmsf_folder_id
@folder = DmsfFolder.find_by_id self.dmsf_folder_id
end
end
@folder
end end
def title def title
@ -110,20 +128,29 @@ class DmsfLink < ActiveRecord::Base
end end
def copy_to(project, folder) def copy_to(project, folder)
link = DmsfLink.new( link = DmsfLink.new
:target_project_id => self.target_project_id, link.target_project_id = self.target_project_id
:target_id => self.target_id, link.target_id = self.target_id
:target_type => self.target_type, link.target_type = self.target_type
:name => self.name, link.name = self.name
:external_url => self.external_url, link.external_url = self.external_url
:project_id => project.id, link.project_id = project.id
:dmsf_folder_id => folder ? folder.id : nil) link.dmsf_folder_id = folder ? folder.id : nil
link.save link.save
link link
end end
def container
if self.folder && self.folder.system
Issue.where(:id => self.folder.title.to_i).first
end
end
def delete(commit = false) def delete(commit = false)
if commit if commit
if self.container.is_a?(Issue)
self.container.dmsf_file_removed(self.target_file)
end
self.destroy self.destroy
else else
self.deleted = STATUS_DELETED self.deleted = STATUS_DELETED
@ -171,6 +198,8 @@ class DmsfLink < ActiveRecord::Base
csv << '' if columns.include?('workflow') csv << '' if columns.include?('workflow')
# Author # Author
csv << self.user.name if columns.include?('author') csv << self.user.name if columns.include?('author')
# Last approver
csv << '' if columns.include?(l(:label_last_approver))
# Url # Url
csv << self.external_url if columns.include?(l(:label_document_url)) csv << self.external_url if columns.include?(l(:label_document_url))
# Revision # Revision

View File

@ -51,7 +51,6 @@ class DmsfMailer < Mailer
end end
def send_documents(project, user, email_params) def send_documents(project, user, email_params)
zipped_content_data = open(email_params[:zipped_content], 'rb') { |io| io.read }
redmine_headers 'Project' => project.identifier if project redmine_headers 'Project' => project.identifier if project
@body = email_params[:body] @body = email_params[:body]
@links_only = email_params[:links_only] == '1' @links_only = email_params[:links_only] == '1'
@ -61,6 +60,7 @@ class DmsfMailer < Mailer
@files = email_params[:files] @files = email_params[:files]
unless @links_only unless @links_only
zipped_content_data = open(email_params[:zipped_content], 'rb') { |io| io.read }
attachments['Documents.zip'] = { :content_type => 'application/zip', :content => zipped_content_data } attachments['Documents.zip'] = { :content_type => 'application/zip', :content => zipped_content_data }
end end
mail :to => email_params[:to], :cc => email_params[:cc], mail :to => email_params[:to], :cc => email_params[:cc],
@ -87,6 +87,7 @@ class DmsfMailer < Mailer
end end
def self.get_notify_users(project, files = []) def self.get_notify_users(project, files = [])
return [] unless project.active?
if files.present? if files.present?
notify_files = files.select { |file| file.notify? } notify_files = files.select { |file| file.notify? }
return [] if notify_files.empty? return [] if notify_files.empty?

View File

@ -33,6 +33,7 @@ class DmsfUpload
attr_accessor :locked attr_accessor :locked
attr_accessor :workflow attr_accessor :workflow
attr_accessor :custom_values attr_accessor :custom_values
attr_accessor :tempfile_path
def disk_file def disk_file
"#{DmsfHelper.temp_dir}/#{self.disk_filename}" "#{DmsfHelper.temp_dir}/#{self.disk_filename}"
@ -45,15 +46,14 @@ class DmsfUpload
:disk_filename => DmsfHelper.temp_filename(a.filename), :disk_filename => DmsfHelper.temp_filename(a.filename),
:content_type => a.content_type, :content_type => a.content_type,
:original_filename => a.filename, :original_filename => a.filename,
:comment => uploaded_file[:description] :comment => uploaded_file[:description],
:tempfile_path => a.diskfile
} }
FileUtils.mv(a.diskfile, "#{DmsfHelper.temp_dir}/#{uploaded[:disk_filename]}") DmsfUpload.new(project, folder, uploaded)
a.destroy
upload = DmsfUpload.new(project, folder, uploaded)
else else
Rails.logger.error "An attachment not found by its token: #{uploaded_file[:token]}" Rails.logger.error "An attachment not found by its token: #{uploaded_file[:token]}"
nil
end end
upload
end end
def initialize(project, folder, uploaded) def initialize(project, folder, uploaded)
@ -67,7 +67,8 @@ class DmsfUpload
@disk_filename = uploaded[:disk_filename] @disk_filename = uploaded[:disk_filename]
@mime_type = uploaded[:content_type] @mime_type = uploaded[:content_type]
@size = File.size(disk_file) @size = File.size(uploaded[:tempfile_path])
@tempfile_path = uploaded[:tempfile_path]
if file.nil? || file.last_revision.nil? if file.nil? || file.last_revision.nil?
@title = DmsfFileRevision.filename_to_title(@name) @title = DmsfFileRevision.filename_to_title(@name)
@ -76,8 +77,7 @@ class DmsfUpload
@minor_version = 0 @minor_version = 0
@workflow = nil @workflow = nil
file = DmsfFile.new file = DmsfFile.new
file.container_type = 'Project' file.project_id = project.id
file.container_id = project.id
revision = DmsfFileRevision.new revision = DmsfFileRevision.new
revision.dmsf_file = file revision.dmsf_file = file
@custom_values = revision.custom_field_values @custom_values = revision.custom_field_values

View File

@ -22,8 +22,8 @@ class DmsfWorkflow < ActiveRecord::Base
has_many :dmsf_workflow_steps, -> { order 'step ASC, operator DESC' }, :dependent => :destroy has_many :dmsf_workflow_steps, -> { order 'step ASC, operator DESC' }, :dependent => :destroy
belongs_to :author, :class_name => 'User' belongs_to :author, :class_name => 'User'
scope :sorted, lambda { order('name ASC') } scope :sorted, lambda { order(:name => :asc) }
scope :global, lambda { where('project_id IS NULL') } scope :global, lambda { where(:project_id => nil) }
scope :active, lambda { where(:status => STATUS_ACTIVE) } scope :active, lambda { where(:status => STATUS_ACTIVE) }
scope :status, lambda { |arg| where(arg.blank? ? nil : {:status => arg.to_i}) } scope :status, lambda { |arg| where(arg.blank? ? nil : {:status => arg.to_i}) }
@ -106,8 +106,8 @@ class DmsfWorkflow < ActiveRecord::Base
def delegates(q, dmsf_workflow_step_assignment_id, dmsf_file_revision_id) def delegates(q, dmsf_workflow_step_assignment_id, dmsf_file_revision_id)
if dmsf_workflow_step_assignment_id && dmsf_file_revision_id if dmsf_workflow_step_assignment_id && dmsf_file_revision_id
sql = [ sql = [
'id NOT IN (SELECT a.user_id FROM dmsf_workflow_step_assignments a WHERE id = ?) AND id IN (SELECT m.user_id FROM members m JOIN dmsf_files f ON f.container_id = m.project_id JOIN dmsf_file_revisions r ON r.dmsf_file_id = f.id WHERE r.id = ? AND container_type = ?)', 'id NOT IN (SELECT a.user_id FROM dmsf_workflow_step_assignments a WHERE id = ?) AND id IN (SELECT m.user_id FROM members m JOIN dmsf_files f ON f.project_id = m.project_id JOIN dmsf_file_revisions r ON r.dmsf_file_id = f.id WHERE r.id = ?)',
dmsf_workflow_step_assignment_id, dmsf_file_revision_id, 'Project'] dmsf_workflow_step_assignment_id, dmsf_file_revision_id]
elsif project elsif project
sql = ['id IN (SELECT user_id FROM members WHERE project_id = ?)', project.id] sql = ['id IN (SELECT user_id FROM members WHERE project_id = ?)', project.id]
else else
@ -167,19 +167,6 @@ class DmsfWorkflow < ActiveRecord::Base
results results
end end
def self.assignments_to_users_str(assignments)
str = ''
if assignments
assignments.each_with_index do |assignment, index|
if index > 0
str << ', '
end
str << assignment.user.name
end
end
str
end
def assign(dmsf_file_revision_id) def assign(dmsf_file_revision_id)
dmsf_workflow_steps.each do |ws| dmsf_workflow_steps.each do |ws|
ws.assign(dmsf_file_revision_id) ws.assign(dmsf_file_revision_id)
@ -230,4 +217,27 @@ class DmsfWorkflow < ActiveRecord::Base
self.status == STATUS_ACTIVE self.status == STATUS_ACTIVE
end end
def notify_users(project, revision, controller)
assignments = self.next_assignments revision.id
recipients = assignments.collect{ |a| a.user }
recipients.uniq!
recipients = recipients & DmsfMailer.get_notify_users(project)
recipients.each do |user|
DmsfMailer.workflow_notification(
user,
self,
revision,
:text_email_subject_started,
:text_email_started,
:text_email_to_proceed).deliver
end
if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] == '1'
unless recipients.blank?
to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ')
to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.')
controller.flash[:warning] = l(:warning_email_notifications, :to => to)
end
end
end
end end

View File

@ -21,6 +21,7 @@
class DmsfWorkflowStepAction < ActiveRecord::Base class DmsfWorkflowStepAction < ActiveRecord::Base
belongs_to :dmsf_workflow_step_assignment belongs_to :dmsf_workflow_step_assignment
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
validates :dmsf_workflow_step_assignment_id, :presence => true validates :dmsf_workflow_step_assignment_id, :presence => true
validates :action, :presence => true validates :action, :presence => true

View File

@ -19,15 +19,18 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.%> # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<% if object %> <% if object %>
<div> <div>
<% object.show_custom_field_values.each do |custom_value| %> <% object.show_custom_field_values.each do |custom_value| %>
<p> <div class="status attribute">
<%= label_tag('', h(custom_value.custom_field.name)) %> <%= content_tag :div, h(custom_value.custom_field.name), :class => 'label' %>
<%= show_value custom_value %> <div class="value">
</p> <%= show_value custom_value %>
</div>
</div>
<% end %> <% end %>
</div> </div>
<% end %> <% end %>

View File

@ -20,13 +20,23 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%> %>
<% locked_for_user = subfolder && subfolder.locked_for_user? %> <td class="dmsf_checkbox">
<% locked = subfolder && subfolder.locked? %> <% unless (subfolder && subfolder.system) %>
<%= check_box_tag(name, id, false, :title => l(:title_check_for_zip_download_or_email), :id => "subfolder_#{id}") %>
<td class="dmsf_checkbox"><%= check_box_tag(name, id, false, <% end %>
:title => l(:title_check_for_zip_download_or_email), :id => "subfolder_#{id}") %></td> </td>
<% if DmsfFolder.is_column_on?('id') %> <% if DmsfFolder.is_column_on?('id') %>
<td class="id"><%= link_to(subfolder.id, edit_dmsf_path(:id => project, :folder_id => subfolder)) %></td> <td class="id">
<% if subfolder %>
<% if subfolder.system %>
<%= subfolder.id %>
<% else %>
<%= link_to(subfolder.id, edit_dmsf_path(:id => project, :folder_id => subfolder)) %>
<% end %>
<% else %>
<%= link_to(link.target_project_id, project_path(link.target_project)) %>
<% end %>
</td>
<% end %> <% end %>
<% if DmsfFolder.is_column_on?('title') %> <% if DmsfFolder.is_column_on?('title') %>
<td class="dmsf_title"> <td class="dmsf_title">
@ -51,21 +61,7 @@
<td class="dmsf_size"></td> <td class="dmsf_size"></td>
<% end %> <% end %>
<% if DmsfFolder.is_column_on?('modified') %> <% if DmsfFolder.is_column_on?('modified') %>
<td class="dmsf_modified"><%= format_time(subfolder.modified) if subfolder %> <td class="dmsf_modified"><%= format_time(subfolder.modified) if subfolder %></td>
<% if locked_for_user %>
<% if subfolder.lock.reverse[0].user %>
<%= link_to(image_tag(link ? 'locked_gray.png' : 'locked.png', :plugin => 'redmine_dmsf'),
user_path(subfolder.lock.reverse[0].user),
:title => l(:title_locked_by_user, :user => subfolder.lock.reverse[0].user)) %>
<% else %>
<%= content_tag(:span, image_tag(link ? 'locked_gray.png' : 'locked.png', :plugin => 'redmine_dmsf'),
:title => l(:notice_account_unknown_email)) %>
<% end %>
<% elsif locked %>
<%= content_tag(:span, image_tag(link ? 'lockedbycurrent_gray.png' : 'lockedbycurrent.png', :plugin => 'redmine_dmsf'),
:title => l(:title_locked_by_you)) %>
<% end %>
</td>
<% end %> <% end %>
<% if DmsfFolder.is_column_on?('version') %> <% if DmsfFolder.is_column_on?('version') %>
<td class="dmsf_version"></td> <td class="dmsf_version"></td>
@ -85,60 +81,51 @@
<% end %> <% end %>
<% end %> <% end %>
<td class="dmsf_buttons"> <td class="dmsf_buttons">
<% if @folder_manipulation_allowed %> <% if @folder_manipulation_allowed && !(subfolder && subfolder.system) %>
<% unless locked_for_user %> <% if subfolder && subfolder.locked? %>
<% if subfolder %> <span class="icon-only"></span>
<%= link_to(image_tag('edit.png'), <% if subfolder.unlockable? && (!subfolder.locked_for_user? || @force_file_unlock_allowed) %>
edit_dmsf_path(:id => project, :folder_id => subfolder), <%= link_to('', unlock_dmsf_path(:id => project, :folder_id => subfolder),
:title => l(:link_edit, :title => subfolder ? h(subfolder.title) : project.name)) %> :title => subfolder.get_locked_title,
<% if locked %> :class => 'icon-only icon-unlock') %>
<% if subfolder.unlockable? %>
<%= link_to(image_tag('unlock.png', :plugin => 'redmine_dmsf'),
unlock_dmsf_path(:id => project, :folder_id => subfolder),
:title => l(:title_unlock_file)) %>
<% else %>
<span class="icon"></span>
<% end %>
<% else %>
<%= link_to(image_tag('lock.png', :plugin => 'redmine_dmsf'),
lock_dmsf_path(:id => project, :folder_id => subfolder),
:title => l(:title_lock_file)) %>
<% end %>
<% else %> <% else %>
<%= link_to(image_tag('edit.png'), edit_root_dmsf_path(:id => @project), <span class="icon-only icon-unlock" title="<%= subfolder.get_locked_title %>"></span>
:title => l(:link_edit, :title => l(:link_documents))) %>
<span class="icon"></span>
<% end %>
<% if (subfolder && subfolder.notification) || (!subfolder && project.dmsf_notification) %>
<%= link_to(image_tag('notify.png', :plugin => 'redmine_dmsf'),
notify_deactivate_dmsf_path(:id => project, :folder_id => subfolder),
:title => l(:title_notifications_active_deactivate)) %>
<% else %>
<%= link_to(image_tag('notifynot.png', :plugin => 'redmine_dmsf'),
notify_activate_dmsf_path(:id => project, :folder_id => subfolder),
:title => l(:title_notifications_not_active_activate)) %>
<% end %>
<% if link %>
<%= link_to(image_tag('delete.png'), dmsf_link_path(link),
:data => {:confirm => l(:text_are_you_sure)},
:method => :delete, :title => l(:title_delete)) %>
<% else %>
<%= link_to(image_tag('delete.png'),
delete_dmsf_path(:id => project, :folder_id => subfolder),
:data => {:confirm => l(:text_are_you_sure)},
:title => l(:title_delete)) %>
<% end %> <% end %>
<% else %> <% else %>
<span class="icon"></span> <% if subfolder %>
<% if (!locked_for_user || @force_file_unlock_allowed) && subfolder.unlockable? %> <%= link_to('', edit_dmsf_path(:id => project, :folder_id => subfolder),
<%= link_to(image_tag('unlock.png', :plugin => 'redmine_dmsf'), :title => l(:link_edit, :title => h(subfolder.title)),
unlock_dmsf_path(:id => project, :folder_id => subfolder), :class => 'icon-only icon-edit') %>
:title => l(:title_unlock_file)) %> <% else %>
<%= link_to('', edit_root_dmsf_path(:id => @project),
:title => l(:link_edit, :title => l(:link_documents)),
:class => 'icon-only icon-edit') %>
<% end %> <% end %>
<% if subfolder %>
<%= link_to('', lock_dmsf_path(:id => project, :folder_id => subfolder),
:title => l(:title_lock_file),
:class => 'icon-only icon-lock') %>
<% else %>
<span class="icon-only"></span>
<% end %>
<% if (subfolder && subfolder.notification) || (!subfolder && project.dmsf_notification) %>
<%= link_to('', notify_deactivate_dmsf_path(:id => project, :folder_id => subfolder),
:title => l(:title_notifications_active_deactivate),
:class => 'icon-only icon-email') %>
<% else %>
<%= link_to('', notify_activate_dmsf_path(:id => project, :folder_id => subfolder),
:title => l(:title_notifications_not_active_activate),
:class => 'icon-only icon-email-add') %>
<% end %>
<%= link_to('', link ? dmsf_link_path(link) : delete_dmsf_path(:id => project, :folder_id => subfolder),
:data => {:confirm => l(:text_are_you_sure)},
:title => l(:title_delete),
:method => :delete,
:class => 'icon-only icon-del') %>
<% end %> <% end %>
<% end %> <% end %>
</td> </td>
<td id="dmsf_position" class="dmsf_invisible"><%= position %></td> <td id="dmsf_position" class="hol"><%= position %></td>
<td class="dmsf_invisible">0</td> <td class="hol">0</td>
<td class="dmsf_invisible"><%= subfolder.modified.to_i if subfolder %></td> <td class="hol"><%= subfolder.modified.to_i if subfolder %></td>
<td class="dmsf_invisible">0</td> <td class="hol">0</td>

View File

@ -67,27 +67,25 @@
<% end %> <% end %>
<td class="dmsf_buttons"> <td class="dmsf_buttons">
<% if @folder_manipulation_allowed %> <% if @folder_manipulation_allowed %>
<%= link_to('', link ? restore_dmsf_link_path(:id => link) : restore_dmsf_path(:id => project, :folder_id => subfolder),
:title => l(:title_restore),
:class => 'icon-only icon-cancel') %>
<% if link %> <% if link %>
<%= link_to(image_tag('restore.png', :plugin => 'redmine_dmsf'), <%= link_to('', dmsf_link_path(:id => link, :commit => 'yes'),
restore_dmsf_link_path(:id => link),
:title => l(:title_restore)) %>
<%= link_to(image_tag('rev_delete.png', :plugin => 'redmine_dmsf'),
dmsf_link_path(:id => link, :commit => 'yes'),
:data => {:confirm => l(:text_are_you_sure)}, :data => {:confirm => l(:text_are_you_sure)},
:method => :delete, :method => :delete,
:title => l(:title_delete)) %> :title => l(:title_delete),
<% else # folder %> :class => 'icon-only icon-delete') %>
<%= link_to(image_tag('restore.png', :plugin => 'redmine_dmsf'), <% else %>
restore_dmsf_path(:id => project, :folder_id => subfolder), <%= link_to('', delete_dmsf_path(:id => project, :folder_id => subfolder, :commit => 'yes'),
:title => l(:title_restore)) %>
<%= link_to(image_tag('rev_delete.png', :plugin => 'redmine_dmsf'),
delete_dmsf_path(:id => project, :folder_id => subfolder, :commit => 'yes'),
:data => {:confirm => l(:text_are_you_sure)}, :data => {:confirm => l(:text_are_you_sure)},
:title => l(:title_delete)) %> :title => l(:title_delete),
:method => :delete,
:class => 'icon-only icon-del') %>
<% end %> <% end %>
<% end %> <% end %>
</td> </td>
<td class="dmsf_invisible">0</td> <td class="hol">0</td>
<td class="dmsf_invisible">0</td> <td class="hol">0</td>
<td class="dmsf_invisible"><%= subfolder.modified.to_i if subfolder %></td> <td class="hol"><%= subfolder.modified.to_i if subfolder %></td>
<td class="dmsf_invisible">0</td> <td class="hol">0</td>

View File

@ -1,9 +1,6 @@
<% parent = @folder ? @folder : @project %> <% parent = @folder ? @folder : @project %>
<% @idnt = 0 unless @idnt %>
<% @pos = 0.0 unless @pos %>
<% DmsfHelper.all_children_sorted(parent, @pos, @idnt).each do |obj, position| %> <% DmsfHelper.all_children_sorted(parent, @pos, @idnt).each do |obj, position| %>
<% classes = "dmsf_tree idnt-#{@idnt}" %> <% classes = "dmsf_tree idnt-#{@idnt}" %>
<% classes += " dmsf-#{cycle('odd', 'even')}" %>
<% if obj.is_a?(DmsfFolder) && ((obj.dmsf_folders.visible.count > 0) || (obj.dmsf_files.visible.count > 0) || (obj.dmsf_links.visible.count > 0)) %> <% if obj.is_a?(DmsfFolder) && ((obj.dmsf_folders.visible.count > 0) || (obj.dmsf_files.visible.count > 0) || (obj.dmsf_links.visible.count > 0)) %>
<% classes += ' idnt dmsf_collapsed dmsf-not-loaded' %> <% classes += ' idnt dmsf_collapsed dmsf-not-loaded' %>
<% id = "id='#{obj.id}span'".html_safe %> <% id = "id='#{obj.id}span'".html_safe %>
@ -19,6 +16,8 @@
<% end %> <% end %>
<% if obj.is_a? DmsfFolder %> <% if obj.is_a? DmsfFolder %>
<% classes << ' dmsf_system' if obj.system %>
<% classes << ' dmsf_system_closed' if obj.issue && obj.issue.closed? %>
<tr <%= id %> class="dir <%= classes %>"> <tr <%= id %> class="dir <%= classes %>">
<%= render(:partial => 'dir', <%= render(:partial => 'dir',
:locals => { :locals => {

View File

@ -20,7 +20,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%> %>
<% wf = DmsfWorkflow.find_by_id(file.last_revision.dmsf_workflow_id) %> <% wf = DmsfWorkflow.find_by_id(file.last_revision.dmsf_workflow_id) if file.last_revision.dmsf_workflow_id %>
<td class="dmsf_checkbox"><%= check_box_tag(name, id, false, <td class="dmsf_checkbox"><%= check_box_tag(name, id, false,
:title => l(:title_check_for_zip_download_or_email), :id => "file_#{id}") %></td> :title => l(:title_check_for_zip_download_or_email), :id => "file_#{id}") %></td>
@ -53,19 +53,6 @@
<% if DmsfFolder.is_column_on?('modified') %> <% if DmsfFolder.is_column_on?('modified') %>
<td class="dmsf_modified"> <td class="dmsf_modified">
<%= format_time(file.last_revision.updated_at) %> <%= format_time(file.last_revision.updated_at) %>
<% if file.locked_for_user? %>
<% if file.lock.reverse[0].user %>
<%= link_to(image_tag(link ? 'locked_gray.png' : 'locked.png', :plugin => 'redmine_dmsf'),
user_path(file.lock.reverse[0].user),
:title => l(:title_locked_by_user, :user => file.lock.reverse[0].user)) %>
<% else %>
<%= content_tag(:span, image_tag(link ? 'locked_gray.png' : 'locked.png', :plugin => 'redmine_dmsf'),
:title => l(:notice_account_unknown_email)) %>
<% end %>
<% elsif file.locked? %>
<%= content_tag(:span, image_tag(link ? 'lockedbycurrent_gray.png' : 'lockedbycurrent.png', :plugin => 'redmine_dmsf'),
:title => l(:title_locked_by_you)) %>
<% end %>
</td> </td>
<% end %> <% end %>
<% if DmsfFolder.is_column_on?('version') %> <% if DmsfFolder.is_column_on?('version') %>
@ -80,7 +67,7 @@
:project_id => project.id, :project_id => project.id,
:id => wf.id, :id => wf.id,
:dmsf_file_revision_id => file.last_revision.id), :dmsf_file_revision_id => file.last_revision.id),
:title => DmsfWorkflow.assignments_to_users_str(wf.next_assignments(file.last_revision.id)), :title => file.last_revision.workflow_tooltip,
:remote => true) %> :remote => true) %>
<% else %> <% else %>
<%= file.last_revision.workflow_str(false) %> <%= file.last_revision.workflow_str(false) %>
@ -100,112 +87,57 @@
<% end %> <% end %>
<td class="dmsf_buttons"> <td class="dmsf_buttons">
<% if @file_manipulation_allowed %> <% if @file_manipulation_allowed %>
<%= link_to(image_tag('filedetails.png', :plugin => 'redmine_dmsf'), <%= link_to('', dmsf_file_path(:id => file),
dmsf_file_path(:id => file), :title => l(:link_details, :title => h(file.last_revision.title)),
:title => l(:link_details, :title => h(file.last_revision.title))) %> :class => 'icon-only icon-edit') %>
<% unless file.locked_for_user? %> <% if !file.locked? %>
<% if !file.locked? %> <%= link_to('', lock_dmsf_files_path(:id => file),
<%= link_to(image_tag('lock.png', :plugin => 'redmine_dmsf'), :title => l(:title_lock_file),
lock_dmsf_files_path(:id => file), :class => 'icon-only icon-lock') %>
:title => l(:title_lock_file)) %> <% elsif file.unlockable? && (!file.locked_for_user? || @force_file_unlock_allowed) %>
<% elsif file.unlockable? %> <%= link_to('', unlock_dmsf_files_path(:id => file),
<%= link_to(image_tag('unlock.png', :plugin => 'redmine_dmsf'), :title => file.get_locked_title,
unlock_dmsf_files_path(:id => file), :class => 'icon-only icon-unlock') %>
:title => l(:title_unlock_file))%> <% else %>
<% else %> <span class="icon-only icon-unlock" title="<%= file.get_locked_title %>"></span>
<span class="icon"></span> <% end %>
<% end %> <% unless file.locked? %>
<% if file.notification %> <% if file.notification %>
<%= link_to(image_tag('notify.png', :plugin => 'redmine_dmsf'), <%= link_to('', notify_deactivate_dmsf_files_path(:id => file),
notify_deactivate_dmsf_files_path(:id => file), :title => l(:title_notifications_active_deactivate),
:title => l(:title_notifications_active_deactivate)) %> :class => 'icon-only icon-email') %>
<% else %> <% else %>
<%= link_to(image_tag('notifynot.png', :plugin => 'redmine_dmsf'), <%= link_to('', notify_activate_dmsf_files_path(:id => file),
notify_activate_dmsf_files_path(:id => file), :title => l(:title_notifications_not_active_activate),
:title => l(:title_notifications_not_active_activate)) %> :class => 'icon-only icon-email-add') %>
<% end %> <% end %>
<% if link %> <% if link %>
<%= link_to(image_tag('delete.png'), <%= link_to('', dmsf_link_path(link),
dmsf_link_path(link), :data => {:confirm => l(:text_are_you_sure)},
:data => {:confirm => l(:text_are_you_sure)}, :title => l(:title_delete),
:method => :delete, :method => :delete,
:title => l(:title_delete)) %> :class => 'icon-only icon-del') %>
<% else %> <% else %>
<% if @file_delete_allowed %> <% if @file_delete_allowed %>
<%= link_to(image_tag('delete.png'), <%= link_to('', dmsf_file_path(:id => file),
dmsf_file_path(:id => file),
:data => {:confirm => l(:text_are_you_sure)}, :data => {:confirm => l(:text_are_you_sure)},
:title => l(:title_delete),
:method => :delete, :method => :delete,
:title => l(:title_delete)) unless file.locked_for_user? %> :class => 'icon-only icon-del') %>
<% else %> <% else %>
<span class="icon"></span> <span class="icon-only"></span>
<% end %> <% end %>
<% end %> <% end %>
<% else %> <% else %>
<% if @force_file_unlock_allowed && file.unlockable? %> <span class="icon-only"></span>
<%= link_to(image_tag('unlock.png', :plugin => 'redmine_dmsf'), <span class="icon-only"></span>
unlock_dmsf_files_path(:id => file),
:title => l(:title_unlock_file))%>
<% else %>
<span class="icon"></span>
<% end %>
<span class="icon"></span>
<span class="icon"></span>
<% end %>
<% end %>
<% if @file_approval_allowed %>
<% case file.last_revision.workflow %>
<% when DmsfWorkflow::STATE_WAITING_FOR_APPROVAL %>
<% if wf %>
<% assignments = wf.next_assignments(file.last_revision.id) %>
<% index = assignments.find_index{|assignment| assignment.user_id == User.current.id} if assignments %>
<% if index %>
<%= link_to(image_tag('waiting_for_approval.png', :plugin => 'redmine_dmsf'),
action_dmsf_workflow_path(
:project_id => project.id,
:id => wf.id,
:dmsf_workflow_step_assignment_id => assignments[index].id,
:dmsf_file_revision_id => file.last_revision.id),
:title => l(:title_waiting_for_approval),
:remote => true) %>
<% else %>
<%= content_tag(:span, image_tag('waiting_for_approval.png', :plugin => 'redmine_dmsf'),
:title => "#{l(:label_dmsf_wokflow_action_approve)} #{l(:label_dmsf_wokflow_action_reject)} #{l(:label_dmsf_wokflow_action_delegate)}") %>
<% end %>
<% else %>
<%= content_tag(:span, image_tag('waiting_for_approval.png', :plugin => 'redmine_dmsf'),
:title => "#{l(:label_dmsf_wokflow_action_approve)} #{l(:label_dmsf_wokflow_action_reject)} #{l(:label_dmsf_wokflow_action_delegate)}") %>
<% end %>
<% when DmsfWorkflow::STATE_APPROVED %>
<%= content_tag(:span, image_tag('approved.png', :plugin => 'redmine_dmsf'),
:title => l(:title_approved)) %>
<% when DmsfWorkflow::STATE_ASSIGNED %>
<% if User.current && (file.last_revision.dmsf_workflow_assigned_by == User.current.id) && wf %>
<%= link_to(image_tag('assigned.png', :plugin => 'redmine_dmsf'),
start_dmsf_workflow_path(
:id => file.last_revision.dmsf_workflow_id,
:dmsf_file_revision_id => file.last_revision.id),
:title => l(:label_dmsf_wokflow_action_start)) %>
<% else %>
<%= content_tag(:span, image_tag('assigned.png', :plugin => 'redmine_dmsf'),
title => l(:label_dmsf_wokflow_action_start)) %>
<% end %>
<% when DmsfWorkflow::STATE_REJECTED %>
<%= content_tag(:span, image_tag('rejected.png', :plugin => 'redmine_dmsf'),
:title => l(:title_rejected)) %>
<% else %>
<% if @workflows_available && !file.locked_for_user? %>
<%= link_to(image_tag('none.png', :plugin => 'redmine_dmsf'),
assign_dmsf_workflow_path(
:project_id => project.id,
:dmsf_file_revision_id => file.last_revision.id),
:title => l(:label_dmsf_wokflow_action_assign),
:remote => true) %>
<% end %>
<% end %> <% end %>
<% end %> <% end %>
<%= render(:partial => 'dmsf_workflows/approval_workflow_button',
:locals => {:file => file, :file_approval_allowed => @file_approval_allowed,
:workflows_available => @workflows_available, :project => project, :wf => wf, :dmsf_link_id => nil }) %>
</td> </td>
<td class="dmsf_invisible"><%= position %></td> <td class="hol"><%= position %></td>
<td class="dmsf_invisible"><%= file.last_revision.size %></td> <td class="hol"><%= file.last_revision.size %></td>
<td class="dmsf_invisible"><%= file.last_revision.updated_at.to_i %></td> <td class="hol"><%= file.last_revision.updated_at.to_i %></td>
<td class="dmsf_invisible"><%= file.last_revision.iversion %></td> <td class="hol"><%= file.last_revision.iversion %></td>

View File

@ -67,28 +67,19 @@
<% end %> <% end %>
<td class="dmsf_buttons"> <td class="dmsf_buttons">
<% if @file_manipulation_allowed %> <% if @file_manipulation_allowed %>
<% if link %> <%= link_to('', link ? restore_dmsf_link_path(:id => link) : restore_dmsf_file_path(:id => file),
<%= link_to(image_tag('restore.png', :plugin => 'redmine_dmsf'), :title => l(:title_restore),
restore_dmsf_link_path(:id => link), :class => 'icon-only icon-cancel') %>
:title => l(:title_restore)) %> <% end %>
<%= link_to(image_tag('rev_delete.png', :plugin => 'redmine_dmsf'), <% if @file_delete_allowed %>
dmsf_link_path(:id => link, :commit => 'yes'), <%= link_to('', link ? dmsf_link_path(:id => link, :commit => 'yes') : dmsf_file_path(:id => file, :commit => 'yes'),
:data => {:confirm => l(:text_are_you_sure)}, :data => {:confirm => l(:text_are_you_sure)},
:method => :delete, :method => :delete,
:title => l(:title_delete)) %> :title => l(:title_delete),
<% else # file %> :class => 'icon-only icon-del') %>
<%= link_to(image_tag('restore.png', :plugin => 'redmine_dmsf'),
restore_dmsf_file_path(:id => file),
:title => l(:title_restore)) %>
<%= link_to(image_tag('rev_delete.png', :plugin => 'redmine_dmsf'),
dmsf_file_path(:id => file, :commit => 'yes'),
:data => {:confirm => l(:text_are_you_sure)},
:method => :delete,
:title => l(:title_delete)) %>
<% end %>
<% end %> <% end %>
</td> </td>
<td class="dmsf_invisible">1</td> <td class="hol">1</td>
<td class="dmsf_invisible"><%= file.last_revision.size %></td> <td class="hol"><%= file.last_revision.size %></td>
<td class="dmsf_invisible"><%= file.last_revision.updated_at.to_i %></td> <td class="hol"><%= file.last_revision.updated_at.to_i %></td>
<td class="dmsf_invisible"><%= file.last_revision.iversion %></td> <td class="hol"><%= file.last_revision.iversion %></td>

View File

@ -57,15 +57,15 @@
<% end %> <% end %>
<% end %> <% end %>
<th class ="dmsf_th"><%# controls %></th> <th class ="dmsf_th"><%# controls %></th>
<th class="dmsf_invisible"><%# position %></th> <th class="hol"><%# position %></th>
<th class="dmsf_invisible"><%# size %></th> <th class="hol"><%# size %></th>
<th class="dmsf_invisible"><%# updated %></th> <th class="hol"><%# updated %></th>
<th class="dmsf_invisible"><%# version %></th> <th class="hol"><%# version %></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<% @subfolders.each do |subfolder| %> <% @subfolders.each do |subfolder| %>
<tr class="dir"> <tr class="dir <%= 'dmsf_system' if subfolder.system %> <%= 'dmsf_system_closed' if subfolder.issue && subfolder.issue.closed? %>">
<%= render(:partial => 'dir', <%= render(:partial => 'dir',
:locals => { :locals => {
:project => @project, :project => @project,

View File

@ -57,10 +57,10 @@
<% end %> <% end %>
<% end %> <% end %>
<th class ="dmsf_th"><%# controls %></th> <th class ="dmsf_th"><%# controls %></th>
<th class="dmsf_invisible"><%# position %></th> <th class="hol"><%# position %></th>
<th class="dmsf_invisible"><%# size %></th> <th class="hol"><%# size %></th>
<th class="dmsf_invisible"><%# updated %></th> <th class="hol"><%# updated %></th>
<th class="dmsf_invisible"><%# version %></th> <th class="hol"><%# version %></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@ -32,7 +32,7 @@
<%= link_to(h(title), <%= link_to(h(title),
link.external_url, link.external_url,
:target => '_blank', :target => '_blank',
:class => 'icon dmsf_icon-link') %> :class => 'icon icon-link') %>
<div class="dmsf_filename" title="<%= l(:label_target_folder) %>"> <div class="dmsf_filename" title="<%= l(:label_target_folder) %>">
<%= link.external_url %> <%= link.external_url %>
</div> </div>
@ -67,17 +67,18 @@
<span class="icon"></span> <span class="icon"></span>
<span class="icon"></span> <span class="icon"></span>
<span class="icon"></span> <span class="icon"></span>
<% if @file_manipulation_allowed %> <% if @file_delete_allowed %>
<%= link_to(image_tag('delete.png'), <%= link_to('',
dmsf_link_path(link), dmsf_link_path(link),
:data => {:confirm => l(:text_are_you_sure)}, :data => {:confirm => l(:text_are_you_sure)},
:method => :delete, :method => :delete,
:title => l(:title_delete)) %> :title => l(:title_delete),
:class => "icon icon-del") %>
<% else %> <% else %>
<span class="icon"></span> <span class="icon"></span>
<% end %> <% end %>
</td> </td>
<td class="dmsf_invisible"><%= position %> </td> <td class="hol"><%= position %> </td>
<td class="dmsf_invisible"></td> <td class="hol"></td>
<td class="dmsf_invisible">link.updated_at.to_i</td> <td class="hol">link.updated_at.to_i</td>
<td class="dmsf_invisible"></td> <td class="hol"></td>

View File

@ -30,7 +30,7 @@
<%= link_to(h(title), <%= link_to(h(title),
link.external_url, link.external_url,
:target => '_blank', :target => '_blank',
:class => 'icon dmsf_icon-link') %> :class => 'icon icon-link') %>
<div class="dmsf_filename" title="<%= l(:label_target_folder)%>"><%= link.external_url %></div> <div class="dmsf_filename" title="<%= l(:label_target_folder)%>"><%= link.external_url %></div>
</td> </td>
<% end %> <% end %>
@ -59,18 +59,15 @@
<% end %> <% end %>
<% end %> <% end %>
<td class="dmsf_buttons"> <td class="dmsf_buttons">
<% if @file_manipulation_allowed %> <%= link_to_if(@file_manipulation_allowed, '', restore_dmsf_link_path(:id => link),
<%= link_to(image_tag('restore.png', :plugin => 'redmine_dmsf'), :title => l(:title_restore), :class => "icon icon-cancel") %>
restore_dmsf_link_path(:id => link), <% if @file_delete_allowed %>
:title => l(:title_restore)) %> <%= link_to_if(@file_delete_allowed, '', dmsf_link_path(:id => link, :commit => 'yes'),
<%= link_to(image_tag('rev_delete.png', :plugin => 'redmine_dmsf'), :data => {:confirm => l(:text_are_you_sure)}, :method => :delete,
dmsf_link_path(:id => link, :commit => 'yes'), :title => l(:title_delete), :class => "icon icon-delete" ) %>
:data => {:confirm => l(:text_are_you_sure)},
:method => :delete,
:title => l(:title_delete)) %>
<% end %> <% end %>
</td> </td>
<td class="dmsf_invisible">1</td> <td class="hol">1</td>
<td class="dmsf_invisible"></td> <td class="hol"></td>
<td class="dmsf_invisible">link.updated_at.to_i</td> <td class="hol">link.updated_at.to_i</td>
<td class="dmsf_invisible"></td> <td class="hol"></td>

View File

@ -13,6 +13,7 @@ $("#browser").dataTable().fnDestroy();
// Add rows // Add rows
$('#<%= params[:row_id] %>').after('<%= escape_javascript(render(:partial => 'dmsf/dmsf_rows')) %>'); $('#<%= params[:row_id] %>').after('<%= escape_javascript(render(:partial => 'dmsf/dmsf_rows')) %>');
hideOnLoad();
// Reinitialize the dataTable // Reinitialize the dataTable
<% title = DmsfFolder.get_column_position('title') %> <% title = DmsfFolder.get_column_position('title') %>

View File

@ -25,42 +25,38 @@
<% html_title(l(:dmsf)) %> <% html_title(l(:dmsf)) %>
<div class="contextual"> <div class="contextual">
<% if !@folder.new_record? && User.current.allowed_to?(:folder_manipulation, @project) %> <% if !@folder.new_record? && User.current.allowed_to?(:folder_manipulation, @project) && !@folder.system %>
<% if !@folder.locked_for_user? %> <% unless @folder.locked? %>
<% unless @folder.locked? %> <%= link_to(l(:button_lock), lock_dmsf_path(:id => @project, :folder_id => @folder),
<%= link_to(l(:button_lock), :title => l(:title_lock_file), :class => 'icon icon-lock') %>
lock_dmsf_path(:id => @project, :folder_id => @folder), <% else %>
:title => l(:title_lock_file), :class => 'icon dmsf_icon-lock') %> <%= link_to_if(@folder.unlockable? && (!@folder.locked_for_user? || @force_file_unlock_allowed), l(:button_unlock),
<% else %>
<%= link_to_if(@folder.unlockable?, l(:button_unlock),
unlock_dmsf_path(:id => @project, :folder_id => @folder),
:title => l(:title_unlock_file), :class => 'icon dmsf_icon-unlock')%>
<% end %>
<% if @folder.notification %>
<%= link_to(l(:label_notifications_off),
notify_deactivate_dmsf_path(:id => @project, :folder_id => @folder),
:title => l(:title_notifications_active_deactivate),
:class => 'icon dmsf_icon-notification-on') %>
<% else %>
<%= link_to(l(:label_notifications_on),
notify_activate_dmsf_path(:id => @project, :folder_id => @folder),
:title => l(:title_notifications_not_active_activate),
:class => 'icon dmsf_icon-notification-off') %>
<% end %>
<%= link_to(l(:label_link_to),
new_dmsf_link_path(:project_id => @project.id, :dmsf_folder_id => @folder.id, :type => 'link_to'),
:title => l(:title_create_link), :class => 'icon dmsf_icon-link') %>
<%= link_to(l(:button_copy), copy_folder_path(:id => @folder),
:title => l(:title_copy), :class => 'icon icon-copy') %>
<%= link_to(l(:button_delete),
delete_dmsf_path(:id => @project, :folder_id => @folder),
:data => {:confirm => l(:text_are_you_sure)},
:title => l(:title_delete), :class => 'icon icon-del') %>
<% elsif @force_file_unlock_allowed %>
<%= link_to_if(@folder.unlockable?, l(:button_unlock),
unlock_dmsf_path(:id => @project, :folder_id => @folder), unlock_dmsf_path(:id => @project, :folder_id => @folder),
:title => l(:title_unlock_file), :class => 'icon dmsf_icon-unlock')%> :title => l(:title_unlock_file), :class => 'icon icon-unlock')%>
<% end %> <% end %>
<% unless @folder.locked? %>
<% if @folder.notification %>
<%= link_to(l(:label_notifications_off),
notify_deactivate_dmsf_path(:id => @project, :folder_id => @folder),
:title => l(:title_notifications_active_deactivate),
:class => 'icon icon-email') %>
<% else %>
<%= link_to(l(:label_notifications_on),
notify_activate_dmsf_path(:id => @project, :folder_id => @folder),
:title => l(:title_notifications_not_active_activate),
:class => 'icon icon-email-add') %>
<% end %>
<% end %>
<%= link_to(l(:label_link_to),
new_dmsf_link_path(:project_id => @project.id, :dmsf_folder_id => @folder.id, :type => 'link_to'),
:title => l(:title_create_link), :class => 'icon icon-link') %>
<%= link_to(l(:button_copy), copy_folder_path(:id => @folder),
:title => l(:title_copy), :class => 'icon icon-copy') %>
<% unless @folder.locked? %>
<%= link_to(l(:button_delete), delete_dmsf_path(:id => @project, :folder_id => @folder),
:data => {:confirm => l(:text_are_you_sure)},
:title => l(:title_delete), :class => 'icon icon-del', :method => :delete) %>
<% end %>
<% end %> <% end %>
</div> </div>
@ -85,7 +81,28 @@
<p> <p>
<%= f.text_area :description, :rows => 8, :class => 'wiki-edit' %> <%= f.text_area :description, :rows => 8, :class => 'wiki-edit' %>
</p> </p>
<% values = @folder ? @folder.custom_field_values : @parent ? @parent.custom_field_values : DmsfFolder.new(:project => @project).custom_field_values %> <p>
<%= label_tag '', l(:label_permissions) %>
<% User.current.managed_roles(@project).each do |role| %>
<% checked = @folder.dmsf_folder_permissions.roles.exists?(:object_id => role.id) %>
<label class="inline"><%= check_box_tag 'permissions[role_ids][]', role.id, checked, :id => nil %> <%= role %></label>
<% end %>
<span id="user_permissions">
<br/>
<% checkboxes = users_checkboxes(@users) %>
<%= checkboxes %>
</span>
<% if checkboxes.present? %>
<br/>
<% end %>
<span class="search_for_watchers">
<%= link_to l(:label_user_search_add),
new_dmsf_folder_permissions_path(:project_id => @project, :dmsf_folder_id => @folder),
:remote => true,
:method => 'get' %>
</span>
</p>
<% values = @folder ? @folder.custom_field_values : @parent ? @parent.custom_field_values : DmsfFolder.new.custom_field_values %>
<% values.each do |value| %> <% values.each do |value| %>
<p><%= custom_field_tag_with_label(:dmsf_folder, value) %></p> <p><%= custom_field_tag_with_label(:dmsf_folder, value) %></p>
<% end %> <% end %>
@ -97,4 +114,4 @@
<script type="text/javascript"> <script type="text/javascript">
$('#dmsf_folder_dmsf_folder_id').select2(); $('#dmsf_folder_dmsf_folder_id').select2();
</script> </script>

View File

@ -30,12 +30,12 @@
<%= link_to(l(:label_notifications_off), <%= link_to(l(:label_notifications_off),
notify_deactivate_dmsf_path(:id => @project), notify_deactivate_dmsf_path(:id => @project),
:title => l(:title_notifications_active_deactivate), :title => l(:title_notifications_active_deactivate),
:class => 'icon dmsf_icon-notification-on') %> :class => 'icon icon-email') %>
<% else %> <% else %>
<%= link_to(l(:label_notifications_on), <%= link_to(l(:label_notifications_on),
notify_activate_dmsf_path(:id => @project), notify_activate_dmsf_path(:id => @project),
:title => l(:title_notifications_active_deactivate), :title => l(:title_notifications_active_deactivate),
:class => 'icon dmsf_icon-notification-off') %> :class => 'icon icon-email-add') %>
<% end %> <% end %>
<% end %> <% end %>
</div> </div>
@ -54,4 +54,4 @@
<%= f.submit l(:submit_save) %> <%= f.submit l(:submit_save) %>
<% end %> <% end %>
<%= wikitoolbar_for 'project_dmsf_description' %> <%= wikitoolbar_for 'project_dmsf_description' %>

View File

@ -1,78 +1,79 @@
<% <%
# encoding: utf-8 # encoding: utf-8
# #
# Redmine plugin for Document Management System "Features" # Redmine plugin for Document Management System "Features"
# #
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com> # Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright (C) 2012 Daniel Munn <dan.munn@munnster.co.uk> # Copyright (C) 2012 Daniel Munn <dan.munn@munnster.co.uk>
# Copyright (C) 2011-17 Karel Pičman <karel.picman@kontron.com> # Copyright (C) 2011-17 Karel Pičman <karel.picman@kontron.com>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%> %>
<% html_title l(:dmsf) %> <% html_title l(:dmsf) %>
<div class="contextual"> <div class="contextual">
<% if @folder_manipulation_allowed %> <% if @folder_manipulation_allowed && !@system_folder %>
<% if @folder.nil? %> <% if @folder.nil? %>
<%= link_to(l(:button_edit), edit_root_dmsf_path(:id => @project), <%= link_to(l(:button_edit), edit_root_dmsf_path(:id => @project),
:title => l(:link_edit, :title => l(:link_documents)), :title => l(:link_edit, :title => l(:link_documents)),
:class => 'icon icon-edit') %> :class => 'icon icon-edit') %>
<% elsif !@locked_for_user %> <% elsif !@locked_for_user %>
<%= link_to(l(:button_edit), <%= link_to(l(:button_edit),
edit_dmsf_path(:id => @project, :folder_id => @folder), edit_dmsf_path(:id => @project, :folder_id => @folder),
:title => l(:link_edit, :title => h(@folder.title)), :title => l(:link_edit, :title => h(@folder.title)),
:class => 'icon icon-edit') %> :class => 'icon icon-edit') %>
<% end %>
<% if @folder && (!@locked_for_user || User.current.allowed_to?(:force_file_unlock, @project)) %>
<% if @folder.locked? %>
<%= link_to_if(@folder.unlockable?, l(:button_unlock),
unlock_dmsf_path(:id => @project, :folder_id => @folder, :current => request.url),
:title => l(:title_unlock_folder), :class => 'icon dmsf_icon-unlock') %>
<% else %>
<%= link_to(l(:button_lock),
lock_dmsf_path(:id => @project, :folder_id => @folder, :current => request.url),
:title => l(:title_lock_folder), :class => 'icon dmsf_icon-lock') %>
<% end %> <% end %>
<% end %> <% if @folder && (!@locked_for_user || User.current.allowed_to?(:force_file_unlock, @project)) %>
<% if !@locked_for_user && ((@folder && @folder.notification) || (!@folder && @project.dmsf_notification)) %> <% if @folder.locked? %>
<%= link_to(l(:label_notifications_off), <%= link_to_if(@folder.unlockable?, l(:button_unlock),
notify_deactivate_dmsf_path(:id => @project, :folder_id => @folder), unlock_dmsf_path(:id => @project, :folder_id => @folder, :current => request.url),
:title => l(:title_notifications_active_deactivate), :title => l(:title_unlock_folder), :class => 'icon icon-unlock') %>
:class => 'icon dmsf_icon-notification-on') %> <% else %>
<% else %> <%= link_to(l(:button_lock),
<%= link_to(l(:label_notifications_on), lock_dmsf_path(:id => @project, :folder_id => @folder, :current => request.url),
notify_activate_dmsf_path(:id => @project, :folder_id => @folder), :title => l(:title_lock_folder), :class => 'icon icon-lock') %>
:title => l(:title_notifications_not_active_activate), <% end %>
:class => 'icon dmsf_icon-notification-off') %> <% end %>
<% end %> <% if !@locked_for_user && ((@folder && @folder.notification) || (!@folder && @project.dmsf_notification)) %>
<% if @file_manipulation_allowed && !@locked_for_user %> <%= link_to(l(:label_notifications_off),
<%= link_to(l(:label_link_from), notify_deactivate_dmsf_path(:id => @project, :folder_id => @folder),
new_dmsf_link_path(:project_id => @project.id, :dmsf_folder_id => @folder ? @folder.id : @folder, :type => 'link_from'), :title => l(:title_notifications_active_deactivate),
:title => l(:title_create_link), :class => 'icon dmsf_icon-link') %> :class => 'icon icon-email') %>
<% end %> <% else %>
<%= link_to(l(:link_create_folder), <%= link_to(l(:label_notifications_on),
new_dmsf_path(:id => @project, :parent_id => @folder), notify_activate_dmsf_path(:id => @project, :folder_id => @folder),
:title => l(:link_create_folder), :title => l(:title_notifications_not_active_activate),
:class => 'icon icon-add') unless @locked_for_user %> :class => 'icon icon-email-add') %>
<% end %>
<% if @file_manipulation_allowed && !@locked_for_user %>
<%= link_to(l(:label_link_from),
new_dmsf_link_path(:project_id => @project.id, :dmsf_folder_id => @folder ? @folder.id : @folder,
:type => 'link_from'), :title => l(:title_create_link),
:class => 'icon icon-link') %>
<% end %>
<%= link_to(l(:link_create_folder),
new_dmsf_path(:id => @project, :parent_id => @folder),
:title => l(:link_create_folder),
:class => 'icon icon-add') unless @locked_for_user %>
<% end %> <% end %>
<%= link_to_if(@trash_enabled, l(:link_trash_bin), trash_dmsf_path(@project), <%= link_to_if(@trash_enabled, l(:link_trash_bin), trash_dmsf_path(@project),
:title => l(:link_trash_bin), :class => 'icon icon-del') if @trash_visible %> :title => l(:link_trash_bin), :class => 'icon icon-del') if @trash_visible %>
</div> </div>
<%= render(:partial => 'path', <%= render(:partial => 'path',
:locals => {:folder => @folder, :filename => nil, :title => nil}) %> :locals => {:folder => @folder, :filename => nil, :title => nil}) %>
<div class="dmsf-header"> <div class="dmsf-header">
<div class="wiki"> <div class="wiki">
@ -82,134 +83,145 @@
<%= error_messages_for('dmsf_workflow') %> <%= error_messages_for('dmsf_workflow') %>
<%= form_tag({:action => :entries_operation, :id => @project, :folder_id => @folder}, :method => :post, <%= form_tag(entries_operations_dmsf_path(:id => @project, :folder_id => @folder), :method => :post,
:class => 'dmsf_entries', :id => 'entries_form') do %> :class => 'dmsf_entries', :id => 'entries_form') do %>
<%= hidden_field_tag('action') %> <%= hidden_field_tag('action') %>
<div id="dmsf_buttons" class="dmsf_controls" style="float: left"> <div id="dmsf_buttons" class="dmsf_controls" style="float: left">
<%= submit_tag(l(:button_download), :title => l(:title_download_checked), :name => 'download_entries') if @file_view_allowed %> <%= submit_tag(l(:button_download), :title => l(:title_download_checked), :name => 'download_entries') if @file_view_allowed %>
<%= submit_tag(l(:field_mail), :title => l(:title_send_checked_by_email), :name => 'email_entries') if (@file_view_allowed && User.current.allowed_to?(:email_documents, @project)) %> <%= submit_tag(l(:field_mail), :title => l(:title_send_checked_by_email), :name => 'email_entries') if (@file_view_allowed && User.current.allowed_to?(:email_documents, @project)) %>
<% if @file_delete_allowed%> <% if @file_delete_allowed%>
<%= submit_tag(l(:button_delete), :title => l(:title_delete_checked), :name => 'delete_entries') if @file_delete_allowed %> <%= submit_tag(l(:button_delete), :title => l(:title_delete_checked), :name => 'delete_entries') if @file_delete_allowed %>
<% end %> <% end %>
</div>
<% values = @folder ? @folder.custom_field_values : @parent ? @parent.custom_field_values : DmsfFolder.new(:project => @project).custom_field_values %>
<% unless values.empty? %>
<div id="dmsf_tag" class="dmsf_controls" style="float: right">
<%= custom_field_tag_with_label(
:dmsf_folder,
CustomValue.new(:custom_field_id => params[:custom_field_id].present? ? params[:custom_field_id] : values.first.custom_field_id, :value => params[:custom_value])) %>
</div> </div>
<% end %> <% unless @system_folder %>
<div class="autoscroll"> <% values = @folder ? @folder.custom_field_values : DmsfFolder.new.custom_field_values %>
<% if @tree_view %> <% unless values.empty? %>
<%= render(:partial => 'tree_view') %> <div id="dmsf_tag" class="dmsf_controls" style="float: right">
<% else %> <% custom_value = values.first %>
<%= render(:partial => 'list_view') %> <% custom_value.custom_field.is_required = false %>
<% custom_value.value = params[:custom_value].present? ? params[:custom_value] : '' %>
<%= h(custom_value.custom_field.name) %>:
<%= custom_value.custom_field.format.edit_tag(self,
custom_field_tag_id(:dmsf_folder, custom_value.custom_field),
custom_field_tag_name(:dmsf_folder, custom_value.custom_field),
custom_value,
:class => "#{custom_value.custom_field.field_format}_cf",
:style => 'width: auto') %>
</div>
<% end %>
<% end %> <% end %>
</div> <div class="autoscroll">
<% if @tree_view %>
<%= render(:partial => 'tree_view') %>
<% else %>
<%= render(:partial => 'list_view') %>
<% end %>
</div>
<% end %> <% end %>
<script type="text/javascript"> <script type="text/javascript">
$('#entries_delete_button').click(function() { $('#entries_delete_button').click(function() {
if(window.confirm("<%= l(:text_are_you_sure) %>")) { if(window.confirm("<%= l(:text_are_you_sure) %>")) {
$('#entries_form').attr('action', "<%= delete_entries_path(:id => @project, :folder_id => @folder) %>"); $('#entries_form').attr('action', "<%= delete_entries_path(:id => @project, :folder_id => @folder) %>");
$('#entries_form').submit(); $('#entries_form').submit();
} }
}); });
$('.list_cf').change(function() { $('.list_cf').change(function() {
$('#entries_form').attr('action', "<%= tag_changed_path(:id => @project, :folder_id => @folder) %>"); $('#entries_form').attr('action', "<%= tag_changed_path(:id => @project, :folder_id => @folder) %>");
$('#entries_form').submit(); $('#entries_form').submit();
}); });
$('#check_all_entries').click(function() { $('#check_all_entries').click(function() {
$('input[type=checkbox]', $('#browser > tbody')).prop('checked', this.checked); $('input[type=checkbox]', $('#browser > tbody')).prop('checked', this.checked);
}); });
</script> </script>
<% content_for :header_tags do %> <% content_for :header_tags do %>
<%= javascript_include_tag 'bowser.min.js', :plugin => 'redmine_dmsf' %> <%= javascript_include_tag 'bowser.min.js', :plugin => 'redmine_dmsf' %>
<%= stylesheet_link_tag 'jquery.dataTables/jquery-ui.dataTables.css', :plugin => 'redmine_dmsf' %> <%= stylesheet_link_tag 'jquery.dataTables/jquery-ui.dataTables.css', :plugin => 'redmine_dmsf' %>
<%= javascript_include_tag 'jquery.dataTables/jquery.dataTables.min.js', :plugin => 'redmine_dmsf' %> <%= javascript_include_tag 'jquery.dataTables/jquery.dataTables.min.js', :plugin => 'redmine_dmsf' %>
<% title = DmsfFolder.get_column_position('title') %> <% title = DmsfFolder.get_column_position('title') %>
<% position = DmsfFolder.get_column_position('position') %> <% position = DmsfFolder.get_column_position('position') %>
<% commands = DmsfFolder.get_column_position('commands') %> <% commands = DmsfFolder.get_column_position('commands') %>
<% position = DmsfFolder.get_column_position('position') %> <% position = DmsfFolder.get_column_position('position') %>
<% version = DmsfFolder.get_column_position('version') %> <% version = DmsfFolder.get_column_position('version') %>
<% size_calculated = DmsfFolder.get_column_position('size_calculated') %> <% size_calculated = DmsfFolder.get_column_position('size_calculated') %>
<% modified_calculated = DmsfFolder.get_column_position('modified_calculated') %> <% modified_calculated = DmsfFolder.get_column_position('modified_calculated') %>
<% version_calculated = DmsfFolder.get_column_position('version_calculated') %> <% version_calculated = DmsfFolder.get_column_position('version_calculated') %>
<% size = DmsfFolder.get_column_position('size') %> <% size = DmsfFolder.get_column_position('size') %>
<% modified = DmsfFolder.get_column_position('modified') %> <% modified = DmsfFolder.get_column_position('modified') %>
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function() { $(document).ready(function() {
$('#browser').dataTable({ $('#browser').dataTable({
'bJQueryUI': true, 'bJQueryUI': true,
'oLanguage': { 'oLanguage': {
'sUrl': "<%= plugin_asset_path(:redmine_dmsf, 'javascripts', json_url) %>" 'sUrl': "<%= plugin_asset_path(:redmine_dmsf, 'javascripts', json_url) %>"
}, },
'bAutoWidth': false, 'bAutoWidth': false,
'bPaginate': false, 'bPaginate': false,
<% if title %> <% if title %>
'aaSorting': [[<%= title %>, 'asc']], 'aaSorting': [[<%= title %>, 'asc']],
<% end %> <% end %>
'aaSortingFixed': [[ <%= position %>, 'asc']], 'aaSortingFixed': [[ <%= position %>, 'asc']],
'aoColumnDefs': [ 'aoColumnDefs': [
{ 'bSearchable': false, 'aTargets': [0, <%= commands %>, <%= position %>, <%= size_calculated %>, <%= modified_calculated %>, <%= version_calculated %>] }, { 'bSearchable': false, 'aTargets': [0, <%= commands %>, <%= position %>, <%= size_calculated %>, <%= modified_calculated %>, <%= version_calculated %>] },
{ 'bSortable': false, 'aTargets': [0, <%= commands %>] } { 'bSortable': false, 'aTargets': [0, <%= commands %>] }
<% if size %> <% if size %>
,{ 'iDataSort': <%= size_calculated %>, 'aTargets': [ <%= size %> ] } ,{ 'iDataSort': <%= size_calculated %>, 'aTargets': [ <%= size %> ] }
<% end %> <% end %>
<% if modified %> <% if modified %>
,{ 'iDataSort': <%= modified_calculated %>, 'aTargets': [ <%= modified %> ] } ,{ 'iDataSort': <%= modified_calculated %>, 'aTargets': [ <%= modified %> ] }
<% end %> <% end %>
<% if version %> <% if version %>
,{ 'iDataSort': <%= version_calculated %>, 'aTargets': [ <%= version %> ] } ,{ 'iDataSort': <%= version_calculated %>, 'aTargets': [ <%= version %> ] }
<% end %> <% end %>
], ],
'fnInitComplete': function() { 'fnInitComplete': function() {
$('#dmsf_buttons').prependTo($('#browser_wrapper div.fg-toolbar')[0]); $('#dmsf_buttons').prependTo($('#browser_wrapper div.fg-toolbar')[0]);
$('#dmsf_tag').prependTo($('#browser_wrapper div.fg-toolbar')[0]); $('#dmsf_tag').prependTo($('#browser_wrapper div.fg-toolbar')[0]);
}, },
'fnInfoCallback': function( oSettings, iStart, iEnd, iMax, iTotal, sPre ) { 'fnInfoCallback': function( oSettings, iStart, iEnd, iMax, iTotal, sPre ) {
<% if @tree_view %> <% if @tree_view %>
<% if @folder %> <% if @folder %>
return "<%= "#{l(:label_number_of_folders)}: #{@folder.deep_folder_count} #{l(:label_number_of_documents)}: #{@folder.deep_file_count}" %>"; return "<%= "#{l(:label_number_of_folders)}: #{@folder.deep_folder_count} #{l(:label_number_of_documents)}: #{@folder.deep_file_count}" %>";
<% else %> <% else %>
return "<%= "#{l(:label_number_of_folders)}: #{DmsfFolder.visible.where(:project_id => @project.id).count + DmsfLink.visible.where(:project_id => @project.id, :target_type => 'DmsfFolder').count}, #{l(:label_number_of_documents)}: #{DmsfFile.visible.where(:container_id => @project.id, :container_type => 'Project').count + DmsfLink.visible.where(:project_id => @project.id, :target_type => 'DmsfFile').count + DmsfLink.visible.where(:project_id => @project.id, :target_type => 'DmsfUrl').count}" %>"; return "<%= "#{l(:label_number_of_folders)}: #{DmsfFolder.visible.where(:project_id => @project.id).count + DmsfLink.visible.where(:project_id => @project.id, :target_type => 'DmsfFolder').count}, #{l(:label_number_of_documents)}: #{DmsfFile.visible.where(:project_id => @project.id).count + DmsfLink.visible.where(:project_id => @project.id, :target_type => ['DmsfFile', 'DmsfUrl']).count}" %>";
<% end %> <% end %>
<% else %> <% else %>
return "<%= "#{l(:label_number_of_folders)}: #{@subfolders.count + @dir_links.count}, #{l(:label_number_of_documents)}: #{@files.count + @file_links.count + @url_links.count}" %>"; return "<%= "#{l(:label_number_of_folders)}: #{@subfolders.count + @dir_links.count}, #{l(:label_number_of_documents)}: #{@files.count + @file_links.count + @url_links.count}" %>";
<% end %> <% end %>
} }
}); });
$('[data-downloadurl]').each(function() { $('[data-downloadurl]').each(function() {
var url = this.getAttribute('data-downloadurl'); var url = this.getAttribute('data-downloadurl');
if (this.addEventListener) { if (this.addEventListener) {
this.addEventListener('dragstart', function(e) { this.addEventListener('dragstart', function(e) {
if (e.dataTransfer) { if (e.dataTransfer) {
e.dataTransfer.setData('DownloadURL', url); e.dataTransfer.setData('DownloadURL', url);
} }
},false); },false);
} }
}); });
$('#entries_form').submit(function () { $('#entries_form').submit(function () {
$(this).removeAttr('data-submitted'); $(this).removeAttr('data-submitted');
}); });
}); });
</script> </script>
<% end %> <% end %>
<% if (@file_manipulation_allowed && !@locked_for_user) %> <% if (@file_manipulation_allowed && !@locked_for_user && !@system_folder) %>
<%= render(:partial => 'dmsf_upload/multi_upload') %> <%= render(:partial => 'dmsf_upload/multi_upload', :local => { :lbl => true }) %>
<% end %> <% end %>
<% other_formats_links do |f| %> <% unless @system_folder %>
<%= f.link_to 'CSV', :url => params, :onclick => "showModal('csv-export-options', '350px'); return false;" %> <% other_formats_links do |f| %>
<%= f.link_to 'CSV', :url => params, :onclick => "showModal('csv-export-options', '350px'); return false;" %>
<% end %>
<% end %> <% end %>
<div id="csv-export-options" style="display:none;"> <div id="csv-export-options" style="display:none;">
@ -218,7 +230,7 @@
<%= hidden_field_tag(:folder_id, @folder.id) if @folder %> <%= hidden_field_tag(:folder_id, @folder.id) if @folder %>
<div class="tabular"> <div class="tabular">
<%= render(:partial => 'settings/dmsf_columns', <%= render(:partial => 'settings/dmsf_columns',
:locals => { :settings => Setting.plugin_redmine_dmsf, :extra_columns => @extra_columns }) %> :locals => { :selected_columns => Setting.plugin_redmine_dmsf['dmsf_columns'], :extra_columns => @extra_columns }) %>
</div> </div>
<p class="buttons"> <p class="buttons">
<%= submit_tag l(:button_export), :name => nil, :onclick => "hideModal(this);" %> <%= submit_tag l(:button_export), :name => nil, :onclick => "hideModal(this);" %>

View File

@ -81,10 +81,10 @@
<% end %> <% end %>
<% end %> <% end %>
<th class ="dmsf_th"><%# controls %></th> <th class ="dmsf_th"><%# controls %></th>
<th class="dmsf_invisible"><%# position %></th> <th class="hol"><%# position %></th>
<th class="dmsf_invisible"><%# size %></th> <th class="hol"><%# size %></th>
<th class="dmsf_invisible"><%# updated %></th> <th class="hol"><%# updated %></th>
<th class="dmsf_invisible"><%# version %></th> <th class="hol"><%# version %></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View File

@ -78,11 +78,12 @@
<div class="box"> <div class="box">
<p> <p>
<%= label_tag('file_upload', l(:label_new_content)) %> <%= label_tag('file_upload', l(:label_new_content)) %>
<%= render :partial => 'dmsf_upload/form', :locals => { :multiple => false } %> <%= render :partial => 'dmsf_upload/form',
:locals => { :multiple => false, :container => nil, :description => false, :awf => false } %>
</p> </p>
</div> </div>
<p> <p>
<%= f.text_area(:comment, :rows => 2, :label => l(:label_comment)) %> <%= f.text_area(:comment, :rows => 2, :label => l(:label_comment), :class => 'wiki-edit') %>
</p> </p>
<%= f.submit l(:submit_create) %> <%= f.submit l(:submit_create) %>
<% end %> <% end %>

View File

@ -0,0 +1,101 @@
<%
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-17 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.
%>
<% if link %>
<p class="dmsf_gray">
<% else %>
<p>
<% end %>
<% file_view_url = url_for({:controller => :dmsf_files, :action => 'view', :id => dmsf_file}) %>
<%= link_to(h(dmsf_file.title),
file_view_url,
:target => '_blank',
:class => "icon icon-file #{DmsfHelper.filetype_css(dmsf_file.name)}",
:title => h(dmsf_file.last_revision.try(:tooltip)),
'data-downloadurl' => "#{dmsf_file.last_revision.detect_content_type}:#{h(dmsf_file.name)}:#{file_view_url}") %>
<% if dmsf_file.text? || dmsf_file.image? %>
<%= link_to l(:button_view),
file_view_url,
:class => 'icon-only icon-magnifier',
:title => l(:button_view) %>
<% end %>
<%= " - #{dmsf_file.description}" unless dmsf_file.description.blank? %>
<span class="size">(<%= number_to_human_size dmsf_file.last_revision.size %>)</span>
<span class="author"><%= dmsf_file.last_revision.user %>, <%= format_time(dmsf_file.last_revision.updated_at) %></span>
<% # Command icons %>
<span class="dmsf_upload_select">
<% # Details %>
<% if User.current.allowed_to? :file_manipulation, dmsf_file.project %>
<%= link_to('', dmsf_file_path(:id => dmsf_file),
:title => l(:link_details, :title => h(dmsf_file.last_revision.title)),
:class => 'icon-only icon-edit') %>
<% else %>
<span class="icon-only"></span>
<% end %>
<% # Email %>
<%= link_to('', entries_operations_dmsf_path(:id => dmsf_file.project_id, :email_entries => 'email',
:files => [dmsf_file.id]), :method => :post, :title => l(:heading_send_documents_by_email),
:class => 'icon-only icon-email-disabled') %>
<% # Lock %>
<% if !dmsf_file.locked? %>
<%= link_to('', lock_dmsf_files_path(:id => dmsf_file),
:title => l(:title_lock_file),
:class => 'icon-only icon-lock') %>
<% elsif dmsf_file.unlockable? && (!dmsf_file.locked_for_user? || User.current.allowed_to?(:force_file_unlock, dmsf_file.project)) %>
<%= link_to('', unlock_dmsf_files_path(:id => dmsf_file),
:title => dmsf_file.get_locked_title,
:class => 'icon-only icon-unlock') %>
<% else %>
<span class="icon-only icon-unlock" title="<%= dmsf_file.get_locked_title %>"></span>
<% end %>
<% unless dmsf_file.locked? %>
<% # Notifications %>
<% if dmsf_file.notification %>
<%= link_to('', notify_deactivate_dmsf_files_path(:id => dmsf_file),
:title => l(:title_notifications_active_deactivate),
:class => 'icon-only icon-email') %>
<% else %>
<%= link_to('', notify_activate_dmsf_files_path(:id => dmsf_file),
:title => l(:title_notifications_not_active_activate),
:class => 'icon-only icon-email-add') %>
<% end %>
<% # Delete %>
<% if @issue.attributes_editable? && User.current.allowed_to?(:file_delete, dmsf_file.project) %>
<%= link_to('',
link ? dmsf_link_path(link, :commit => 'yes') : dmsf_file_path(:id => dmsf_file, :commit => 'yes'),
:data => {:confirm => l(:text_are_you_sure)},
:method => :delete,
:title => l(:title_delete),
:class => 'icon-only icon-del') %>
<% end %>
<% else %>
<span class="icon-only"></span>
<span class="icon-only"></span>
<% end %>
<% # Approval workflow %>
<% wf = DmsfWorkflow.find_by_id(dmsf_file.last_revision.dmsf_workflow_id) if dmsf_file.last_revision.dmsf_workflow_id %>
<%= render(:partial => 'dmsf_workflows/approval_workflow_button',
:locals => {:file => dmsf_file,
:file_approval_allowed => User.current.allowed_to?(:file_approval, dmsf_file.project),
:workflows_available => DmsfWorkflow.where(['project_id = ? OR project_id IS NULL', dmsf_file.project_id]).exists?,
:project => dmsf_file.project, :wf => wf, :dmsf_link_id => nil }) %>
</span>
</p>

View File

@ -20,51 +20,14 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%> %>
<% if dmsf_files.present? %> <% if links.present? %>
<hr/> <hr/>
<div class="attachments"> <strong><%= l(:menu_dmsf) %></strong>
<% for dmsf_file in dmsf_files %> <div class="attachments dmsf_parent_container">
<% if dmsf_file.last_revision %> <% # DMS documents & links %>
<p> <% links.each do |dmsf_file, link, create_at| %>
<% file_view_url = url_for({:controller => :dmsf_files, :action => 'view', :id => dmsf_file}) %> <%= render :partial => 'dmsf_files/link', :locals => { :dmsf_file => dmsf_file, :link => link } %>
<%= link_to(h(dmsf_file.title),
file_view_url,
:target => '_blank',
:class => "icon icon-file #{DmsfHelper.filetype_css(dmsf_file.name)}",
:title => h(dmsf_file.last_revision.try(:tooltip)),
'data-downloadurl' => "#{dmsf_file.last_revision.detect_content_type}:#{h(dmsf_file.name)}:#{file_view_url}") %>
<% if dmsf_file.text? || dmsf_file.image? %>
<%= link_to l(:button_view),
file_view_url,
:class => 'icon-only icon-magnifier',
:title => l(:button_view) %>
<% end %>
<%= " - #{dmsf_file.description}" unless dmsf_file.description.blank? %>
<span class="size">(<%= number_to_human_size dmsf_file.last_revision.size %>)</span>
<% if User.current.allowed_to?(:file_delete, dmsf_file.project) %>
<%= link_to(image_tag('delete.png'),
dmsf_file_path(:id => dmsf_file, :commit => 'yes'),
:data => {:confirm => l(:text_are_you_sure)},
:method => :delete,
:title => l(:title_delete)) %>
<% end %>
<span class="author"><%= dmsf_file.last_revision.user %>, <%= format_time(dmsf_file.last_revision.updated_at) %></span>
</p>
<% end %>
<% end %>
<% if defined?(thumbnails) && thumbnails %>
<% images = dmsf_files.select(&:image?) %>
<% if images.any? %>
<div class="thumbnails">
<% images.each do |file| %>
<div>
<%= link_to image_tag(dmsf_thumbnail_path(file)),
url_for({:controller => :dmsf_files, :action => 'view', :id => file}),
:alt => dmsf_file.title %>
</div>
<% end %>
</div>
<% end %>
<% end %> <% end %>
<%= render :partial => 'dmsf_files/thumbnails', :locals => { :links => links, :thumbnails => thumbnails, :link_to => true } %>
</div> </div>
<% end %> <% end %>

View File

@ -0,0 +1,44 @@
<%
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-17 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.
%>
<% # Thumbnails %>
<% if defined?(thumbnails) && thumbnails %>
<% images = links.map{ |x| x[0] }.select(&:image?) %>
<% if images.any? %>
<% if link_to # Redmine classic %>
<div class="thumbnails">
<% end %>
<% images.each do |file| %>
<div>
<% if link_to # Redmine classic %>
<%= link_to image_tag(dmsf_thumbnail_path(file)), view_dmsf_file_path(file), :alt => file.title %>
<% else # jQuery gallery %>
<%= image_tag(dmsf_thumbnail_path(file),
{ :'data-fullsrc' => view_dmsf_file_path(file), :alt => file.title }) %>
<% end %>
</div>
<% end %>
<% if link_to # Redmine classic %>
</div>
<% end %>
<% end %>
<% end %>

View File

@ -1,9 +1,14 @@
api.dmsf_file do api.dmsf_file do
api.id @file.id api.id @file.id
api.name @file.name api.name @file.name
api.container_id @file.container_id api.project_id @file.project_id
api.container_type @file.container_type api.dmsf_folder_id @file.dmsf_folder_id if @file.dmsf_folder_id
api.dmsf_folder_id @file.folder if @file.dmsf_folder_id if @file.last_revision
api.version "#{@file.last_revision.major_version}.#{@file.last_revision.minor_version}" if @file.last_revision api.version "#{@file.last_revision.major_version}.#{@file.last_revision.minor_version}"
api.mime_type @file.last_revision.mime_type
api.digest @file.last_revision.digest
api.size @file.last_revision.size
api.description @file.last_revision.description
end
api.content_url url_for(:controller => :dmsf_files, :action => 'show', :download => '', :id => @file) api.content_url url_for(:controller => :dmsf_files, :action => 'show', :download => '', :id => @file)
end end

View File

@ -29,33 +29,33 @@
<% unless @file.locked_for_user? %> <% unless @file.locked_for_user? %>
<% unless @file.locked? %> <% unless @file.locked? %>
<%= link_to(l(:button_lock), lock_dmsf_files_path(:id => @file), <%= link_to(l(:button_lock), lock_dmsf_files_path(:id => @file),
:title => l(:title_lock_file), :class => 'icon dmsf_icon-lock') %> :title => l(:title_lock_file), :class => 'icon icon-lock') %>
<% else %> <% else %>
<%= link_to_if(@file.unlockable?, l(:button_unlock), unlock_dmsf_files_path(:id => @file), <%= link_to_if(@file.unlockable?, l(:button_unlock), unlock_dmsf_files_path(:id => @file),
:title => l(:title_unlock_file), :class => 'icon dmsf_icon-unlock') %> :title => l(:title_unlock_file), :class => 'icon icon-unlock') %>
<% end %> <% end %>
<% if @file.notification %> <% if @file.notification %>
<%= link_to(l(:label_notifications_off), <%= link_to(l(:label_notifications_off),
notify_deactivate_dmsf_files_path(:id => @file), notify_deactivate_dmsf_files_path(:id => @file),
:title => l(:title_notifications_active_deactivate), :title => l(:title_notifications_active_deactivate),
:class => 'icon dmsf_icon-notification-on') %> :class => 'icon icon-email') %>
<% else %> <% else %>
<%= link_to(l(:label_notifications_on), <%= link_to(l(:label_notifications_on),
notify_activate_dmsf_files_path(:id => @file), notify_activate_dmsf_files_path(:id => @file),
:title => l(:title_notifications_not_active_activate), :title => l(:title_notifications_not_active_activate),
:class => 'icon dmsf_icon-notification-off') %> :class => 'icon icon-email-add') %>
<% end %> <% end %>
<%= link_to(l(:label_link_to), <%= link_to(l(:label_link_to),
new_dmsf_link_path(:project_id => @project.id, :dmsf_folder_id => @file.dmsf_folder ? @file.dmsf_folder.id : nil, :dmsf_file_id => @file.id, :type => 'link_to'), new_dmsf_link_path(:project_id => @project.id, :dmsf_folder_id => @file.dmsf_folder ? @file.dmsf_folder.id : nil, :dmsf_file_id => @file.id, :type => 'link_to'),
:title => l(:title_create_link), :title => l(:title_create_link),
:class => 'icon dmsf_icon-link') %> :class => 'icon icon-link') %>
<%= link_to("#{l(:button_copy)}/#{l(:button_move)}", copy_file_path(:id => @file), <%= link_to("#{l(:button_copy)}/#{l(:button_move)}", copy_file_path(:id => @file),
:title => l(:title_copy), :class => 'icon icon-copy') %> :title => l(:title_copy), :class => 'icon icon-copy') %>
<%= delete_link(dmsf_file_path(:id => @file, :details => true)) if @file_delete_allowed %> <%= delete_link(dmsf_file_path(:id => @file, :details => true)) if @file_delete_allowed %>
<% else %> <% else %>
<% if User.current.allowed_to?(:force_file_unlock, @project) %> <% if User.current.allowed_to?(:force_file_unlock, @project) %>
<%= link_to_if(@file.unlockable?, l(:button_unlock), unlock_dmsf_files_path(:id => @file), <%= link_to_if(@file.unlockable?, l(:button_unlock), unlock_dmsf_files_path(:id => @file),
:title => l(:title_unlock_file), :class => 'icon dmsf_icon-unlock')%> :title => l(:title_unlock_file), :class => 'icon icon-unlock')%>
<% end %> <% end %>
<% end %> <% end %>
<% end %> <% end %>
@ -81,13 +81,13 @@
<div class="fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix"> <div class="fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix">
<div class="dataTables_lenght"> <div class="dataTables_lenght">
<div class="dmsf_controls" style="float: right"> <div class="dmsf_controls" style="float: right">
<%= link_to_function image_tag('rev_downloads.png', :plugin => 'redmine_dmsf'), <%= link_to_function image_tag('group.png'),
"$('#revision_access-#{revision.id}').toggle()", "$('#revision_access-#{revision.id}').toggle()",
:title => l(:title_download_entries) %> :title => l(:title_download_entries) %>
<%= link_to image_tag('rev_download.png', :plugin => 'redmine_dmsf'), <%= link_to image_tag('download.png'),
view_dmsf_file_path(@file, :download => revision), view_dmsf_file_path(@file, :download => revision),
:title => l(:title_title_version_version_download, :title => h(revision.title), :version => revision.version) %> :title => l(:title_title_version_version_download, :title => h(revision.title), :version => revision.version) %>
<%= link_to image_tag('rev_delete.png', :plugin => 'redmine_dmsf'), <%= link_to image_tag('delete.png'),
delete_revision_path(revision), delete_revision_path(revision),
:data => {:confirm => l(:text_are_you_sure)}, :data => {:confirm => l(:text_are_you_sure)},
:title => l(:title_delete_revision) if @file_delete_allowed && (@file.dmsf_file_revisions.visible.count > 1) %> :title => l(:title_delete_revision) if @file_delete_allowed && (@file.dmsf_file_revisions.visible.count > 1) %>
@ -101,61 +101,70 @@
<div class="attributes dmsf_revision_inner_box"> <div class="attributes dmsf_revision_inner_box">
<div class="splitcontent"> <div class="splitcontent">
<div class="splitcontentleft"> <div class="splitcontentleft">
<p> <div class="status attribute">
<%= label_tag('', l(:label_title)) %> <%= content_tag :div, l(:label_title), :class => 'label' %>
<%= h(revision.title) %> <%= content_tag :div, h(revision.title), :class => 'value' %>
</p> </div>
<% if revision.description.present? %> <% if revision.description.present? %>
<p> <div class="status attribute">
<%= label_tag('', l(:label_description)) %> <%= content_tag :div, l(:label_description), :class => 'label' %>
<div class="wiki"> <% text = textilizable(revision.description) %>
<%= textilizable(revision.description) %> <% if text =~ /^<p>(.*)<\/p>$/ %>
</div> <% text = $1 %>
</p> <% end %>
<%= content_tag :div, text.html_safe, :class => 'value wiki' %>
</div>
<% end %> <% end %>
<p> <div class="status attribute">
<%= label_tag('', l(:label_dmsf_version)) %> <%= content_tag :div, l(:label_dmsf_version), :class => 'label' %>
<%= revision.major_version %>.<%= revision.minor_version %> <%= content_tag :div, "#{revision.major_version}.#{revision.minor_version}", :class => 'value' %>
</p> </div>
<p> <div class="status attribute">
<%= label_tag('', l(:label_size)) %> <%= content_tag :div, l(:label_size), :class => 'label' %>
<%= number_to_human_size(revision.size) %> <%= content_tag :div, number_to_human_size(revision.size), :class => 'value' %>
</p> </div>
<% wf = DmsfWorkflow.find_by_id(revision.dmsf_workflow_id) %> <% wf = DmsfWorkflow.find_by_id(revision.dmsf_workflow_id) %>
<% if wf %> <% if wf %>
<p> <div class="status attribute">
<%= label_tag('', l(:link_workflow)) %> <%= content_tag :div, l(:label_workflow), :class => 'label' %>
<%= "#{wf.name} - " %> <div class="value">
<%= link_to(revision.workflow_str(false), <%= "#{wf.name} - " %>
log_dmsf_workflow_path(:project_id => @project.id, <%= link_to(revision.workflow_str(false),
:id => wf.id, :dmsf_file_revision_id => revision.id), log_dmsf_workflow_path(:project_id => @project.id,
:title => DmsfWorkflow.assignments_to_users_str(wf.next_assignments(revision.id)), :id => wf.id, :dmsf_file_revision_id => revision.id),
:remote => true) %> :title => revision.workflow_tooltip,
</p> :remote => true) %>
</div>
</div>
<% end %> <% end %>
<% if revision.comment.present? %> <% if revision.comment.present? %>
<p> <div class="status attribute">
<%= label_tag('', l(:label_comment)) %> <%= content_tag :div, l(:label_comment), :class => 'label' %>
<div class="wiki"> <% text = textilizable(revision.comment) %>
<%= textilizable(revision.comment) %> <% if text =~ /^<p>(.*)<\/p>$/ %>
</div> <% text = $1 %>
</p> <% end %>
<%= content_tag :div, text.html_safe, :class => 'value wiki' %>
</div>
<% end %> <% end %>
</div> </div>
<div class="splitcontentright"> <div class="splitcontentright">
<p> <div class="status attribute">
<%= label_tag('', l(:label_file)) %> <%= content_tag :div, l(:label_file), :class => 'label' %>
<%= (h("#{revision.dmsf_file.dmsf_folder.dmsf_path_str}/")) if revision.dmsf_file.dmsf_folder %><%= h(revision.name) %> <div class="value">
</p> <% path = "#{revision.dmsf_file.dmsf_folder.dmsf_path_str}/" if revision.dmsf_file.dmsf_folder %>
<p> <%= h("#{path}#{revision.name}") %>
<%= label_tag('', l(:label_mime)) %> </div>
<%= h(revision.mime_type) %> </div>
</p> <div class="status attribute">
<%= content_tag :div, l(:label_mime), :class => 'label' %>
<%= content_tag :div, revision.mime_type, :class => 'value' %>
</div>
<% if revision.digest.present? %> <% if revision.digest.present? %>
<p> <div class="status attribute">
<%= label_tag('', 'MD5') %> <%= content_tag :div, 'MD5', :class => 'label' %>
<%= revision.digest %> <%= content_tag :div, revision.digest, :class => 'value wiki' %>
</p> </div>
<% end %> <% end %>
<%= render 'dmsf/custom_fields', :object => revision %> <%= render 'dmsf/custom_fields', :object => revision %>
</div> </div>

View File

@ -46,7 +46,7 @@
</div> </div>
<p> <p>
<%= submit_tag(l(:button_copy)) %> <%= submit_tag(l(:button_copy)) %>
<% if User.current.allowed_to?(:file_manipulation, @project) %> <% if !@file.locked? && User.current.allowed_to?(:file_manipulation, @project) %>
<%= submit_tag(l(:button_move), :id => 'move_button') %> <%= submit_tag(l(:button_move), :id => 'move_button') %>
<% end %> <% end %>
</p> </p>

View File

@ -0,0 +1,22 @@
<h3 class="title"><%= l(:label_user_search) %></h3>
<%= form_tag(append_dmsf_folder_permissions_path,
:remote => true,
:method => :post,
:id => 'new-user-form') do %>
<%= hidden_field_tag :project_id, @project.id %>
<p><%= label_tag 'user_search', l(:label_user_search) %><%= text_field_tag 'user_search', nil %></p>
<%= javascript_tag "observeSearchfield('user_search', 'users_for_users', '#{ escape_javascript url_for(:controller => 'dmsf_folder_permissions',
:action => 'autocomplete_for_user',
:project_id => @project) }')" %>
<div id="users_for_watcher">
<%= render_principals_for_new_folder_permissions(@principals) %>
</div>
<p class="buttons">
<%= submit_tag l(:button_add), :name => nil, :onclick => "hideModal(this);" %>
<%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %>
</p>
<% end %>

View File

@ -0,0 +1,4 @@
<% @principals.each do |principal| %>
$("#user_permission_ids_<%= principal.id %>").remove();
<% end %>
$('#user_permissions').append('<%= escape_javascript(users_checkboxes(@principals)) %>');

View File

@ -0,0 +1,2 @@
$('#users_for_watcher').html('<%= escape_javascript(
render_principals_for_new_folder_permissions(@principals)) %>');

View File

@ -0,0 +1,3 @@
$('#ajax-modal').html('<%= escape_javascript(render :partial => 'dmsf_folder_permissions/new') %>');
showModal('ajax-modal', '400px');
$('#ajax-modal').addClass('new-user');

View File

@ -20,40 +20,41 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%> %>
<% html_title l(:dmsf) %> <h3 class="title"><%= l(:title_create_link) %></h3>
<% if @dmsf_file_id %> <%= labelled_form_for @dmsf_link, :remote => modal do |f| %>
<% file = DmsfFile.find_by_id @dmsf_file_id%>
<% title = file.title if file %>
<% end %>
<%= render(:partial => '/dmsf/path',
:locals => {:folder => @dmsf_link.folder, :filename => nil,
:title => (@type == 'link_from') ? l(:label_link_from) : l(:label_link_to) }) %>
<%= labelled_form_for @dmsf_link do |f| %>
<%= error_messages_for @dmsf_link %> <%= error_messages_for @dmsf_link %>
<%= f.hidden_field :project_id, :value => @dmsf_link.project_id %> <%= f.hidden_field :project_id, :value => @dmsf_link.project_id %>
<%= f.hidden_field :dmsf_folder_id, :value => @dmsf_link.dmsf_folder_id if @dmsf_link.dmsf_folder_id %> <%= f.hidden_field :dmsf_folder_id, :value => @dmsf_link.dmsf_folder_id if @dmsf_link.dmsf_folder_id %>
<%= f.hidden_field :type, :value => @type %> <%= f.hidden_field :type, :value => @type %>
<%= f.hidden_field :dmsf_file_id, :value => @dmsf_file_id %> <%= f.hidden_field :dmsf_file_id, :value => @dmsf_file_id %>
<%= f.hidden_field(:container, :value => @container) if @container %>
<div class="box tabular"> <div class="box tabular">
<% if @type == 'link_from' %> <% if (@type == 'link_from') && !@container %>
<p> <p>
<%= radio_button_tag(:external_link, 'false', @link_external == false) %> <%= l(:label_internal) %><br/> <%= radio_button_tag(:external_link, 'false', true) %> <%= l(:label_internal) %><br/>
<%= radio_button_tag(:external_link, 'true', @link_external) %> <%= l(:label_external) %> <%= radio_button_tag(:external_link, 'true', false) %> <%= l(:label_external) %>
</p> </p>
<% end %> <% end %>
<div id="link_internal" style="<%= @link_external ? 'display:none' : '' %>"> <div id="link_internal">
<p> <p>
<% if @type == 'link_from' %> <% if @type == 'link_from' %>
<label for="dmsf_link[target_project_id]"><%= l(:label_source_project) %><span class="required">*</span></label> <label for="dmsf_link[target_project_id]"><%= l(:label_source_project) %></label>
<% else %> <% else %>
<label for="dmsf_link[target_project_id]"><%= l(:label_target_project) %><span class="required">*</span></label> <label for="dmsf_link[target_project_id]"><%= l(:label_target_project) %></label>
<% end %> <% end %>
<%= select_tag('dmsf_link[target_project_id]', <%= select_tag('dmsf_link[target_project_id]',
project_tree_options_for_select(DmsfFile.allowed_target_projects_on_copy, project_tree_options_for_select(DmsfFile.allowed_target_projects_on_copy,
:selected => @dmsf_link.target_project)) %> :selected => @dmsf_link.target_project), :style => "width=100%") %>
<%= javascript_tag do %>
$('#dmsf_link_target_project_id').change(function(){
$.ajax({
url: '<%= autocomplete_for_project_dmsf_link_path(@project, :format => 'js') %>',
type: 'get',
data: $('#new_dmsf_link').serialize()
});
});
<% end %>
</p> </p>
<p> <p>
<% if @type == 'link_from' %> <% if @type == 'link_from' %>
@ -64,52 +65,64 @@
<%= select_tag('dmsf_link[target_folder_id]', <%= select_tag('dmsf_link[target_folder_id]',
folder_tree_options_for_select(DmsfFolder.directory_tree(@dmsf_link.target_project), folder_tree_options_for_select(DmsfFolder.directory_tree(@dmsf_link.target_project),
:selected => @target_folder_id)) %> :selected => @target_folder_id)) %>
<%= javascript_tag do %>
$('#dmsf_link_target_folder_id').change(function(){
$.ajax({
url: '<%= autocomplete_for_folder_dmsf_link_path(@project, :format => 'js') %>',
type: 'get',
data: $('#new_dmsf_link').serialize()
});
});
<% end %>
</p> </p>
<% if @type == 'link_from' %> <% if @type == 'link_from' %>
<p> <p>
<% if @target_folder_id %> <%= label_tag('dmsf_link[target_file_id]', l(:field_target_file)) %>
<% folder = DmsfFolder.find_by_id @target_folder_id %> <% files = files_for_select(@dmsf_link.target_project.id, @target_folder_id) %>
<% files = folder.dmsf_files.visible if folder %> <%= select_tag('dmsf_link[target_file_id]',
<% else %> options_for_select(DmsfFolder.file_list(files)), :required => modal) %>
<% files = @dmsf_link.target_project.dmsf_files.visible if @dmsf_link.target_project %>
<% end %>
<%= f.select(:target_file_id,
options_for_select(DmsfFolder.file_list(files), @target_file_id)) %>
</p> </p>
<% end %> <% end %>
</div> </div>
<div id="link_external" style="<%= @link_external ? '' : 'display:none' %>"> <% if (@type == 'link_from') && !@container %>
<p> <div id="link_external" style="display: none">
<%= f.text_field :external_url, :required => true, <p>
:label => l(:label_link_external_url) %> <%= f.text_field :external_url, :required => true %>
</p> </p>
</div> </div>
<% end %>
<p> <p>
<%= f.text_field :name, :required => true, :label => l(:label_link_name) %> <%= f.text_field :name, :required => true %>
</p> </p>
</div> </div>
<p><%= f.submit l(:button_create) %></p> <p>
<% if modal %>
<%= f.submit l(:button_create), :onclick => 'hideModal(this);' %>
<% else %>
<%= f.submit l(:button_create) %>
<% end %>
</p>
<% end %> <% end %>
<script type="text/javascript"> <script type="text/javascript">
$('#dmsf_link_target_project_id').change(function () { <%# Select2 extension, TODO: in case of a modal window, select2 makes problems %>
$('#content').load("<%= url_for(:action => 'new', :project_id => @project.id, :reload => true) %>", $('#new_dmsf_link').serialize()); <% unless modal %>
}); $('#dmsf_link_target_project_id').select2();
$('#dmsf_link_target_folder_id').select2();
$('#dmsf_link_target_folder_id').change(function () { $('#dmsf_link_target_file_id').select2();
$('#content').load("<%= url_for(:action => 'new', :project_id => @project.id) %>", $('#new_dmsf_link').serialize()); <% end %>
}); <%# Suggest a link name when a file is selected %>
$('#dmsf_link_target_file_id').change(function () { $('#dmsf_link_target_file_id').change(function () {
$('#content').load("<%= url_for(:action => 'new', :project_id => @project.id) %>", $('#new_dmsf_link').serialize()); var linkName = $('#dmsf_link_name');
}); var name = linkName.val();
if(name == '') {
linkName.val($('#dmsf_link_target_file_id option:selected').text().replace(/\./g, ''));
}
});
<%# Internal/External link switch %>
$("input[name=external_link]:radio").change(function(){ $("input[name=external_link]:radio").change(function(){
$("#link_internal").toggle(); $("#link_internal").toggle();
$("#link_external").toggle(); $("#link_external").toggle();
}); });
</script>
$('#dmsf_link_target_project_id').select2();
$('#dmsf_link_target_folder_id').select2();
$('#dmsf_link_target_file_id').select2();
</script>

View File

@ -0,0 +1,4 @@
$('#dmsf_link_target_file_id').html('<%= escape_javascript(
select_tag('dmsf_link[target_file_id]',
options_for_select(DmsfFolder.file_list(files_for_select(params[:dmsf_link][:target_project_id],
params[:dmsf_link][:target_folder_id]))))) %>');

View File

@ -0,0 +1,4 @@
$('#dmsf_link_target_folder_id').html('<%= escape_javascript(
select_tag('dmsf_link[target_folder_id]',
folder_tree_options_for_select(DmsfFolder.directory_tree(params[:dmsf_link][:target_project_id])))) %>');
$('#dmsf_link_target_folder_id').change();

View File

@ -0,0 +1,38 @@
<%
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-17 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.
%>
var linksSpan = $("#dmsf_links_attachments_fields");
var linkId = "<%= @dmsf_link.id %>";
var linkName = "<%= @dmsf_link.name %>";
var title = "<%= l(:label_dmsf_wokflow_action_assign) %>";
var project = "<%= @project.identifier %>"
var awf = false;
<% file = @dmsf_link.target_file %>
<% if file && !file.locked? && User.current.allowed_to?(:file_approval, file.project) %>
<% revision = file.last_revision %>
<% if revision && (revision.workflow == DmsfWorkflow::STATE_NONE) %>
awf = true;
<% end %>
<% end %>
dmsfAddLink(linksSpan, linkId, linkName, title, project, awf, <%= !defined?(EasyExtensions) %>);

View File

@ -20,4 +20,4 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%> %>
<%= render 'form' %> <%= render :partial => 'form', :locals => { :modal => false } %>

View File

@ -0,0 +1,24 @@
<%
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-17 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.
%>
$('#ajax-modal').html('<%= escape_javascript(render :partial => 'form', :locals => { :modal => true }) %>');
showModal('ajax-modal', '40%');

View File

@ -21,7 +21,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%> %>
<span id="public_url" class="dmsf_invisible"> <span id="public_url" class="hol">
<%= check_box_tag('email[public_urls]', 1, false) %> <%= l(:label_public_urls) %> <%= 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, <%= date_field_tag('email[expired_at]', '', :value => (DateTime.now + 3.days).to_date, :size => 10,
:readonly => true) + calendar_for('email_expired_at') %> :readonly => true) + calendar_for('email_expired_at') %>

View File

@ -26,7 +26,7 @@
<%= form_tag(dmsf_user_pref_save_path(@project)) do %> <%= form_tag(dmsf_user_pref_save_path(@project)) do %>
<fieldset class="box tabular"> <fieldset class="box tabular">
<legend><%= l(:link_user_preferences) %></legend> <legend><%= l(:link_user_preferences) %></legend>
<p> <p>
<%= content_tag(:label, "#{l(:label_notifications)}:") %> <%= content_tag(:label, "#{l(:label_notifications)}:") %>
<%= select_tag( <%= select_tag(
@ -41,5 +41,19 @@
<em class="info"><%= l(:text_title_format) %></em> <em class="info"><%= l(:text_title_format) %></em>
</p> </p>
</fieldset> </fieldset>
<% if Setting.plugin_redmine_dmsf['dmsf_act_as_attachable'] %>
<fieldset class="box tabular">
<legend><%= l(:field_project) %> <%= l(:label_preferences) %></legend>
<p>
<%= content_tag(:label, "#{l(:label_act_as_attachable)}:") %>
<%= select_tag(
'act_as_attachable',
options_for_select([
[l(:label_attachment_plural) + ' & ' + l(:menu_dmsf), Project::ATTACHABLE_DMS_AND_ATTACHMENTS],
[l(:label_attachment_plural), Project::ATTACHABLE_ATTACHMENTS],
],:selected => @project.dmsf_act_as_attachable)) %>
</p>
</fieldset>
<% end %>
<%= submit_tag(l(:submit_save), :title => l(:title_save_preferences)) %> <%= submit_tag(l(:submit_save), :title => l(:title_save_preferences)) %>
<% end %> <% end %>

View File

@ -21,29 +21,79 @@
%> %>
<span id="dmsf_attachments_fields"> <span id="dmsf_attachments_fields">
<% if defined?(container) && container && container.saved_attachments %> <% if defined?(container) && container && container.saved_dmsf_attachments.present? %>
<% container.saved_attachments.each_with_index do |attachment, i| %> <% container.saved_dmsf_attachments.each_with_index do |attachment, i| %>
<span id="dmsf_attachments_p<%= i %>"> <span id="dmsf_attachments_p<%= i %>", class="attachment">
<%= text_field_tag("dmsf_attachments[p#{i}][filename]", attachment.filename, :class => 'filename') + <%= hidden_field_tag "dmsf_attachments[p#{i}][token]", "#{attachment.token}" %>
text_field_tag("dmsf_attachments[p#{i}][description]", attachment.description, :maxlength => 255, :placeholder => l(:label_optional_description), :class => 'description') + <%= text_field_tag("dmsf_attachments[p#{i}][filename]", attachment.filename, :class => 'filename') %>
link_to('&nbsp;'.html_safe, dmsf_attachment_path(attachment, :attachment_id => "p#{i}", :format => 'js'), :method => 'delete', :remote => true, :class => 'remove-upload') %> <%= text_field_tag("dmsf_attachments[p#{i}][description]", attachment.description, :maxlength => 255,
<%= hidden_field_tag "dmsf_attachments[p#{i}][token]", "#{attachment.token}" %> :placeholder => l(:label_optional_description), :class => 'description') if description %>
</span> <%= link_to('', dmsf_attachment_path(attachment, :attachment_id => "p#{i}", :format => 'js'),
:method => 'delete', :remote => true, :class => 'remove-upload icon-only icon-del') %>
<% wf = container.saved_dmsf_attachments_wfs[attachment.id] %>
<% if wf %>
<a href="javascript:void(0);" title="<%= l(:title_assigned) %>" class="icon-only icon-wf-assigned"></a>
<%= hidden_field_tag("dmsf_attachments_wfs[p#{i}]", wf.id) if wf %>
<% else %>
<%= link_to('', assign_dmsf_workflow_path(:id => container.project.id, :project_id => container.project.id,
:attachment_id => i + 1), :title => l(:label_dmsf_wokflow_action_assign),
:remote => true, :class => 'modify-upload icon-only icon-wf-none') %>
<% end %>
</span>
<% end %>
<% end %> <% end %>
</span>
<span id="dmsf_links_attachments_fields">
<% if defined?(container) && container && container.saved_dmsf_links.present? %>
<% container.saved_dmsf_links.each_with_index do |dmsf_link, index| %>
<span id="dmsf_links_attachments_<%= index %>", class="attachment">
<input name="dmsf_links[<%= index %>]" value="<%= dmsf_link.id %>" type="hidden">
<input type="text" class='filename readonly' value="<%= dmsf_link.name %>">
<%= link_to('', dmsf_link_attachment_path(dmsf_link, :link_id => "#{index}", :format => 'js'),
:method => 'delete', :remote => true, :class => 'remove-upload icon-only icon-del') %>
<% wf = container.saved_dmsf_links_wfs[dmsf_link.id] %>
<% if wf %>
<a href="javascript:void(0);" title="<%= l(:title_assigned) %>" class="modify-upload icon-only icon-wf-assigned"></a>
<%= hidden_field_tag("dmsf_links_wfs[#{dmsf_link.id}]", wf.id) if wf %>
<% else %>
<%= render(:partial => 'dmsf_workflows/approval_workflow_button',
:locals => {:file => dmsf_link.target_file,
:file_approval_allowed => User.current.allowed_to?(:file_approval, dmsf_link.target_file.project),
:workflows_available => DmsfWorkflow.where(
['project_id = ? OR project_id IS NULL', dmsf_link.target_file.project_id]).exists?,
:project => dmsf_link.target_file.project, :wf => wf, :dmsf_link_id => dmsf_link.id }) %>
<% end %>
</span>
<% end %>
<% end %> <% end %>
</span> </span>
<span class="dmsf_add_attachment">
<%= file_field_tag 'dmsf_attachments[dummy][file]', <span class="dmsf_add_attachment add_attachment">
<%= file_field_tag 'dmsf_attachments[dummy][file]',
:id => nil, :id => nil,
:class => 'file_selector', :class => 'file_selector',
:multiple => multiple, :multiple => multiple,
:onchange => "dmsfAddInputFiles(this);", :onchange => "dmsfAddInputFiles(this);",
:data => { :data => {
:max_file_size => Setting.attachment_max_size.to_i.kilobytes, :max_file_size => Setting.attachment_max_size.to_i.kilobytes,
:max_file_size_message => l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)), :max_file_size_message => l(:error_attachment_too_big,
:max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)),
:max_concurrent_uploads => Redmine::Configuration['max_concurrent_ajax_uploads'].to_i, :max_concurrent_uploads => Redmine::Configuration['max_concurrent_ajax_uploads'].to_i,
:upload_path => dmsf_uploads_path(:format => 'js'), :upload_path => dmsf_uploads_path(:format => 'js'),
:description_placeholder => l(:label_optional_description) :description_placeholder => l(:label_optional_description),
:project => "#{@project.identifier}",
:description => description,
:awf => awf
} %> } %>
(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>) </span>
<% if defined?(container) && container %>
<span class="dmsf_add_link">
<%= link_to l(:label_link_from),
new_dmsf_link_path(:project_id => container.project.id, :type => 'link_from', :container => container.class.name),
:title => l(:title_create_link), :class => 'icon icon-add file_selector', :remote => true %>
</span>
<% end %>
<span class="info">
(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)
</span> </span>

View File

@ -37,12 +37,10 @@
<%= form_tag({:controller => 'dmsf_upload', :action => 'upload_files', :id => @project, :folder_id => @folder}, <%= form_tag({:controller => 'dmsf_upload', :action => 'upload_files', :id => @project, :folder_id => @folder},
:id => 'uploadform', :method => :post, :multipart => true) do %> :id => 'uploadform', :method => :post, :multipart => true) do %>
<div id="dmsf_uploader"> <div id="dmsf_uploader">
<div class="dmsf_uploader"> <span class="dmsf_uploader">
<p> <%= render :partial => 'dmsf_upload/form',
<label><%= l(:label_document_plural) %></label> :locals => { :multiple => true, :container => nil, :description => true, :awf => false } %>
<%= render :partial => 'dmsf_upload/form', :locals => { :multiple => true } %> </span>
</p>
</div>
<%= submit_tag l(:label_upload) %> <%= submit_tag l(:label_upload) %>
</div> </div>
<% end %> <% end %>
@ -128,6 +126,10 @@
.attr('name', 'uploaded[' + dmsfFileFieldCount + '][original_filename]') .attr('name', 'uploaded[' + dmsfFileFieldCount + '][original_filename]')
.val(responseObject.original_filename); .val(responseObject.original_filename);
uploader.append(original_filename_input); uploader.append(original_filename_input);
var tempfile_path = $('<input/>').attr('type', 'hidden')
.attr('name', 'uploaded[' + dmsfFileFieldCount + '][tempfile_path]')
.val(responseObject.tempfile_path);
uploader.append(tempfile_path);
} else { } else {
file.status = plupload.FAILED; file.status = plupload.FAILED;
pluploader.trigger('UploadProgress', file); pluploader.trigger('UploadProgress', file);

View File

@ -1,47 +1,50 @@
<% <%
# encoding: utf-8 # encoding: utf-8
# #
# Redmine plugin for Document Management System "Features" # Redmine plugin for Document Management System "Features"
# #
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com> # Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright (C) 2012 Daniel Munn <dan.munn@munnster.co.uk> # Copyright (C) 2012 Daniel Munn <dan.munn@munnster.co.uk>
# Copyright (C) 2011-17 Karel Pičman <karel.picman@kontron.com> # Copyright (C) 2011-17 Karel Pičman <karel.picman@kontron.com>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%> %>
<div class="box tabular"> <div class="box tabular" style="padding-top: 10px">
<%= hidden_field_tag("commited_files[#{i}][disk_filename]", upload.disk_filename) %> <%= hidden_field_tag("commited_files[#{i}][disk_filename]", upload.disk_filename) %>
<%= hidden_field_tag("commited_files[#{i}][tempfile_path]", upload.tempfile_path) %>
<%= hidden_field_tag("commited_files[#{i}][size]", upload.size) %>
<%= hidden_field_tag("commited_files[#{i}][mime_type]", upload.mime_type) %>
<div class="clear"> <div class="clear">
<div class="splitcontentleft"> <div class="splitcontentleft">
<p> <p>
<%= label_tag("commited_files[#{i}][title]", l(:label_title)) %> <%= label_tag("commited_files[#{i}][title]", l(:label_title)) %>
<%= text_field_tag("commited_files[#{i}][title]", upload.title, :size => 32, :required => true) %> <%= text_field_tag("commited_files[#{i}][title]", upload.title, :required => true) %>
</p> </p>
</div> </div>
<div class="splitcontentright"> <div class="splitcontentright">
<p> <p>
<%= label_tag('', l(:label_filename)) %> <%= label_tag('', l(:label_filename)) %>
<%= h(upload.name) %> <%= text_field_tag(:name, h(upload.name), :readonly => true) %>
<%= hidden_field_tag("commited_files[#{i}][name]", upload.name) %> <%= hidden_field_tag("commited_files[#{i}][name]", upload.name) %>
</p> </p>
</div> </div>
</div> </div>
<p> <p>
<%= label_tag("commited_files[#{i}][description]", l(:label_description)) %> <%= label_tag("commited_files[#{i}][description]", l(:label_description)) %>
<%= text_area_tag("commited_files[#{i}][description]", upload.description, :rows => 6, :class => 'wiki-edit') %> <%= text_area_tag("commited_files[#{i}][description]", upload.description, :rows => 6, :class => 'wiki-edit') %>
</p> </p>
<div class="clear"> <div class="clear">
<div class="splitcontentright"> <div class="splitcontentright">
@ -55,32 +58,38 @@
<div class="splitcontentleft"> <div class="splitcontentleft">
<p> <p>
<%= label_tag("commited_files[#{i}][version]_minor", l(:label_dmsf_version)) %> <%= label_tag("commited_files[#{i}][version]_minor", l(:label_dmsf_version)) %>
<%= radio_button_tag("commited_files[#{i}][version]", 1, true) %> <%= radio_button_tag("commited_files[#{i}][version]", 1, true) %>
<%= upload.major_version %>.<%= upload.minor_version + 1 %> <%= upload.major_version %>.<%= upload.minor_version + 1 %>
<%= l(:option_version_minor) %><br/> <%= l(:option_version_minor) %><br/>
<%= radio_button_tag("commited_files[#{i}][version]", 2) %> <%= radio_button_tag("commited_files[#{i}][version]", 2) %>
<%= upload.major_version + 1 %>.0 <%= upload.major_version + 1 %>.0
<%= l(:option_version_major) %><br/> <%= l(:option_version_major) %><br/>
<%= radio_button_tag("commited_files[#{i}][version]", 3) %> <%= radio_button_tag("commited_files[#{i}][version]", 3) %>
<%= select_tag "commited_files[#{i}][custom_version_major]", options_for_select(0..99, upload.major_version + 2), :onchange => "$('#commited_files_#{i}_version_3').prop('checked', true)" %>. <%= select_tag "commited_files[#{i}][custom_version_major]",
<%= select_tag "commited_files[#{i}][custom_version_minor]", options_for_select(0..99, upload.minor_version + 1), :onchange => "$('#commited_files_#{i}_version_3').prop('checked', true)" %> options_for_select(0..99, upload.major_version + 2),
<%= l(:option_version_custom) %> :onchange => "$('#commited_files_#{i}_version_3').prop('checked', true)",
:class => 'dmsf_select_version'%>.
<%= select_tag "commited_files[#{i}][custom_version_minor]",
options_for_select(0..99, upload.minor_version + 1),
:onchange => "$('#commited_files_#{i}_version_3').prop('checked', true)",
:class => 'dmsf_select_version' %>
<%= l(:option_version_custom) %>
</p> </p>
</div> </div>
<div class="splitcontentright"> <div class="splitcontentright">
<p> <p>
<%= label_tag('', l(:label_mime)) %> <%= label_tag '', l(:label_mime) %>
<%= h(upload.mime_type) %> <%= text_field_tag(:name, h(upload.mime_type), :readonly => true) %>
</p> </p>
<p> <p>
<%= label_tag('', l(:label_size)) %> <%= label_tag('', l(:label_size)) %>
<%= number_to_human_size(upload.size) %> <%= text_field_tag(:name, number_to_human_size(upload.size), :readonly => true) %>
</p> </p>
</div> </div>
</div> </div>
<p> <p>
<%= label_tag("commited_files[#{i}][comment]", l(:label_comment)) %> <%= label_tag("commited_files[#{i}][comment]", l(:label_comment)) %>
<%= text_area_tag("commited_files[#{i}][comment]", upload.comment, :rows => 2) %> <%= text_area_tag("commited_files[#{i}][comment]", upload.comment, :rows => 2, :class => 'wiki-edit') %>
</p> </p>
</div> </div>

View File

@ -1,52 +1,55 @@
<% <%
# encoding: utf-8 # encoding: utf-8
# #
# Redmine plugin for Document Management System "Features" # Redmine plugin for Document Management System "Features"
# #
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com> # Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright (C) 2012 Daniel Munn <dan.munn@munnster.co.uk> # Copyright (C) 2012 Daniel Munn <dan.munn@munnster.co.uk>
# Copyright (C) 2011-17 Karel Pičman <karel.picman@kontron.com> # Copyright (C) 2011-17 Karel Pičman <karel.picman@kontron.com>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%> %>
<div class="box tabular"> <div class="box tabular" style="padding-top: 10px">
<%= hidden_field_tag("commited_files[#{i}][disk_filename]", upload.disk_filename) %> <%= hidden_field_tag("commited_files[#{i}][disk_filename]", upload.disk_filename) %>
<%= hidden_field_tag("commited_files[#{i}][tempfile_path]", upload.tempfile_path) %>
<%= hidden_field_tag("commited_files[#{i}][size]", upload.size) %>
<%= hidden_field_tag("commited_files[#{i}][mime_type]", upload.mime_type) %>
<%= hidden_field_tag("commited_files[#{i}][name]", upload.name) %> <%= hidden_field_tag("commited_files[#{i}][name]", upload.name) %>
<p class="warning"><%= l(:info_file_locked) %></p> <p class="warning"><%= l(:info_file_locked) %></p>
<div class="clear"> <div class="clear">
<div class="splitcontentleft"> <div class="splitcontentleft">
<p> <p>
<%= label_tag('', l(:label_title)) %> <%= label_tag('', l(:label_title)) %>
<%= h(upload.title) %> <%= text_field_tag(:name, h(upload.title), :readonly => true) %>
</p> </p>
</div> </div>
<div class="splitcontentright"> <div class="splitcontentright">
<p> <p>
<%= label_tag('', l(:label_filename)) %> <%= label_tag('', l(:label_filename)) %>
<%= h(upload.name) %> <%= text_field_tag(:name, h(upload.name), :readonly => true) %>
</p> </p>
</div> </div>
</div> </div>
<% if upload.description.present? %> <% if upload.description.present? %>
<p> <p>
<%= label_tag('', l(:label_description)) %> <%= label_tag('', l(:label_description)) %>
<div class="wiki"> <div class="wiki">
<%= textilizable(upload.description) %> <%= textilizable(upload.description) %>
</div> </div>
</p> </p>
<% end %> <% end %>
<div class="clear"> <div class="clear">
<div class="splitcontentright"> <div class="splitcontentright">
@ -55,7 +58,7 @@
<p> <p>
<%= label_tag('', h(value.custom_field.name)) %> <%= label_tag('', h(value.custom_field.name)) %>
<% value.value = nil if value.custom_field.dmsf_not_inheritable %> <% value.value = nil if value.custom_field.dmsf_not_inheritable %>
<%= h(value.value) %> <%= text_field_tag(:name, h(value.value), :readonly => true) %>
</p> </p>
<% end %> <% end %>
</div> </div>
@ -63,24 +66,24 @@
<div class="splitcontentleft"> <div class="splitcontentleft">
<p> <p>
<%= label_tag('', l(:label_dmsf_version)) %> <%= label_tag('', l(:label_dmsf_version)) %>
<%= upload.major_version %>.<%= upload.minor_version %> <%= text_field_tag(:name, "#{upload.major_version}.#{upload.minor_version}", :readonly => true) %>
</p> </p>
</div> </div>
<div class="splitcontentright"> <div class="splitcontentright">
<p> <p>
<%= label_tag('', l(:label_mime)) %> <%= label_tag('', l(:label_mime)) %>
<%= h(upload.mime_type) %> <%= text_field_tag(:name, h(upload.mime_type), :readonly => true) %>
</p> </p>
<p> <p>
<%= label_tag('', l(:label_size)) %> <%= label_tag('', l(:label_size)) %>
<%= number_to_human_size(upload.size) %> <%= text_field_tag(:name, h(number_to_human_size(upload.size)), :readonly => true) %>
</p> </p>
</div> </div>
</div> </div>
<% if upload.comment.present? %> <% if upload.comment.present? %>
<p> <p>
<%= label_tag('', l(:label_comment)) %> <%= label_tag('', l(:label_comment)) %>
<div class="wiki"><%= textilizable(upload.comment) %></div> <div class="wiki"><%= textilizable(upload.comment) %></div>
</p> </p>
<% end %> <% end %>
</div> </div>

View File

@ -0,0 +1 @@
$('#dmsf_links_attachments_<%= j params[:link_id] %>').remove();

View File

@ -26,7 +26,7 @@ var fileSpan = $('#dmsf_attachments_<%= j params[:attachment_id] %>');
alert("<%= escape_javascript @attachment.errors.full_messages.join(', ') %>"); alert("<%= escape_javascript @attachment.errors.full_messages.join(', ') %>");
<% else %> <% else %>
$('<input>', { type: 'hidden', name: 'dmsf_attachments[<%= j params[:attachment_id] %>][token]' } ).val('<%= j @attachment.token %>').appendTo(fileSpan); $('<input>', { type: 'hidden', name: 'dmsf_attachments[<%= j params[:attachment_id] %>][token]' } ).val('<%= j @attachment.token %>').appendTo(fileSpan);
fileSpan.find('a.remove-upload') fileSpan.find('a.dmsf-remove-upload')
.attr({ .attr({
"data-remote": true, "data-remote": true,
"data-method": 'delete', "data-method": 'delete',

View File

@ -19,8 +19,12 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.%> # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
{"original_filename":"<%= (@tempfile.original_filename).html_safe %>", {
"content_type":"<%= (@tempfile.content_type.gsub('"', '')).html_safe %>", "original_filename":"<%= @tempfile.original_filename.html_safe %>",
"disk_filename":"<%= (@disk_filename).html_safe %>"} "content_type": "<%= @tempfile.content_type.gsub('"', '').html_safe %>",
"disk_filename": "<%= @disk_filename.html_safe %>",
"tempfile_path": "<%= @tempfile.path.html_safe %>"
}

View File

@ -41,7 +41,9 @@
<% else %> <% else %>
<%= render(:partial => 'upload_file', :locals => {:upload => upload, :i => i}) %> <%= render(:partial => 'upload_file', :locals => {:upload => upload, :i => i}) %>
<% end %> <% end %>
<% i += 1 %>
<% end %> <% end %>
<%= submit_tag l(:submit_commit) %> <%#= submit_tag l(:submit_commit) %>
<div class="form-actions">
<%= submit_tag l(:submit_commit), :class => 'button-positive' %>
</div>
<% end %> <% end %>

View File

@ -0,0 +1,77 @@
<%
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-17 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.
%>
<% if file_approval_allowed %>
<% case file.last_revision.workflow %>
<% when DmsfWorkflow::STATE_WAITING_FOR_APPROVAL %>
<% if wf %>
<% assignments = wf.next_assignments(file.last_revision.id) %>
<% index = assignments.find_index{|assignment| assignment.user_id == User.current.id} if assignments %>
<% if index %>
<%= link_to('',
action_dmsf_workflow_path(
:project_id => project.id,
:id => wf.id,
:dmsf_workflow_step_assignment_id => assignments[index].id,
:dmsf_file_revision_id => file.last_revision.id),
:title => l(:title_waiting_for_approval),
:remote => true,
:class => "icon-only icon-wf-waiting") %>
<% else %>
<span class="icon-only"></span>
<% end %>
<% else %>
<span class="icon-only"></span>
<% end %>
<% when DmsfWorkflow::STATE_ASSIGNED %>
<% if User.current && (file.last_revision.dmsf_workflow_assigned_by == User.current.id) && wf %>
<%= link_to('',
start_dmsf_workflow_path(
:id => file.last_revision.dmsf_workflow_id,
:dmsf_file_revision_id => file.last_revision.id),
:title => l(:label_dmsf_wokflow_action_start),
:class => 'icon-only icon-wf-assigned') %>
<% else %>
<span class="icon"></span>
<% end %>
<% when DmsfWorkflow::STATE_APPROVED, DmsfWorkflow::STATE_REJECTED %>
<span class="icon-only"></span>
<% else %>
<% if workflows_available %>
<%= link_to('',
dmsf_link_id ?
assign_dmsf_workflow_path(
:id => project.id,
:project_id => project.id,
:dmsf_link_id => dmsf_link_id) :
assign_dmsf_workflow_path(
:id => project.id,
:project_id => project.id,
:dmsf_file_revision_id => file.last_revision.id),
:title => l(:label_dmsf_wokflow_action_assign),
:remote => true,
:class => 'icon-only icon-wf-none') %>
<% else %>
<span class="icon-only"></span>
<% end %>
<% end %>
<% end %>

View File

@ -17,22 +17,26 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.%> # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<h3 class="title"><%= l(:field_label_dmsf_workflow) %></h3> <h3 class="title"><%= l(:field_label_dmsf_workflow) %></h3>
<% remote = params[:dmsf_link_id] || params[:attachment_id] %>
<%= form_tag({:controller => 'dmsf_workflows', :action => 'assignment'}, <%= form_tag({:controller => 'dmsf_workflows', :action => 'assignment'},
:method => :post, :method => :post, :id => 'assignment-form', :remote => remote) do %>
:id => 'assignment-form') do %>
<%= hidden_field_tag :dmsf_file_revision_id, params[:dmsf_file_revision_id] %> <%= hidden_field_tag :dmsf_file_revision_id, params[:dmsf_file_revision_id] %>
<%= hidden_field_tag :dmsf_link_id, params[:dmsf_link_id] %>
<%= hidden_field_tag :attachment_id, params[:attachment_id] %>
<p> <p>
<%= label_tag('workflow', "#{l(:link_workflow)}:") %> <%= label_tag('workflow', "#{l(:link_workflow)}:") %>
<%= select_tag( <%= select_tag(
'dmsf_workflow_id', 'dmsf_workflow_id',
dmsf_workflows_for_select(@project, nil))%> dmsf_workflows_for_select(@project, nil))%>
</p> </p>
<% if User.current.allowed_to?(:manage_workflows, @project) %> <% if (!remote) && User.current.allowed_to?(:manage_workflows, @project) %>
<p> <p>
<%= link_to l(:label_dmsf_workflow_new), new_dmsf_workflow_path(:project_id => @project.id), :class => 'icon icon-add' %> <%= link_to l(:label_dmsf_workflow_new), new_dmsf_workflow_path(:project_id => @project.id),
:class => 'icon icon-add' %>
</p> </p>
<% end %> <% end %>
<p class="buttons"> <p class="buttons">

View File

@ -82,7 +82,7 @@
<% result = DmsfWorkflowStep.connection.exec_query sql %> <% result = DmsfWorkflowStep.connection.exec_query sql %>
<% last_step = 0 %> <% last_step = 0 %>
<% result.each_with_index do |row, i| %> <% result.each_with_index do |row, i| %>
<tr id="step-<%= i + 3 %> " class="<%= cycle 'odd', 'even' %>"> <tr id="step-<%= i + 3 %>">
<td class="id"><%= row['step'] unless row['step'] == last_step %></td> <td class="id"><%= row['step'] unless row['step'] == last_step %></td>
<% last_step = row['step'] %> <% last_step = row['step'] %>
<td class="name"><%= row['name'] %></td> <td class="name"><%= row['name'] %></td>

View File

@ -47,7 +47,7 @@
</tr></thead> </tr></thead>
<tbody> <tbody>
<% for workflow in @workflows %> <% for workflow in @workflows %>
<tr id="workflow-<%= workflow.id %>" class="dmsf_workflow <%= workflow.active? ? 'active' : 'locked' %> <%= cycle('odd', 'even') %>"> <tr id="workflow-<%= workflow.id %>" class="dmsf_workflows <%= workflow.active? ? 'active' : 'locked' %>">
<td class="name"><%= link_to(h(workflow.name), dmsf_workflow_path(workflow)) %></td> <td class="name"><%= link_to(h(workflow.name), dmsf_workflow_path(workflow)) %></td>
<td class="buttons"> <td class="buttons">
<%= change_status_link(workflow) unless @project %> <%= change_status_link(workflow) unless @project %>

View File

@ -27,6 +27,6 @@
<p class="buttons"> <p class="buttons">
<%= f.submit l(:dmsf_and), :id => 'add-step-and' %> <%= f.submit l(:dmsf_and), :id => 'add-step-and' %>
<%= f.submit l(:dmsf_or), :id => 'add-step-or' %> <%= f.submit l(:dmsf_or), :id => 'add-step-or' %>
<%= f.submit l(:button_cancel), :name => nil, :onclick => 'hideModal(this);', :type => 'button' %> <%= f.submit l(:button_cancel), :name => nil, :onclick => 'hideModal(this);', :type => 'button', :class => 'button' %>
</p> </p>
<% end %> <% end %>

View File

@ -51,26 +51,18 @@
</tr></thead> </tr></thead>
<tbody> <tbody>
<% steps.each do |i|%> <% steps.each do |i|%>
<tr id="step-<%= i %>" class="<%= cycle 'odd', 'even' %> step"> <tr id="step-<%= i %>" class="step">
<td class="id"><%= i %></td>
<% index = @dmsf_workflow.dmsf_workflow_steps.order(:id).index{ |s| s.step == i } %> <% index = @dmsf_workflow.dmsf_workflow_steps.order(:id).index{ |s| s.step == i } %>
<%= form_for(@dmsf_workflow,
:url => update_step_dmsf_workflow_path(:step => index),
:method => :put,
:html => {:id => "step-index-#{index}-form", :class => 'hol'}) do |f| %>
<td class="id"><%= i %></td>
<td class="name"> <td class="name">
<span id="step-index-<%= index %>-name"><%= @dmsf_workflow.dmsf_workflow_steps[index].name if index %></span> <span id="step-index-<%= index %>-name"><%= @dmsf_workflow.dmsf_workflow_steps[index].name if index %></span>
<%= form_for(@dmsf_workflow, <div id="<%= "step-index-#{index}-name-form" %>" class="hol">
:url => update_step_dmsf_workflow_path(:step => index), <%= f.text_field(:name, :value => @dmsf_workflow.dmsf_workflow_steps[index].name) %>
:method => :put, </div>
:html => {:id => "step-index-#{index}-name-form", :class => 'hol'}) do |f| %>
<p>
<%= f.text_field(:name, :value => @dmsf_workflow.dmsf_workflow_steps[index].name) %>
</p>
<p>
<%= submit_tag l(:button_change), :class => 'small' %>
<%= link_to_function(
l(:button_cancel),
"$('#step-index-#{index}-name').show(); $('#step-index-#{index}-approvers').show(); $('#step-index-#{index}-name-form').hide(); $('#step-index-#{index}-approvers-form').hide();")
%>
</p>
<% end %>
</td> </td>
<td> <td>
<span id="step-index-<%= index %>-approvers"> <span id="step-index-<%= index %>-approvers">
@ -82,10 +74,7 @@
<%= link_to_user step.user %> <%= link_to_user step.user %>
<% end %> <% end %>
</span> </span>
<%= form_for(@dmsf_workflow, <div id="<%= "step-index-#{index}-approvers-form" %>", class="hol">
:url => update_step_dmsf_workflow_path(:step => index),
:method => :put,
:html => {:id => "step-index-#{index}-approvers-form", :class => 'hol'}) do |f| %>
<div class="dmsf_parent_container"> <div class="dmsf_parent_container">
<% stps.each_with_index do |step, j| %> <% stps.each_with_index do |step, j| %>
<div class="dmsf_child_container"> <div class="dmsf_child_container">
@ -115,7 +104,8 @@
"$('#step-index-#{index}-name').show(); $('#step-index-#{index}-approvers').show(); $('#step-index-#{index}-name-form').hide(); $('#step-index-#{index}-approvers-form').hide();") "$('#step-index-#{index}-name').show(); $('#step-index-#{index}-approvers').show(); $('#step-index-#{index}-name-form').hide(); $('#step-index-#{index}-approvers-form').hide();")
%> %>
</p> </p>
<% end %> </div>
<% end %>
</td> </td>
<td class="buttons"> <td class="buttons">
<%= reorder_handle(@dmsf_workflow, :url => url_for(:action => 'edit', :id => @dmsf_workflow, :step => i) ) %> <%= reorder_handle(@dmsf_workflow, :url => url_for(:action => 'edit', :id => @dmsf_workflow, :step => i) ) %>
@ -125,7 +115,7 @@
<%= delete_link edit_dmsf_workflow_path(@dmsf_workflow, :step => i) %> <%= delete_link edit_dmsf_workflow_path(@dmsf_workflow, :step => i) %>
</td> </td>
</tr> </tr>
<% end; reset_cycle %> <% end %>
</tbody> </tbody>
</table> </table>
<% else %> <% else %>

View File

@ -1,6 +1,9 @@
<%# Redmine plugin for Document Management System "Features" <%
# encoding: utf-8
# #
# Copyright (C) 2011-15 Karel Pičman <karel.picman@kontron.com> # Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-17 Karel Pičman <karel.picman@kontron.com>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@ -14,8 +17,9 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.%> # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
$('#ajax-modal').html('<%= escape_javascript(render :partial => 'assign', :locals => {:workflow => @dmsf_workflow}) %>'); $('#ajax-modal').html('<%= escape_javascript(render :partial => 'assign') %>');
showModal('ajax-modal', '30%'); showModal('ajax-modal', '30%');
$('#ajax-modal').addClass('assignment'); $('#ajax-modal').addClass('assignment');

View File

@ -0,0 +1,45 @@
<%
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-17 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.
%>
var input;
<% if @dmsf_link_id %>
input = $('input[value="<%= @dmsf_link_id %>"]');
<% else %>
input = $('input[name="dmsf_attachments[<%= @attachment_id %>][token]"]');
<% end %>
var span = input.parent();
<% if @dmsf_link_id %>
span.append(
"<input name='dmsf_links_wfs[<%= @dmsf_link_id %>]' value='<%= @dmsf_workflow_id %>' type='hidden'>");
<% else %>
span.append(
"<input name='dmsf_attachments_wfs[<%= @attachment_id %>]' value='<%= @dmsf_workflow_id %>' type='hidden'>");
<% end %>
var a = span.children("a.icon-wf-none");
a.attr("class", "icon icon-wf-assigned");
a.attr("href", "javascript:void(0);");
a.attr("title", "<%= l(:title_assigned) %>");

View File

@ -0,0 +1,22 @@
<%
# encoding: utf-8
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-17 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.%>
<%= render :partial => 'log', :locals => {:workflow => @dmsf_workflow} %>

View File

@ -1,6 +1,9 @@
<%# Redmine plugin for Document Management System "Features" <%
# encoding: utf-8
# #
# Copyright (C) 2013 Karel Pičman <karel.picman@kontron.com> # Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-17 Karel Pičman <karel.picman@kontron.com>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@ -14,6 +17,7 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.%> # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<%= render 'steps' %> <%= render 'steps' %>

View File

@ -1,6 +1,8 @@
<%# Redmine plugin for Document Management System "Features" <%
# encoding: utf-8
# Redmine plugin for Document Management System "Features"
# #
# Copyright (C) 2013 Karel Pičman <karel.picman@kontron.com> # Copyright (C) 2011-17 Karel Pičman <karel.picman@kontron.com>
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@ -14,6 +16,7 @@
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.%> # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<%= render 'steps' %> <%= render 'steps' %>

View File

@ -43,7 +43,7 @@
</thead> </thead>
<tbody> <tbody>
<% folders.each do |folder| %> <% folders.each do |folder| %>
<tr id="folder-<%= folder.id %>" class="<%= cycle('odd', 'even') %>"> <tr id="folder-<%= folder.id %>">
<td class="project"> <td class="project">
<%= link_to_project(folder.project) %> <%= link_to_project(folder.project) %>
</td> </td>
@ -63,7 +63,7 @@
</tr> </tr>
<% end %> <% end %>
<% files.each do |file| %> <% files.each do |file| %>
<tr id="file-<%= file.id %>" class="<%= cycle('odd', 'even') %>"> <tr id="file-<%= file.id %>">
<td class="project"> <td class="project">
<%= link_to_project(file.project) %> <%= link_to_project(file.project) %>
</td> </td>

View File

@ -24,7 +24,7 @@
<% if @user %> <% if @user %>
<% all_assignments = DmsfWorkflowStepAssignment.joins( <% all_assignments = DmsfWorkflowStepAssignment.joins(
'LEFT JOIN dmsf_workflow_step_actions ON dmsf_workflow_step_assignments.id = dmsf_workflow_step_actions.dmsf_workflow_step_assignment_id').where( 'LEFT JOIN dmsf_workflow_step_actions ON dmsf_workflow_step_assignments.id = dmsf_workflow_step_actions.dmsf_workflow_step_assignment_id').where(
'dmsf_workflow_step_assignments.user_id = ? AND dmsf_workflow_step_actions.id IS NULL', @user.id).all %> :dmsf_workflow_step_assignments => { :user_id => @user.id }, :dmsf_workflow_step_actions => { :id => nil }) %>
<% all_assignments.each do |assignment| %> <% all_assignments.each do |assignment| %>
<% if assignment.dmsf_file_revision.dmsf_file.last_revision && <% if assignment.dmsf_file_revision.dmsf_file.last_revision &&
!assignment.dmsf_file_revision.dmsf_file.last_revision.deleted? && !assignment.dmsf_file_revision.dmsf_file.last_revision.deleted? &&
@ -42,6 +42,7 @@
<tr> <tr>
<th><%= l(:field_project) %></th> <th><%= l(:field_project) %></th>
<th><%= l(:field_label_dmsf_workflow) %></th> <th><%= l(:field_label_dmsf_workflow) %></th>
<th><%= l(:field_status) %></th>
<th><%= l(:label_document) %></th> <th><%= l(:label_document) %></th>
<th><%= l(:field_folder) %></th> <th><%= l(:field_folder) %></th>
<th></th> <th></th>
@ -49,7 +50,7 @@
</thead> </thead>
<tbody> <tbody>
<% assignments.each do |assignment| %> <% assignments.each do |assignment| %>
<tr id="assignment-<%= assignment.id %>" class="<%= cycle('odd', 'even') %>"> <tr id="assignment-<%= assignment.id %>">
<td class="project"> <td class="project">
<% if assignment.dmsf_file_revision.dmsf_file.project %> <% if assignment.dmsf_file_revision.dmsf_file.project %>
<%= link_to_project(assignment.dmsf_file_revision.dmsf_file.project) %> <%= link_to_project(assignment.dmsf_file_revision.dmsf_file.project) %>
@ -61,6 +62,20 @@
edit_dmsf_workflow_path(assignment.dmsf_workflow_step.dmsf_workflow)) %> edit_dmsf_workflow_path(assignment.dmsf_workflow_step.dmsf_workflow)) %>
<% end %> <% end %>
</td> </td>
<td class="dmsf_workflow">
<% if assignment.dmsf_workflow_step.dmsf_workflow %>
<%= link_to(
assignment.dmsf_file_revision.workflow_str(false),
log_dmsf_workflow_path(
:project_id => assignment.dmsf_file_revision.dmsf_file.project_id,
:id => assignment.dmsf_workflow_step.dmsf_workflow_id,
:dmsf_file_revision_id => assignment.dmsf_file_revision_id),
:title => assignment.dmsf_file_revision.workflow_tooltip,
:remote => true) %>
<% else %>
<%= assignment.dmsf_file_revision.workflow_str(false) %>
<% end %>
</td>
<td class="title"> <td class="title">
<% if assignment.dmsf_file_revision && assignment.dmsf_file_revision.dmsf_file %> <% if assignment.dmsf_file_revision && assignment.dmsf_file_revision.dmsf_file %>
<%= link_to(h(assignment.dmsf_file_revision.title), <%= link_to(h(assignment.dmsf_file_revision.title),
@ -71,27 +86,22 @@
<% if assignment.dmsf_file_revision %> <% if assignment.dmsf_file_revision %>
<% if assignment.dmsf_file_revision.dmsf_file.dmsf_folder %> <% if assignment.dmsf_file_revision.dmsf_file.dmsf_folder %>
<%= link_to(h(assignment.dmsf_file_revision.dmsf_file.dmsf_folder.title), <%= link_to(h(assignment.dmsf_file_revision.dmsf_file.dmsf_folder.title),
{:controller => 'dmsf', :action => 'show', :id => assignment.dmsf_file_revision.dmsf_file.project, :folder_id => assignment.dmsf_file_revision.dmsf_file.dmsf_folder}) %> {:controller => 'dmsf', :action => 'show', :id => assignment.dmsf_file_revision.dmsf_file.project,
:folder_id => assignment.dmsf_file_revision.dmsf_file.dmsf_folder}) %>
<% elsif assignment.dmsf_file_revision.dmsf_file.project %> <% elsif assignment.dmsf_file_revision.dmsf_file.project %>
<%= link_to(l(:link_documents), {:controller => 'dmsf', :action => 'show', :id => assignment.dmsf_file_revision.dmsf_file.project }) %> <%= link_to(l(:link_documents), {:controller => 'dmsf', :action => 'show',
:id => assignment.dmsf_file_revision.dmsf_file.project }) %>
<% end %> <% end %>
<% end %> <% end %>
</td> </td>
<td class="dmsf_buttons"> <td class="dmsf_buttons">
<% if assignment.dmsf_workflow_step.dmsf_workflow %> <%= render(:partial => 'dmsf_workflows/approval_workflow_button',
<% assigns = assignment.dmsf_workflow_step.dmsf_workflow.next_assignments(assignment.dmsf_file_revision.id) %> :locals => {:file => assignment.dmsf_file_revision.dmsf_file,
<% index = assigns.find_index{|assign| assign.user_id == User.current.id} if assigns %> :file_approval_allowed => User.current.allowed_to?(:file_approval,
<% if index %> assignment.dmsf_file_revision.dmsf_file.project),
<%= link_to(image_tag('waiting_for_approval.png', :plugin => 'redmine_dmsf'), :workflows_available => nil,
action_dmsf_workflow_path( :project => assignment.dmsf_file_revision.dmsf_file.project,
:project_id => assignment.dmsf_file_revision.dmsf_file.project.id, :wf => assignment.dmsf_workflow_step.dmsf_workflow, :dmsf_link_id => nil }) %>
:id => assignment.dmsf_workflow_step.dmsf_workflow.id,
:dmsf_workflow_step_assignment_id => assigns[index].id,
:dmsf_file_revision_id => assignment.dmsf_file_revision.id),
:title => l(:title_waiting_for_approval),
:remote => true) %>
<% end %>
<% end %>
</td> </td>
</tr> </tr>
<% end %> <% end %>

View File

@ -0,0 +1,31 @@
<%
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011-17 Karel Picman <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.
%>
<% dmsf_file_or_folder = object %>
<% if dmsf_file_or_folder.dmsf_folder_id %>
<% dmsf_folder = DmsfFolder.find_by_id dmsf_file_or_folder.dmsf_folder_id %>
<% title = dmsf_folder.title if dmsf_folder %>
<% else %>
<% title = dmsf_file_or_folder.project.name %>
<% end %>
<%= link_to(h(title), dmsf_folder_path(:id => dmsf_file_or_folder.project,
:folder_id => dmsf_file_or_folder.dmsf_folder_id), :class => 'icon icon-folder') %>

View File

@ -31,8 +31,7 @@
<% end %> <% end %>
<% cfs = CustomField.where(:type => 'DmsfFileRevisionCustomField').order(:position) %> <% cfs = CustomField.where(:type => 'DmsfFileRevisionCustomField').order(:position) %>
<% columns.concat(cfs.map{ |c| c.name }) %> <% columns.concat(cfs.map{ |c| c.name }) %>
<% selected_columns = settings[:dmsf_columns] %> <% selected_columns = DmsfFolder::DEFAULT_COLUMNS if selected_columns.blank? %>
<% selected_columns = DmsfFolder::DEFAULT_COLUMNS unless selected_columns %>
<% columns.each_with_index do |column, i| %> <% columns.each_with_index do |column, i| %>
<%= check_box_tag('settings[dmsf_columns][]', column, selected_columns.include?(column)) %> <%= check_box_tag('settings[dmsf_columns][]', column, selected_columns.include?(column)) %>
<%= h column.capitalize %> <%= h column.capitalize %>

View File

@ -62,21 +62,21 @@
<%= content_tag(:label, l(:label_file_storage_directory)) %> <%= content_tag(:label, l(:label_file_storage_directory)) %>
<% <%
storage_dir = @settings['dmsf_storage_directory'].strip if @settings['dmsf_storage_directory'].present? storage_dir = @settings['dmsf_storage_directory'].strip if @settings['dmsf_storage_directory'].present?
storage_dir = "#{Rails.root}/files/dmsf" if storage_dir.blank? storage_dir = 'dmsf' if storage_dir.blank?
%> %>
<%= text_field_tag 'settings[dmsf_storage_directory]', storage_dir, :size => 50 %> <%= text_field_tag 'settings[dmsf_storage_directory]', storage_dir, :size => 50 %>
<em class="info"> <em class="info">
<%= l(:label_default) %>: <%= "#{Rails.root}/files/dmsf" %> <%= l(:label_default) %>: dmsf
</em> </em>
</p> </p>
<% unless File.exist?(storage_dir) %> <% unless File.exist?(DmsfFile.storage_path) %>
<% begin %> <% begin %>
<% Dir.mkdir(storage_dir) %> <% Dir.mkdir(DmsfFile.storage_path) %>
<% rescue %> <% rescue %>
<p class="warning"><%= l(:error_file_storage_directory_does_not_exist) %></p> <p class="warning"><%= l(:error_file_storage_directory_does_not_exist) %></p>
<% end %> <% end %>
<% end %> <% end %>
<% testfilename = "#{storage_dir}/test.test" %> <% testfilename = DmsfFile.storage_path.join('test.test') %>
<% if File.exist?(storage_dir) %> <% if File.exist?(storage_dir) %>
<% begin %> <% begin %>
<% File.open(testfilename, 'wb') do |file| %> <% File.open(testfilename, 'wb') do |file| %>
@ -142,7 +142,7 @@
<%= l(:menu_dmsf) %> <%= l(:field_column_names) %> <%= l(:menu_dmsf) %> <%= l(:field_column_names) %>
</em> </em>
<%= render(:partial => 'settings/dmsf_columns', :locals => { :settings => @settings }) %> <%= render(:partial => 'settings/dmsf_columns', :locals => { :selected_columns => @settings['dmsf_columns'] }) %>
<hr/> <hr/>
<em class="info"> <em class="info">
@ -187,14 +187,6 @@
</em> </em>
</p> </p>
<p>
<%= content_tag(:label, l(:label_memcached_servers)) %>
<%= text_field_tag 'settings[dmsf_memcached_servers]', @settings['dmsf_memcached_servers'], :size => 50 %>
<em class="info">
<%= l(:text_memcached_servers) %>
</em>
</p>
<p> <p>
<%= content_tag(:label, l(:label_webdav_ignore)) %> <%= content_tag(:label, l(:label_webdav_ignore)) %>
<%= text_field_tag 'settings[dmsf_webdav_ignore]', @settings['dmsf_webdav_ignore'], :size => 50 %> <%= text_field_tag 'settings[dmsf_webdav_ignore]', @settings['dmsf_webdav_ignore'], :size => 50 %>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 739 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 316 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 797 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 530 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 263 B

Some files were not shown because too many files have changed in this diff Show More