approval process for 3 users 'user1 AND user2 AND user3' #432
This commit is contained in:
parent
2e15dd3930
commit
80dc263646
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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: ロック中
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user