Technical migration manual from version 2.5.3 to version 2.6.0


  1. Modification of "mention" field import by CDMfr
  2. Publishing to a portal
  3. Duplicating a catalog
  4. Unpublish a training course from a non-web entry device ODF
    1. 1) Add the right to unpublish
    2. 2) Add workflow action
    3. Add the unpublish button
  5. Unpublish a training course from an entry device ODF-web
  6. Pedagogical elements by training catalog
    1. Add "catalog" metadata to ELPs
    2. Add workflow action to create a ELP by copy
    3. Migration of existing ELPs
    4. Addition of the "Catalog" criterion and result column to the ELPs search tool
    5. Catalog selection for the educational search service
    6. Catalog synchronization between input device and portal ODF

 

Modification of "mention" field import by CDMfr

The XML format expected for the processing of the mention has been modified:

Format expected in 2.5.3Format expected in 2.5.4
<mention type="string">Libellé de la mention</mention> 
<mention type="string" constant="MENTION">CODE_MENTION</mention> 

If you have overloaded the XSL import files for the CDMfr format, be sure to provide the expected format reference

Treatment XSL of the reference in 2.5.3Treatment XSL of the reference in 2.5.4
<xsl:template name="program-mention"> 
        <mention type="string"> 
            <xsl:choose> 
                <xsl:when test="/cdm:CDM/cdmfr:habilitation/cdmfr:field/cdmfr:fieldName/cdmfr:controlled"> 
                    <xsl:value-of select="/cdm:CDM/cdmfr:habilitation/cdmfr:field/cdmfr:fieldName/cdmfr:controlled/@fieldNameCode"/> 
                </xsl:when> 
                <xsl:when test="/cdm:CDM/cdmfr:habilitation/cdmfr:field/cdmfr:fieldName/cdmfr:free"> 
                    <xsl:value-of select="/cdm:CDM/cdmfr:habilitation/cdmfr:field/cdmfr:fieldName/cdmfr:free"/> 
                </xsl:when> 
            </xsl:choose> 
        </mention> 
</xsl:template> 
<xsl:template name="program-mention"> 
        <mention type="string" constant="MENTION"> 
            <xsl:choose> 
                <xsl:when test="/cdm:CDM/cdmfr:habilitation/cdmfr:field/cdmfr:fieldName/cdmfr:controlled"> 
                    <xsl:value-of select="/cdm:CDM/cdmfr:habilitation/cdmfr:field/cdmfr:fieldName/cdmfr:controlled/cdmfr:registeredName"/> 
                </xsl:when> 
                <xsl:when test="/cdm:CDM/cdmfr:habilitation/cdmfr:field/cdmfr:fieldName/cdmfr:free"> 
                    <xsl:value-of select="/cdm:CDM/cdmfr:habilitation/cdmfr:field/cdmfr:fieldName/cdmfr:free"/> 
                </xsl:when> 
            </xsl:choose> 
        </mention> 
    </xsl:template> 

Publishing to a portal

If you publish your training offer from an entry device ODF-Web portal to ODF, a bug caused the links to the internal pages of the entry device not to work on the portal: https: //issues.ametys.org/browse/ODF -1297

To correct this, you need to modify the WEB-INF/param/workflow-program.xml your applications ODF-Web (caution: ODF applications alone must not be modified).

In these files, find and replace org.ametys.odf.cdmfr.SendCDMFRFunction by org.ametys.plugins.odfweb.workflow.SendCDMFRFunction

Duplicating a catalog

To correct the bug https://issues.ametys.org/browse/ODF-1314you need to modify the workflow file WEB-INF/param/workflow-program.xml by adding the following action to the <initial-actions>

<initial-actions> 
 [...] 
 <!-- Create container or subprogram by copy --> 
 <action id="100" name="plugin.odf:WORKFLOW_ACTION_CREATE"> 
    <results> 
        <unconditional-result old-status=" " status=" " step="0" /> 
    </results> 
 </action> 
</initial-actions> 

Unpublish a training course from a non-web entry device ODF

This section concerns only non-Web ODF input devices, i.e. those that do not use plugin ODF -Web

A workflow action to unpublish a training course has been added in order to be able to unpublish a training course published on a ODF portal. This new action only makes sense if the entry device publishes its training courses on a ODF portal.
However, the following steps must be followed in all cases:

