Community
Vault Forum
Welcome to Autodesk’s Vault Forums. Share your knowledge, ask questions, and explore popular Vault topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Lifecycle (four-eyes-principle)

17 REPLIES 17
Reply
Message 1 of 18
bjr001
2027 Views, 17 Replies

Lifecycle (four-eyes-principle)

Trying to customizie a lifecycle, I'm wondering how to implement a "four-eyes-principle". What that means? Here a short example: We have two persons (A and B). Person A changes the state from "Work in Progress"  to "For Review". Now Person A must not change the state to "Released". And that's were Person B comes into play who can change to "Released". With this principle, they keep each other safe.

 

So is there a possibilty to implement something like that with the criteria of the relative transition?

For example in PSP there was an condition like "!wcomp("$USERD","#STATUS_CHG_USER") .

 

Any ideas?

17 REPLIES 17
Message 2 of 18
broepke
in reply to: bjr001

This is pretty straight forward.  Simply edit the "Transition" security to tell the Lifecycle who is allowed to make the change.  You'll notice on the transitions tab there are a series of "from <> to" arrows between the states.  Here what you're basically telling the system is that "Person A" has the ability to move from WIP to Reivew but only "Person B" can make the change to released.

 

There is a great series out there that details how to configure this.  Check it out.  The section you're looking for seems to be in Video 4 around the 5:00 mark.  I would however watch the whole thing because it has a ton of information.

 

http://www.youtube.com/watch?v=OcSEgbBe6rI&feature=&p=E90F2AD408C2ED29&index=0&playnext=1

 

Enjoy



Brian Roepke
Director, Analytics & Insights
Message 3 of 18
bjr001
in reply to: bjr001

Thanks for your answer, but I guess  you've missunderstood me. 

Also Person B can be the one who changes the state vom "WIP" to "For Review" but must not change to "Released".

 

 

So for the transition from "For Review" to "Released" I need a query like:

check if person who wants to change the status to "Released" isn't the same person who made the change to "For Review"

Message 4 of 18
broepke
in reply to: bjr001

Got it... so... There is a "fixed" person that change it from one to another... it just has to be the person that wasn't the one who made the previous change.

 

I don't know if there is a way to do this without customization; you should be able to do this via the client SDK if you're able to write some code.



Brian Roepke
Director, Analytics & Insights
Message 5 of 18
Redmond.D
in reply to: bjr001

There is no way to do what you want in Vault 2011.  We are aware of this issue and are working to address it sometime in the future.



Doug Redmond
Software Engineer
Autodesk, Inc.

Message 6 of 18
bjr001
in reply to: Redmond.D

That's pretty bad. Thanks anyway.

Message 7 of 18
mikel_martin
in reply to: bjr001

There is a way to do this but it is not straight forward and could get complicated if you had many users.

The following is an email that I returned to someone else that had simular question.

Hope it helps.

___

 

There might be away to make this work in Vault Workgroup.

It would be a little strange and was not really the intent when the feature was designed.

 

When you do a change state the transitions dictates who can move from one state to another.

Each state has a transition for each of the states in the lifecycle def.

For example there is a transition that goes from WIP to Review and one that goes from WIP to Released.

However, in most cases the transition from WIP to Released is blocked via the transition security.

When it is not available to a given user the user will not see that state as an option in the change state command.

 

The unique problem that you have is that you want this transition to be variable depending on who put the file into the state.

This is not possible. However, what if there were multiple Review states? For example what if User 1 had the right to transition from WIP to Review1 but did not have the right to transition from WIP to Review2. When User1 did a change state he would only see Review1 as a valid option in the command.

 

To continue this scenario, what if user1 did not have access to transition from Review1 to Released but did have rights to transition from Review2 to Released. In this scenario User1 could never release anything that he put into a Review state.

 

As far as I know this type of implementation has never been put into production. But in theory it could solve your customer need.

___



Mikel Martin
User Experience Architect
Autodesk, Inc.
Message 8 of 18
AlexFielder
in reply to: mikel_martin

