From 61b41775597c8147c27da19c32e792581f944a62 Mon Sep 17 00:00:00 2001 From: "karel.picman@lbcfree.net" Date: Wed, 3 Mar 2021 10:44:24 +0100 Subject: [PATCH] Global DMS view #1217 --- after_init.rb | 11 +- .../dmsf_context_menus_controller.rb | 30 +- app/controllers/dmsf_controller.rb | 11 +- app/models/dmsf_query.rb | 261 +++++++++--------- app/views/dmsf/_add_email.html.erb | 14 +- app/views/dmsf/_main.html.erb | 98 +++++++ app/views/dmsf/_path.html.erb | 6 +- app/views/dmsf/_query_rows.erb | 2 +- app/views/dmsf/email_entries.html.erb | 2 +- app/views/dmsf/index.html.erb | 25 ++ app/views/dmsf/show.html.erb | 70 +---- .../_approval_workflow.html.erb | 2 +- app/views/dmsf_context_menus/_file.html.erb | 4 +- app/views/dmsf_context_menus/_folder.html.erb | 16 +- .../dmsf_context_menus/_multiple.html.erb | 2 +- config/routes.rb | 13 +- init.rb | 2 +- test/functional/dmsf_controller_test.rb | 40 +++ 18 files changed, 370 insertions(+), 239 deletions(-) create mode 100644 app/views/dmsf/_main.html.erb create mode 100644 app/views/dmsf/index.html.erb diff --git a/after_init.rb b/after_init.rb index 2d19cff7..d6a2c38f 100644 --- a/after_init.rb +++ b/after_init.rb @@ -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] } diff --git a/app/controllers/dmsf_context_menus_controller.rb b/app/controllers/dmsf_context_menus_controller.rb index 39c3c82b..fae07c70 100644 --- a/app/controllers/dmsf_context_menus_controller.rb +++ b/app/controllers/dmsf_context_menus_controller.rb @@ -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 diff --git a/app/controllers/dmsf_controller.rb b/app/controllers/dmsf_controller.rb index 0dfe61fb..562744f5 100644 --- a/app/controllers/dmsf_controller.rb +++ b/app/controllers/dmsf_controller.rb @@ -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? diff --git a/app/models/dmsf_query.rb b/app/models/dmsf_query.rb index 309d5482..f6216984 100644 --- a/app/models/dmsf_query.rb +++ b/app/models/dmsf_query.rb @@ -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 diff --git a/app/views/dmsf/_add_email.html.erb b/app/views/dmsf/_add_email.html.erb index 4ed6ffe9..24ab9d84 100644 --- a/app/views/dmsf/_add_email.html.erb +++ b/app/views/dmsf/_add_email.html.erb @@ -22,20 +22,14 @@

<%= l(:label_email_address_add) %>

-<%= 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 %>

<%= label_tag 'user_search', l(:label_user_search) %><%= text_field_tag 'user_search', nil %>

<%= 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') }')" %>
- <%= render_principals_for_new_email(@principals) %> + <%= render_principals_for_new_email @principals %>
-

<%= submit_tag l(:button_add), name: nil, onclick: 'hideModal(this);' %> <%= submit_tag l(:button_cancel), name: nil, onclick: 'hideModal(this);', type: 'button' %> diff --git a/app/views/dmsf/_main.html.erb b/app/views/dmsf/_main.html.erb new file mode 100644 index 00000000..2f430cfb --- /dev/null +++ b/app/views/dmsf/_main.html.erb @@ -0,0 +1,98 @@ +<% + # encoding: utf-8 + # + # Redmine plugin for Document Management System "Features" + # + # Copyright © 2011 Vít Jonáš + # Copyright © 2012 Daniel Munn + # Copyright © 2011-21 Karel Pičman + # + # This program is free software; you can redistribute it and/or + # modify it under the terms of the GNU General Public License + # as published by the Free Software Foundation; either version 2 + # of the License, or (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this program; if not, write to the Free Software + # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +%> + +<% html_title l(:dmsf) %> +<% if @project %> +

+ <% 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 %> +
+<% end %> + +<%= render partial: 'path', locals: { folder: @folder, filename: nil, title: nil } %> + +<% if @project %> +
+
+ <%= textilizable @folder ? @folder.description : @project.dmsf_description %> +
+
+<% 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 %> +

<%= l(:label_no_data) %>

+ <% else %> + <%= render partial: 'query_list', locals: { query: @query, dmsf_pages: @dmsf_pages, folder: @folder } %> + <%= pagination_links_full @dmsf_pages, @dmsf_count %> + <% 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 %> + + <%= link_to 'WebDAV', webdav_url(@project, @folder) %> + + <% end %> +<% end %> + +<% content_for :sidebar do %> + <%= render partial: 'dmsf/sidebar' %> +<% end %> diff --git a/app/views/dmsf/_path.html.erb b/app/views/dmsf/_path.html.erb index bc4e4366..76e161fa 100644 --- a/app/views/dmsf/_path.html.erb +++ b/app/views/dmsf/_path.html.erb @@ -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 %> / diff --git a/app/views/dmsf/_query_rows.erb b/app/views/dmsf/_query_rows.erb index 4a384fb2..93247992 100644 --- a/app/views/dmsf/_query_rows.erb +++ b/app/views/dmsf/_query_rows.erb @@ -55,7 +55,7 @@ <% 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"); diff --git a/app/views/dmsf/email_entries.html.erb b/app/views/dmsf/email_entries.html.erb index 6cf01a3b..f65a4739 100644 --- a/app/views/dmsf/email_entries.html.erb +++ b/app/views/dmsf/email_entries.html.erb @@ -41,7 +41,7 @@ <%= label_tag 'email[to]', l(:label_email_to) %> <%= 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 %>

