Global DMS view #1217

This commit is contained in:
karel.picman@lbcfree.net 2021-03-03 10:44:24 +01:00
parent d044857cad
commit 61b4177559
18 changed files with 370 additions and 239 deletions

View File

@ -32,21 +32,28 @@ def dmsf_init
menu.push :dmsf_approvalworkflows, :dmsf_workflows_path, caption: :label_dmsf_workflow_plural,
html: { class: 'icon icon-workflows' }, if: Proc.new { |_| User.current.admin? }
end
# Project menu extension
Redmine::MenuManager.map :project_menu do |menu|
menu.push :dmsf, { controller: 'dmsf', action: 'show' }, caption: :menu_dmsf, before: :documents,
param: :id
end
# Main menu extension
Redmine::MenuManager.map :top_menu do |menu|
menu.push :dmsf, { controller: 'dmsf', action: 'index' }, caption: :menu_dmsf
end
# Permissions
#permission :view_dmsf_index, { dmsf: [:index] }
Redmine::AccessControl.map do |map|
#map.permission :view_dmsf_index, { dmsf: [:index] }, require: :loggedin
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: [:show, :index] },
read: true
pmap.permission :user_preferences,
{ dmsf_state: [:user_pref_save] }

View File

@ -23,7 +23,6 @@ class DmsfContextMenusController < ApplicationController
helper :context_menus
before_action :find_project
before_action :find_folder
before_action :find_dmsf_file
before_action :find_dmsf_folder
@ -31,12 +30,14 @@ class DmsfContextMenusController < ApplicationController
def dmsf
if @dmsf_file
@locked = @dmsf_file.locked?
@project = @dmsf_file.project
@allowed = User.current.allowed_to? :file_manipulation, @project
@unlockable = @allowed && @dmsf_file.unlockable? && (!@dmsf_file.locked_for_user? ||
User.current.allowed_to?(:force_file_unlock, @project))
@email_allowed = User.current.allowed_to?(:email_documents, @project)
elsif @dmsf_folder
@locked = @dmsf_folder.locked?
@project = @dmsf_folder.project
@allowed = User.current.allowed_to?(:folder_manipulation, @project)
@unlockable = @allowed && @dmsf_folder.unlockable? && (!@dmsf_folder.locked_for_user?) &&
User.current.allowed_to?(:force_file_unlock, @project)
@ -44,9 +45,11 @@ class DmsfContextMenusController < ApplicationController
elsif @dmsf_link # url link
@locked = false
@unlockable = false
@project = @dmsf_link.project
@allowed = User.current.allowed_to? :file_manipulation, @project
@email_allowed = false
else # multiple selection
@project = get_project
@locked = false
@unlockable = false
@allowed = User.current.allowed_to?(:file_manipulation, @project) &&
@ -60,15 +63,19 @@ class DmsfContextMenusController < ApplicationController
def trash
if @dmsf_file
@project = @dmsf_file.project
@allowed_restore = User.current.allowed_to? :file_manipulation, @project
@allowed_delete = User.current.allowed_to? :file_delete, @project
elsif @dmsf_folder
@project = @dmsf_folder.project
@allowed_restore = User.current.allowed_to? :folder_manipulation, @project
@allowed_delete = @allowed_restore
elsif @dmsf_link # url link
@project = @dmsf_link.project
@allowed_restore = User.current.allowed_to? :file_manipulation, @project
@allowed_delete = User.current.allowed_to? :file_delete, @project
else # multiple selection
@project = get_project
@allowed_restore = User.current.allowed_to?(:file_manipulation, @project) &&
User.current.allowed_to?(:folder_manipulation, @project)
@allowed_delete = User.current.allowed_to?(:file_delete, @project) &&
@ -81,6 +88,27 @@ class DmsfContextMenusController < ApplicationController
private
def get_project
prj = nil
params[:ids].each do |id|
if id =~ /file-(\d+)/
item = DmsfFile.find_by(id: $1)
elsif id =~ /(file|url)-link-(\d+)/
item = DmsfLink.find_by(id: $2)
elsif id =~ /folder-(\d+)/
item = DmsfFolder.find_by(id: $1)
elsif id =~ /folder-link-(\d+)/
item = DmsfLink.find_by(id: $1)
end
unless prj
prj = item&.project
else
return nil if(prj != item.project)
end
end
prj
end
def find_folder
@folder = DmsfFolder.find params[:folder_id] if params[:folder_id].present?
rescue ActiveRecord::RecordNotFound

View File