1) Add the right to unpublish

In the WEB-INF/param/rights.xmladd the right Workflow_Rights_Unpublish

<right id="Workflow_Rights_Unpublish"> 
 <label>APPLICATION_RIGHTS_UNPUBLISH_LABEL</label> 
 <description>APPLICATION_RIGHTS_UNPUBLISH_DESCRIPTION</description> 
 <category>plugin.cms:PLUGINS_CMS_RIGHTS_CONTENT_CATEGORY</category> 
</right> 

Add translations of the right wording and description to the WEB-INF/i18n/application.xml and WEB-INF/i18n/application_en.xml

application.xml

<message key="APPLICATION_RIGHTS_UNPUBLISH_LABEL">Dépublication</message> 
<message key="APPLICATION_RIGHTS_UNPUBLISH_DESCRIPTION">Autorise à dépublier un contenu</message>  

application_en.xml

<message key="APPLICATION_RIGHTS_UNPUBLISH_LABEL">Unpublish</message> 
<message key="APPLICATION_RIGHTS_UNPUBLISH_DESCRIPTION">Allow unpublish action on contents</message>  

2) Add workflow action

Then add workflow action no. 10 for unpublishing a course in the file WEB-INF/param/workflow-program.xml
The action is available in draft, proposed or validated states.

<common-actions> 
   [...] 
   <action id="10" name="plugin.odf:WORKFLOW_ACTION_UNPUBLISH"> 
    <restrict-to> 
         <conditions type="AND"> 
             <condition type="avalon"> 
                 <arg name="role">org.ametys.odf.workflow.ODFContentCheckRightsCondition</arg> 
                    <arg name="right">Workflow_Rights_Unpublish</arg> 
                </condition> 
                <condition type="avalon"> 
                 <arg name="role">org.ametys.cms.workflow.LockCondition</arg> 
                </condition> 
                <condition type="avalon"> 
                 <arg name="role">org.ametys.odf.workflow.ODFContentPublishedCondition</arg> 
                </condition> 
            </conditions> 
 </restrict-to> 
        <pre-functions> 
         <function type="avalon"> 
             <arg name="role">org.ametys.odf.workflow.UnpublishODFContentFunction</arg> 
            </function> 
        </pre-functions> 
        <results> 
         <unconditional-result old-status=" " status=" " step="1" /> 
        </results> 
        <post-functions> 
         <function type="avalon"> 
             <arg name="role">org.ametys.odf.cdmfr.DeleteRemoteProgramFunction</arg> 
            </function> 
       </post-functions> 
 </action> 
</common-actions> 
<step id="1" name="plugin.odf:WORKFLOW_STATE_DRAFT"> 
 <actions> 
 [...] 
 <!-- Unpublish action --> 
        <common-action id="10" /> 
 [...] 
 </actions> 
</step> 
<step id="2" name="plugin.odf:WORKFLOW_STATE_PROPOSED"> 
 <actions> 
 [...] 
 <!-- Unpublish action --> 
        <common-action id="10" /> 
 [...] 
 </actions> 
</step> 
<step id="3" name="plugin.odf:WORKFLOW_STATE_VALIDATED"> 
 <actions> 
 [...] 
 <!-- Unpublish action --> 
        <common-action id="10" /> 
 [...] 
 </actions> 
</step> 

Add the unpublish button

In the plugin.xml of your plugin default-odf-workflowFinally, add the depublication button declaration:

