approval process for 3 users 'user1 AND user2 AND user3' #432

This commit is contained in:
Karel Pičman 2015-08-09 07:52:29 +02:00
parent 2e15dd3930
commit 80dc263646
17 changed files with 134 additions and 60 deletions

View File

@ -49,9 +49,10 @@ class DmsfWorkflowsController < ApplicationController
file = DmsfFile.joins(:revisions).where(:dmsf_file_revisions => {:id => revision.id}).first
if file
begin
file.unlock!
file.unlock! true
rescue DmsfLockError => e
logger.warn e.message
flash[:info] = e.message
#logger.warn e.message
end
end
if revision.workflow == DmsfWorkflow::STATE_APPROVED
@ -287,18 +288,18 @@ class DmsfWorkflowsController < ApplicationController
step = params[:step].to_i
end
operator = (params[:commit] == l(:dmsf_and)) ? DmsfWorkflowStep::OPERATOR_AND : DmsfWorkflowStep::OPERATOR_OR
users = User.where(:id => params[:user_ids])
users = User.where(:id => params[:user_ids]).to_a
if users.count > 0
users.each do |user|
ws = DmsfWorkflowStep.new(
:dmsf_workflow_id => @dmsf_workflow.id,
:step => step,
:user_id => user.id,
:operator => operator)
ws = DmsfWorkflowStep.new
ws.dmsf_workflow_id = @dmsf_workflow.id
ws.step = step
ws.user_id = user.id
ws.operator = operator
if ws.save
@dmsf_workflow.dmsf_workflow_steps << ws
else
flash[:error] = @dmsf_workflow.errors.full_messages.to_sentence
flash[:error] = ws.errors.full_messages.to_sentence
end
end
else

View File

@ -1,8 +1,10 @@
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright (C) 2012 Daniel Munn <dan.munn@munnster.co.uk>
# Copyright (C) 2011-14 Karel Picman <karel.picman@kontorn.com>
# Copyright (C) 2011-15 Karel Pičman <karel.picman@kontorn.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@ -26,20 +28,20 @@ class DmsfLock < ActiveRecord::Base
belongs_to :folder, :class_name => 'DmsfFolder', :foreign_key => 'entity_id'
belongs_to :user
#At the moment apparently we're only supporting a write lock?
# At the moment apparently we're only supporting a write lock?
as_enum :lock_type, [:type_write, :type_other]
as_enum :lock_scope, [:scope_exclusive, :scope_shared]
# We really loosly bind the value in the belongs_to above
# We really loosely bind the value in the belongs_to above
# here we just ensure the data internal to the model is correct
# to ensure everything lists fine - it's the same as a join
# just without runing the join in the first place
# just without running the join in the first place
def file
entity_type == 0 ? super : nil;
end
# see file, exact same scenario
# See the file, exact same scenario
def folder
entity_type == 1 ? super : nil;
end
@ -57,11 +59,11 @@ class DmsfLock < ActiveRecord::Base
self.delete_all ["#{DmsfLock.table_name}.expires_at IS NOT NULL && #{DmsfLock.table_name}.expires_at < ?", Time.now]
end
#Lets allow our UUID to be searchable
# Let's allow our UUID to be searchable
def self.find(*args)
if args.first && args.first.is_a?(String) && !args.first.match(/^\d*$/)
lock = find_by_uuid(*args)
raise ActiveRecord::RecordNotFound, "Couldn't find lock with uuid=#{args.first}" if lock.nil?
raise ActiveRecord::RecordNotFound, "Couldn't find lock with uuid = #{args.first}" if lock.nil?
lock
else
super
@ -72,4 +74,4 @@ class DmsfLock < ActiveRecord::Base
self.find(*args)
end
end
end

View File

@ -25,9 +25,7 @@ class DmsfWorkflowStep < ActiveRecord::Base
validates :step, :presence => true
validates :user_id, :presence => true
validates :operator, :presence => true
validates_uniqueness_of :user_id, :scope => [:dmsf_workflow_id, :step]
attr_accessible :dmsf_workflow_id, :step, :user_id, :operator
validates_uniqueness_of :user_id, :scope => [:dmsf_workflow_id, :step]
OPERATOR_OR = 0
OPERATOR_AND = 1

View File

