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
rvm:
- 2.0.0
- 2.3
install: "echo skip bundle install"
install: 'echo skip bundle install'
script:
- export WORKSPACE=`pwd`/workspace

View File

@ -1,6 +1,62 @@
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*
------------------

View File

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

136
README.md
View File

@ -1,7 +1,7 @@
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.
@ -37,7 +37,8 @@ Features
* Documents and folders symbolic links
* Document tagging
* Trash bin
* Compatible with Redmine 3.3.x
* Documents attachable to issues
* Compatible with Redmine 3.4.x
Dependencies
------------
@ -46,51 +47,76 @@ Dependencies
### Full-text search (optional)
If you want to use fulltext search abilities:
* Xapian (<http://www.xapian.org>) search engine
* Xapian Omega indexing tool
* Xapian ruby bindings - xapian or xapian-full gem
If you want to use fulltext search abilities, install xapian-omega and ruby-xapian packages. See https://xapian.org
for details.
```
sudo apt-get install xapian-omega ruby-xapian
```
To index some files with omega you may have to install some other packages like
xpdf, antiword, ...
From Omega documentation:
* PDF (.pdf) if pdftotext is available (comes with xpdf)
* PostScript (.ps, .eps, .ai) if ps2pdf (from ghostscript) and pdftotext (comes with xpdf) are available
* OpenOffice/StarOffice documents (.sxc, .stc, .sxd, .std, .sxi, .sti, .sxm, .sxw, .sxg, .stw) if unzip is available.
* 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 Word documents (.doc, .dot) if antiword is available
* MS Excel documents (.xls, .xlb, .xlt) if xls2csv is available (comes with catdoc)
* MS Powerpoint documents (.ppt, .pps) if catppt is available (comes with catdoc)
* MS Office 2007 documents (.docx, .dotx, .xlsx, .xlst, .pptx, .potx, .ppsx) if unzip is available
* Wordperfect documents (.wpd) if wpd2text is available (comes with libwpd)
* MS Works documents (.wps, .wpt) if wps2text is available (comes with libwps)
* AbiWord documents (.abw)
* Compressed AbiWord documents (.zabw) if gzip is available
* Rich Text Format documents (.rtf) if unrtf is available
* Perl POD documentation (.pl, .pm, .pod) if pod2text 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
* HTML (.html, .htm, .shtml, .shtm, .xhtml, .xhtm)
* PHP (.php) - our HTML parser knows to ignore PHP code
* text files (.txt, .text)
* SVG (.svg)
* CSV (Comma-Separated Values) files (.csv)
* PDF (.pdf) if pdftotext is available (comes with poppler or xpdf)
* PostScript (.ps, .eps, .ai) if ps2pdf (from ghostscript) and pdftotext (comes with poppler or xpdf) are available
* OpenOffice/StarOffice documents (.sxc, .stc, .sxd, .std, .sxi, .sti, .sxm, .sxw, .sxg, .stw) if unzip is available
* 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 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).
* MS Excel documents (.xls, .xlb, .xlt, .xlr, .xla) if xls2csv is available (comes with catdoc)
* MS Powerpoint documents (.ppt, .pps) if catppt is available (comes with catdoc)
* MS Office 2007 documents (.docx, .docm, .dotx, .dotm, .xlsx, .xlsm, .xltx, .xltm, .pptx, .pptm, .potx, .potm, .ppsx, .ppsm) if unzip is available
* Wordperfect documents (.wpd) if wpd2text is available (comes with libwpd)
* MS Works documents (.wps, .wpt) if wps2text is available (comes with libwps)
* MS Outlook message (.msg) if perl with Email::Outlook::Message and HTML::Parser modules 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:
```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 \
djview djview3 uuid uuid-dev xz-utils```
djview djview3 uuid uuid-dev xz-utils libemail-outlook-message-perl
```
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 \
uuid uuid-dev xz-utils```
uuid uuid-dev xz-utils libemail-outlook-message-perl
```
On CentOS user:
```sudo yum install xapian-omega libxapian-dev xpdf poppler-utils antiword \
On CentOS use:
```
sudo yum install xapian-omega libxapian-dev xpdf poppler-utils antiword \
unzip catdoc libwpd-tools libwps-tools gzip unrtf catdvi djview djview3 \
uuid uuid-dev xz```
uuid uuid-dev xz libemail-outlook-message-perl
```
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>
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`
@ -211,9 +237,9 @@ Before installing ensure that the Redmine instance is stopped.
6. Restart the web server.
7. You should configure the plugin via Redmine interface: Administration -> Plugins -> DMSF -> Configure.
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:
@ -229,21 +255,53 @@ Before installing ensure that the Redmine instance is stopped.
chown -R www-data:www-data /redmine/files/dmsf
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:
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)
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.
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):

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
#
# Redmine plugin for Document Management System "Features"
#
@ -23,17 +24,24 @@
class DmsfController < ApplicationController
unloadable
before_filter :find_project
before_filter :authorize, :except => [:expand_folder]
before_filter :find_folder, :except => [:new, :create, :edit_root, :save_root]
before_filter :find_parent, :only => [:new, :create]
before_filter :tree_view, :only => [:delete, :show]
before_action :find_project
before_action :authorize, :except => [:expand_folder]
before_action :find_folder, :except => [:new, :create, :edit_root, :save_root]
before_action :find_parent, :only => [:new, :create]
before_action :tree_view, :only => [:delete, :show]
before_action :permissions
accept_api_auth :show, :create, :save
skip_before_action :verify_authenticity_token, if: -> { request.headers['HTTP_X_REDMINE_API_KEY'].present? }
helper :all
helper :dmsf_folder_permissions
def permissions
render_403 unless DmsfFolder.permissions?(@folder)
true
end
def expand_folder
@tree_view = true
@ -73,13 +81,15 @@ class DmsfController < ApplicationController
@file_manipulation_allowed = User.current.allowed_to? :file_manipulation, @project
@file_delete_allowed = User.current.allowed_to? :file_delete, @project
@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)
@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')
end
def download_email_entries
# IE has got a tendency to cache files
expires_in(0.year, "must-revalidate" => true)
send_file(
params[:path],
:filename => 'Documents.zip',
@ -150,6 +160,7 @@ class DmsfController < ApplicationController
if params[:dmsf_folder] && params[:dmsf_folder][:custom_field_values].present?
redirect_to dmsf_folder_path(
:id => @project,
:folder_id => @folder,
:custom_field_id => params[:dmsf_folder][:custom_field_values].first[0],
:custom_value => params[:dmsf_folder][:custom_field_values].first[1])
else
@ -174,25 +185,18 @@ class DmsfController < ApplicationController
render :action => 'edit'
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
@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.user = User.current
# 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
saved = @folder.update_from_params(params)
respond_to do |format|
format.js
format.api {
@ -203,7 +207,7 @@ class DmsfController < ApplicationController
format.html {
if saved
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
@pathfolder = @parent
render :action => 'edit'
@ -213,30 +217,13 @@ class DmsfController < ApplicationController
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
unless params[:dmsf_folder]
redirect_to dmsf_folder_path(:id => @project, :folder_id => @folder)
return
end
@pathfolder = copy_folder(@folder)
@folder.title = params[:dmsf_folder][:title].strip
@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
saved = @folder.update_from_params(params)
respond_to do |format|
format.api {
unless saved
@ -246,7 +233,7 @@ class DmsfController < ApplicationController
format.html {
if 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
render :action => 'edit'
end
@ -529,7 +516,7 @@ class DmsfController < ApplicationController
recipients.each do |u|
DmsfMailer.files_deleted(u, @project, deleted_files).deliver
end
if Setting.plugin_redmine_dmsf[:dmsf_display_notified_recipients] == '1'
if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] == '1'
unless recipients.empty?
to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ')
to << ((recipients.count > DMSF_MAX_NOTIFICATION_RECEIVERS_INFO) ? ',...' : '.')
@ -563,7 +550,8 @@ class DmsfController < ApplicationController
def find_folder_by_title
# 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
render_403
rescue ActiveRecord::RecordNotFound
@ -592,6 +580,7 @@ class DmsfController < ApplicationController
private
def get_display_params
@system_folder = @folder && @folder.system
@folder_manipulation_allowed = User.current.allowed_to?(:folder_manipulation, @project)
@file_manipulation_allowed = User.current.allowed_to?(:file_manipulation, @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?
@file_approval_allowed = User.current.allowed_to?(:file_approval, @project)
tag = params[:custom_field_id].present? && params[:custom_value].present?
@folder = nil if tag
@extra_columns = [l(:field_project), l(:label_document_url), l(:label_last_revision_id)]
@extra_columns = [l(:label_last_approver), l(:field_project), l(:label_document_url), l(:label_last_revision_id)]
if @tree_view
@locked_for_user = false
else
unless @folder
if tag
@subfolders = []
DmsfFolder.where(:project_id => @project.id).visible.each do |f|
f.custom_field_values.each do |v|
if tag
@subfolders = []
folder_id = @folder.id if @folder
DmsfFolder.where(:project_id => @project.id, :dmsf_folder_id => folder_id, :system => false).visible.each do |f|
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.compare_values?(v.value, params[:custom_value])
@subfolders << f
@files << f
break
end
end
end
end
@files = []
DmsfFile.where(:container_id => @project.id, :container_type => 'Project').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.compare_values?(v.value, params[:custom_value])
@files << f
break
end
end
end
@dir_links = []
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|
l.target_folder.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])
@dir_links << l
break
end
end
end
@dir_links = []
DmsfLink.where(:project_id => @project.id, :target_type => DmsfFolder.model_name.to_s).visible.each do |l|
l.target_folder.custom_field_values.each do |v|
end
@file_links = []
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.compare_values?(v.value, params[:custom_value])
@dir_links << l
@file_links << l
break
end
end
end
end
@file_links = []
DmsfLink.where(:project_id => @project.id, :target_type => DmsfFile.model_name.to_s).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
@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
end
@url_links = []
else
if @folder
@subfolders = @folder.dmsf_folders.visible.to_a
@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?
else
@subfolders = @project.dmsf_folders.visible
@subfolders = @project.dmsf_folders.visible.to_a
@files = @project.dmsf_files.visible
@dir_links = @project.folder_links.visible
@file_links = @project.file_links.visible
@url_links = @project.url_links.visible
@locked_for_user = false
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
# 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
@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 &&
@file_delete_allowed && !@locked_for_user && !@folder
@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?
end

View File

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

View File

@ -1,6 +1,7 @@
# 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
# modify it under the terms of the GNU General Public License
@ -21,11 +22,19 @@ class DmsfFilesCopyController < ApplicationController
menu_item :dmsf
before_filter :find_file
before_filter :authorize
before_action :find_file
before_action :authorize
before_action :permissions
helper :all
def permissions
if @file
render_403 unless DmsfFolder.permissions?(@file.dmsf_folder)
end
true
end
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 ||= @project if User.current.allowed_to?(:file_manipulation, @project)
@ -108,12 +117,15 @@ class DmsfFilesCopyController < ApplicationController
private
def log_activity(file, action)
Rails.logger.info "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} #{User.current.login}@#{request.remote_ip}/#{request.env['HTTP_X_FORWARDED_FOR']}: #{action} dmsf://#{file.project.identifier}/#{file.id}/#{file.last_revision.id}"
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
def find_file
@file = DmsfFile.visible.find(params[:id])
@project = @file.project
@file = DmsfFile.visible.find_by_id params[:id]
@project = @file.project if @file
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
before_filter :find_folder
before_filter :authorize
before_action :find_folder
before_action :authorize
before_action :permissions
def permissions
render_403 unless DmsfFolder.permissions?(@folder)
true
end
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]
@ -80,8 +86,8 @@ class DmsfFoldersCopyController < ApplicationController
end
def find_folder
@folder = DmsfFolder.visible.find(params[:id])
@project = @folder.project
@folder = DmsfFolder.visible.find_by_id(params[:id])
@project = @folder.project if @folder
end
end

View File

@ -22,9 +22,18 @@ class DmsfLinksController < ApplicationController
unloadable
model_object DmsfLink
before_filter :find_model_object, :only => [:destroy, :restore]
before_filter :find_link_project
before_filter :authorize
before_action :find_model_object, :only => [:destroy, :restore]
before_action :find_link_project
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
@dmsf_link = nil
@ -35,109 +44,78 @@ class DmsfLinksController < ApplicationController
def new
@dmsf_link = DmsfLink.new
@dmsf_link.project_id = params[:project_id]
if params[:dmsf_link].present?
# Reload
@dmsf_link.dmsf_folder_id = params[:dmsf_link][:dmsf_folder_id]
@dmsf_file_id = params[:dmsf_link][:dmsf_file_id]
@type = params[:dmsf_link][:type]
@link_external = (@type == 'link_from') && (params[:external_link] == 'true')
@dmsf_link.target_project_id = params[:dmsf_link][:target_project_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])
if @type == 'link_to'
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
@dmsf_link.dmsf_folder_id = params[:dmsf_folder_id]
@dmsf_file_id = params[:dmsf_file_id]
@type = params[:type]
@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
if params[:dmsf_link][:target_file_id].present?
@target_file_id = params[:dmsf_link][:target_file_id]
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
folder = DmsfFolder.find_by_id @target_folder_id
@dmsf_link.name = folder.title if folder
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
def create
@dmsf_link = DmsfLink.new
@dmsf_link.user = User.current
if params[:dmsf_link][:type] == 'link_from'
# Link from
@dmsf_link.project_id = params[:dmsf_link][:project_id]
@dmsf_link.dmsf_folder_id = params[:dmsf_link][:dmsf_folder_id]
if params[:dmsf_link][:container].blank?
@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]
@link_external = (params[:external_link] == 'true')
@dmsf_link.external_url = params[:dmsf_link][:external_url]
if (@link_external)
if (params[:external_link] == 'true')
@dmsf_link.external_url = params[:dmsf_link][:external_url]
@dmsf_link.target_type = 'DmsfUrl'
elsif params[:dmsf_link][:target_file_id].present?
@dmsf_link.target_id = params[:dmsf_link][:target_file_id]
@dmsf_link.target_type = DmsfFile.model_name.to_s
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
end
@dmsf_link.name = params[:dmsf_link][:name]
if @dmsf_link.save
flash[:notice] = l(:notice_successful_create)
redirect_to dmsf_folder_path(:id => @project.id, :folder_id => @dmsf_link.dmsf_folder_id)
else
@dmsf_file_id = params[:dmsf_link][:dmsf_file_id]
@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'
flash[:error] = @dmsf_link.errors.full_messages.to_sentence
end
else
# Link to
@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]
@link_external = (params[:external_link] == 'true')
@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?
if params[:dmsf_link][:dmsf_file_id].present?
@dmsf_link.target_id = params[:dmsf_link][:dmsf_file_id]
@dmsf_link.target_type = DmsfFile.model_name.to_s
else
@ -145,24 +123,26 @@ class DmsfLinksController < ApplicationController
@dmsf_link.target_type = DmsfFolder.model_name.to_s
end
@dmsf_link.name = params[:dmsf_link][:name]
if @dmsf_link.save
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
@dmsf_file_id = params[:dmsf_link][:dmsf_file_id]
@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'
flash[:error] = @dmsf_link.errors.full_messages.to_sentence
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
def destroy