Is this a feature that is now available in Vault? If so, in what version was it implemented as I am having to (due to our small team size) look at setting up exactly this (four-eyes) scenario.

 

Thanks,


Alex.

Message 9 of 18
mikel_martin
in reply to: AlexFielder

There has been no change in this area of the product.



Mikel Martin
User Experience Architect
Autodesk, Inc.
Message 10 of 18
AlexFielder
in reply to: mikel_martin

Hi Mikel,

 

I just found this post by Doug Redmond, I don't suppose you or he can tell me if the (really surprisingly simple) piece of code he posted there will work in Vault Pro 2014?

 

Thanks,

 

Alex.

Message 11 of 18
Redmond.D
in reply to: AlexFielder

Some minor adjustments are needed for the code to work with Vault 2014.  The code also needs to be compiled and deployed as a plug-in.

 

Another option is the Vault Enterprise Add-on, which includes a 4-eyes check.



Doug Redmond
Software Engineer
Autodesk, Inc.

Message 12 of 18
AlexFielder
in reply to: Redmond.D

Thanks Doug,

 

That Enterprise Add-on might be something we consider in the future, but in the meantime here is my modified version of the FourEyes.cs file you posted (for anyone else that would like to implement this in Vault Pro 2014):

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Autodesk.Connectivity.Explorer.Extensibility;
using Autodesk.Connectivity.WebServices;
using Autodesk.Connectivity.WebServicesTools;
using Autodesk.Connectivity.Extensibility.Framework;

[assembly: ApiVersion("6.0")]
[assembly: ExtensionId("6B41BDD4-1D98-4072-9005-2D790AACA998")]

namespace Speccy
{
    public class FourEyesChecker : IWebServiceExtension
    {
        // implement IWebServiceExtension
        public void OnLoad()
        {
            DocumentServiceExtensions.UpdateFileLifecycleStateEvents.GetRestrictions += new EventHandler<UpdateFileLifeCycleStateCommandEventArgs>(UpdateFileLifecycleStateEvents_GetRestrictions);
        }

        // event handler
        void UpdateFileLifecycleStateEvents_GetRestrictions(
            object sender, UpdateFileLifeCycleStateCommandEventArgs e)
        {
            try
            {
                IWebService service = sender as IWebService;
                if (service == null)
                    return;
                WebServiceCredentials cred = new WebServiceCredentials(service);
                //WebServiceCredentials_bugfix cred = new WebServiceCredentials_bugfix(service);
                using (WebServiceManager mgr = new WebServiceManager(cred))
                {
                    long currentUserId = mgr.SecurityService.SecurityHeader.UserId;

                    LfCycDef[] defs =
                        mgr.DocumentServiceExtensions.GetAllLifeCycleDefinitions();
                    //LfCycDef releaseProcess = defs.FirstOrDefault(
                    //    n => n.SysName == "Flexible Release Process");
                    LfCycDef releaseProcess = defs.FirstOrDefault(
                        n => n.SysName == "Basic Release Process");

                    LfCycState reviewState =
                        releaseProcess.StateArray.FirstOrDefault(
                        n => n.DispName == "For Review");

                    LfCycState releaseState =
                        releaseProcess.StateArray.FirstOrDefault(
                        n => n.DispName == "Released");

                    FileArray[] fileCollection =
                        mgr.DocumentService.GetFilesByMasterIds(e.FileMasterIds);

                    for (int i = 0; i < fileCollection.Length; i++)
                    {
                        CheckFile(fileCollection[i].Files, e.ToStateIds[i],
                            currentUserId, reviewState, releaseState, e);
                    }
                }
            }
            catch { }
        }