@ -27,7 +27,7 @@ cs:
label_dmsf_file_revision_access_plural: Přístupy k dokumentům
warning_no_entries_selected: Není nic vybráno
error_email_to_must_be_entered: Musí být zadán adresát
warning_file_already_locked: Soubor už je zamčen
warning_file_already_locked: Soubor je již zamčen
notice_file_locked: Soubor byl zamčen
warning_file_not_locked: Soubor není zamčen
notice_file_unlocked: Soubor byl odemčen
@ -317,6 +317,12 @@ cs:
notice_dmsf_link_restored: Odkaz byl úspěšně obnoven
title_restore_checked: Obnov vybrané
error_parent_folder: Nadřazený adresář neexistuje
error_resource_or_parent_locked: Nelze zamknout - zdrojový nebo nadřazený objekt je zamčený
error_parent_locked: Nelze zamknout - nadřazený objekt je zamčený
error_resource_locked: Nelze zamknout - zdrojový objekt je zamčený
error_lock_exclusively: Nelze zamknout již zamčený objekt
error_unlock_parent_locked: Nelze odemknout - nadřazený objekt je zamčený
my:
blocks:

View File

@ -318,6 +318,12 @@ de:
title_restore_checked: Restore checked
error_parent_folder: "The parent folder doesn't exist"
error_resource_or_parent_locked: Unable to complete lock - resource (or parent) is locked
error_parent_locked: Unable to complete lock - resource parent is locked
error_resource_locked: Unable to complete lock - resource is locked
error_lock_exclusively: unable to lock exclusively an already-locked resource
error_unlock_parent_locked: Unlock failed - resource parent is locked
my:
blocks:
locked_documents: Gesperrte Dateien

View File

@ -31,7 +31,7 @@ en:
notice_file_locked: File locked
warning_file_not_locked: File not locked
notice_file_unlocked: File unlocked
error_only_user_that_locked_file_can_unlock_it: Only user that locked file can unlock it
error_only_user_that_locked_file_can_unlock_it: Only user that locked the file can unlock it
error_max_files_exceeded: "Limit for %{number} simultaneously downloaded files exceeded"
error_entry_project_does_not_match_current_project: "Entry project doesn't match current project"
notice_folder_created: Folder created
@ -318,6 +318,12 @@ en:
title_restore_checked: Restore checked
error_parent_folder: "The parent folder doesn't exist"
error_resource_or_parent_locked: Unable to complete lock - resource (or parent) is locked
error_parent_locked: Unable to complete lock - resource parent is locked
error_resource_locked: Unable to complete lock - resource is locked
error_lock_exclusively: unable to lock exclusively an already-locked resource
error_unlock_parent_locked: Unlock failed - resource parent is locked
my:
blocks:
locked_documents: Locked documents

View File

@ -318,6 +318,12 @@ es:
title_restore_checked: Restaurar Seleccionados
error_parent_folder: "El directorio padre no existe"
error_resource_or_parent_locked: Unable to complete lock - resource (or parent) is locked
error_parent_locked: Unable to complete lock - resource parent is locked
error_resource_locked: Unable to complete lock - resource is locked
error_lock_exclusively: unable to lock exclusively an already-locked resource
error_unlock_parent_locked: Unlock failed - resource parent is locked
my:
blocks:
locked_documents: Documentos bloqueados

View File

@ -317,6 +317,12 @@ fr:
notice_dmsf_link_restored: Le lien a été récupéré avec succès
title_restore_checked: Restauration vérifiée
error_parent_folder: "Le dossier parent n'existe pas"
error_resource_or_parent_locked: Unable to complete lock - resource (or parent) is locked
error_parent_locked: Unable to complete lock - resource parent is locked
error_resource_locked: Unable to complete lock - resource is locked
error_lock_exclusively: unable to lock exclusively an already-locked resource
error_unlock_parent_locked: Unlock failed - resource parent is locked
my:
blocks:

View File

@ -318,6 +318,12 @@ ja:
title_restore_checked: チェックしたものを復元します
error_parent_folder: "親フォルダが存在しません"
error_resource_or_parent_locked: Unable to complete lock - resource (or parent) is locked
error_parent_locked: Unable to complete lock - resource parent is locked
error_resource_locked: Unable to complete lock - resource is locked
error_lock_exclusively: unable to lock exclusively an already-locked resource
error_unlock_parent_locked: Unlock failed - resource parent is locked
my:
blocks:
locked_documents: ロック中

View File