View File

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

View File

@ -24,8 +24,8 @@ class DmsfStateController < ApplicationController
menu_item :dmsf
before_filter :find_project
before_filter :authorize
before_action :find_project
before_action :authorize
def user_pref_save
member = @project.members.where(:user_id => User.current.id).first
@ -39,7 +39,10 @@ class DmsfStateController < ApplicationController
end
else
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')
end

View File

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

View File

@ -22,12 +22,21 @@ class DmsfWorkflowsController < ApplicationController
unloadable
model_object DmsfWorkflow
before_filter :find_model_object, :except => [:create, :new, :index, :assign, :assignment]
before_filter :find_project
before_filter :authorize_custom
before_action :find_model_object, :except => [:create, :new, :index, :assign, :assignment]
before_action :find_project
before_action :authorize_custom
before_action :permissions, :only => [:new_action, :assignment, :start]
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
@dmsf_workflow = nil
@project = nil
@ -72,7 +81,7 @@ class DmsfWorkflowsController < ApplicationController
:text_email_finished_approved,
:text_email_to_see_history).deliver if user
end
if Setting.plugin_redmine_dmsf[:dmsf_display_notified_recipients] == '1'
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) ? ',...' : '.')
@ -95,7 +104,7 @@ class DmsfWorkflowsController < ApplicationController
:text_email_to_see_history,
action.note).deliver
end
if Setting.plugin_redmine_dmsf[:dmsf_display_notified_recipients] == '1'
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) ? ',...' : '.')
@ -116,7 +125,7 @@ class DmsfWorkflowsController < ApplicationController
:text_email_finished_delegated,
:text_email_to_proceed,
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)
end
end
@ -147,7 +156,7 @@ class DmsfWorkflowsController < ApplicationController
:text_email_finished_step_short,
:text_email_to_see_status).deliver
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 << to if to
recipients.uniq!
@ -178,31 +187,54 @@ class DmsfWorkflowsController < ApplicationController
def assignment
if (params[:commit] == l(:button_submit)) &&
params[:dmsf_workflow_id].present? && (params[:dmsf_workflow_id] != '-1')
revision = DmsfFileRevision.find_by_id params[:dmsf_file_revision_id]
if revision
revision.set_workflow(params[:dmsf_workflow_id], params[:action])
revision.assign_workflow(params[:dmsf_workflow_id])
if request.post?
if revision.save
file = DmsfFile.find_by_id revision.dmsf_file_id
if file
begin
file.lock!
rescue DmsfLockError => e
logger.warn e.message
# DMS file
if params[:dmsf_file_revision_id].present? && params[:dmsf_link_id].blank? && params[:attachment_id].blank?
revision = DmsfFileRevision.find_by_id params[:dmsf_file_revision_id]
if revision
revision.set_workflow(params[:dmsf_workflow_id], params[:action])
revision.assign_workflow(params[:dmsf_workflow_id])
if request.post?
if revision.save
file = DmsfFile.find_by_id revision.dmsf_file_id
if file
begin
file.lock!
rescue DmsfLockError => e
Rails.logger.warn e.message
end
flash[:notice] = l(:notice_successful_update)
end
flash[:notice] = l(:notice_successful_update)
else
flash[:error] = l(:error_workflow_assign)
end
else
flash[:error] = l(:error_workflow_assign)
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
else
redirect_to :back
return
end
respond_to do |format|
format.html
format.js
end
redirect_to :back
end
def log
respond_to do |format|
format.html
format.js
end
end
def edit
@ -366,26 +398,7 @@ class DmsfWorkflowsController < ApplicationController
if revision
revision.set_workflow(@dmsf_workflow.id, params[:action])
if revision.save
assignments = @dmsf_workflow.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,
@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
@dmsf_workflow.notify_users(@project, revision, self)
flash[:notice] = l(:notice_workflow_started)
else
flash[:error] = l(:notice_cannot_start_workflow)
@ -399,22 +412,21 @@ class DmsfWorkflowsController < ApplicationController
if params[:dmsf_workflow].present?
index = params[:step].to_i
name = params[:dmsf_workflow][:name]
if name.present?
step = @dmsf_workflow.dmsf_workflow_steps[index]
step.name = name
unless step.save
flash[:error] = step.errors.full_messages.to_sentence
else
@dmsf_workflow.dmsf_workflow_steps.each do |s|
if s.step == step.step
s.name = step.name
s.save
end
step = @dmsf_workflow.dmsf_workflow_steps[index]
step.name = name
unless step.save
flash[:error] = step.errors.full_messages.to_sentence
else
@dmsf_workflow.dmsf_workflow_steps.each do |s|
if s.step == step.step
s.name = step.name
s.save
end
end
end
else
# Operators
end
# Operators
if params[:operator_step].present?
params[:operator_step].each do |id, operator|
step = DmsfWorkflowStep.find_by_id id
if step
@ -462,9 +474,11 @@ private
elsif params[:project_id]
@project = Project.find_by_id params[:project_id]
else
@project = Project.find_by_identifier params[:id]
@project = Project.find params[:id]
end
end
rescue ActiveRecord::RecordNotFound
@project = nil
end
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 = extension[1, extension.length-1]
if File.exist?("#{File.dirname(__FILE__)}/../../assets/images/filetypes/#{extension}.png")
"filetype-#{extension}";
cls = "filetype-#{extension}";
else
Redmine::MimeType.css_class_of(filename)
cls = Redmine::MimeType.css_class_of(filename)
end
cls << ' dmsf-icon-file' if cls
cls
end
def plugin_asset_path(plugin, asset_type, source)
@ -89,9 +91,31 @@ module DmsfHelper
'plupload/js/i18n/en.js'
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)
# 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
nodes.sort! do |x, y|
if ((x.is_a?(DmsfFolder) || (x.is_a?(DmsfLink) && x.is_folder?)) &&
@ -105,7 +129,9 @@ module DmsfHelper
end
end
# Calculate position
step = 1.0 / (10 ** ident)
ident = 0 unless ident
pos = (10 ** 12) unless pos
step = (10 ** 12) / (10 ** (ident * 3))
tree = []
i = 0
nodes.each do |x|
@ -113,7 +139,7 @@ module DmsfHelper
i += 1
tree << [x, pos + (step * i)]
else
tree << [x, pos + step + i]
tree << [x, pos + (step * (i + 1))]
end
end
tree

View File

@ -37,6 +37,18 @@ module DmsfLinksHelper
# An integer test
def self.is_a_number?(s)
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

View File

@ -21,20 +21,15 @@
module DmsfUploadHelper
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 = []
files = []
if container.is_a?(Project)
project = container
else
project = container.project
end
if commited_files && commited_files.is_a?(Hash)
failed_uploads = []
commited_files.each_value do |commited_file|
name = commited_file[:name]
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
link = DmsfLink.find_link_by_file_name(project, folder, name)
file = link.target_file if link
@ -42,11 +37,10 @@ module DmsfUploadHelper
unless file
file = DmsfFile.new
file.container_type = container.class.name.demodulize
file.container_id = container.id
file.project_id = project.id
file.name = name
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.major_version = 0
else
@ -66,8 +60,6 @@ module DmsfUploadHelper
next
end
commited_disk_filepath = "#{DmsfHelper.temp_dir}/#{commited_file[:disk_filename].gsub(/[\/\\]/,'')}"
new_revision.dmsf_file = file
new_revision.user = User.current
new_revision.name = name
@ -81,9 +73,9 @@ module DmsfUploadHelper
else
new_revision.increase_version(version)
end
new_revision.mime_type = Redmine::MimeType.of(new_revision.name)
new_revision.size = File.size(commited_disk_filepath)
new_revision.digest = DmsfFileRevision.create_digest commited_disk_filepath
new_revision.mime_type = commited_file[:mime_type]
new_revision.size = commited_file[:size]
new_revision.digest = DmsfFileRevision.create_digest commited_file[:tempfile_path]
if commited_file[:custom_field_values].present?
commited_file[:custom_field_values].each_with_index do |v, i|
@ -104,7 +96,8 @@ module DmsfUploadHelper
if new_revision.save
new_revision.assign_workflow(commited_file[:dmsf_workflow_id])
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
files.push(file)
if file.container.is_a?(Issue)
@ -118,14 +111,36 @@ module DmsfUploadHelper
else
failed_uploads.push(commited_file)
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
if container.is_a?(Project) && ((folder && folder.notification?) || (!folder && project.dmsf_notification?))
# Notifications
if ((folder && folder.notification?) || (!folder && project.dmsf_notification?))
begin
recipients = DmsfMailer.get_notify_users(project, files)
recipients.each do |u|
DmsfMailer.files_updated(u, project, files).deliver
end
if Setting.plugin_redmine_dmsf[:dmsf_display_notified_recipients] == '1'
if Setting.plugin_redmine_dmsf['dmsf_display_notified_recipients'] == '1'
unless recipients.empty?
to = recipients.collect{ |r| r.name }.first(DMSF_MAX_NOTIFICATION_RECEIVERS_INFO).join(', ')
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)
scope = workflow.delegates(params[:q], dmsf_workflow_step_assignment_id, dmsf_file_revision_id)
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
# Delegation