<extension id="org.ametys.odf.program.workflow.Unpublish" 
           point="org.ametys.cms.workspace.ribbon.RibbonControlsManager" 
           class="org.ametys.cms.clientsideelement.SmartContentClientSideElement"> 
    <action class="org.ametys.cms.ribbon.button.SmartContentButton"> 
         <param name="action">org.ametys.odf.program.Unpublish</param> 
         <param name="enable-multiselection">true</param> 
         <param name="workflow-name">.*</param> 
                
         <param name="label" i18n="true">plugin.odf:PLUGINS_ODF_UNPUBLISH_LABEL</param> 
         <param name="default-description" i18n="true">plugin.odf:PLUGINS_ODF_UNPUBLISH_DESCRIPTION</param> 
                    
         <param name="icon-small" file="true" plugin="odf">img/actions/unpublish_16.png</param> 
         <param name="icon-medium" file="true" plugin="odf">img/actions/unpublish_32.png</param> 
         <param name="icon-large" file="true" plugin="odf">img/actions/unpublish_48.png</param> 
                    
         <param name="allright-start-description" i18n="true">plugin.odf:PLUGINS_ODF_UNPUBLISH_DESCRIPTION_START</param> 
         <param name="allright-end-description" i18n="true">plugin.odf:PLUGINS_ODF_UNPUBLISH_DESCRIPTION_END</param> 
         <param name="allright-content-description" i18n="true">plugin.odf:PLUGINS_ODF_UNPUBLISH_DESCRIPTION_CONTENT</param> 
         <param name="error-description" i18n="true">plugin.odf:PLUGINS_ODF_UNPUBLISH_DESCRIPTION_ERROR</param> 
                    
         <param name="enabled-on-workflow-action-only">10</param> 
         <param name="workflowaction-start-description" i18n="true">plugin.odf:PLUGINS_ODF_UNPUBLISH_DESCRIPTION_WORKFLOWACTION_START</param> 
         <param name="workflowaction-end-description" i18n="true">plugin.odf:PLUGINS_ODF_UNPUBLISH_DESCRIPTION_WORKFLOWACTION_END</param> 
         <param name="workflowaction-content-description" i18n="true">plugin.odf:PLUGINS_ODF_UNPUBLISH_DESCRIPTION_WORKFLOWACTION_CONTENT</param> 
                    
         <param name="enabled-on-unlock-only">true</param> 
         <param name="locked-start-description" i18n="true">plugin.odf:PLUGINS_ODF_UNPUBLISH_DESCRIPTION_LOCKED_START</param> 
         <param name="locked-end-description" i18n="true">plugin.odf:PLUGINS_ODF_UNPUBLISH_DESCRIPTION_LOCKED_END</param> 
         <param name="locked-content-description" i18n="true">plugin.odf:PLUGINS_ODF_UNPUBLISH_DESCRIPTION_LOCKED_CONTENT</param> 
   </action> 
   <scripts> 
         <file plugin="cms">js/org/ametys/cms/ribbon/button/SmartContentButton.js</file> 
         <file plugin="odf">js/org/ametys/odf/program/ProgramActions.i18n.js</file> 
   </scripts> 
   <right>Workflow_Rights_Unpublish</right> 
</extension> 

The button will be available if the contributor has the right to unpublish and the course has been validated at least once.

Don't forget to add the right to unpublish to your contributors!

Unpublish a training course from an entry device ODF-web

This section only applies to ODF Web entry systems, which publish their training offer on a portal.
If you have a ODF non-web entry system, you must follow the instructions in the previous chapter.

The depublishing workflow action already exists on ODF-Web applications.

If courses are published on a portal, you simply need to add an instruction in the workflow file to remove a course from the portal, following its unpublication from the entry device.

To do this, in the workflow file WEB-INF/param/workflow-program.xml of the device, add the post-function org.ametys.odf.cdmfr.DeleteRemoteProgramFunction to depublication action n°10

<action id="10" name="plugin.web:WORKFLOW_ACTION_UNPUBLISH"> 
 [...] 
 <results> 
       <unconditional-result old-status=" " status=" " step="1" /> 
    </results> 
 <post-functions> 
        <function type="avalon"> 
         <arg name="role">org.ametys.odf.cdmfr.DeleteRemoteProgramFunction</arg> 
        </function> 
    </post-functions> 
</action> 

Pedagogical elements by training catalog

From version 2.6.0 onwards, pedagogical elements must be part of a catalog, just like training courses.

In this way, catalog duplication also duplicates teaching elements (teaching elements are no longer shared between catalogs).

Add "catalog" metadata to ELPs

The ELPs (or UE) model must contain a "catalog" metadata. If you have overloaded the ELPs model (content type org.ametys.plugins.odf.Content.course), you must add this metadata.

If you're using the standard content type for ELPs, skip to the next section.

<cms:metadata name="catalog" type="string"> 
    <label i18n="true">PLUGINS_ODF_PROGRAM_CATALOG</label> 
    <description i18n="true">PLUGINS_ODF_PROGRAM_CATALOG_DESC</description>    
    <widget>sorted-enumeration</widget>    
    <widget-params> 
         <param name="forceItemSelection">true</param> 
    </widget-params> 
    <enumeration> 
     <custom-enumerator class="org.ametys.odf.catalog.CatalogEnumerator"/> 
    </enumeration> 