@ -318,6 +318,12 @@ pl:
title_restore_checked: Restore checked
error_parent_folder: "Folder nadrzędny nie istnieje"
error_resource_or_parent_locked: Unable to complete lock - resource (or parent) is locked
error_parent_locked: Unable to complete lock - resource parent is locked
error_resource_locked: Unable to complete lock - resource is locked
error_lock_exclusively: unable to lock exclusively an already-locked resource
error_unlock_parent_locked: Unlock failed - resource parent is locked
my:
blocks:
locked_documents: Dokumenty zablokowane

View File

@ -316,6 +316,12 @@ en:
notice_dmsf_link_restored: The link has been successfully restored
title_restore_checked: Restore checked
error_parent_folder: "The parent folder doesn't exist"
error_resource_or_parent_locked: Unable to complete lock - resource (or parent) is locked
error_parent_locked: Unable to complete lock - resource parent is locked
error_resource_locked: Unable to complete lock - resource is locked
error_lock_exclusively: unable to lock exclusively an already-locked resource
error_unlock_parent_locked: Unlock failed - resource parent is locked
my:
blocks:

View File

@ -318,6 +318,12 @@ ru:
title_restore_checked: Restore checked
error_parent_folder: "The parent folder doesn't exist"
error_resource_or_parent_locked: Unable to complete lock - resource (or parent) is locked
error_parent_locked: Unable to complete lock - resource parent is locked
error_resource_locked: Unable to complete lock - resource is locked
error_lock_exclusively: unable to lock exclusively an already-locked resource
error_unlock_parent_locked: Unlock failed - resource parent is locked
my:
blocks:
locked_documents: Locked documents

View File

@ -318,6 +318,12 @@ sl:
title_restore_checked: Restore checked
error_parent_folder: "The parent folder doesn't exist"
error_resource_or_parent_locked: Unable to complete lock - resource (or parent) is locked
error_parent_locked: Unable to complete lock - resource parent is locked
error_resource_locked: Unable to complete lock - resource is locked
error_lock_exclusively: unable to lock exclusively an already-locked resource
error_unlock_parent_locked: Unlock failed - resource parent is locked
my:
blocks:
locked_documents: Locked documents

View File

@ -317,6 +317,12 @@ zh-TW:
notice_dmsf_link_restored: The link has been successfully restored
title_restore_checked: Restore checked
error_parent_folder: "The parent folder doesn't exist"
error_resource_or_parent_locked: Unable to complete lock - resource (or parent) is locked
error_parent_locked: Unable to complete lock - resource parent is locked
error_resource_locked: Unable to complete lock - resource is locked
error_lock_exclusively: unable to lock exclusively an already-locked resource
error_unlock_parent_locked: Unlock failed - resource parent is locked
my:
blocks:

View File

@ -318,6 +318,12 @@ zh:
title_restore_checked: Restore checked
error_parent_folder: "The parent folder doesn't exist"
error_resource_or_parent_locked: Unable to complete lock - resource (or parent) is locked
error_parent_locked: Unable to complete lock - resource parent is locked
error_resource_locked: Unable to complete lock - resource is locked
error_lock_exclusively: unable to lock exclusively an already-locked resource
error_unlock_parent_locked: Unlock failed - resource parent is locked
my:
blocks:
locked_documents: Locked documents

View File