View File

@ -23,7 +23,8 @@ begin
require 'xapian'
$xapian_bindings_available = true
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
end
@ -32,6 +33,7 @@ class DmsfFile < ActiveRecord::Base
include RedmineDmsf::Lockable
belongs_to :project
belongs_to :dmsf_folder
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
has_many :dmsf_public_urls, :dependent => :destroy
STATUS_DELETED = 1
STATUS_ACTIVE = 0
STATUS_DELETED = 1.freeze
STATUS_ACTIVE = 0.freeze
scope :visible, -> { where(:deleted => STATUS_ACTIVE) }
scope :deleted, -> { where(:deleted => STATUS_DELETED) }
@ -55,10 +57,8 @@ class DmsfFile < ActiveRecord::Base
validate :validates_name_uniqueness
attr_accessible :project, :project_id
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)
end
@ -69,7 +69,7 @@ class DmsfFile < ActiveRecord::Base
Redmine::Search.cache_store.delete("DmsfFile-#{o.id}")
else
# 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 += o.last_revision.comment if o.last_revision.comment.present?
end
@ -84,12 +84,10 @@ class DmsfFile < ActiveRecord::Base
:date_column => "#{table_name}.updated_at"
before_create :default_values
def default_values
@notifications = Setting.plugin_redmine_dmsf['dmsf_default_notifications']
if @notifications == '1'
if (Setting.plugin_redmine_dmsf['dmsf_default_notifications'] == '1') && (!self.dmsf_folder || !self.dmsf_folder.system)
self.notification = true
else
self.notification = nil
end
end
@ -98,36 +96,24 @@ class DmsfFile < ActiveRecord::Base
super
end
@@storage_path = nil
def self.storage_path
return @@storage_path if @@storage_path.present?
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?
path = Rails.root.join('files/dmsf').to_s if path.blank?
path.strip if path
path
end
# 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
if path.blank?
path = Pathname.new('files').join('dmsf').to_s
else
pn = Pathname.new(path)
return pn if pn.absolute?
end
@@storage_path = path
Rails.root.join(path)
end
def self.find_file_by_name(container, folder, name)
self.findn_file_by_name(container.id, container.class.name.demodulize, folder, name)
def self.find_file_by_name(project, folder, name)
self.findn_file_by_name(project.id, folder, name)
end
def self.findn_file_by_name(container_id, container_type, folder, name)
def self.findn_file_by_name(project_id, folder, name)
where(
:container_id => container_id,
:container_type => container_type,
:project_id => project_id,
:dmsf_folder_id => folder ? folder.id : nil,
:name => name).visible.first
end
@ -148,9 +134,13 @@ class DmsfFile < ActiveRecord::Base
end
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)
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
end
begin
@ -245,63 +235,43 @@ class DmsfFile < ActiveRecord::Base
projects
end
def move_to(container, folder)
def move_to(project, folder)
if self.locked_for_user?
errors[:base] << l(:error_file_is_locked)
return false
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
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
self.container_type = self.container_type
self.container_id = container.id
self.project_id = project.id
self.dmsf_folder = folder
new_revision = self.last_revision.clone
new_revision.dmsf_file = self
new_revision.comment = l(:comment_moved_from, :source => "#{self.project.identifier}:#{self.dmsf_path_str}")
new_revision.custom_values = []
self.last_revision.custom_values.each do |cv|
new_revision.custom_values << CustomValue.new({:custom_field => cv.custom_field, :value => cv.value})
end
self.set_last_revision(new_revision)
self.save && new_revision.save
end
def copy_to(container, folder = nil)
copy_to_filename(container, folder, self.name)
def copy_to(project, folder = nil)
copy_to_filename(project, folder, self.name)
end
def copy_to_filename(container, folder=nil, 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
def copy_to_filename(project, folder, filename)
file = DmsfFile.new
file.dmsf_folder = folder
file.container_type = self.container_type
file.container_id = container.id
file.project_id = project.id
file.name = filename
file.notification = Setting.plugin_redmine_dmsf['dmsf_default_notifications'].present?
if file.save && self.last_revision
new_revision = self.last_revision.clone
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.custom_values = []
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.table_name}.id IN (#{project_ids.join(',')})" if project_ids.present?
scope = self.visible.joins(:dmsf_file_revisions).joins(
"JOIN #{Project.table_name} ON #{DmsfFile.table_name}.container_id = #{Project.table_name}.id AND #{DmsfFile.table_name}.container_type = 'Project'")
scope = self.visible.joins('JOIN dmsf_file_revisions ON dmsf_file_revisions.dmsf_file_id = dmsf_files.id').joins(:project)
scope = scope.limit(options[:limit]) unless options[:limit].blank?
scope = scope.where(limit_options) unless limit_options.blank?
scope = scope.where(project_conditions.join(' AND '))
@ -352,8 +321,8 @@ class DmsfFile < ActiveRecord::Base
Setting.plugin_redmine_dmsf['dmsf_index_database'].strip, lang)
database = Xapian::Database.new(databasepath)
rescue Exception => e
Rails.logger.warn "REDMAIN_XAPIAN ERROR: Xapian database is not properly set, initiated or it's corrupted."
Rails.logger.warn e.message
Rails.logger.error "REDMINE_XAPIAN ERROR: Xapian database is not properly set, initiated or it's corrupted."
Rails.logger.error e.message
end
if database
@ -401,7 +370,7 @@ class DmsfFile < ActiveRecord::Base
if dmsf_file
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}",
dochash['sample'].force_encoding('UTF-8')) if dochash['sample']
break if(!options[:limit].blank? && results.count >= options[:limit])
@ -423,7 +392,7 @@ class DmsfFile < ActiveRecord::Base
end
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?
title_format = member.title_format
else
@ -496,7 +465,13 @@ class DmsfFile < ActiveRecord::Base
def custom_value(custom_field)
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
nil
end
@ -522,18 +497,16 @@ class DmsfFile < ActiveRecord::Base
end
def propfind_cache_key
if self.container_type == 'Project'
if dmsf_folder_id.nil?
# File is in project root
return "PROPFIND/#{self.container_id}"
else
return "PROPFIND/#{self.container_id}/#{self.dmsf_folder_id}"
end
unless dmsf_folder_id
# File is in project root
return "PROPFIND/#{self.project_id}"
else
return "PROPFIND/#{self.project_id}/#{self.dmsf_folder_id}"
end
end
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
include ActionView::Helpers::NumberHelper
@ -583,6 +556,14 @@ class DmsfFile < ActiveRecord::Base
csv << ''
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
if columns.include?(l(:label_document_url))
default_url_options[:host] = Setting.host_name
@ -604,31 +585,6 @@ class DmsfFile < ActiveRecord::Base
csv
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={})
if image?
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")
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
Rails.logger.error "An error occured while generating thumbnail for #{self.last_revision.disk_file} to #{target}\nException was: #{e.message}"
return nil
@ -652,4 +608,24 @@ class DmsfFile < ActiveRecord::Base
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

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 :user
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_workflow_step_assignment, :dependent => :destroy
@ -48,10 +49,8 @@ class DmsfFileRevision < ActiveRecord::Base
:timestamp => "#{DmsfFileRevision.table_name}.updated_at",
:author_key => "#{DmsfFileRevision.table_name}.user_id",
:permission => :view_dmsf_file_revisions,
:scope => select("#{DmsfFileRevision.table_name}.*").
joins(:dmsf_file).joins(
"LEFT JOIN #{Project.table_name} ON #{DmsfFile.table_name}.container_id = #{Project.table_name}.id").
where("#{DmsfFile.table_name}.container_type = ?", 'Project').visible
:scope => DmsfFileRevision.joins(:dmsf_file).
joins("JOIN #{Project.table_name} ON #{Project.table_name}.id = #{DmsfFile.table_name}.project_id").visible
validates :title, :presence => true
validates_format_of :name, :with => DmsfFolder::INVALID_CHARACTERS,
@ -72,6 +71,10 @@ class DmsfFileRevision < ActiveRecord::Base
def self.filename_to_title(filename)
remove_extension(filename).gsub(/_+/, ' ');
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)
if self.dmsf_file.locked_for_user?
@ -105,7 +108,7 @@ class DmsfFileRevision < ActiveRecord::Base
d.save!
end
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)
end
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
@ -131,20 +134,37 @@ class DmsfFileRevision < ActiveRecord::Base
"#{self.major_version}.#{self.minor_version}"
end
def storage_base_path(project = nil)
project = self.dmsf_file.project unless project
path = DmsfFile.storage_path.dup
if self.dmsf_file && project
project_base = project.identifier.gsub(/[^\w\.\-]/,'_')
path << "/p_#{project_base}"
end
def storage_base_path
time = self.created_at || DateTime.now
path = time.strftime('%Y/%m')
DmsfFile.storage_path.join path
end
def disk_file(project = nil)
project = self.dmsf_file.project unless project
path = storage_base_path(project)
def disk_file(search_if_not_exists = true)
path = self.storage_base_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
def detect_content_type
@ -227,16 +247,6 @@ class DmsfFileRevision < ActiveRecord::Base
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)
File.open(self.disk_file, 'wb') do |f|
while (buffer = open_file.read(8192))
@ -311,4 +321,25 @@ class DmsfFileRevision < ActiveRecord::Base
dmsf_file.propfind_cache_key
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

View File

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

View File