</cms:metadata>        

Please do not add the reference to this new metadata in the editing view. The catalog must not be modified from the editing form, as it requires verification.

Add a reference to this metadata in the "details", "index" and "main" views in "view" mode.

<cms:metadata-set name="index" type="view"> 
    <cms:metadata-ref name="title" /> 
    <cms:metadata-ref name="keywords" /> 
    <cms:metadata-ref name="catalog" /> 
    <cms:metadata-ref name="teachingActivity" /> 
    <cms:metadata-ref name="formofteachingOrg" /> 
    <cms:metadata-ref name="formofteachingMethod" /> 
    <cms:metadata-ref name="orgUnit" /> 
    <cms:metadata-ref name="teachingTerm" /> 
    <cms:metadata-ref name="erasmusCode" /> 
    <cms:metadata-ref name="timeSlot" /> 
    <cms:metadata-ref name="teachingLocation" /> 
    <cms:metadata-ref name="level" /> 
</cms:metadata-set> 

Add workflow action to create a ELP by copy

To be able to copy ELPs when duplicating a training catalog, modify the workflow file WEB-INF/param/workflow-course.xml to add the create-by-copying action in the <initial-actions>

<initial-actions> 
 [...] 
 <!-- Create course by copy --> 
    <action id="100" name="plugin.odf:WORKFLOW_ACTION_CREATE"> 
     <results> 
         <unconditional-result old-status=" " status=" " step="1" /> 
        </results> 
    </action> 
</initial-actions> 

 

Migration of existing ELPs

Run the following script to automatically position the name of the belonging catalog on all ELPs. TheELP catalog is retrieved from the parent courses.

If a ELP is attached to several formations from different catalogs, an error message will be displayed. Migration must then be carried out manually. It will be necessary to delete theELP from one or more courses, so that theELP belongs only to courses in a single catalog. You can then run script again.

  
var qm = session.getWorkspace().getQueryManager(); 
    
var getCatalogs = function (clContainer) 
{ 
  var parentNode = clContainer; 
  var catalog = null; 
    
  while (parentNode != null && catalog == null) 
  { 
      if (parentNode.getPrimaryNodeType().getName() == 'ametys:courseContent') 
      { 
         var query = qm.createQuery("//element(*, ametys:courseList)[@ametys:coursesReferences = 'courseContent://" + parentNode.getUUID() + "']",   javax.jcr.query.Query.XPATH); 
         var clNodes = query.execute().getNodes(); 
   
         var catalogs = []; 
         while (clNodes.hasNext()) 
         { 
            var clCatalogs = getCatalogs(clNodes.next().getParent()); 
            for (var i=0; i<clCatalogs.length; i++)
            { 
                if (catalogs.indexOf(clCatalogs[i]) == -1) 
                { 
                    catalogs.push(clCatalogs[i]); 
                } 
            } 
         } 
         return catalogs; 
      } 
      else if (parentNode.getPrimaryNodeType().getName() == 'ametys:programContent') 
      { 
          catalog = parentNode.getProperty("ametys:catalog").getString() + ''; 
      } 
      else 
      { 
          parentNode = parentNode.getParent(); 
      } 
  } 
    
  return catalog != null ? [catalog] : []; 
} 
   
var processCourse = function (course) 
{ 
    if (!course.hasProperty("ametys:catalog")) 
    { 
        var query = qm.createQuery("//element(*, ametys:courseList)[@ametys:coursesReferences = 'courseContent://" + course.getUUID() + "']",   javax.jcr.query.Query.XPATH); 
        var clNodes = query.execute().getNodes(); 
   
        var catalog = null; 
        while (clNodes.hasNext()) 
        { 
            var clCatalogs = getCatalogs(clNodes.next().getParent()); 
            if (catalog == null && clCatalogs.length == 1) 
            { 
                catalog = clCatalogs[0]; 
            } 
            else if (clCatalogs.length > 1 || clCatalogs[0] != catalog) 
            { 
 var title = course.getProperty("ametys:title").getString(); 
                var code = course.getProperty("ametys:elpCode").getString(); 
 print("ERROR >> L'ELP " + title + " (" + code  + ") est référencée par plusieurs listes appartenant à des catalogues différents => migration impossible"); 
                catalog = null; 
                break; 
            } 
        } 
   
        if (catalog != null) 
        { 
          course.setProperty("ametys:catalog", catalog); 
          course.save(); 
          return true; 
        } 
          
    } 
    return false; 
} 
    