        // checks for a four eyes violation for a given file history
        private void CheckFile(File[] files, long toStateId,
            long currentUserId, LfCycState reviewState,
            LfCycState releaseState, WebServiceCommandEventArgs eventArgs)
        {
            // if we are not moving to released, don't event bother with the check
            if (toStateId != releaseState.Id)
                return;

            File maxFile = files.First(n => n.MaxCkInVerNum == n.VerNum);
            if (maxFile.FileRev == null)
                return;

            // gather all the files in the revision and arrange them by version
            IEnumerable<File> filesInRev =
                from n in files
                where n.FileRev.RevId == maxFile.FileRev.RevId
                orderby n.VerNum
                select n;

            File[] filesArray = filesInRev.ToArray();

            long reviewUserId = -1;
            for (int i = 1; i < filesArray.Length; i++)
            {
                File f1 = filesArray[i - 1];
                File f2 = filesArray[i];

                // compare two concecutive file versions to determine 
                // where a state changed happened
                if (f1.FileLfCyc != null && f2.FileLfCyc != null &&
                    f1.FileLfCyc.LfCycStateName != f2.FileLfCyc.LfCycStateName &&
                    f2.VerNum - f1.VerNum == 1)
                {
                    // f2 is a version where the state changed
                    if (f2.FileLfCyc.LfCycStateName == reviewState.DispName)
                        reviewUserId = f2.CreateUserId;
                }
            }

            if (reviewUserId > 0 && currentUserId == reviewUserId)
            {
                // the same person reviewed the file in an earlier version
                eventArgs.AddRestriction(
                    new ExtensionRestriction(maxFile.Name,
                    "File cannot be reviewed and released by the same person"));
            }
        }
    }
}

As you can see I didn't have to change that much really.

 

Here are the contents of the Speccy.vcet.config file:

 

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectivity.ExtensionSettings3>
    <extension
      interface="Autodesk.Connectivity.WebServices.IWebServiceExtension, Autodesk.Connectivity.WebServices, Version=18.0.0.0, Culture=neutral, PublicKeyToken=aa20f34aedd220e1"
      type="Speccy.FourEyesChecker, Speccy">
    </extension>
  </connectivity.ExtensionSettings3>
</configuration>

I had a bit of bother getting the event to fire and subsequently be able to debug things but it was because I'd originally copied the above from the "HelloWorld" API sample and that uses the IExplorerExtension as opposed to the IWebServiceExtension used in this example. 

 

I notice however that the event doesn't (seem to) fire if the user selects (and Changes the State of) a project folder- is that by design? 

 

Thanks again,

 

Alex.

Message 13 of 18
Redmond.D
in reply to: AlexFielder

Sorry, there is no event for folder lifecycle state change, but I'll pass the suggestion on to the Vault team.



Doug Redmond
Software Engineer
Autodesk, Inc.

Message 14 of 18
AlexFielder
in reply to: Redmond.D

Hi All,

 

Here's my amended Four Eyes code that works in Vault Pro 2014:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using Autodesk.Connectivity.Explorer.Extensibility;
using Autodesk.Connectivity.Extensibility.Framework;
using Autodesk.Connectivity.WebServices;
using Autodesk.Connectivity.WebServicesTools;
using VDF = Autodesk.DataManagement.Client.Framework;
using Autodesk.Connectivity.JobProcessor.Extensibility;


//There are  5 assembly attributes you need to have in your code:
//Items 1-3 are provided by Visual Studio in the AssemblyInfo file.  
//You just need to check that they have accurate data.  
//Items 4 and 5 need to be created by you.

//[assembly: AssemblyCompany("Your Company")]
//[assembly: AssemblyProduct("FourEyes")]
//[assembly: AssemblyDescription("Your assembly description")]
//For Autodesk Vault 2014, ApiVersion is "6.0"
[assembly: ApiVersion("6.0")]
[assembly: ExtensionId("ded8a16c-842b-461f-bf19-44839fd50a05")]

namespace FourEyes
{
    //if you rename this class name, please make sure change accordingly in vaultplugin.vcet.config
    public class Class1 : IWebServiceExtension
    {
        #region "FourEyes"
        #region IWebServiceExtension implementation
        public void OnLoad()
        {
            DocumentServiceExtensions.UpdateFileLifecycleStateEvents.GetRestrictions += new EventHandler<UpdateFileLifeCycleStateCommandEventArgs>(UpdateFileLifecycleStateEvents_GetRestrictions);
        }
        #endregion
        // event handler
        
        private long relProcess = 0;