@ -26,8 +26,16 @@ class DmsfFileRevisionCustomField < CustomField
end
def compare_values?(x, y)
if x.is_a?(Array) && y.is_a?(Array) && !y.empty?
x.include? y[0]
if x.is_a?(Array) && y.is_a?(Array)
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
x == y
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 :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 :folder_links, -> { where(:target_type => 'DmsfFolder').order(:name) },
: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
has_many :locks, -> { where(entity_type: 1).order("#{DmsfLock.table_name}.updated_at DESC") },
: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_ACTIVE = 0.freeze
AVAILABLE_COLUMNS = %w(id title extension size modified version workflow author).freeze
DEFAULT_COLUMNS = %w(title size modified version workflow author).freeze
scope :visible, -> { where(:deleted => STATUS_ACTIVE) }
scope :deleted, -> { where(:deleted => STATUS_DELETED) }
scope :visible, -> (system=true) { joins(:project).joins(
"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
@ -72,14 +81,57 @@ class DmsfFolder < ActiveRecord::Base
validates_format_of :title, :with => INVALID_CHARACTERS,
:message => l(:error_contains_invalid_character)
validate :check_cycle
validates_length_of :description, :maximum => 65535
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
@notifications = Setting.plugin_redmine_dmsf['dmsf_default_notifications']
if @notifications == '1'
if Setting.plugin_redmine_dmsf['dmsf_default_notifications'] == '1' && !self.system
self.notification = true
else
self.notification = nil
end
end
@ -108,7 +160,7 @@ class DmsfFolder < ActiveRecord::Base
if self.locked?
errors[:base] << l(:error_folder_is_locked)
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)
return false
end
@ -169,8 +221,11 @@ class DmsfFolder < ActiveRecord::Base
end
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]]
project.dmsf_folders.visible.each do |folder|
project.dmsf_folders.notsystem.visible(false).each do |folder|
unless folder == current_folder
tree.push(["...#{folder.title}", folder.id])
directory_subtree(tree, folder, 2, current_folder)
@ -262,6 +317,10 @@ class DmsfFolder < ActiveRecord::Base
l.copy_to project, new_folder
end
self.dmsf_folder_permissions.each do |p|
p.copy_to new_folder
end
return new_folder
end
@ -272,37 +331,32 @@ class DmsfFolder < ActiveRecord::Base
def modified
last_update = updated_at
dmsf_folders.each do |subfolder|
last_update = subfolder.updated_at if subfolder.updated_at > last_update
end
dmsf_files.each do |file|
last_update = file.updated_at if file.updated_at > last_update
end
folder_links.each do |folder_link|
last_update = folder_link.updated_at if folder_link.updated_at > last_update
end
file_links.each do |file_link|
last_update = file_link.updated_at if file_link.updated_at > last_update
end
url_links.each do |url_link|
last_update = url_link.updated_at if url_link.updated_at > last_update
end
time = DmsfFolder.where(
['project_id = ? AND dmsf_folder_id = ? AND updated_at > ?',
self.project_id, self.id, last_update]).maximum(:updated_at)
last_update = time if time
time = DmsfFile.where(
['project_id = ? AND dmsf_folder_id = ? AND updated_at > ?',
self.project_id, self.id, last_update]).maximum(:updated_at)
last_update = time if time
time = DmsfLink.where(
['project_id = ? AND dmsf_folder_id = ? AND updated_at > ?',
self.project_id, self.id, last_update]).maximum(:updated_at)
last_update = time if time
last_update
end
# Number of items in the folder
def items
dmsf_folders.visible.count +
dmsf_files.visible.count +
folder_links.visible.count +
file_links.visible.count +
url_links.visible.count
dmsf_folders.visible.where(:project_id => self.project_id).count +
dmsf_files.visible.where(:project_id => self.project_id).count +
dmsf_links.visible.where(:project_id => self.project_id).count
end
def self.is_column_on?(column)
columns = Setting.plugin_redmine_dmsf['dmsf_columns']
columns = DmsfFolder::DEFAULT_COLUMNS unless columns
columns.include? column
dmsf_columns = Setting.plugin_redmine_dmsf['dmsf_columns']
dmsf_columns = DmsfFolder::DEFAULT_COLUMNS unless dmsf_columns
dmsf_columns.include? column
end
def custom_value(custom_field)
@ -313,61 +367,61 @@ class DmsfFolder < ActiveRecord::Base
end
def self.get_column_position(column)
dmsf_columns = Setting.plugin_redmine_dmsf['dmsf_columns']
dmsf_columns = DmsfFolder::DEFAULT_COLUMNS unless dmsf_columns
pos = 0
columns = Setting.plugin_redmine_dmsf['dmsf_columns']
columns = DmsfFolder::DEFAULT_COLUMNS unless columns
# 0 - checkbox
# 1 - id
if columns.include?('id')
if dmsf_columns.include?('id')
pos += 1
return pos if column == 'id'
else
return nil if column == 'id'
end
# 2 - title
if columns.include?('title')
if dmsf_columns.include?('title')
pos += 1
return pos if column == 'title'
else
return nil if column == 'title'
end
# 3 - extension
if columns.include?('extension')
if dmsf_columns.include?('extension')
pos += 1
return pos if column == 'extension'
else
return nil if column == 'extension'
end
# 4 - size
if columns.include?('size')
if dmsf_columns.include?('size')
pos += 1
return pos if column == 'size'
else
return nil if column == 'size'
end
# 5 - modified
if columns.include?('modified')
if dmsf_columns.include?('modified')
pos += 1
return pos if column == 'modified'
else
return nil if column == 'modified'
end
# 6 - version
if columns.include?('version')
if dmsf_columns.include?('version')
pos += 1
return pos if column == 'version'
else
return nil if column == 'version'
end
# 7 - workflow
if columns.include?('workflow')
if dmsf_columns.include?('workflow')
pos += 1
return pos if column == 'workflow'
else
return nil if column == 'workflow'
end
# 8 - author
if columns.include?('author')
if dmsf_columns.include?('author')
pos += 1
return pos if column == 'author'
else
@ -399,22 +453,22 @@ class DmsfFolder < ActiveRecord::Base
end
def save(*args)
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
super(*args)
end
def save!(*args)
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
super(*args)
end
def destroy
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
super
end
def destroy!
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
RedmineDmsf::Webdav::Cache.invalidate_item(propfind_cache_key)
super
end
@ -450,6 +504,8 @@ class DmsfFolder < ActiveRecord::Base
csv << '' if columns.include?('workflow')
# Author
csv << self.user.name if columns.include?('author')
# Last approver
csv << '' if columns.include?(l(:label_last_approver))
# Url
if columns.include?(l(:label_document_url))
default_url_options[:host] = Setting.host_name
@ -465,10 +521,66 @@ class DmsfFolder < ActiveRecord::Base
csv
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
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
tree.push(["#{'...' * level}#{subfolder.title}", subfolder.id])
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
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
def target_file_id
@ -70,15 +75,28 @@ class DmsfLink < ActiveRecord::Base
end
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
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
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
def title
@ -110,20 +128,29 @@ class DmsfLink < ActiveRecord::Base
end
def copy_to(project, folder)
link = DmsfLink.new(
:target_project_id => self.target_project_id,
:target_id => self.target_id,
:target_type => self.target_type,
:name => self.name,
:external_url => self.external_url,
:project_id => project.id,
:dmsf_folder_id => folder ? folder.id : nil)
link = DmsfLink.new
link.target_project_id = self.target_project_id
link.target_id = self.target_id
link.target_type = self.target_type
link.name = self.name
link.external_url = self.external_url
link.project_id = project.id
link.dmsf_folder_id = folder ? folder.id : nil
link.save
link
end
def container
if self.folder && self.folder.system
Issue.where(:id => self.folder.title.to_i).first
end
end
def delete(commit = false)
if commit
if self.container.is_a?(Issue)
self.container.dmsf_file_removed(self.target_file)
end
self.destroy
else
self.deleted = STATUS_DELETED
@ -171,6 +198,8 @@ class DmsfLink < ActiveRecord::Base
csv << '' if columns.include?('workflow')
# Author
csv << self.user.name if columns.include?('author')
# Last approver
csv << '' if columns.include?(l(:label_last_approver))
# Url
csv << self.external_url if columns.include?(l(:label_document_url))
# Revision

View File

@ -51,7 +51,6 @@ class DmsfMailer < Mailer
end
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
@body = email_params[:body]
@links_only = email_params[:links_only] == '1'
@ -61,6 +60,7 @@ class DmsfMailer < Mailer
@files = email_params[:files]
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 }
end
mail :to => email_params[:to], :cc => email_params[:cc],
@ -87,6 +87,7 @@ class DmsfMailer < Mailer
end
def self.get_notify_users(project, files = [])
return [] unless project.active?
if files.present?
notify_files = files.select { |file| file.notify? }
return [] if notify_files.empty?

View File

@ -33,6 +33,7 @@ class DmsfUpload
attr_accessor :locked
attr_accessor :workflow
attr_accessor :custom_values
attr_accessor :tempfile_path
def disk_file
"#{DmsfHelper.temp_dir}/#{self.disk_filename}"
@ -45,15 +46,14 @@ class DmsfUpload
:disk_filename => DmsfHelper.temp_filename(a.filename),
:content_type => a.content_type,
: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]}")
a.destroy
upload = DmsfUpload.new(project, folder, uploaded)
DmsfUpload.new(project, folder, uploaded)
else
Rails.logger.error "An attachment not found by its token: #{uploaded_file[:token]}"
nil
end
upload
end
def initialize(project, folder, uploaded)
@ -67,7 +67,8 @@ class DmsfUpload
@disk_filename = uploaded[:disk_filename]
@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?
@title = DmsfFileRevision.filename_to_title(@name)
@ -76,8 +77,7 @@ class DmsfUpload
@minor_version = 0
@workflow = nil
file = DmsfFile.new
file.container_type = 'Project'
file.container_id = project.id
file.project_id = project.id
revision = DmsfFileRevision.new
revision.dmsf_file = file
@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
belongs_to :author, :class_name => 'User'
scope :sorted, lambda { order('name ASC') }
scope :global, lambda { where('project_id IS NULL') }
scope :sorted, lambda { order(:name => :asc) }
scope :global, lambda { where(:project_id => nil) }
scope :active, lambda { where(:status => STATUS_ACTIVE) }
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)
if dmsf_workflow_step_assignment_id && dmsf_file_revision_id
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 = ?)',
dmsf_workflow_step_assignment_id, dmsf_file_revision_id, 'Project']
'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]
elsif project
sql = ['id IN (SELECT user_id FROM members WHERE project_id = ?)', project.id]
else
@ -167,19 +167,6 @@ class DmsfWorkflow < ActiveRecord::Base
results
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)
dmsf_workflow_steps.each do |ws|
ws.assign(dmsf_file_revision_id)
@ -230,4 +217,27 @@ class DmsfWorkflow < ActiveRecord::Base
self.status == STATUS_ACTIVE
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

View File

@ -21,6 +21,7 @@
class DmsfWorkflowStepAction < ActiveRecord::Base
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 :action, :presence => true

View File

@ -19,15 +19,18 @@
#
# 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.%>
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<% if object %>
<div>
<% object.show_custom_field_values.each do |custom_value| %>
<p>
<%= label_tag('', h(custom_value.custom_field.name)) %>
<%= show_value custom_value %>
</p>
<div class="status attribute">
<%= content_tag :div, h(custom_value.custom_field.name), :class => 'label' %>
<div class="value">
<%= show_value custom_value %>
</div>
</div>
<% end %>
</div>
<% end %>

View File

