To enable the creation of a user file from the registration service, workflow action 1111 must be added to the user workflow (file WEB-INF/param/workflows/user.xml).
<action id="1111" name="plugin.user-directory:WORKFLOW_ACTION_CREATE_ACCOUNT"> <pre-functions> <function type="avalon"> <arg name="role">org.ametys.web.workflow.CreateContentFunction</arg> </function> <function type="avalon"> <arg name="role">org.ametys.cms.workflow.EditContentFunction</arg> </function> </pre-functions> <results> <unconditional-result old-status=" " status=" " step="3" /> </results> <post-functions> <function type="avalon"> <arg name="role">org.ametys.cms.workflow.SetCurrentStepIdAndNotifyFunction</arg> </function> <function type="avalon"> <arg name="role">org.ametys.cms.workflow.CreateVersionFunction</arg> </function> <function type="avalon"> <arg name="role">org.ametys.web.workflow.ValidateContentFunction</arg> </function> <function type="avalon"> <arg name="role">org.ametys.cms.workflow.ValidationStepFunction</arg> </function> </post-functions> </action>
Before starting the migration, please make sure that you have done the following migration: plugin-contentIO
User synchronization action :
We've added a new parameter for entity synchronization (Source SQL entities).
This parameter is: 'User synchronization action'.
The default setting is 800. In most cases, leave 800.
For each synchronization of content of type "Source SQL of entities", click on "Modify" and then on "Save and close" to take this new parameter into account.
New user lifecycle :
A new user lifecycle has been added here
We recommend that you run all your user content through this lifecycle. View documentation
Next, define the associated i18n key and give it a name in WEB-INF/i18n/applications.xml :
<message key="WORKFLOW_user">Cycle de vie des utilisateurs</message>
Then go to script to migrate:
Warning: if you have already defined a different lifecycle for users (other than the 'contentio' lifecycle), you must adapt this script and change the worfklow name (defaultWorkflowName variable).
var defaultWorkflowName = "contentio"; var contentTypeEP = serviceManager.lookup('org.ametys.cms.contenttype.ContentTypeExtensionPoint'); var request = "@ametys-internal:contentType='org.ametys.plugins.userdirectory.Content.user'"; contentTypeEP.getSubTypes('org.ametys.plugins.userdirectory.Content.user').forEach(function(contentTypeId) { request += " or @ametys-internal:contentType='" + contentTypeId + "'" }); var qm = session.getWorkspace().getQueryManager(); var query = qm.createQuery("//element(*, ametys:content)[" + request + "]", javax.jcr.query.Query.XPATH); var nodes = query.execute().getNodes(); var nbUserChanged = 0; while (nodes.hasNext()) { var content = nodes.next(); if (content.hasNode("ametys-internal:workflows")) { var workflows = content.getNode("ametys-internal:workflows"); var workflowNodes = workflows.getNodes(); var hasChanged = false; while (workflowNodes.hasNext()) { var workflowNode = workflowNodes.next(); var workflowName = workflowNode.getProperty("oswf:workflowName").getString(); if (workflowName == defaultWorkflowName) { workflowNode.setProperty("oswf:workflowName", "user"); hasChanged = true; } } if (hasChanged) { content.save(); nbUserChanged++; } } } print(nbUserChanged + " contenu(s) 'utilisateur' changé(s)");
All that's left is to modify the synchronization of your users' content by defining the right associated life cycle:
Lifecycle for entities :
You can delete action 22 from your workflow file (WEB-INF/param/workflows/udorgunit.xml).
New fields for 'user' content:
We now have a bi-directional link between entities and users. To achieve this, we have added an "orgunits" data item to the content type org.ametys.plugins.userdirectory.Content.user.xml :
<cms:metadata name="orgunits" invert="users/user" type="content" contentType="org.ametys.plugins.userdirectory.Content.udorgunit" multiple="true"> <label i18n="true">PLUGINS_USER_DIRECTORY_CONTENT_TYPE_ORGUNITS_LABEL_TITLE</label> <description i18n="true">PLUGINS_USER_DIRECTORY_CONTENT_TYPE_ORGUNITS_LABEL_DESC</description> </cms:metadata>
In your project, your 'user' content type extends this one. You'll need to add this data to all your content type's metadataSets.
The "User" abstract type has changed.
It now provides the "user" data, which is of type "user".
For projects that have defined their own "user" content type that extends "org.ametys.plugins.userdirectory.Content.user", it will be necessary to change the content metadataset to take the "user" data into account:
If your directory users are linked to CMS users:
When you change the type of SCC, some settings will be reset. To see the old settings, you can look at the "synchronizable-collection.xml" file in the /data/config folder.
This file will be overwritten when you save.
var contentType = "org.ametys.plugin.defaultud.Content.uduser"; // TODO set this field var sccId = "utilisateurs"; // TODO set this field var fieldId = "login"; // TODO set this field var unlock = function(node) { var lockToken = node.getProperty(RepositoryConstants.METADATA_LOCKTOKEN).getString(); var lockManager = node.getSession().getWorkspace().getLockManager(); lockManager.addLockToken(lockToken); lockManager.unlock(node.getPath()); // Remove residual properties node["setProperty(java.lang.String,javax.jcr.Value)"](RepositoryConstants.METADATA_LOCKTOKEN, null); node["setProperty(java.lang.String,javax.jcr.Value)"](RepositoryConstants.METADATA_LOCKOWNER, null); node.getSession().save(); } var qm = session.getWorkspace().getQueryManager(); var query = qm.createQuery("//element(*, ametys:content)[@ametys-internal:contentType='" + contentType + "' " + "and @ametys-internal:scc = '" + sccId + "']", javax.jcr.query.Query.XPATH); var nodes = query.execute().getNodes(); var nbContent = 0; while (nodes.hasNext()) { var content = nodes.next(); if (content.isLocked()) { unlock(content); } content.setProperty("ametys:uniqueId", content.getProperty("ametys:" + fieldId).getString()); content.save(); nbContent++; } print(nbContent + " contenu(s) changé(s)"); queryPage = qm.createQuery("//element(*, ametys:defaultPage)[@ametys-internal:virtual ='org.ametys.plugins.userdirectory.page.VirtualUserDirectoryPageFactory']", javax.jcr.query.Query.XPATH); var nodePages = queryPage.execute().getNodes(); var nbPage = 0; while (nodePages.hasNext()) { var page = nodePages.next(); var metadata = page.getProperty("ametys:user-directory-root-classification-metadata").getString(); if (metadata == fieldId) { page.setProperty("ametys:user-directory-root-classification-metadata", "uniqueId"); page.save(); nbPage++; } } print(nbPage + " page(s) changée(s)");
Chances are that in your projects you have created your own helper XSLT to override the getCurrentUserContent method.
You can now remove this override and use the getCurrentUserContent core method of the helper org.ametys.plugins.userdirectory.transformation.xslt.UserXSLTHelper.
You should also remember to put this kernel helper back in your XSL in place of the project helper.
What's more, there's probably a workflow condition that's been created in your project to call up your custom Helper (this condition is often called CheckCurrentUserContentCondition)
It's no longer useful either, so you can delete it (along with its declaration in plugin.xml)
And you can call up the kernel condition again org.ametys.plugins.userdirectory.workflow.CheckCurrentUserContentCondition.
A new lifecycle action must be added to your "users" and "entities" lifecycle files. This action is called up when relationships are deleted from the directory.
You therefore need to add the common action 200 below to your lifecycle files:
Ajouter l'action suivante dans la section <common-actions>
<!-- Edit references --> <action id="200" name="plugin.user-directory:WORKFLOW_ACTION_EDIT_REFERENCES"> <restrict-to> <conditions type="AND"> <condition type="avalon"> <arg name="role">org.ametys.cms.workflow.LockCondition</arg> </condition> <condition type="avalon"> <arg name="role">org.ametys.plugins.contentio.synchronize.workflow.ValidateMetadataSynchronizeCondition</arg> <arg name="validation-step">3</arg> </condition> </conditions> </restrict-to> <results> <result old-status=" " status=" " step="1"> <conditions type="AND"> <condition type="avalon"> <arg name="role">org.ametys.cms.workflow.ContentCurrentStepCondition</arg> <arg name="step">1</arg> </condition> </conditions> <post-functions> <function type="avalon"> <arg name="role">org.ametys.cms.workflow.SetCurrentStepIdAndNotifyFunction</arg> </function> </post-functions> </result> <result old-status=" " status=" " step="2"> <conditions type="AND"> <condition type="avalon"> <arg name="role">org.ametys.cms.workflow.ContentCurrentStepCondition</arg> <arg name="step">2</arg> </condition> </conditions> <post-functions> <function type="avalon"> <arg name="role">org.ametys.cms.workflow.SetCurrentStepIdAndNotifyFunction</arg> </function> </post-functions> </result> <result old-status=" " status=" " step="3"> <conditions type="AND"> <condition type="avalon"> <arg name="role">org.ametys.cms.workflow.ContentCurrentStepCondition</arg> <arg name="step">3</arg> </condition> </conditions> <post-functions> <function type="avalon"> <arg name="role">org.ametys.plugins.contentio.synchronize.workflow.ValidateSynchronizedContentFunction</arg> </function> <function type="avalon"> <arg name="role">org.ametys.cms.workflow.ValidationStepFunction</arg> </function> </post-functions> </result> <unconditional-result old-status=" " status=" " step="1"/> </results> <post-functions> <function type="avalon"> <arg name="role">org.ametys.cms.workflow.ExtractOutgoingReferencesFunction</arg> </function> </post-functions> </action>
then add its reference for each workflow state (step):
<step id="X" name="...."> <actions> <!-- Edit Action --> <common-action id="2" /> // ... <!-- Edit references --> <common-action id="200" /> <!-- Synchronize Action --> <common-action id="800" /> <actions> </step>