        void UpdateFileLifecycleStateEvents_GetRestrictions(
            object sender, UpdateFileLifeCycleStateCommandEventArgs e)
        {
            try
            {
                IWebService service = sender as IWebService;
                if (service == null)
                    return;
                WebServiceCredentials cred = new WebServiceCredentials(service);
                //WebServiceCredentials_bugfix cred = new WebServiceCredentials_bugfix(service);
                using (WebServiceManager mgr = new WebServiceManager(cred))
                {
                    long currentUserId = mgr.SecurityService.SecurityHeader.UserId;
                    FileArray[] fileCollection = mgr.DocumentService.GetFilesByMasterIds(e.FileMasterIds);
                    //checks the lifecycle of the first file we are changing the state of.
                    CheckFile(fileCollection[0].Files);

                    LfCycDef[] defs = mgr.DocumentServiceExtensions.GetAllLifeCycleDefinitions();

                    LfCycDef releaseProcess = defs.FirstOrDefault(n => n.Id == relProcess);

                    LfCycState reviewState = null;
                    LfCycState releaseState = null;

                    switch (releaseProcess.DispName)
                    {
                        case "Basic Release Process": //just for testing with one of the default Release Processes
                            reviewState = releaseProcess.StateArray.FirstOrDefault(n => n.DispName == "For Review");
                            releaseState = releaseProcess.StateArray.FirstOrDefault(n => n.DispName == "Released");
                            break;
                        case "Client Legacy Release Process":
                            reviewState = releaseProcess.StateArray.FirstOrDefault(n => n.DispName == "For Review");
                            releaseState = releaseProcess.StateArray.FirstOrDefault(n => n.DispName == "Released");
                            break;
                        case "Client Project Release Process":
                            reviewState = releaseProcess.StateArray.FirstOrDefault(n => n.DispName == "Internal Review");
                            releaseState = releaseProcess.StateArray.FirstOrDefault(n => n.DispName == "Customer Approval");
                            break;
                        case "Company Release Process":
                            reviewState = releaseProcess.StateArray.FirstOrDefault(n => n.DispName == "For Review");
                            releaseState = releaseProcess.StateArray.FirstOrDefault(n => n.DispName == "Sign & Release");
                            break;
                        default:
                            break;
                    }

                    for (int i = 0; i < fileCollection.Length; i++)
                    {
                        CheckFile(fileCollection[i].Files, e.ToStateIds[i],currentUserId, reviewState, releaseState, e);
                    }
                }
            }
            catch { }
        }

        private void CheckFile(File[] files)
        {
            // we don't care about states or anything else at this point only that the latest version of the file(s) selected have a lifecycle assigned to them and what it is.
            File maxFile = files.First(n => n.MaxCkInVerNum == n.VerNum);
            if (maxFile.FileRev == null)
                return;

            // gather all the files in the revision and arrange them by version
            IEnumerable<File> filesInRev =
                from n in files
                where n.FileRev.RevId == maxFile.FileRev.RevId
                orderby n.VerNum
                select n;

            File[] filesArray = filesInRev.ToArray();

            for (int i = 1; i < filesArray.Length; i++)
            {
                File f2 = filesArray[i];
                if (f2.FileLfCyc != null)
                {
                    // f2 is a version where the state changed
                    relProcess = f2.FileLfCyc.LfCycDefId;
                    continue;
                }
            }
        }

