From 71281cdebd66b592596f48d4f456b41af5258f58 Mon Sep 17 00:00:00 2001 From: Karel Picman Date: Wed, 17 Feb 2016 13:20:06 +0100 Subject: [PATCH] Global approval workflows Lock/Unlock feature added --- app/controllers/dmsf_workflows_controller.rb | 26 ++++++++----- app/helpers/dmsf_workflows_helper.rb | 28 +++++++++++--- app/models/dmsf_workflow.rb | 16 +++++++- app/views/dmsf_workflows/_main.html.erb | 24 +++++++++--- assets/stylesheets/dmsf.css | 1 + db/migrate/20151209100001_title_format.rb | 2 +- ...20160215125801_approval_workflow_status.rb | 9 +++-- test/fixtures/dmsf_workflows.yml | 7 +++- .../dmsf_workflow_controller_test.rb | 26 ++++++++++++- test/unit/dmsf_lock_test.rb | 4 +- test/unit/dmsf_workflow_test.rb | 38 ++++++++++++++----- 11 files changed, 138 insertions(+), 43 deletions(-) diff --git a/app/controllers/dmsf_workflows_controller.rb b/app/controllers/dmsf_workflows_controller.rb index 126fd262..c50f69f0 100644 --- a/app/controllers/dmsf_workflows_controller.rb +++ b/app/controllers/dmsf_workflows_controller.rb @@ -28,8 +28,9 @@ class DmsfWorkflowsController < ApplicationController layout :workflows_layout - def index - @workflow_pages, @workflows = paginate DmsfWorkflow.global.sorted, :per_page => 25 + def index + @status = params[:status] || 1 + @workflow_pages, @workflows = paginate DmsfWorkflow.status(@status).global.sorted, :per_page => 25 end def action @@ -238,16 +239,21 @@ class DmsfWorkflowsController < ApplicationController end def update - if params[:dmsf_workflow] && @dmsf_workflow.update_attributes( - {:name => params[:dmsf_workflow][:name]}) - flash[:notice] = l(:notice_successful_update) - if @project - redirect_to settings_project_path(@project, :tab => 'dmsf_workflow') + if params[:dmsf_workflow] + res = @dmsf_workflow.update_attributes({:name => params[:dmsf_workflow][:name]}) if params[:dmsf_workflow][:name].present? + res = @dmsf_workflow.update_attributes({:status => params[:dmsf_workflow][:status]}) if params[:dmsf_workflow][:status].present? + if res + flash[:notice] = l(:notice_successful_update) + if @project + redirect_to settings_project_path(@project, :tab => 'dmsf_workflow') + else + redirect_to dmsf_workflows_path + end else - redirect_to dmsf_workflows_path - end + flash[:error] = @dmsf_workflow.errors.full_messages.to_sentence + redirect_to dmsf_workflow_path(@dmsf_workflow) + end else - flash[:error] = @dmsf_workflow.errors.full_messages.to_sentence redirect_to dmsf_workflow_path(@dmsf_workflow) end end diff --git a/app/helpers/dmsf_workflows_helper.rb b/app/helpers/dmsf_workflows_helper.rb index d930bb76..a4acf3d2 100644 --- a/app/helpers/dmsf_workflows_helper.rb +++ b/app/helpers/dmsf_workflows_helper.rb @@ -1,8 +1,7 @@ -# encoding: utf-8 -# +# encoding: utf-8# # Redmine plugin for Document Management System "Features" # -# Copyright (C) 2011-15 Karel Pičman +# Copyright (C) 2011-16 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 @@ -56,7 +55,7 @@ module DmsfWorkflowsHelper def dmsf_workflows_for_select(project, dmsf_workflow_id) options = Array.new options << ['', -1] - DmsfWorkflow.sorted.where(['project_id = ? OR project_id IS NULL', project.id]).each do |wf| + DmsfWorkflow.active.sorted.where(['project_id = ? OR project_id IS NULL', project.id]).each do |wf| if wf.project_id options << [wf.name, wf.id] else @@ -69,7 +68,7 @@ module DmsfWorkflowsHelper def dmsf_all_workflows_for_select(dmsf_workflow_id) options = Array.new options << ['', 0] - DmsfWorkflow.sorted.all.each do |wf| + DmsfWorkflow.active.sorted.all.each do |wf| if wf.project_id prj = Project.find_by_id wf.project_id if User.current.allowed_to?(:manage_workflows, prj) @@ -95,4 +94,21 @@ module DmsfWorkflowsHelper end s.html_safe end -end + + def change_status_link(workflow) + url = { :controller => 'dmsf_workflows', :action => 'update', :id => workflow.id } + if workflow.locked? + link_to l(:button_unlock), url.merge(:dmsf_workflow => {:status => DmsfWorkflow::STATUS_ACTIVE}), :method => :put, :class => 'icon icon-unlock' + else + link_to l(:button_lock), url.merge(:dmsf_workflow => {:status => DmsfWorkflow::STATUS_LOCKED}), :method => :put, :class => 'icon icon-lock' + end + end + + def workflows_status_options_for_select(selected) + worflows_count_by_status = DmsfWorkflow.global.group('status').count.to_hash + options_for_select([[l(:label_all), ''], + ["#{l(:status_active)} (#{worflows_count_by_status[DmsfWorkflow::STATUS_ACTIVE].to_i})", DmsfWorkflow::STATUS_ACTIVE.to_s], + ["#{l(:status_locked)} (#{worflows_count_by_status[DmsfWorkflow::STATUS_LOCKED].to_i})", DmsfWorkflow::STATUS_LOCKED.to_s]], selected.to_s) + end + +end \ No newline at end of file diff --git a/app/models/dmsf_workflow.rb b/app/models/dmsf_workflow.rb index 6bf6393c..d74b8a0d 100644 --- a/app/models/dmsf_workflow.rb +++ b/app/models/dmsf_workflow.rb @@ -24,6 +24,8 @@ class DmsfWorkflow < ActiveRecord::Base scope :sorted, lambda { order('name ASC') } scope :global, lambda { where('project_id IS NULL') } + scope :active, lambda { where(:status => STATUS_ACTIVE) } + scope :status, lambda { |arg| where(arg.blank? ? nil : {:status => arg.to_i}) } validate :name_validation validates :name, :presence => true @@ -61,6 +63,9 @@ class DmsfWorkflow < ActiveRecord::Base STATE_APPROVED = 2 STATE_REJECTED = 4 + STATUS_LOCKED = 0 + STATUS_ACTIVE = 1 + def participiants users = Array.new self.dmsf_workflow_steps.each do |step| @@ -247,4 +252,13 @@ class DmsfWorkflow < ActiveRecord::Base end return new_wf end -end + + def locked? + self.status == STATUS_LOCKED + end + + def active? + self.status == STATUS_ACTIVE + end + +end \ No newline at end of file diff --git a/app/views/dmsf_workflows/_main.html.erb b/app/views/dmsf_workflows/_main.html.erb index b40cde8d..1eddcd10 100644 --- a/app/views/dmsf_workflows/_main.html.erb +++ b/app/views/dmsf_workflows/_main.html.erb @@ -16,7 +16,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.%> -<% @workflows = DmsfWorkflow.sorted.where(:project_id => @project.id) if @project && @workflows.nil? %> +<% @workflows = DmsfWorkflow.active.sorted.where(:project_id => @project.id) if @project && @workflows.nil? %> <% unless @project %>
@@ -24,9 +24,18 @@