@ -20,13 +20,23 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<% locked_for_user = subfolder && subfolder.locked_for_user? %>
<% locked = subfolder && subfolder.locked? %>
<td class="dmsf_checkbox"><%= check_box_tag(name, id, false,
:title => l(:title_check_for_zip_download_or_email), :id => "subfolder_#{id}") %></td>
<td class="dmsf_checkbox">
<% unless (subfolder && subfolder.system) %>
<%= check_box_tag(name, id, false, :title => l(:title_check_for_zip_download_or_email), :id => "subfolder_#{id}") %>
<% end %>
</td>
<% 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 %>
<% if DmsfFolder.is_column_on?('title') %>
<td class="dmsf_title">
@ -51,21 +61,7 @@
<td class="dmsf_size"></td>
<% end %>
<% if DmsfFolder.is_column_on?('modified') %>
<td class="dmsf_modified"><%= format_time(subfolder.modified) if subfolder %>
<% 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>
<td class="dmsf_modified"><%= format_time(subfolder.modified) if subfolder %></td>
<% end %>
<% if DmsfFolder.is_column_on?('version') %>
<td class="dmsf_version"></td>
@ -85,60 +81,51 @@
<% end %>
<% end %>
<td class="dmsf_buttons">
<% if @folder_manipulation_allowed %>
<% unless locked_for_user %>
<% if subfolder %>
<%= link_to(image_tag('edit.png'),
edit_dmsf_path(:id => project, :folder_id => subfolder),
:title => l(:link_edit, :title => subfolder ? h(subfolder.title) : project.name)) %>
<% if locked %>
<% 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 %>
<% if @folder_manipulation_allowed && !(subfolder && subfolder.system) %>
<% if subfolder && subfolder.locked? %>
<span class="icon-only"></span>
<% if subfolder.unlockable? && (!subfolder.locked_for_user? || @force_file_unlock_allowed) %>
<%= link_to('', unlock_dmsf_path(:id => project, :folder_id => subfolder),
:title => subfolder.get_locked_title,
:class => 'icon-only icon-unlock') %>
<% else %>
<%= link_to(image_tag('edit.png'), edit_root_dmsf_path(:id => @project),
: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)) %>
<span class="icon-only icon-unlock" title="<%= subfolder.get_locked_title %>"></span>
<% end %>
<% else %>
<span class="icon"></span>
<% if (!locked_for_user || @force_file_unlock_allowed) && subfolder.unlockable? %>
<%= link_to(image_tag('unlock.png', :plugin => 'redmine_dmsf'),
unlock_dmsf_path(:id => project, :folder_id => subfolder),
:title => l(:title_unlock_file)) %>
<% if subfolder %>
<%= link_to('', edit_dmsf_path(:id => project, :folder_id => subfolder),
:title => l(:link_edit, :title => h(subfolder.title)),
:class => 'icon-only icon-edit') %>
<% else %>
<%= link_to('', edit_root_dmsf_path(:id => @project),
:title => l(:link_edit, :title => l(:link_documents)),
:class => 'icon-only icon-edit') %>
<% 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 %>
</td>
<td id="dmsf_position" class="dmsf_invisible"><%= position %></td>
<td class="dmsf_invisible">0</td>
<td class="dmsf_invisible"><%= subfolder.modified.to_i if subfolder %></td>
<td class="dmsf_invisible">0</td>
<td id="dmsf_position" class="hol"><%= position %></td>
<td class="hol">0</td>
<td class="hol"><%= subfolder.modified.to_i if subfolder %></td>
<td class="hol">0</td>

View File

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

View File

@ -1,9 +1,6 @@
<% parent = @folder ? @folder : @project %>
<% @idnt = 0 unless @idnt %>
<% @pos = 0.0 unless @pos %>
<% DmsfHelper.all_children_sorted(parent, @pos, @idnt).each do |obj, position| %>
<% 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)) %>
<% classes += ' idnt dmsf_collapsed dmsf-not-loaded' %>
<% id = "id='#{obj.id}span'".html_safe %>
@ -19,6 +16,8 @@
<% end %>
<% 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 %>">
<%= render(:partial => 'dir',
:locals => {

View File

@ -20,7 +20,7 @@
# 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,
:title => l(:title_check_for_zip_download_or_email), :id => "file_#{id}") %></td>
@ -53,19 +53,6 @@
<% if DmsfFolder.is_column_on?('modified') %>
<td class="dmsf_modified">
<%= 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>
<% end %>
<% if DmsfFolder.is_column_on?('version') %>
@ -80,7 +67,7 @@
:project_id => project.id,
:id => wf.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) %>
<% else %>
<%= file.last_revision.workflow_str(false) %>
@ -100,112 +87,57 @@
<% end %>
<td class="dmsf_buttons">
<% if @file_manipulation_allowed %>
<%= link_to(image_tag('filedetails.png', :plugin => 'redmine_dmsf'),
dmsf_file_path(:id => file),
:title => l(:link_details, :title => h(file.last_revision.title))) %>
<% unless file.locked_for_user? %>
<% if !file.locked? %>
<%= link_to(image_tag('lock.png', :plugin => 'redmine_dmsf'),
lock_dmsf_files_path(:id => file),
:title => l(:title_lock_file)) %>
<% elsif file.unlockable? %>
<%= link_to(image_tag('unlock.png', :plugin => 'redmine_dmsf'),
unlock_dmsf_files_path(:id => file),
:title => l(:title_unlock_file))%>
<% else %>
<span class="icon"></span>
<% end %>
<%= link_to('', dmsf_file_path(:id => file),
:title => l(:link_details, :title => h(file.last_revision.title)),
:class => 'icon-only icon-edit') %>
<% if !file.locked? %>
<%= link_to('', lock_dmsf_files_path(:id => file),
:title => l(:title_lock_file),
:class => 'icon-only icon-lock') %>
<% elsif file.unlockable? && (!file.locked_for_user? || @force_file_unlock_allowed) %>
<%= link_to('', unlock_dmsf_files_path(:id => file),
:title => file.get_locked_title,
:class => 'icon-only icon-unlock') %>
<% else %>
<span class="icon-only icon-unlock" title="<%= file.get_locked_title %>"></span>
<% end %>
<% unless file.locked? %>
<% if file.notification %>
<%= link_to(image_tag('notify.png', :plugin => 'redmine_dmsf'),
notify_deactivate_dmsf_files_path(:id => file),
:title => l(:title_notifications_active_deactivate)) %>
<%= link_to('', notify_deactivate_dmsf_files_path(:id => file),
:title => l(:title_notifications_active_deactivate),
:class => 'icon-only icon-email') %>
<% else %>
<%= link_to(image_tag('notifynot.png', :plugin => 'redmine_dmsf'),
notify_activate_dmsf_files_path(:id => file),
:title => l(:title_notifications_not_active_activate)) %>
<%= link_to('', notify_activate_dmsf_files_path(:id => file),
:title => l(:title_notifications_not_active_activate),
:class => 'icon-only icon-email-add') %>
<% 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)) %>
<%= link_to('', dmsf_link_path(link),
:data => {:confirm => l(:text_are_you_sure)},
:title => l(:title_delete),
:method => :delete,
:class => 'icon-only icon-del') %>
<% else %>
<% if @file_delete_allowed %>
<%= link_to(image_tag('delete.png'),
dmsf_file_path(:id => file),
<%= link_to('', dmsf_file_path(:id => file),
:data => {:confirm => l(:text_are_you_sure)},
:title => l(:title_delete),
:method => :delete,
:title => l(:title_delete)) unless file.locked_for_user? %>
:class => 'icon-only icon-del') %>
<% else %>
<span class="icon"></span>
<span class="icon-only"></span>
<% end %>
<% end %>
<% else %>
<% if @force_file_unlock_allowed && file.unlockable? %>
<%= link_to(image_tag('unlock.png', :plugin => 'redmine_dmsf'),
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 %>
<span class="icon-only"></span>
<span class="icon-only"></span>
<% 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 class="dmsf_invisible"><%= position %></td>
<td class="dmsf_invisible"><%= file.last_revision.size %></td>
<td class="dmsf_invisible"><%= file.last_revision.updated_at.to_i %></td>
<td class="dmsf_invisible"><%= file.last_revision.iversion %></td>
<td class="hol"><%= position %></td>
<td class="hol"><%= file.last_revision.size %></td>
<td class="hol"><%= file.last_revision.updated_at.to_i %></td>
<td class="hol"><%= file.last_revision.iversion %></td>

View File

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

View File

@ -57,15 +57,15 @@
<% end %>
<% end %>
<th class ="dmsf_th"><%# controls %></th>
<th class="dmsf_invisible"><%# position %></th>
<th class="dmsf_invisible"><%# size %></th>
<th class="dmsf_invisible"><%# updated %></th>
<th class="dmsf_invisible"><%# version %></th>
<th class="hol"><%# position %></th>
<th class="hol"><%# size %></th>
<th class="hol"><%# updated %></th>
<th class="hol"><%# version %></th>
</tr>
</thead>
<tbody>
<% @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',
:locals => {
:project => @project,

View File

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

View File

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

View File

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

View File

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

View File

@ -25,42 +25,38 @@
<% html_title(l(:dmsf)) %>
<div class="contextual">
<% if !@folder.new_record? && User.current.allowed_to?(:folder_manipulation, @project) %>
<% if !@folder.locked_for_user? %>
<% unless @folder.locked? %>
<%= link_to(l(:button_lock),
lock_dmsf_path(:id => @project, :folder_id => @folder),
:title => l(:title_lock_file), :class => 'icon dmsf_icon-lock') %>
<% 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),
<% if !@folder.new_record? && User.current.allowed_to?(:folder_manipulation, @project) && !@folder.system %>
<% unless @folder.locked? %>
<%= link_to(l(:button_lock), lock_dmsf_path(:id => @project, :folder_id => @folder),
:title => l(:title_lock_file), :class => 'icon icon-lock') %>
<% else %>
<%= link_to_if(@folder.unlockable? && (!@folder.locked_for_user? || @force_file_unlock_allowed), l(:button_unlock),
unlock_dmsf_path(:id => @project, :folder_id => @folder),
:title => l(:title_unlock_file), :class => 'icon dmsf_icon-unlock')%>
<% end %>
:title => l(:title_unlock_file), :class => 'icon icon-unlock')%>
<% 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 %>
</div>
@ -85,7 +81,28 @@
<p>
<%= f.text_area :description, :rows => 8, :class => 'wiki-edit' %>
</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| %>
<p><%= custom_field_tag_with_label(:dmsf_folder, value) %></p>
<% end %>
@ -97,4 +114,4 @@
<script type="text/javascript">
$('#dmsf_folder_dmsf_folder_id').select2();
</script>
</script>

View File

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

View File