@ -24,15 +24,16 @@
class DmsfController < ApplicationController
include RedmineDmsf::DmsfZip
before_action :find_project
before_action :authorize, except: [:expand_folder]
before_action :find_project, except: [:expand_folder, :index]
before_action :authorize, except: [:expand_folder, :index]
before_action :authorize_global, only: [:index]
before_action :find_folder, except: [:new, :create, :edit_root, :save_root, :add_email, :append_email,
:autocomplete_for_user]
before_action :find_parent, only: [:new, :create, :delete]
before_action :permissions
# Also try to lookup folder by title if this is an API call
before_action :find_folder_by_title, only: [:show]
before_action :get_query, only: [:expand_folder, :show, :trash, :empty_trash]
before_action :get_query, only: [:expand_folder, :show, :trash, :empty_trash, :index]
before_action :get_project_roles, only: [:new, :edit, :create, :save]
accept_api_auth :show, :create, :save, :delete
@ -61,6 +62,10 @@ class DmsfController < ApplicationController
end
end
def index
show
end
def show
@system_folder = @folder && @folder.system
@locked_for_user = @folder && @folder.locked_for_user?

View File

@ -82,17 +82,15 @@ class DmsfQuery < Query
def base_scope
unless @scope
@scope = [dmsf_folders_scope, dmsf_folder_links_scope, dmsf_projects_scope, dmsf_files_scope, dmsf_file_links_scope, dmsf_url_links_scope].
compact.inject(:union_all)
@scope = [dmsf_folders_scope, dmsf_folder_links_scope, dmsf_projects_scope, dmsf_files_scope,
dmsf_file_links_scope, dmsf_url_links_scope].compact.inject(:union_all)
end
@scope
end
# Returns the issue count
def dmsf_count
base_scope.
where(statement).
count
base_scope.where(statement).count
rescue ::ActiveRecord::StatementInvalid => e
raise StatementInvalid.new e.message
end
@ -192,37 +190,36 @@ class DmsfQuery < Query
private
def dmsf_projects_scope
return nil unless Setting.plugin_redmine_dmsf['dmsf_projects_as_subfolders']
return nil if(project && !Setting.plugin_redmine_dmsf['dmsf_projects_as_subfolders'])
cf_columns = +''
if statement.present?
DmsfFileRevisionCustomField.visible.order(:position).pluck(:id).each do |id|
cf_columns << ",NULL AS cf_#{id}"
end
end
scope = Project.
select(%{
projects.id AS id,
projects.id AS project_id,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS revision_id,
projects.name AS title,
projects.identifier AS filename,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS size,
projects.updated_on AS updated,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS major_version,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS minor_version,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS workflow,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS workflow_id,
'' AS firstname,
'' AS lastname,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS author,
'project' AS type,
CAST(0 AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS deleted,
0 AS sort #{cf_columns}}).visible
scope = Project.select(%{
projects.id AS id,
projects.id AS project_id,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS revision_id,
projects.name AS title,
projects.identifier AS filename,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS size,
projects.updated_on AS updated,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS major_version,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS minor_version,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS workflow,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS workflow_id,
'' AS firstname,
'' AS lastname,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS author,
'project' AS type,
CAST(0 AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS deleted,
0 AS sort #{cf_columns}}).visible
if dmsf_folder_id || deleted
scope.where '1=0'
else
scope = scope.non_templates if scope.respond_to?(:non_templates)
scope.where projects: { parent_id: project.id }
scope.where projects: { parent_id: project&.id }
end
end
@ -233,26 +230,26 @@ class DmsfQuery < Query
cf_columns << ",(SELECT value from custom_values WHERE custom_field_id = #{id} AND customized_type = 'DmsfFolder' AND customized_id = dmsf_folders.id) AS cf_#{id}"
end
end
scope = DmsfFolder.
select(%{
dmsf_folders.id AS id,
dmsf_folders.project_id AS project_id,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS revision_id,
dmsf_folders.title AS title,
NULL AS filename,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS size,
dmsf_folders.updated_at AS updated,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS major_version,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS minor_version,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS workflow,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS workflow_id,
users.firstname AS firstname,
users.lastname AS lastname,
users.id AS author,
'folder' AS type,
dmsf_folders.deleted AS deleted,
1 AS sort #{cf_columns}}).
joins('LEFT JOIN users ON dmsf_folders.user_id = users.id')
scope = DmsfFolder.select(%{
dmsf_folders.id AS id,
dmsf_folders.project_id AS project_id,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS revision_id,
dmsf_folders.title AS title,
NULL AS filename,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS size,
dmsf_folders.updated_at AS updated,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS major_version,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS minor_version,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS workflow,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS workflow_id,
users.firstname AS firstname,
users.lastname AS lastname,
users.id AS author,
'folder' AS type,
dmsf_folders.deleted AS deleted,
1 AS sort #{cf_columns}}).
joins('LEFT JOIN users ON dmsf_folders.user_id = users.id')
return scope.where('1=0') unless project
if deleted
scope = scope.deleted
else
@ -270,33 +267,33 @@ class DmsfQuery < Query
end
def dmsf_folder_links_scope
return nil unless project
cf_columns = +''
if statement.present?
DmsfFileRevisionCustomField.visible.order(:position).pluck(:id).each do |id|
cf_columns << ",(SELECT value from custom_values WHERE custom_field_id = #{id} AND customized_type = 'DmsfFolder' AND customized_id = dmsf_folders.id) AS cf_#{id}"
end
end
scope = DmsfLink.
select(%{
dmsf_links.id AS id,
COALESCE(dmsf_folders.project_id, dmsf_links.project_id) AS project_id,
dmsf_links.target_id AS revision_id,
dmsf_links.name AS title,
dmsf_folders.title AS filename,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS size,
COALESCE(dmsf_folders.updated_at, dmsf_links.updated_at) AS updated,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS major_version,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS minor_version,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS workflow,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS workflow_id,
users.firstname AS firstname,
users.lastname AS lastname,
users.id AS author,
'folder-link' AS type,
dmsf_links.deleted AS deleted,
1 AS sort #{cf_columns}}).
joins('LEFT JOIN dmsf_folders ON dmsf_links.target_id = dmsf_folders.id').
joins('LEFT JOIN users ON users.id = COALESCE(dmsf_folders.user_id, dmsf_links.user_id)')
scope = DmsfLink.select(%{
dmsf_links.id AS id,
COALESCE(dmsf_folders.project_id, dmsf_links.project_id) AS project_id,
dmsf_links.target_id AS revision_id,
dmsf_links.name AS title,
dmsf_folders.title AS filename,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS size,
COALESCE(dmsf_folders.updated_at, dmsf_links.updated_at) AS updated,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS major_version,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS minor_version,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS workflow,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS workflow_id,
users.firstname AS firstname,
users.lastname AS lastname,
users.id AS author,
'folder-link' AS type,
dmsf_links.deleted AS deleted,
1 AS sort #{cf_columns}}).
joins('LEFT JOIN dmsf_folders ON dmsf_links.target_id = dmsf_folders.id').
joins('LEFT JOIN users ON users.id = COALESCE(dmsf_folders.user_id, dmsf_links.user_id)')
if dmsf_folder_id
scope.where dmsf_links: { target_type: 'DmsfFolder', dmsf_folder_id: dmsf_folder_id, deleted: deleted }
else
@ -309,34 +306,34 @@ class DmsfQuery < Query
end
def dmsf_files_scope
return nil unless project
cf_columns = +''
if statement.present?
DmsfFileRevisionCustomField.visible.order(:position).pluck(:id).each do |id|
cf_columns << ",(SELECT value from custom_values WHERE custom_field_id = #{id} AND customized_type = 'DmsfFileRevision' AND customized_id = dmsf_file_revisions.id) AS cf_#{id}"
end
end
scope = DmsfFile.
select(%{
dmsf_files.id AS id,
dmsf_files.project_id AS project_id,
dmsf_file_revisions.id AS revision_id,
dmsf_file_revisions.title AS title,
dmsf_file_revisions.name AS filename,
dmsf_file_revisions.size AS size,
dmsf_file_revisions.updated_at AS updated,
dmsf_file_revisions.major_version AS major_version,
dmsf_file_revisions.minor_version AS minor_version,
dmsf_file_revisions.workflow AS workflow,
dmsf_file_revisions.dmsf_workflow_id AS workflow_id,
users.firstname AS firstname,
users.lastname AS lastname,
users.id AS author,
'file' AS type,
dmsf_files.deleted AS deleted,
2 AS sort #{cf_columns}}).
joins(:dmsf_file_revisions).
joins('LEFT JOIN users ON dmsf_file_revisions.user_id = users.id ').
where(sub_query)
scope = DmsfFile.select(%{
dmsf_files.id AS id,
dmsf_files.project_id AS project_id,
dmsf_file_revisions.id AS revision_id,
dmsf_file_revisions.title AS title,
dmsf_file_revisions.name AS filename,
dmsf_file_revisions.size AS size,
dmsf_file_revisions.updated_at AS updated,
dmsf_file_revisions.major_version AS major_version,
dmsf_file_revisions.minor_version AS minor_version,
dmsf_file_revisions.workflow AS workflow,
dmsf_file_revisions.dmsf_workflow_id AS workflow_id,
users.firstname AS firstname,
users.lastname AS lastname,
users.id AS author,
'file' AS type,
dmsf_files.deleted AS deleted,
2 AS sort #{cf_columns}}).
joins(:dmsf_file_revisions).
joins('LEFT JOIN users ON dmsf_file_revisions.user_id = users.id ').
where(sub_query)
if dmsf_folder_id
scope.where dmsf_files: { dmsf_folder_id: dmsf_folder_id, deleted: deleted }
else
@ -349,35 +346,35 @@ class DmsfQuery < Query
end
def dmsf_file_links_scope
return nil unless project
cf_columns = +''
if statement.present?
DmsfFileRevisionCustomField.visible.order(:position).pluck(:id).each do |id|
cf_columns << ",(SELECT value from custom_values WHERE custom_field_id = #{id} AND customized_type = 'DmsfFileRevision' AND customized_id = dmsf_file_revisions.id) AS cf_#{id}"
end
end
scope = DmsfLink.
select(%{
dmsf_links.id AS id,
dmsf_files.project_id AS project_id,
dmsf_files.id AS revision_id,
dmsf_links.name AS title,
dmsf_file_revisions.name AS filename,
dmsf_file_revisions.size AS size,
dmsf_file_revisions.updated_at AS updated,
dmsf_file_revisions.major_version AS major_version,
dmsf_file_revisions.minor_version AS minor_version,
dmsf_file_revisions.workflow AS workflow,
dmsf_file_revisions.dmsf_workflow_id AS workflow_id,
users.firstname AS firstname,
users.lastname AS lastname,
users.id AS author,
'file-link' AS type,
dmsf_links.deleted AS deleted,
2 AS sort #{cf_columns}}).
joins('JOIN dmsf_files ON dmsf_files.id = dmsf_links.target_id').
joins('JOIN dmsf_file_revisions ON dmsf_file_revisions.dmsf_file_id = dmsf_files.id').
joins('LEFT JOIN users ON dmsf_file_revisions.user_id = users.id ').
where(sub_query)
scope = DmsfLink.select(%{
dmsf_links.id AS id,
dmsf_files.project_id AS project_id,
dmsf_files.id AS revision_id,
dmsf_links.name AS title,
dmsf_file_revisions.name AS filename,
dmsf_file_revisions.size AS size,
dmsf_file_revisions.updated_at AS updated,
dmsf_file_revisions.major_version AS major_version,
dmsf_file_revisions.minor_version AS minor_version,
dmsf_file_revisions.workflow AS workflow,
dmsf_file_revisions.dmsf_workflow_id AS workflow_id,
users.firstname AS firstname,
users.lastname AS lastname,
users.id AS author,
'file-link' AS type,
dmsf_links.deleted AS deleted,
2 AS sort #{cf_columns}}).
joins('JOIN dmsf_files ON dmsf_files.id = dmsf_links.target_id').
joins('JOIN dmsf_file_revisions ON dmsf_file_revisions.dmsf_file_id = dmsf_files.id').
joins('LEFT JOIN users ON dmsf_file_revisions.user_id = users.id ').
where(sub_query)
if dmsf_folder_id
scope.where dmsf_links: { target_type: 'DmsfFile', dmsf_folder_id: dmsf_folder_id, deleted: deleted }
else
@ -391,32 +388,32 @@ class DmsfQuery < Query
end
def dmsf_url_links_scope
return nil unless project
cf_columns = +''
if statement.present?
DmsfFileRevisionCustomField.visible.order(:position).pluck(:id).each do |id|
cf_columns << ",NULL AS cf_#{id}"
end
end
scope = DmsfLink.
select(%{
dmsf_links.id AS id,
dmsf_links.project_id AS project_id,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS revision_id,
dmsf_links.name AS title,
dmsf_links.external_url AS filename,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS size,
dmsf_links.updated_at AS updated,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS major_version,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS minor_version,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS workflow,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS workflow_id,
users.firstname AS firstname,
users.lastname AS lastname,
users.id AS author,
'url-link' AS type,
dmsf_links.deleted AS deleted,
2 AS sort #{cf_columns}}).
joins('LEFT JOIN users ON dmsf_links.user_id = users.id ')
scope = DmsfLink.select(%{
dmsf_links.id AS id,
dmsf_links.project_id AS project_id,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS revision_id,
dmsf_links.name AS title,
dmsf_links.external_url AS filename,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS size,
dmsf_links.updated_at AS updated,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS major_version,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS minor_version,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS workflow,
CAST(NULL AS #{ActiveRecord::Base.connection.type_to_sql(:decimal)}) AS workflow_id,
users.firstname AS firstname,
users.lastname AS lastname,
users.id AS author,
'url-link' AS type,
dmsf_links.deleted AS deleted,
2 AS sort #{cf_columns}}).
joins('LEFT JOIN users ON dmsf_links.user_id = users.id ')
if dmsf_folder_id
scope.where dmsf_links: { target_type: 'DmsfUrl', dmsf_folder_id: dmsf_folder_id, deleted: deleted }
else

View File

@ -22,20 +22,14 @@
<h3 class="title"><%= l(:label_email_address_add) %></h3>
<%= form_tag(append_email_dmsf_path,
remote: true,
method: :post,
id: 'new-user-form') do %>
<%= hidden_field_tag :project_id, @project.id %>
<%= form_tag(append_email_dmsf_path(id: @project.id), 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>
<%= late_javascript_tag "observeSearchfield('user_search', 'users_for_users', '#{ escape_javascript url_for(
controller: 'dmsf', action: 'autocomplete_for_user', project_id: @project) }')" %>
controller: 'dmsf', action: 'autocomplete_for_user') }')" %>
<div id="users_for_watcher">
<%= render_principals_for_new_email(@principals) %>
<%= render_principals_for_new_email @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' %>

View File

@ -0,0 +1,98 @@
<%
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright © 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright © 2012 Daniel Munn <dan.munn@munnster.co.uk>
# Copyright © 2011-21 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) %>
<% if @project %>
<div class="contextual">
<% unless @locked_for_user || @system_folder %>
<% if @file_manipulation_allowed %>
<%= link_to l(:label_attachment_new), multi_dmsf_upload_path(id: @project, folder_id: @folder),
class: 'icon icon-add' %>
<% end %>
<% if @folder_manipulation_allowed %>
<%= link_to l(:link_create_folder), new_dmsf_path(id: @project, parent_id: @folder), class: 'icon icon-add' %>
<% end %>
<% end %>
<% if defined?(EasyExtensions) %>
<%= render partial: 'dmsf_context_menus/main', locals: {
folder_manipulation_allowed: @folder_manipulation_allowed,
system_folder: @system_folder,
folder: @folder,
project: @project,
locked_for_user: @locked_for_user,
file_manipulation_allowed: @file_manipulation_allowed,
trash_enabled: @trash_enabled } %>
<% else %>
<%= actions_dropdown do %>
<%= render partial: 'dmsf_context_menus/main', locals: {
folder_manipulation_allowed: @folder_manipulation_allowed,
system_folder: @system_folder,
folder: @folder,
project: @project,
locked_for_user: @locked_for_user,
file_manipulation_allowed: @file_manipulation_allowed,
trash_enabled: @trash_enabled } %>
<% end %>
<% end %>
</div>
<% end %>
<%= render partial: 'path', locals: { folder: @folder, filename: nil, title: nil } %>
<% if @project %>
<div class="dmsf-header">
<div class="wiki">
<%= textilizable @folder ? @folder.description : @project.dmsf_description %>
</div>
</div>
<% end %>
<%= form_tag(@project ? dmsf_folder_path(id: @project, folder_id: @folder) : dmsf_index_path,
method: :get, id: 'query_form', class: 'dmsf-query-form') do %>
<%= hidden_field_tag('folder_id', @folder.id) if @folder %>
<%= render partial: 'queries/query_form' %>
<% end %>
<% if @query.valid? %>
<% if @dmsf_count == 0 %>
<p class="nodata"><%= l(:label_no_data) %></p>
<% else %>
<%= render partial: 'query_list', locals: { query: @query, dmsf_pages: @dmsf_pages, folder: @folder } %>
<span class="pagination"><%= pagination_links_full @dmsf_pages, @dmsf_count %></span>
<% end %>
<% end %>
<%= context_menu %>
<% unless @folder && @folder.system %>
<% other_formats_links do |f| %>
<%= f.link_to 'CSV', url: { action: :show, id: @project, folder_id: @folder, encoding: Encoding::UTF_8 } if @project %>
<span>
<%= link_to 'WebDAV', webdav_url(@project, @folder) %>
</span>
<% end %>
<% end %>
<% content_for :sidebar do %>
<%= render partial: 'dmsf/sidebar' %>
<% end %>

View File

@ -32,7 +32,11 @@
<% end %>
<% end %>
<% else %>
<%= link_to l(:link_documents), dmsf_folder_path(id: @project) %>
<% if @project %>
<%= link_to l(:link_documents), dmsf_folder_path(id: @project) %>
<% else %>
<%= l(:link_documents) %>
<% end %>
<% end %>
<% if filename %>
/

View File

@ -55,7 +55,7 @@
</tr>
<% end %>
<% unless query.deleted %>
<% unless query.deleted || @project.nil? %>
<%= late_javascript_tag do %>
$(function() {
$("table.dmsf tr").removeClass("ui-draggable-dragging ui-droppable-active ui-droppable-hover ui-draggable-handle");

View File

@ -41,7 +41,7 @@
<%= label_tag 'email[to]', l(:label_email_to) %>
<span>
<%= text_field_tag 'email[to]', @email_params[:to], class: 'dmsf-full-width', required: true %>
<%= link_to l(:button_add), add_email_dmsf_path(project_id: @project),
<%= link_to l(:button_add), add_email_dmsf_path(id: @project),
title: l(:label_email_address_add), class: 'icon icon-add', remote: true %>
</span>
</p>

View File

@ -0,0 +1,25 @@
<%
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright © 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright © 2012 Daniel Munn <dan.munn@munnster.co.uk>
# Copyright © 2011-21 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: 'main', locals: { } %>

View File

@ -22,72 +22,4 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<% html_title l(:dmsf) %>
<div class="contextual">
<% unless @locked_for_user || @system_folder %>
<% if @file_manipulation_allowed %>
<%= link_to l(:label_attachment_new), multi_dmsf_upload_path(id: @project, folder_id: @folder),
class: 'icon icon-add' %>
<% end %>
<% if @folder_manipulation_allowed %>
<%= link_to l(:link_create_folder), new_dmsf_path(id: @project, parent_id: @folder), class: 'icon icon-add' %>
<% end %>
<% end %>
<% if defined?(EasyExtensions) %>
<%= render partial: 'dmsf_context_menus/main', locals: {
folder_manipulation_allowed: @folder_manipulation_allowed,
system_folder: @system_folder,
folder: @folder,
project: @project,
locked_for_user: @locked_for_user,
file_manipulation_allowed: @file_manipulation_allowed,
trash_enabled: @trash_enabled } %>
<% else %>
<%= actions_dropdown do %>
<%= render partial: 'dmsf_context_menus/main', locals: {
folder_manipulation_allowed: @folder_manipulation_allowed,
system_folder: @system_folder,
folder: @folder,
project: @project,
locked_for_user: @locked_for_user,
file_manipulation_allowed: @file_manipulation_allowed,
trash_enabled: @trash_enabled } %>
<% end %>
<% end %>
</div>
<%= render partial: 'path', locals: { folder: @folder, filename: nil, title: nil } %>
<div class="dmsf-header">
<div class="wiki">
<%= textilizable @folder ? @folder.description : @project.dmsf_description %>
</div>
</div>
<%= form_tag(dmsf_folder_path(id: @project, folder_id: @folder), method: :get, id: 'query_form', class: 'dmsf-query-form') do %>
<%= hidden_field_tag('folder_id', @folder.id) if @folder %>
<%= render partial: 'queries/query_form' %>
<% end %>
<% if @query.valid? %>
<% if @dmsf_count == 0 %>
<p class="nodata"><%= l(:label_no_data) %></p>
<% else %>
<%= render partial: 'query_list', locals: { query: @query, dmsf_pages: @dmsf_pages, folder: @folder } %>
<span class="pagination"><%= pagination_links_full @dmsf_pages, @dmsf_count %></span>
<% end %>
<% end %>
<%= context_menu %>
<% unless @folder && @folder.system %>
<% other_formats_links do |f| %>
<%= f.link_to 'CSV', url: { action: :show, id: @project, folder_id: @folder, encoding: Encoding::UTF_8 } %>
<span>
<%= link_to 'WebDAV', webdav_url(@project, @folder) %>
</span>
<% end %>
<% end %>
<% content_for :sidebar do %>
<%= render partial: 'dmsf/sidebar' %>
<% end %>
<%= render partial: 'main', locals: { } %>

View File

@ -20,7 +20,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
%>
<% workflows_available = DmsfWorkflow.where(['project_id = ? OR project_id IS NULL', project.id]).exists? %>
<% workflows_available = DmsfWorkflow.where(['project_id = ? OR project_id IS NULL', project&.id]).exists? %>
<% wf = DmsfWorkflow.find_by(id: dmsf_file.last_revision.dmsf_workflow_id) if dmsf_file.last_revision.dmsf_workflow_id %>
<% file_approval_allowed = User.current.allowed_to?(:file_approval, project) %>
<% allowed = User.current && (dmsf_file.last_revision.dmsf_workflow_assigned_by_user == User.current) && wf %>

View File

@ -31,7 +31,7 @@
</li>
<li>
<%= link_to l(:label_link_to),
new_dmsf_link_path(project_id: project.id, dmsf_folder_id: dmsf_file.dmsf_folder&.id,
new_dmsf_link_path(project_id: dmsf_file.project.id, dmsf_folder_id: dmsf_file.dmsf_folder&.id,
dmsf_file_id: dmsf_file.id, type: 'link_to'),
title: l(:title_create_link), class: 'icon icon-link' %>
</li>
@ -63,7 +63,7 @@
class: 'icon icon-download', disabled: false %>
</li>
<li>
<%= context_menu_link l(:field_mail), entries_operations_dmsf_path(id: @project, folder_id: folder,
<%= context_menu_link l(:field_mail), entries_operations_dmsf_path(id: project, folder_id: folder,
ids: params[:ids], email_entries: true), method: :post, class: 'icon icon-email',
disabled: !email_allowed %>
</li>

View File

@ -21,7 +21,7 @@
%>
<li>
<%= context_menu_link l(:button_edit), edit_dmsf_path(id: project, folder_id: dmsf_folder),
<%= context_menu_link l(:button_edit), edit_dmsf_path(id: dmsf_folder.project, folder_id: dmsf_folder),
class: 'icon icon-edit', disabled: !allowed || locked %>
</li>
<% unless dmsf_link %>
@ -31,26 +31,26 @@
</li>
<li>
<%= context_menu_link l(:label_link_to),
new_dmsf_link_path(project_id: project.id, dmsf_folder_id: dmsf_folder.id, type: 'link_to'),
new_dmsf_link_path(project_id: dmsf_folder.id, dmsf_folder_id: dmsf_folder.id, type: 'link_to'),
class: 'icon icon-link' %>
</li>
<% end %>
<li>
<% if locked %>
<%= context_menu_link l(:button_unlock), unlock_dmsf_path(id: project, folder_id: dmsf_folder),
<%= context_menu_link l(:button_unlock), unlock_dmsf_path(id: dmsf_folder, folder_id: dmsf_folder),
title: l(:title_locked_by_user, user: dmsf_folder.locked_by),
class: 'icon icon-unlock', disabled: !allowed || !unlockable %>
<% else %>
<%= context_menu_link l(:button_lock), lock_dmsf_path(id: project, folder_id: dmsf_folder),
<%= context_menu_link l(:button_lock), lock_dmsf_path(id: dmsf_folder.project, folder_id: dmsf_folder),
class: 'icon icon-lock', disabled: !allowed %>
<% end %>
</li>
<li>
<% if dmsf_folder.notification %>
<%= context_menu_link l(:label_notifications_off), notify_deactivate_dmsf_path(id: project, folder_id: dmsf_folder),
<%= context_menu_link l(:label_notifications_off), notify_deactivate_dmsf_path(id: dmsf_folder.project, folder_id: dmsf_folder),
class: 'icon icon-email', disabled: !allowed || locked || !dmsf_folder.notification? %>
<% else %>
<%= context_menu_link l(:label_notifications_on), notify_activate_dmsf_path(id: project, folder_id: dmsf_folder),
<%= context_menu_link l(:label_notifications_on), notify_activate_dmsf_path(id: dmsf_folder.project, folder_id: dmsf_folder),
class: 'icon icon-email-add', disabled: !allowed || locked || dmsf_folder.notification? %>
<% end %>
</li>
@ -60,14 +60,14 @@
id: 'dmsf-cm-download', disabled: false %>
</li>
<li>
<%= context_menu_link l(:field_mail), entries_operations_dmsf_path(id: project, folder_id: folder,
<%= context_menu_link l(:field_mail), entries_operations_dmsf_path(id: dmsf_folder.project, folder_id: folder,
ids: params[:ids], email_entries: true), method: :post, class: 'icon icon-email',
disabled: !email_allowed %>
</li>
<li>
<%= context_menu_link l(:button_delete),
dmsf_link ? dmsf_link_path(id: dmsf_link, folder_id: folder) :
delete_dmsf_path(id: project, folder_id: dmsf_folder, parent_id: folder),
delete_dmsf_path(id: dmsf_folder.project, folder_id: dmsf_folder, parent_id: folder),
data: { confirm: "#{l(:text_are_you_sure)}\n#{l(:text_not_empty) unless dmsf_folder.empty?}" }, method: :delete,
class: 'icon icon-del', id: 'dmsf-cm-delete', disabled: !allowed || (locked && !dmsf_link) %>
</li>

View File

@ -22,7 +22,7 @@
<li>
<%= context_menu_link l(:button_download), entries_operations_dmsf_path(id: project, folder_id: folder,
ids: params[:ids], download_entries: true), method: :post, class: 'icon icon-download', disabled: false %>
ids: params[:ids], download_entries: true), method: :post, class: 'icon icon-download', disabled: project.nil? %>
</li>
<li>
<%= context_menu_link l(:field_mail), entries_operations_dmsf_path(id: project, folder_id: folder,

View File

@ -36,7 +36,7 @@ if Redmine::Plugin.installed? :redmine_dmsf
delete '/projects/:id/dmsf/delete', controller: 'dmsf', action: 'delete', as: 'delete_dmsf'
post '/projects/:id/dmsf/save', controller: 'dmsf', action: 'save'
post '/projects/:id/dmsf/save/root', controller: 'dmsf', action: 'save_root'
post '/projects/:id/dmsf/entries', controller: 'dmsf', action: 'entries_operation', as: 'entries_operations_dmsf'
post '/projects/dmsf/entries', controller: 'dmsf', action: 'entries_operation', as: 'entries_operations_dmsf'
post '/projects/:id/dmsf/tag_changed', controller: 'dmsf', action: 'tag_changed', as: 'tag_changed'
post '/projects/:id/dmsf/entries/delete', controller: 'dmsf', action: 'delete_entries', as: 'delete_entries'
post '/projects/:id/dmsf/entries/email', to: 'dmsf#entries_email', as: 'email_entries'
@ -49,15 +49,16 @@ if Redmine::Plugin.installed? :redmine_dmsf
get '/projects/:id/dmsf/edit/root', controller: 'dmsf', action: 'edit_root', as: 'edit_root_dmsf'
get '/projects/:id/dmsf/trash', controller: 'dmsf', action: 'trash', as: 'trash_dmsf'
get '/projects/:id/dmsf/restore', controller: 'dmsf', action: 'restore', as: 'restore_dmsf'
post '/projects/:id/dmsf/expand_folder', controller: 'dmsf', action: 'expand_folder', as: 'expand_folder_dmsf'
get '/projects/:id/dmsf/add_email', controller: 'dmsf', action: 'add_email', as: 'add_email_dmsf'
post '/projects/:id/dmsf/append_email', controller: 'dmsf', action: 'append_email', as: 'append_email_dmsf'
get '/projects/:id/dmsf/autocomplete_for_user', controller: 'dmsf', action: 'autocomplete_for_user'
post '/projects/dmsf/expand_folder', controller: 'dmsf', action: 'expand_folder', as: 'expand_folder_dmsf'
get '/projects/dmsf/add_email', to: 'dmsf#add_email', as: 'add_email_dmsf'
post '/projects/dmsf/append_email', to: 'dmsf#append_email', as: 'append_email_dmsf'
get '/projects/dmsf/autocomplete_for_user', to: 'dmsf#autocomplete_for_user'
put '/projects/:id/dmsf', controller: 'dmsf', action: 'drop'
get '/projects/:id/dmsf/empty_trash', to: 'dmsf#empty_trash', as: 'empty_trash'
get '/dmsf', to: 'dmsf#index', as: 'dmsf_index'
# dmsf_context_menu_controller
match '/projects/:id/dmsf/context_menu', to: 'dmsf_context_menus#dmsf', as: 'dmsf_context_menu', via: [:get, :post]
match '/projects/dmsf/context_menu', to: 'dmsf_context_menus#dmsf', as: 'dmsf_context_menu', via: [:get, :post]
match '/projects/:id/dmsf/trash/context_menu', to: 'dmsf_context_menus#trash', as: 'dmsf_trash_context_menu', via: [:get, :post]
#

View File

@ -60,7 +60,7 @@ Redmine::Plugin.register :redmine_dmsf do
'dmsf_enable_cjk_ngrams' => nil,
'dmsf_webdav_use_project_names' => Redmine::Plugin.installed?(:easy_extensions) ? '1' : nil,
'dmsf_webdav_ignore_1b_file_for_authentication' => '1',
'dmsf_projects_as_subfolders' => Redmine::Plugin.installed?(:easy_extensions) ? '1' : nil,
'dmsf_projects_as_subfolders' => nil
}
end

View File

@ -366,4 +366,44 @@ class DmsfControllerTest < RedmineDmsf::Test::TestCase
assert_select "tr##{@project3.id}pspan", count: 0
end
def test_index
get :index
assert_response :success
# Projects
assert_select 'table.dmsf' do
assert_select 'tr' do
assert_select 'td.dmsf-title' do
assert_select 'a', text: "[#{@project1.name}]"
assert_select 'a', text: "[#{@project2.name}]"
end
end
end
# No context menu
assert_select 'div.contextual', count: 0
# No description
assert_select 'div.dmsf-header', count: 0
# No CSV export
assert_select 'a.csv', count: 0
end
def test_index_non_member
@request.session[:user_id] = @dlopper.id
get :index
assert_response :success
assert_select 'table.dmsf' do
assert_select 'tr' do
assert_select 'td.dmsf-title' do
assert_select 'a', text: "[#{@project1.name}]"
assert_select 'a', text: "[#{@project2.name}]", count: 0
end
end
end
end
def test_index_no_membership
@request.session[:user_id] = @someone.id
get :index
assert_response :forbidden
end
end