diff --git a/app/views/dmsf/index.html.erb b/app/views/dmsf/index.html.erb new file mode 100644 index 00000000..cc501cb1 --- /dev/null +++ b/app/views/dmsf/index.html.erb @@ -0,0 +1,25 @@ +<% + # encoding: utf-8 + # + # Redmine plugin for Document Management System "Features" + # + # Copyright © 2011 Vít Jonáš + # Copyright © 2012 Daniel Munn + # Copyright © 2011-21 Karel Pičman + # + # This program is free software; you can redistribute it and/or + # modify it under the terms of the GNU General Public License + # as published by the Free Software Foundation; either version 2 + # of the License, or (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this program; if not, write to the Free Software + # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +%> + +<%= render partial: 'main', locals: { } %> diff --git a/app/views/dmsf/show.html.erb b/app/views/dmsf/show.html.erb index efa7bbd9..cc501cb1 100644 --- a/app/views/dmsf/show.html.erb +++ b/app/views/dmsf/show.html.erb @@ -22,72 +22,4 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. %> -<% html_title l(:dmsf) %> -
- <% 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 %> -
- -<%= render partial: 'path', locals: { folder: @folder, filename: nil, title: nil } %> - -
-
- <%= textilizable @folder ? @folder.description : @project.dmsf_description %> -
-
- -<%= 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 %> -

<%= l(:label_no_data) %>

- <% else %> - <%= render partial: 'query_list', locals: { query: @query, dmsf_pages: @dmsf_pages, folder: @folder } %> - <%= pagination_links_full @dmsf_pages, @dmsf_count %> - <% 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 } %> - - <%= link_to 'WebDAV', webdav_url(@project, @folder) %> - - <% end %> -<% end %> - -<% content_for :sidebar do %> - <%= render partial: 'dmsf/sidebar' %> -<% end %> +<%= render partial: 'main', locals: { } %> diff --git a/app/views/dmsf_context_menus/_approval_workflow.html.erb b/app/views/dmsf_context_menus/_approval_workflow.html.erb index 61844661..25fb44ea 100644 --- a/app/views/dmsf_context_menus/_approval_workflow.html.erb +++ b/app/views/dmsf_context_menus/_approval_workflow.html.erb @@ -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 %> diff --git a/app/views/dmsf_context_menus/_file.html.erb b/app/views/dmsf_context_menus/_file.html.erb index edf90898..65ba25ae 100644 --- a/app/views/dmsf_context_menus/_file.html.erb +++ b/app/views/dmsf_context_menus/_file.html.erb @@ -31,7 +31,7 @@
  • <%= 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' %>
  • @@ -63,7 +63,7 @@ class: 'icon icon-download', disabled: false %>
  • -<%= 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 %>
  • diff --git a/app/views/dmsf_context_menus/_folder.html.erb b/app/views/dmsf_context_menus/_folder.html.erb index b94d2bc3..400dcda2 100644 --- a/app/views/dmsf_context_menus/_folder.html.erb +++ b/app/views/dmsf_context_menus/_folder.html.erb @@ -21,7 +21,7 @@ %>
  • - <%= 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 %>
  • <% unless dmsf_link %> @@ -31,26 +31,26 @@
  • <%= 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' %>
  • <% end %>
  • <% 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 %>
  • <% 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 %>
  • @@ -60,14 +60,14 @@ id: 'dmsf-cm-download', disabled: false %>
  • - <%= 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 %>
  • <%= 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) %>
  • diff --git a/app/views/dmsf_context_menus/_multiple.html.erb b/app/views/dmsf_context_menus/_multiple.html.erb index 6b98e756..fc9903c9 100644 --- a/app/views/dmsf_context_menus/_multiple.html.erb +++ b/app/views/dmsf_context_menus/_multiple.html.erb @@ -22,7 +22,7 @@
  • <%= 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? %>
  • <%= context_menu_link l(:field_mail), entries_operations_dmsf_path(id: project, folder_id: folder, diff --git a/config/routes.rb b/config/routes.rb index a0467028..060cda82 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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] # diff --git a/init.rb b/init.rb index 24af342f..4afc5bef 100644 --- a/init.rb +++ b/init.rb @@ -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 diff --git a/test/functional/dmsf_controller_test.rb b/test/functional/dmsf_controller_test.rb index 43a41547..63811714 100644 --- a/test/functional/dmsf_controller_test.rb +++ b/test/functional/dmsf_controller_test.rb @@ -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 \ No newline at end of file