// Default workspace 
var query = qm.createQuery("//element(*, ametys:courseContent)[not(@ametys:catalog)]", javax.jcr.query.Query.XPATH); 
var nodes = query.execute().getNodes(); 
        
var count = 0; 
while (nodes.hasNext()) 
{ 
    if (processCourse(nodes.next())) 
    { 
        count++; 
    } 
} 
print(count + " ELPs ont été mises à jour dans le workspace 'default'"); 

After running script, go to the back office and check that all ELPs are in the "Validated" state.
Validate all ELPs that are not in the validated state!

Then run the following script to correctly reflect the changes for the "Live" label.

var query = session.getWorkspace().getQueryManager().createQuery("//element(*, ametys:courseContent)", javax.jcr.query.Query.XPATH); 
var nodes = query.execute().getNodes(); 
     
var count = 0; 
while (nodes.hasNext()) 
{ 
    var node = nodes.next(); 
    node.checkin(); 
    node.checkout(); 
       
    var versionName = node.getBaseVersion().getName(); 
    node.getVersionHistory().addVersionLabel(versionName, "Live", true); 
    count++; 
} 
print(count + " courses have been checkpoint"); 

Addition of the "Catalog" criterion and result column to the ELPs search tool

If you have overloaded the BO search model with educational elements, you need to add the "Catalog" search criterion and the result column.

If you're using the standard search engine, skip to the next section.

Criteria definition and search column

<search-criteria> 
 [...] 
 <criteria name="catalog" type="string" column="1"> 
    <label i18n="true">PLUGINS_ODF_UITOOL_PROGRAM_CATALOG</label> 
    <test-operator>eq</test-operator> 
    <enumeration> 
        <custom-enumerator class="org.ametys.odf.catalog.CatalogEnumerator"> 
            <all-option>blank</all-option> 
        </custom-enumerator> 
    </enumeration> 
    <widget>sorted-enumeration</widget> 
 </criteria> 
 [...] 
<search-criteria> 
<property-mapping> 
    <property id="id" path="@id"/> 
    <property id="language" path="@language"/> 
    <property id="language-image" path="@language-image"/> 
    <property id="title" path="metadata/title"/> 
    <property id="catalog" path="metadata/catalog"/> 
 [...] 
</property-mapping> 
<columns> 
 [...] 
 <column id="catalog"> 
       <label i18n="true">PLUGINS_ODF_UITOOL_PROGRAM_CATALOG</label> 
       <width>150</width> 
    </column> 
 [...] 
</columns> 

Catalog selection for the educational search service

If you are using the "Search for a pedagogical element" service, you need to set the parameters to define the search catalog.

Catalog synchronization between input device and portal ODF

The name of the catalog linked to a teaching element is available in the export. CDM-fr Ametys

<course id="FRUAI3182988BCOH6YRY93H" language="fr"> 
    <courseID>FRUAI3182988BCOH6YRY93H</courseID> 
    <courseName> 
      <text>Histoire ancienne 3</text> 
    </courseName> 
    [...] 
    <infoBlock userDefined="ametys-extension"> 
      <extension> 
        <ametys-cdm:catalog value="2013-2017">Catalogue 2013-2017</ametys-cdm:catalog> 
      </extension> 
    </infoBlock> 
</course> 

When importing a course from a XML CDM-fr feed, the following rules apply:

  • if the catalog is not present or empty in CDM-fr, theELP is directly assigned to the catalog of the imported or synchronized course.
  • if the catalog is non-empty,
    • and it is identical to that of the imported course, theELP is imported or synchronized.
    • and it is different from that of the imported course, an error is raised and theELP is neither imported nor synchronized.

Please note that if you are in "remote" (Portal) synchronization mode, and you have forced the import catalog in the configuration parameters, the value contained in CDM-fr will be ignored. Training courses and ELPs will automatically be assigned to the catalog defined in the configuration parameter.

 

 

 

 

 

 

 

Back to top