        // checks for a four eyes violation for a given file history
        private void CheckFile(File[] files, long toStateId,
            long currentUserId, LfCycState reviewState,
            LfCycState releaseState, WebServiceCommandEventArgs eventArgs)
        {
            // if we are not moving to released, don't event bother with the check
            if (toStateId != releaseState.Id)
                return;

            File maxFile = files.First(n => n.MaxCkInVerNum == n.VerNum);
            if (maxFile.FileRev == null)
                return;

            // gather all the files in the revision and arrange them by version
            IEnumerable<File> filesInRev =
                from n in files
                where n.FileRev.RevId == maxFile.FileRev.RevId
                orderby n.VerNum
                select n;

            File[] filesArray = filesInRev.ToArray();

            long reviewUserId = -1;
            for (int i = 1; i < filesArray.Length; i++)
            {
                File f1 = filesArray[i - 1];
                File f2 = filesArray[i];

                // compare two concecutive file versions to determine 
                // where a state changed happened
                if (f1.FileLfCyc != null && f2.FileLfCyc != null &&
                    f1.FileLfCyc.LfCycStateName != f2.FileLfCyc.LfCycStateName &&
                    f2.VerNum - f1.VerNum == 1)
                {
                    // f2 is a version where the state changed
                    if (f2.FileLfCyc.LfCycStateName == reviewState.DispName)
                        reviewUserId = f2.CreateUserId;
                }
            }

            if (reviewUserId > 0 && currentUserId == reviewUserId)
            {
                // the same person reviewed the file in an earlier version
                eventArgs.AddRestriction(
                    new ExtensionRestriction(maxFile.Name,
                    "File cannot be reviewed and released by the same person"));
            }
        }
        #endregion
    }
}

This project was setup/installed using the Visual Studio Wizard Doug posted here:

 

http://adndevblog.typepad.com/manufacturing/2014/01/autodesk-vault-plug-in-wizard-helps-creating-vau...

 

Questions/comments?

 

Message 15 of 18
mpatchus
in reply to: AlexFielder

We have worked around this by giving our users who perform multiple roles, separate log-ins for each role.

The security is assigned at the group level.

 

Designer Group can take the state WIP to Ready For Approval (user utilizes his normal windows account).

QA Group can take the state Ready For Approval to Released (user utilizes his QA_user vault account).

 

The user simply logs in using the appropriate user account for the role he is performing.

 

That being said, technically a user could promote his own work to Released even with this workflow.

However, users know that they are not to advance their own work, and within Vault it can be traced.

We've not had any issues in this area to date.

Folks police themselves.

 

Mike Patchus - Lancaster SC

Inventor 2025 Beta


Alienware m17, Intel(R) Core(TM) i9-10980HK CPU @ 2.40GHz 3.10 GHz, Win 11, 64gb RAM, NVIDIA GeForce RTX 2080 Super

Did you find this reply helpful ? If so please use the Accept as Solution or Kudos button below. 🙂
Message 16 of 18
Leon.VASSE
in reply to: bjr001

Hi there!

 

Since this thread has been opened, the Four EyesPolicy Addin (thx Doug!) may have been further developed to include the below requirement, so correct me whenever I am wrong.

 

After implementing the Four EyesPolicy Addin, how to make appear both User A and User B in the Vault Revision Table?

 

Roles reminder:

-User A: changed the file state from "Work in Progress"  to "For Review"

-User B: changed the file state from "For Review" to "Released"

 

So far, modifying a property during a lifecycle transition can be performed only via a Custom Job, which is pretty tough for me.

 

Some availableproperties that can be mapped to the Vault Revision Table:

-Originator: System property set at the file very first check-in, but never updated on further file versions/revisions > it cannot be used to identify User A (who is not fixed forever all along the file life)

-Created By: System property set up and updated at the file each check-in > it can be mapped in the Revision Table to identify User B

-Author: User-defined property mapped to the file eponymous property (I don't know which software applies which rule to fill it at file creation , save or save as, but this property remains editable)

 

Considering Inventor files (for AutoCAD or Office files, I suppose the following is not applicable?), can an iLogic rule, applied to "All documents", be triggered at "Before Save document", so as to update the Author iProperty with the current Username > Author could then be mapped in the Revision Table to identify User A?

 

This said, and provided such workflows is possible, as an iLogic newbee,  where can I find iLogic examples:

1) to retrieve the Username value

2) to set an iProperty value

 

Best regards,

Message 17 of 18
Leon.VASSE
in reply to: Leon.VASSE

Like this seems to work fine:

'iLogic rule to be triggered at "Before Save Document" event
Try
	iProperties.Value("Project", "Author") = Environment.UserName
	Catch
End Try

 

Message 18 of 18
Leon.VASSE
in reply to: Leon.VASSE

iProperties.Value("Summary", "Author")

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report