<%=l(:label_dmsf_workflow_plural)%>

-<% end %> + + <%= form_tag(dmsf_workflows_path, :method => :get) do %> +
+ <%= l(:label_filter_plural) %> + + <%= select_tag 'status', workflows_status_options_for_select(@status), :class => 'small', :onchange => "this.form.submit(); return false;" %> +
+ <% end %> +   +<% end %> -<% if @workflows.any? %> +<% if @workflows.any? %> @@ -34,9 +43,12 @@ <% for workflow in @workflows %> - - - + + + <% end %> diff --git a/assets/stylesheets/dmsf.css b/assets/stylesheets/dmsf.css index 459cb512..d4cfe0ae 100644 --- a/assets/stylesheets/dmsf.css +++ b/assets/stylesheets/dmsf.css @@ -211,6 +211,7 @@ table.access-table tbody td, table.access-table tbody tr:hover td { #admin-menu a.approvalworkflows { background-image: url(../images/ticket_go.png); } #users_for_delegate {height: 200px; overflow:auto;} #users_for_delegate label {display: block;} +tr.workflow.locked a { color: #aaa; } .revision_box{ padding: 0px 0px 0px 0px; diff --git a/db/migrate/20151209100001_title_format.rb b/db/migrate/20151209100001_title_format.rb index 1ace097d..8efd7d77 100644 --- a/db/migrate/20151209100001_title_format.rb +++ b/db/migrate/20151209100001_title_format.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright (C) 2015 Karel Pičman +# Copyright (C) 2011-16 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 diff --git a/db/migrate/20160215125801_approval_workflow_status.rb b/db/migrate/20160215125801_approval_workflow_status.rb index 1ace097d..1e447a0c 100644 --- a/db/migrate/20160215125801_approval_workflow_status.rb +++ b/db/migrate/20160215125801_approval_workflow_status.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright (C) 2015 Karel Pičman +# Copyright (C) 2011-16 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 @@ -18,12 +18,13 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class TitleFormat < ActiveRecord::Migration +class ApprovalWorkflowStatus < ActiveRecord::Migration def self.up - add_column :members, :title_format, :text, :null => true, :limit => 100 + add_column :dmsf_workflows, :status, :integer, :null => false, :default => DmsfWorkflow::STATUS_ACTIVE + DmsfWorkflow.all.each {|wf| wf.update_attribute(:status, DmsfWorkflow::STATUS_ACTIVE)} end def self.down - remove_column :members, :title_format + remove_column :dmsf_workflows, :status end end \ No newline at end of file diff --git a/test/fixtures/dmsf_workflows.yml b/test/fixtures/dmsf_workflows.yml index ebb4d1cf..ed0981cb 100644 --- a/test/fixtures/dmsf_workflows.yml +++ b/test/fixtures/dmsf_workflows.yml @@ -6,4 +6,9 @@ wf1: wf2: id: 2 - name: wf2 \ No newline at end of file + name: wf2 + +wf3: + id: 3 + name: wf3 + status: 0 \ No newline at end of file diff --git a/test/functional/dmsf_workflow_controller_test.rb b/test/functional/dmsf_workflow_controller_test.rb index 0564d1ee..ab220685 100644 --- a/test/functional/dmsf_workflow_controller_test.rb +++ b/test/functional/dmsf_workflow_controller_test.rb @@ -43,6 +43,7 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase @project1 = Project.find_by_id 1 @project1.enable_module! :dmsf @wf1 = DmsfWorkflow.find_by_id 1 + @wf3 = DmsfWorkflow.find_by_id 3 @wfsa2 = DmsfWorkflowStepAssignment.find_by_id 2 @revision1 = DmsfFileRevision.find_by_id 1 @revision2 = DmsfFileRevision.find_by_id 2 @@ -66,6 +67,7 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase assert_kind_of DmsfWorkflowStep, @wfs5 assert_kind_of Project, @project1 assert_kind_of DmsfWorkflow, @wf1 + assert_kind_of DmsfWorkflow, @wf3 assert_kind_of DmsfWorkflowStepAssignment, @wfsa2 assert_kind_of DmsfFileRevision, @revision1 assert_kind_of DmsfFileRevision, @revision2 @@ -133,7 +135,14 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase assert_response :forbidden end - def test_index + def test_index_administration + @request.session[:user_id] = @user_admin.id + get :index + assert_response :success + assert_template 'index' + end + + def test_index_project get :index, :project_id => @project1.id assert_response :success assert_template 'index' @@ -144,6 +153,19 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase assert_response :success assert_template 'new' end + + def test_lock + put :update, :id => @wf1.id, :dmsf_workflow => { :status => DmsfWorkflow::STATUS_LOCKED } + @wf1.reload + assert @wf1.locked?, "#{@wf1.name} status is #{@wf1.status}" + end + + def test_unlock + @request.session[:user_id] = @user_admin.id + put :update, :id => @wf3.id, :dmsf_workflow => { :status => DmsfWorkflow::STATUS_ACTIVE } + @wf3.reload + assert @wf3.active?, "#{@wf3.name} status is #{@wf3.status}" + end def test_show get :show, :id => @wf1.id @@ -153,7 +175,7 @@ class DmsfWorkflowsControllerTest < RedmineDmsf::Test::TestCase def test_create assert_difference 'DmsfWorkflow.count', +1 do - post :create, :dmsf_workflow => {:name => 'wf3'}, :project_id => @project1.id + post :create, :dmsf_workflow => {:name => 'wf4'}, :project_id => @project1.id end assert_redirected_to settings_project_path(@project1, :tab => 'dmsf_workflow') end diff --git a/test/unit/dmsf_lock_test.rb b/test/unit/dmsf_lock_test.rb index 211f97c6..e8fb63e2 100644 --- a/test/unit/dmsf_lock_test.rb +++ b/test/unit/dmsf_lock_test.rb @@ -21,8 +21,7 @@ require File.expand_path('../../test_helper.rb', __FILE__) -class DmsfLockTest < RedmineDmsf::Test::UnitTest - #attr_reader :lock +class DmsfLockTest < RedmineDmsf::Test::UnitTest fixtures :projects, :users, :email_addresses, :dmsf_folders, :dmsf_files, :dmsf_file_revisions, :roles, :members, :member_roles, :enabled_modules, :enumerations, :dmsf_locks @@ -77,6 +76,7 @@ class DmsfLockTest < RedmineDmsf::Test::UnitTest end def test_locked_folder_cannot_be_unlocked_by_someone_without_rights_or_anon + User.current = nil assert_no_difference ('@folder2.lock.count') do assert_raise DmsfLockError do @folder2.unlock! diff --git a/test/unit/dmsf_workflow_test.rb b/test/unit/dmsf_workflow_test.rb index a56b7e71..ed3cd15a 100644 --- a/test/unit/dmsf_workflow_test.rb +++ b/test/unit/dmsf_workflow_test.rb @@ -2,7 +2,7 @@ # # Redmine plugin for Document Management System "Features" # -# Copyright (C) 2011-16 Karel Picman +# Copyright (C) 2011-16 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 @@ -27,15 +27,16 @@ class DmsfWorkflowTest < RedmineDmsf::Test::UnitTest :dmsf_workflow_step_assignments, :dmsf_workflow_step_actions def setup - @wf1 = DmsfWorkflow.find_by_id(1) - @wf2 = DmsfWorkflow.find_by_id(2) - @wfs1 = DmsfWorkflowStep.find_by_id(1) - @wfs2 = DmsfWorkflowStep.find_by_id(2) - @wfs3 = DmsfWorkflowStep.find_by_id(3) - @wfs4 = DmsfWorkflowStep.find_by_id(4) - @wfs5 = DmsfWorkflowStep.find_by_id(5) - @wfsa1 = DmsfWorkflowStepAssignment.find_by_id(1) - @wfsac1 = DmsfWorkflowStepAction.find_by_id(1) + @wf1 = DmsfWorkflow.find_by_id 1 + @wf2 = DmsfWorkflow.find_by_id 2 + @wf3 = DmsfWorkflow.find_by_id 3 + @wfs1 = DmsfWorkflowStep.find_by_id 1 + @wfs2 = DmsfWorkflowStep.find_by_id 2 + @wfs3 = DmsfWorkflowStep.find_by_id 3 + @wfs4 = DmsfWorkflowStep.find_by_id 4 + @wfs5 = DmsfWorkflowStep.find_by_id 5 + @wfsa1 = DmsfWorkflowStepAssignment.find_by_id 1 + @wfsac1 = DmsfWorkflowStepAction.find_by_id 1 @revision1 = DmsfFileRevision.find_by_id 1 @revision2 = DmsfFileRevision.find_by_id 2 @project = Project.find_by_id 2 @@ -45,6 +46,7 @@ class DmsfWorkflowTest < RedmineDmsf::Test::UnitTest def test_truth assert_kind_of DmsfWorkflow, @wf1 assert_kind_of DmsfWorkflow, @wf2 + assert_kind_of DmsfWorkflow, @wf3 assert_kind_of DmsfWorkflowStep, @wfs1 assert_kind_of DmsfWorkflowStep, @wfs2 assert_kind_of DmsfWorkflowStep, @wfs3 @@ -210,4 +212,20 @@ class DmsfWorkflowTest < RedmineDmsf::Test::UnitTest assert_equal participiants.count, 2 end + def test_locked + assert @wf3.locked?, "#{@wf2.name} status is #{@wf3.status}" + end + + def test_active + assert @wf1.active?, "#{@wf1.name} status is #{@wf1.status}" + end + + def test_scope_active + assert_equal DmsfWorkflow.count, (DmsfWorkflow.active.count + 1) + end + + def test_scope_status + assert_equal 1, DmsfWorkflow.status(DmsfWorkflow::STATUS_LOCKED).count + end + end
<%=l(:field_name)%>
<%= link_to(h(workflow.name), dmsf_workflow_path(workflow)) %><%= delete_link dmsf_workflow_path(workflow) %>
<%= link_to(h(workflow.name), dmsf_workflow_path(workflow)) %> + <%= change_status_link(workflow) unless @project %> + <%= delete_link dmsf_workflow_path(workflow) %> +