@ -1,78 +1,79 @@
<%
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright (C) 2012 Daniel Munn <dan.munn@munnster.co.uk>
# 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.
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright (C) 2012 Daniel Munn <dan.munn@munnster.co.uk>
# 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.
%>
<% html_title l(:dmsf) %>
<div class="contextual">
<% if @folder_manipulation_allowed %>
<% if @folder.nil? %>
<%= link_to(l(:button_edit), edit_root_dmsf_path(:id => @project),
:title => l(:link_edit, :title => l(:link_documents)),
:class => 'icon icon-edit') %>
<% elsif !@locked_for_user %>
<%= link_to(l(:button_edit),
edit_dmsf_path(:id => @project, :folder_id => @folder),
:title => l(:link_edit, :title => h(@folder.title)),
: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') %>
<% if @folder_manipulation_allowed && !@system_folder %>
<% if @folder.nil? %>
<%= link_to(l(:button_edit), edit_root_dmsf_path(:id => @project),
:title => l(:link_edit, :title => l(:link_documents)),
:class => 'icon icon-edit') %>
<% elsif !@locked_for_user %>
<%= link_to(l(:button_edit),
edit_dmsf_path(:id => @project, :folder_id => @folder),
:title => l(:link_edit, :title => h(@folder.title)),
:class => 'icon icon-edit') %>
<% end %>
<% end %>
<% if !@locked_for_user && ((@folder && @folder.notification) || (!@folder && @project.dmsf_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 %>
<% 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 dmsf_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 %>
<% 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 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 icon-lock') %>
<% end %>
<% end %>
<% if !@locked_for_user && ((@folder && @folder.notification) || (!@folder && @project.dmsf_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 %>
<% 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 %>
<%= 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>
<%= render(:partial => 'path',
:locals => {:folder => @folder, :filename => nil, :title => nil}) %>
:locals => {:folder => @folder, :filename => nil, :title => nil}) %>
<div class="dmsf-header">
<div class="wiki">
@ -82,134 +83,145 @@
<%= error_messages_for('dmsf_workflow') %>
<%= form_tag({:action => :entries_operation, :id => @project, :folder_id => @folder}, :method => :post,
:class => 'dmsf_entries', :id => 'entries_form') do %>
<%= hidden_field_tag('action') %>
<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(: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%>
<%= submit_tag(l(:button_delete), :title => l(:title_delete_checked), :name => 'delete_entries') if @file_delete_allowed %>
<% 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])) %>
<%= form_tag(entries_operations_dmsf_path(:id => @project, :folder_id => @folder), :method => :post,
:class => 'dmsf_entries', :id => 'entries_form') do %>
<%= hidden_field_tag('action') %>
<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(: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%>
<%= submit_tag(l(:button_delete), :title => l(:title_delete_checked), :name => 'delete_entries') if @file_delete_allowed %>
<% end %>
</div>
<% end %>
<div class="autoscroll">
<% if @tree_view %>
<%= render(:partial => 'tree_view') %>
<% else %>
<%= render(:partial => 'list_view') %>
<% unless @system_folder %>
<% values = @folder ? @folder.custom_field_values : DmsfFolder.new.custom_field_values %>
<% unless values.empty? %>
<div id="dmsf_tag" class="dmsf_controls" style="float: right">
<% custom_value = values.first %>
<% 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 %>
</div>
<div class="autoscroll">
<% if @tree_view %>
<%= render(:partial => 'tree_view') %>
<% else %>
<%= render(:partial => 'list_view') %>
<% end %>
</div>
<% end %>
<script type="text/javascript">
$('#entries_delete_button').click(function() {
if(window.confirm("<%= l(:text_are_you_sure) %>")) {
$('#entries_form').attr('action', "<%= delete_entries_path(:id => @project, :folder_id => @folder) %>");
$('#entries_form').submit();
}
});
$('#entries_delete_button').click(function() {
if(window.confirm("<%= l(:text_are_you_sure) %>")) {
$('#entries_form').attr('action', "<%= delete_entries_path(:id => @project, :folder_id => @folder) %>");
$('#entries_form').submit();
}
});
$('.list_cf').change(function() {
$('#entries_form').attr('action', "<%= tag_changed_path(:id => @project, :folder_id => @folder) %>");
$('#entries_form').submit();
});
$('.list_cf').change(function() {
$('#entries_form').attr('action', "<%= tag_changed_path(:id => @project, :folder_id => @folder) %>");
$('#entries_form').submit();
});
$('#check_all_entries').click(function() {
$('input[type=checkbox]', $('#browser > tbody')).prop('checked', this.checked);
});
$('#check_all_entries').click(function() {
$('input[type=checkbox]', $('#browser > tbody')).prop('checked', this.checked);
});
</script>
<% content_for :header_tags do %>
<%= javascript_include_tag 'bowser.min.js', :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 'bowser.min.js', :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' %>
<% title = DmsfFolder.get_column_position('title') %>
<% position = DmsfFolder.get_column_position('position') %>
<% commands = DmsfFolder.get_column_position('commands') %>
<% position = DmsfFolder.get_column_position('position') %>
<% version = DmsfFolder.get_column_position('version') %>
<% size_calculated = DmsfFolder.get_column_position('size_calculated') %>
<% modified_calculated = DmsfFolder.get_column_position('modified_calculated') %>
<% version_calculated = DmsfFolder.get_column_position('version_calculated') %>
<% size = DmsfFolder.get_column_position('size') %>
<% modified = DmsfFolder.get_column_position('modified') %>
<% title = DmsfFolder.get_column_position('title') %>
<% position = DmsfFolder.get_column_position('position') %>
<% commands = DmsfFolder.get_column_position('commands') %>
<% position = DmsfFolder.get_column_position('position') %>
<% version = DmsfFolder.get_column_position('version') %>
<% size_calculated = DmsfFolder.get_column_position('size_calculated') %>
<% modified_calculated = DmsfFolder.get_column_position('modified_calculated') %>
<% version_calculated = DmsfFolder.get_column_position('version_calculated') %>
<% size = DmsfFolder.get_column_position('size') %>
<% modified = DmsfFolder.get_column_position('modified') %>
<script type="text/javascript">
$(document).ready(function() {
$('#browser').dataTable({
'bJQueryUI': true,
'oLanguage': {
'sUrl': "<%= plugin_asset_path(:redmine_dmsf, 'javascripts', json_url) %>"
},
'bAutoWidth': false,
'bPaginate': false,
<% if title %>
'aaSorting': [[<%= title %>, 'asc']],
<% end %>
'aaSortingFixed': [[ <%= position %>, 'asc']],
'aoColumnDefs': [
{ 'bSearchable': false, 'aTargets': [0, <%= commands %>, <%= position %>, <%= size_calculated %>, <%= modified_calculated %>, <%= version_calculated %>] },
{ 'bSortable': false, 'aTargets': [0, <%= commands %>] }
<% if size %>
,{ 'iDataSort': <%= size_calculated %>, 'aTargets': [ <%= size %> ] }
<% end %>
<% if modified %>
,{ 'iDataSort': <%= modified_calculated %>, 'aTargets': [ <%= modified %> ] }
<% end %>
<% if version %>
,{ 'iDataSort': <%= version_calculated %>, 'aTargets': [ <%= version %> ] }
<% end %>
],
'fnInitComplete': function() {
$('#dmsf_buttons').prependTo($('#browser_wrapper div.fg-toolbar')[0]);
$('#dmsf_tag').prependTo($('#browser_wrapper div.fg-toolbar')[0]);
},
'fnInfoCallback': function( oSettings, iStart, iEnd, iMax, iTotal, sPre ) {
<% if @tree_view %>
<% if @folder %>
return "<%= "#{l(:label_number_of_folders)}: #{@folder.deep_folder_count} #{l(:label_number_of_documents)}: #{@folder.deep_file_count}" %>";
<% 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}" %>";
<% end %>
<% 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}" %>";
<% end %>
}
});
<script type="text/javascript">
$(document).ready(function() {
$('#browser').dataTable({
'bJQueryUI': true,
'oLanguage': {
'sUrl': "<%= plugin_asset_path(:redmine_dmsf, 'javascripts', json_url) %>"
},
'bAutoWidth': false,
'bPaginate': false,
<% if title %>
'aaSorting': [[<%= title %>, 'asc']],
<% end %>
'aaSortingFixed': [[ <%= position %>, 'asc']],
'aoColumnDefs': [
{ 'bSearchable': false, 'aTargets': [0, <%= commands %>, <%= position %>, <%= size_calculated %>, <%= modified_calculated %>, <%= version_calculated %>] },
{ 'bSortable': false, 'aTargets': [0, <%= commands %>] }
<% if size %>
,{ 'iDataSort': <%= size_calculated %>, 'aTargets': [ <%= size %> ] }
<% end %>
<% if modified %>
,{ 'iDataSort': <%= modified_calculated %>, 'aTargets': [ <%= modified %> ] }
<% end %>
<% if version %>
,{ 'iDataSort': <%= version_calculated %>, 'aTargets': [ <%= version %> ] }
<% end %>
],
'fnInitComplete': function() {
$('#dmsf_buttons').prependTo($('#browser_wrapper div.fg-toolbar')[0]);
$('#dmsf_tag').prependTo($('#browser_wrapper div.fg-toolbar')[0]);
},
'fnInfoCallback': function( oSettings, iStart, iEnd, iMax, iTotal, sPre ) {
<% if @tree_view %>
<% if @folder %>
return "<%= "#{l(:label_number_of_folders)}: #{@folder.deep_folder_count} #{l(:label_number_of_documents)}: #{@folder.deep_file_count}" %>";
<% 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(:project_id => @project.id).count + DmsfLink.visible.where(:project_id => @project.id, :target_type => ['DmsfFile', 'DmsfUrl']).count}" %>";
<% end %>
<% 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}" %>";
<% end %>
}
});
$('[data-downloadurl]').each(function() {
var url = this.getAttribute('data-downloadurl');
if (this.addEventListener) {
this.addEventListener('dragstart', function(e) {
if (e.dataTransfer) {
e.dataTransfer.setData('DownloadURL', url);
}
},false);
}
});
$('[data-downloadurl]').each(function() {
var url = this.getAttribute('data-downloadurl');
if (this.addEventListener) {
this.addEventListener('dragstart', function(e) {
if (e.dataTransfer) {
e.dataTransfer.setData('DownloadURL', url);
}
},false);
}
});
$('#entries_form').submit(function () {
$(this).removeAttr('data-submitted');
});
});
</script>
$('#entries_form').submit(function () {
$(this).removeAttr('data-submitted');
});
});
</script>
<% end %>
<% if (@file_manipulation_allowed && !@locked_for_user) %>
<%= render(:partial => 'dmsf_upload/multi_upload') %>
<% if (@file_manipulation_allowed && !@locked_for_user && !@system_folder) %>
<%= render(:partial => 'dmsf_upload/multi_upload', :local => { :lbl => true }) %>
<% end %>
<% other_formats_links do |f| %>
<%= f.link_to 'CSV', :url => params, :onclick => "showModal('csv-export-options', '350px'); return false;" %>
<% unless @system_folder %>
<% other_formats_links do |f| %>
<%= f.link_to 'CSV', :url => params, :onclick => "showModal('csv-export-options', '350px'); return false;" %>
<% end %>
<% end %>
<div id="csv-export-options" style="display:none;">
@ -218,7 +230,7 @@
<%= hidden_field_tag(:folder_id, @folder.id) if @folder %>
<div class="tabular">
<%= 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>
<p class="buttons">
<%= submit_tag l(:button_export), :name => nil, :onclick => "hideModal(this);" %>

View File

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

View File

@ -78,11 +78,12 @@
<div class="box">
<p>
<%= 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>
</div>
<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>
<%= f.submit l(:submit_create) %>
<% 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.
%>
<% if dmsf_files.present? %>
<% if links.present? %>
<hr/>
<div class="attachments">
<% for dmsf_file in dmsf_files %>
<% if dmsf_file.last_revision %>
<p>
<% 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>
<% 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 %>
<strong><%= l(:menu_dmsf) %></strong>
<div class="attachments dmsf_parent_container">
<% # DMS documents & links %>
<% links.each do |dmsf_file, link, create_at| %>
<%= render :partial => 'dmsf_files/link', :locals => { :dmsf_file => dmsf_file, :link => link } %>
<% end %>
<%= render :partial => 'dmsf_files/thumbnails', :locals => { :links => links, :thumbnails => thumbnails, :link_to => true } %>
</div>
<% 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.id @file.id
api.name @file.name
api.container_id @file.container_id
api.container_type @file.container_type
api.dmsf_folder_id @file.folder if @file.dmsf_folder_id
api.version "#{@file.last_revision.major_version}.#{@file.last_revision.minor_version}" if @file.last_revision
api.project_id @file.project_id
api.dmsf_folder_id @file.dmsf_folder_id if @file.dmsf_folder_id
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)
end