@ -1,7 +1,10 @@
# encoding: utf-8
#
# Redmine plugin for Document Management System "Features"
#
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright (C) 2012 Daniel Munn <dan.munn@munnster.co.uk>
# Copyright (C) 2011 Vít Jonáš <vit.jonas@gmail.com>
# Copyright (C) 2012 Daniel Munn <dan.munn@munnster.co.uk>
# Copyright (C) 2011-15 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
@ -30,9 +33,9 @@ module RedmineDmsf
def lock(tree = true)
ret = []
unless locks.empty?
locks.each {|lock|
locks.each do |lock|
ret << lock unless lock.expired?
}
end
end
if tree
ret = ret | (folder.locks.empty? ? folder.lock : folder.locks) unless folder.nil?
@ -43,20 +46,20 @@ module RedmineDmsf
def lock! scope = :scope_exclusive, type = :type_write, expire = nil
# Raise a lock error if entity is locked, but its not at resource level
existing = locks(false)
raise DmsfLockError.new("Unable to complete lock - resource (or parent) is locked") if self.locked? && existing.empty?
raise DmsfLockError.new(l(:error_resource_or_parent_locked)) if self.locked? && existing.empty?
unless existing.empty?
if existing[0].lock_scope == :scope_shared && scope == :scope_shared
# RFC states if an item is exclusively locked and another lock is attempted we reject
# if the item is shared locked however, we can always add another lock to it
if self.folder.locked?
raise DmsfLockError.new("Unable to complete lock - resource parent is locked")
raise DmsfLockError.new(l(:error_parent_locked))
else
existing.each {|l|
raise DmsfLockError.new("Unable to complete lock - resource is locked") if l.user.id == User.current.id
}
existing.each do |l|
raise DmsfLockError.new(l(:error_resource_locked)) if l.user.id == User.current.id
end
end
else
raise DmsfLockError.new("unable to lock exclusively an already-locked resource") if scope == :scope_exclusive
raise DmsfLockError.new(l(:error_lock_exclusively)) if scope == :scope_exclusive
end
end
l = DmsfLock.new
@ -75,69 +78,67 @@ module RedmineDmsf
def unlockable?
return false unless self.locked?
existing = self.lock(true)
return false if existing.empty? || (!self.folder.nil? && self.folder.locked?) #If its empty its a folder thats locked (not root)
true
# If its empty its a folder that's locked (not root)
(existing.empty? || (!self.folder.nil? && self.folder.locked?)) ? false : true
end
#
# By using the path upwards, surely this would be quicker?
def locked_for_user?(tree = true)
def locked_for_user?
return false unless locked?
b_shared = nil
heirarchy = self.dmsf_path
heirarchy.each {|folder|
heirarchy.each do |folder|
locks = folder.locks || folder.lock(false)
next if locks.empty?
locks.each {|lock|
next if lock.expired? #Incase we're inbetween updates
locks.each do |lock|
next if lock.expired? # In case we're in between updates
if (lock.lock_scope == :scope_exclusive && b_shared.nil?)
return true if (!lock.user) || (lock.user.id != User.current.id)
else
b_shared = true if b_shared.nil?
b_shared = false if lock.user.id == User.current.id
end
}
end
return true if b_shared
}
end
false
end
def unlock!
raise DmsfLockError.new("Unable to complete unlock - requested resource is not reported locked") unless self.locked?
def unlock!(force_file_unlock_allowed = false)
raise DmsfLockError.new(l(:warning_file_not_locked)) unless self.locked?
existing = self.lock(true)
if existing.empty? || (!self.folder.nil? && self.folder.locked?) #If its empty its a folder thats locked (not root)
raise DmsfLockError.new("Unlock failed - resource parent is locked")
raise DmsfLockError.new(l(:error_unlock_parent_locked))
else
# If entity is locked to you, you arent the lock originator (or named in a shared lock) so deny action
# If entity is locked to you, you aren't the lock originator (or named in a shared lock) so deny action
# Unless of course you have the rights to force an unlock
raise DmsfLockError.new("Unlock failed - resource is locked by another user") if (
self.locked_for_user?(false) &&
!User.current.allowed_to?(:force_file_unlock, self.project))
raise DmsfLockError.new(l(:error_only_user_that_locked_file_can_unlock_it)) if (
self.locked_for_user? && !User.current.allowed_to?(:force_file_unlock, self.project) && !force_file_unlock_allowed)
#Now we need to determine lock type and do the needful
# Now we need to determine lock type and do the needful
if (existing.count == 1 && existing[0].lock_scope == :exclusive)
existing[0].destroy
else
b_destroyed = false
existing.each {|lock|
existing.each do |lock|
if (lock.user && (lock.user.id == User.current.id)) || User.current.admin?
lock.destroy
b_destroyed = true
break
end
}
end
# At first it was going to be allowed for someone with force_file_unlock to delete all shared by default
# Instead, they by default remove themselves from sahred lock, and everyone from shared lock if they're not
# Instead, they by default remove themselves from shared lock, and everyone from shared lock if they're not
# on said lock
if (!b_destroyed && User.current.allowed_to?(:force_file_unlock, self.project))
if (!b_destroyed && (User.current.allowed_to?(:force_file_unlock, self.project) || force_file_unlock_allowed))
locks.delete_all
end
end
end
reload
locks.reload
end
true
end
end
end

View File

@ -35,11 +35,11 @@ class DmsfWorkflowStepTest < RedmineDmsf::Test::UnitTest
end
def test_create
wfs = DmsfWorkflowStep.new(
:dmsf_workflow_id => 1,
:step => 2,
:user_id => 3,
:operator => 1)
wfs = DmsfWorkflowStep.new
wfs.dmsf_workflow_id = 1
wfs.step = 2
wfs.user_id = 3
wfs.operator = 1
assert wfs.save
end