View File

@ -29,33 +29,33 @@
<% unless @file.locked_for_user? %>
<% unless @file.locked? %>
<%= 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 %>
<%= 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 %>
<% if @file.notification %>
<%= link_to(l(:label_notifications_off),
notify_deactivate_dmsf_files_path(:id => @file),
:title => l(:title_notifications_active_deactivate),
:class => 'icon dmsf_icon-notification-on') %>
:class => 'icon icon-email') %>
<% else %>
<%= link_to(l(:label_notifications_on),
notify_activate_dmsf_files_path(:id => @file),
:title => l(:title_notifications_not_active_activate),
:class => 'icon dmsf_icon-notification-off') %>
:class => 'icon icon-email-add') %>
<% end %>
<%= 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'),
: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),
:title => l(:title_copy), :class => 'icon icon-copy') %>
<%= delete_link(dmsf_file_path(:id => @file, :details => true)) if @file_delete_allowed %>
<% else %>
<% if User.current.allowed_to?(:force_file_unlock, @project) %>
<%= 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 %>
@ -81,13 +81,13 @@
<div class="fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix">
<div class="dataTables_lenght">
<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()",
: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),
: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),
:data => {:confirm => l(:text_are_you_sure)},
: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="splitcontent">
<div class="splitcontentleft">
<p>
<%= label_tag('', l(:label_title)) %>
<%= h(revision.title) %>
</p>
<div class="status attribute">
<%= content_tag :div, l(:label_title), :class => 'label' %>
<%= content_tag :div, h(revision.title), :class => 'value' %>
</div>
<% if revision.description.present? %>
<p>
<%= label_tag('', l(:label_description)) %>
<div class="wiki">
<%= textilizable(revision.description) %>
</div>
</p>
<div class="status attribute">
<%= content_tag :div, l(:label_description), :class => 'label' %>
<% text = textilizable(revision.description) %>
<% if text =~ /^<p>(.*)<\/p>$/ %>
<% text = $1 %>
<% end %>
<%= content_tag :div, text.html_safe, :class => 'value wiki' %>
</div>
<% end %>
<p>
<%= label_tag('', l(:label_dmsf_version)) %>
<%= revision.major_version %>.<%= revision.minor_version %>
</p>
<p>
<%= label_tag('', l(:label_size)) %>
<%= number_to_human_size(revision.size) %>
</p>
<div class="status attribute">
<%= content_tag :div, l(:label_dmsf_version), :class => 'label' %>
<%= content_tag :div, "#{revision.major_version}.#{revision.minor_version}", :class => 'value' %>
</div>
<div class="status attribute">
<%= content_tag :div, l(:label_size), :class => 'label' %>
<%= content_tag :div, number_to_human_size(revision.size), :class => 'value' %>
</div>
<% wf = DmsfWorkflow.find_by_id(revision.dmsf_workflow_id) %>
<% if wf %>
<p>
<%= label_tag('', l(:link_workflow)) %>
<%= "#{wf.name} - " %>
<%= link_to(revision.workflow_str(false),
log_dmsf_workflow_path(:project_id => @project.id,
:id => wf.id, :dmsf_file_revision_id => revision.id),
:title => DmsfWorkflow.assignments_to_users_str(wf.next_assignments(revision.id)),
:remote => true) %>
</p>
<div class="status attribute">
<%= content_tag :div, l(:label_workflow), :class => 'label' %>
<div class="value">
<%= "#{wf.name} - " %>
<%= link_to(revision.workflow_str(false),
log_dmsf_workflow_path(:project_id => @project.id,
:id => wf.id, :dmsf_file_revision_id => revision.id),
:title => revision.workflow_tooltip,
:remote => true) %>
</div>
</div>
<% end %>
<% if revision.comment.present? %>
<p>
<%= label_tag('', l(:label_comment)) %>
<div class="wiki">
<%= textilizable(revision.comment) %>
</div>
</p>
<div class="status attribute">
<%= content_tag :div, l(:label_comment), :class => 'label' %>
<% text = textilizable(revision.comment) %>
<% if text =~ /^<p>(.*)<\/p>$/ %>
<% text = $1 %>
<% end %>
<%= content_tag :div, text.html_safe, :class => 'value wiki' %>
</div>
<% end %>
</div>
<div class="splitcontentright">
<p>
<%= label_tag('', l(:label_file)) %>
<%= (h("#{revision.dmsf_file.dmsf_folder.dmsf_path_str}/")) if revision.dmsf_file.dmsf_folder %><%= h(revision.name) %>
</p>
<p>
<%= label_tag('', l(:label_mime)) %>
<%= h(revision.mime_type) %>
</p>
<div class="status attribute">
<%= content_tag :div, l(:label_file), :class => 'label' %>
<div class="value">
<% path = "#{revision.dmsf_file.dmsf_folder.dmsf_path_str}/" if revision.dmsf_file.dmsf_folder %>
<%= h("#{path}#{revision.name}") %>
</div>
</div>
<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? %>
<p>
<%= label_tag('', 'MD5') %>
<%= revision.digest %>
</p>
<div class="status attribute">
<%= content_tag :div, 'MD5', :class => 'label' %>
<%= content_tag :div, revision.digest, :class => 'value wiki' %>
</div>
<% end %>
<%= render 'dmsf/custom_fields', :object => revision %>
</div>

View File

@ -46,7 +46,7 @@
</div>
<p>
<%= 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') %>
<% end %>
</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.
%>
<% html_title l(:dmsf) %>
<h3 class="title"><%= l(:title_create_link) %></h3>
<% if @dmsf_file_id %>
<% 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| %>
<%= labelled_form_for @dmsf_link, :remote => modal do |f| %>
<%= error_messages_for @dmsf_link %>
<%= 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 :type, :value => @type %>
<%= f.hidden_field :dmsf_file_id, :value => @dmsf_file_id %>
<%= f.hidden_field(:container, :value => @container) if @container %>
<div class="box tabular">
<% if @type == 'link_from' %>
<% if (@type == 'link_from') && !@container %>
<p>
<%= radio_button_tag(:external_link, 'false', @link_external == false) %> <%= l(:label_internal) %><br/>
<%= radio_button_tag(:external_link, 'true', @link_external) %> <%= l(:label_external) %>
<%= radio_button_tag(:external_link, 'false', true) %> <%= l(:label_internal) %><br/>
<%= radio_button_tag(:external_link, 'true', false) %> <%= l(:label_external) %>
</p>
<% end %>
<div id="link_internal" style="<%= @link_external ? 'display:none' : '' %>">
<div id="link_internal">
<p>
<% 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 %>
<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 %>
<%= select_tag('dmsf_link[target_project_id]',
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>
<% if @type == 'link_from' %>
@ -64,52 +65,64 @@
<%= select_tag('dmsf_link[target_folder_id]',
folder_tree_options_for_select(DmsfFolder.directory_tree(@dmsf_link.target_project),
: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>
<% if @type == 'link_from' %>
<p>
<% if @target_folder_id %>
<% folder = DmsfFolder.find_by_id @target_folder_id %>
<% files = folder.dmsf_files.visible if folder %>
<% else %>
<% 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)) %>
<%= label_tag('dmsf_link[target_file_id]', l(:field_target_file)) %>
<% files = files_for_select(@dmsf_link.target_project.id, @target_folder_id) %>
<%= select_tag('dmsf_link[target_file_id]',
options_for_select(DmsfFolder.file_list(files)), :required => modal) %>
</p>
<% end %>
</div>
<div id="link_external" style="<%= @link_external ? '' : 'display:none' %>">
<p>
<%= f.text_field :external_url, :required => true,
:label => l(:label_link_external_url) %>
</p>
</div>
<% if (@type == 'link_from') && !@container %>
<div id="link_external" style="display: none">
<p>
<%= f.text_field :external_url, :required => true %>
</p>
</div>
<% end %>
<p>
<%= f.text_field :name, :required => true, :label => l(:label_link_name) %>
<%= f.text_field :name, :required => true %>
</p>
</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 %>
<script type="text/javascript">
$('#dmsf_link_target_project_id').change(function () {
$('#content').load("<%= url_for(:action => 'new', :project_id => @project.id, :reload => true) %>", $('#new_dmsf_link').serialize());
});
$('#dmsf_link_target_folder_id').change(function () {
$('#content').load("<%= url_for(:action => 'new', :project_id => @project.id) %>", $('#new_dmsf_link').serialize());
});
<%# Select2 extension, TODO: in case of a modal window, select2 makes problems %>
<% unless modal %>
$('#dmsf_link_target_project_id').select2();
$('#dmsf_link_target_folder_id').select2();
$('#dmsf_link_target_file_id').select2();
<% end %>
<%# Suggest a link name when a file is selected %>
$('#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(){
$("#link_internal").toggle();
$("#link_external").toggle();
});
$('#dmsf_link_target_project_id').select2();
$('#dmsf_link_target_folder_id').select2();
$('#dmsf_link_target_file_id').select2();
</script>
</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.
%>
<%= 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.
%>
<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) %>
<%= date_field_tag('email[expired_at]', '', :value => (DateTime.now + 3.days).to_date, :size => 10,
:readonly => true) + calendar_for('email_expired_at') %>

View File

@ -26,7 +26,7 @@
<%= form_tag(dmsf_user_pref_save_path(@project)) do %>
<fieldset class="box tabular">
<legend><%= l(:link_user_preferences) %></legend>
<legend><%= l(:link_user_preferences) %></legend>
<p>
<%= content_tag(:label, "#{l(:label_notifications)}:") %>
<%= select_tag(
@ -41,5 +41,19 @@
<em class="info"><%= l(:text_title_format) %></em>
</p>
</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)) %>
<% end %>

View File

@ -21,29 +21,79 @@
%>
<span id="dmsf_attachments_fields">
<% if defined?(container) && container && container.saved_attachments %>
<% container.saved_attachments.each_with_index do |attachment, i| %>
<span id="dmsf_attachments_p<%= i %>">
<%= text_field_tag("dmsf_attachments[p#{i}][filename]", attachment.filename, :class => 'filename') +
text_field_tag("dmsf_attachments[p#{i}][description]", attachment.description, :maxlength => 255, :placeholder => l(:label_optional_description), :class => 'description') +
link_to('&nbsp;'.html_safe, dmsf_attachment_path(attachment, :attachment_id => "p#{i}", :format => 'js'), :method => 'delete', :remote => true, :class => 'remove-upload') %>
<%= hidden_field_tag "dmsf_attachments[p#{i}][token]", "#{attachment.token}" %>
</span>
<% if defined?(container) && container && container.saved_dmsf_attachments.present? %>
<% container.saved_dmsf_attachments.each_with_index do |attachment, i| %>
<span id="dmsf_attachments_p<%= i %>", class="attachment">
<%= hidden_field_tag "dmsf_attachments[p#{i}][token]", "#{attachment.token}" %>
<%= text_field_tag("dmsf_attachments[p#{i}][filename]", attachment.filename, :class => 'filename') %>
<%= text_field_tag("dmsf_attachments[p#{i}][description]", attachment.description, :maxlength => 255,
:placeholder => l(:label_optional_description), :class => 'description') if description %>
<%= 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 %>
</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 %>
</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,
:class => 'file_selector',
:multiple => multiple,
:onchange => "dmsfAddInputFiles(this);",
:data => {
: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,
: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>

View File

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

View File

@ -1,47 +1,50 @@
<%
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright (C) 2012 Daniel Munn <dan.munn@munnster.co.uk>
# 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.
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright (C) 2012 Daniel Munn <dan.munn@munnster.co.uk>
# 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.
%>
<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}][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="splitcontentleft">
<p>
<%= 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>
</div>
<div class="splitcontentright">
<p>
<%= 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) %>
</p>
</div>
</div>
<p>
<%= label_tag("commited_files[#{i}][description]", l(:label_description)) %>
<%= text_area_tag("commited_files[#{i}][description]", upload.description, :rows => 6, :class => 'wiki-edit') %>
<%= label_tag("commited_files[#{i}][description]", l(:label_description)) %>
<%= text_area_tag("commited_files[#{i}][description]", upload.description, :rows => 6, :class => 'wiki-edit') %>
</p>
<div class="clear">
<div class="splitcontentright">
@ -55,32 +58,38 @@
<div class="splitcontentleft">
<p>
<%= 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 %>
<%= l(:option_version_minor) %><br/>
<%= radio_button_tag("commited_files[#{i}][version]", 2) %>
<%= upload.major_version + 1 %>.0
<%= radio_button_tag("commited_files[#{i}][version]", 2) %>
<%= upload.major_version + 1 %>.0
<%= l(:option_version_major) %><br/>
<%= 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_minor]", options_for_select(0..99, upload.minor_version + 1), :onchange => "$('#commited_files_#{i}_version_3').prop('checked', true)" %>
<%= l(:option_version_custom) %>
<%= 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)",
: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>
</div>
<div class="splitcontentright">
<p>
<%= label_tag('', l(:label_mime)) %>
<%= h(upload.mime_type) %>
<%= label_tag '', l(:label_mime) %>
<%= text_field_tag(:name, h(upload.mime_type), :readonly => true) %>
</p>
<p>
<%= label_tag('', l(:label_size)) %>
<%= number_to_human_size(upload.size) %>
<%= text_field_tag(:name, number_to_human_size(upload.size), :readonly => true) %>
</p>
</div>
</div>
</div>
<p>
<%= label_tag("commited_files[#{i}][comment]", l(:label_comment)) %>
<%= text_area_tag("commited_files[#{i}][comment]", upload.comment, :rows => 2) %>
<%= label_tag("commited_files[#{i}][comment]", l(:label_comment)) %>
<%= text_area_tag("commited_files[#{i}][comment]", upload.comment, :rows => 2, :class => 'wiki-edit') %>
</p>
</div>

View File

@ -1,52 +1,55 @@
<%
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright (C) 2012 Daniel Munn <dan.munn@munnster.co.uk>
# 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.
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright (C) 2012 Daniel Munn <dan.munn@munnster.co.uk>
# 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.
%>
<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}][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) %>
<p class="warning"><%= l(:info_file_locked) %></p>
<div class="clear">
<div class="splitcontentleft">
<p>
<%= label_tag('', l(:label_title)) %>
<%= h(upload.title) %>
<%= text_field_tag(:name, h(upload.title), :readonly => true) %>
</p>
</div>
<div class="splitcontentright">
<p>
<%= label_tag('', l(:label_filename)) %>
<%= h(upload.name) %>
<%= text_field_tag(:name, h(upload.name), :readonly => true) %>
</p>
</div>
</div>
<% if upload.description.present? %>
<p>
<%= label_tag('', l(:label_description)) %>
<p>
<%= label_tag('', l(:label_description)) %>
<div class="wiki">
<%= textilizable(upload.description) %>
</div>
</p>
</p>
<% end %>
<div class="clear">
<div class="splitcontentright">
@ -55,7 +58,7 @@
<p>
<%= label_tag('', h(value.custom_field.name)) %>
<% value.value = nil if value.custom_field.dmsf_not_inheritable %>
<%= h(value.value) %>
<%= text_field_tag(:name, h(value.value), :readonly => true) %>
</p>
<% end %>
</div>
@ -63,24 +66,24 @@
<div class="splitcontentleft">
<p>
<%= label_tag('', l(:label_dmsf_version)) %>
<%= upload.major_version %>.<%= upload.minor_version %>
</p>
<%= text_field_tag(:name, "#{upload.major_version}.#{upload.minor_version}", :readonly => true) %>
</p>
</div>
<div class="splitcontentright">
<p>
<%= label_tag('', l(:label_mime)) %>
<%= h(upload.mime_type) %>
<%= text_field_tag(:name, h(upload.mime_type), :readonly => true) %>
</p>
<p>
<%= 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>
</div>
</div>
</div>
</div>
<% if upload.comment.present? %>
<p>
<%= label_tag('', l(:label_comment)) %>
<div class="wiki"><%= textilizable(upload.comment) %></div>
</p>
<p>
<%= label_tag('', l(:label_comment)) %>
<div class="wiki"><%= textilizable(upload.comment) %></div>
</p>
<% end %>
</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(', ') %>");
<% else %>
$('<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({
"data-remote": true,
"data-method": 'delete',

View File

@ -19,8 +19,12 @@
#
# 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.%>
# 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 %>",
"disk_filename":"<%= (@disk_filename).html_safe %>"}
{
"original_filename":"<%= @tempfile.original_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 %>
<%= render(:partial => 'upload_file', :locals => {:upload => upload, :i => i}) %>
<% end %>
<% i += 1 %>
<% 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 %>

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
# 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>
<% remote = params[:dmsf_link_id] || params[:attachment_id] %>
<%= form_tag({:controller => 'dmsf_workflows', :action => 'assignment'},
:method => :post,
:id => 'assignment-form') do %>
:method => :post, :id => 'assignment-form', :remote => remote) do %>
<%= 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>
<%= label_tag('workflow', "#{l(:link_workflow)}:") %>
<%= select_tag(
'dmsf_workflow_id',
dmsf_workflows_for_select(@project, nil))%>
</p>
<% if User.current.allowed_to?(:manage_workflows, @project) %>
<% if (!remote) && User.current.allowed_to?(:manage_workflows, @project) %>
<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>
<% end %>
<p class="buttons">

View File

@ -82,7 +82,7 @@
<% result = DmsfWorkflowStep.connection.exec_query sql %>
<% last_step = 0 %>
<% 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>
<% last_step = row['step'] %>
<td class="name"><%= row['name'] %></td>

View File

@ -47,7 +47,7 @@
</tr></thead>
<tbody>
<% 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="buttons">
<%= change_status_link(workflow) unless @project %>

View File

@ -27,6 +27,6 @@
<p class="buttons">
<%= f.submit l(:dmsf_and), :id => 'add-step-and' %>
<%= 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>
<% end %>

View File

@ -51,26 +51,18 @@
</tr></thead>
<tbody>
<% steps.each do |i|%>
<tr id="step-<%= i %>" class="<%= cycle 'odd', 'even' %> step">
<td class="id"><%= i %></td>
<tr id="step-<%= i %>" class="step">
<% 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">
<span id="step-index-<%= index %>-name"><%= @dmsf_workflow.dmsf_workflow_steps[index].name if index %></span>
<%= form_for(@dmsf_workflow,
:url => update_step_dmsf_workflow_path(:step => index),
:method => :put,
: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 %>
<div id="<%= "step-index-#{index}-name-form" %>" class="hol">
<%= f.text_field(:name, :value => @dmsf_workflow.dmsf_workflow_steps[index].name) %>
</div>
</td>
<td>
<span id="step-index-<%= index %>-approvers">
@ -82,10 +74,7 @@
<%= link_to_user step.user %>
<% end %>
</span>
<%= form_for(@dmsf_workflow,
:url => update_step_dmsf_workflow_path(:step => index),
:method => :put,
:html => {:id => "step-index-#{index}-approvers-form", :class => 'hol'}) do |f| %>
<div id="<%= "step-index-#{index}-approvers-form" %>", class="hol">
<div class="dmsf_parent_container">
<% stps.each_with_index do |step, j| %>
<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();")
%>
</p>
<% end %>
</div>
<% end %>
</td>
<td class="buttons">
<%= 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) %>
</td>
</tr>
<% end; reset_cycle %>
<% end %>
</tbody>
</table>
<% 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
# 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
# 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%');
$('#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
# 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
# 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' %>

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

View File

@ -24,7 +24,7 @@
<% if @user %>
<% 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(
'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| %>
<% if assignment.dmsf_file_revision.dmsf_file.last_revision &&
!assignment.dmsf_file_revision.dmsf_file.last_revision.deleted? &&
@ -42,6 +42,7 @@
<tr>
<th><%= l(:field_project) %></th>
<th><%= l(:field_label_dmsf_workflow) %></th>
<th><%= l(:field_status) %></th>
<th><%= l(:label_document) %></th>
<th><%= l(:field_folder) %></th>
<th></th>
@ -49,7 +50,7 @@
</thead>
<tbody>
<% assignments.each do |assignment| %>
<tr id="assignment-<%= assignment.id %>" class="<%= cycle('odd', 'even') %>">
<tr id="assignment-<%= assignment.id %>">
<td class="project">
<% if 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)) %>
<% end %>
</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">
<% if assignment.dmsf_file_revision && assignment.dmsf_file_revision.dmsf_file %>
<%= link_to(h(assignment.dmsf_file_revision.title),
@ -71,27 +86,22 @@
<% if assignment.dmsf_file_revision %>
<% if assignment.dmsf_file_revision.dmsf_file.dmsf_folder %>
<%= 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 %>
<%= 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 %>
</td>
<td class="dmsf_buttons">
<% if assignment.dmsf_workflow_step.dmsf_workflow %>
<% assigns = assignment.dmsf_workflow_step.dmsf_workflow.next_assignments(assignment.dmsf_file_revision.id) %>
<% index = assigns.find_index{|assign| assign.user_id == User.current.id} if assigns %>
<% if index %>
<%= link_to(image_tag('waiting_for_approval.png', :plugin => 'redmine_dmsf'),
action_dmsf_workflow_path(
:project_id => assignment.dmsf_file_revision.dmsf_file.project.id,
: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 %>
<%= render(:partial => 'dmsf_workflows/approval_workflow_button',
:locals => {:file => assignment.dmsf_file_revision.dmsf_file,
:file_approval_allowed => User.current.allowed_to?(:file_approval,
assignment.dmsf_file_revision.dmsf_file.project),
:workflows_available => nil,
:project => assignment.dmsf_file_revision.dmsf_file.project,
:wf => assignment.dmsf_workflow_step.dmsf_workflow, :dmsf_link_id => nil }) %>
</td>
</tr>
<% 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 %>
<% cfs = CustomField.where(:type => 'DmsfFileRevisionCustomField').order(:position) %>
<% columns.concat(cfs.map{ |c| c.name }) %>
<% selected_columns = settings[:dmsf_columns] %>
<% selected_columns = DmsfFolder::DEFAULT_COLUMNS unless selected_columns %>
<% selected_columns = DmsfFolder::DEFAULT_COLUMNS if selected_columns.blank? %>
<% columns.each_with_index do |column, i| %>
<%= check_box_tag('settings[dmsf_columns][]', column, selected_columns.include?(column)) %>
<%= h column.capitalize %>

View File

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