### Eclipse Workspace Patch 1.0
#P Ametys - Plugin ODF
Index: main/plugin-odf/plugin.xml
===================================================================
--- main/plugin-odf/plugin.xml	(revision 16258)
+++ main/plugin-odf/plugin.xml	(working copy)
@@ -365,6 +365,23 @@
         </components>
     </feature>  
     
+    <!-- Dépôt dans un dossier -->
+    <feature name="workflow.depositcdmfr.onvalidation">
+        <components>
+			<component role="org.ametys.odf.cdmfr.DepositCDMFRFunction"
+					   class="org.ametys.odf.cdmfr.DepositCDMFRFunction"/>
+        </components>
+        
+        <config>
+			<param type="string" id="odf.publish.output.folder">
+				<label i18n="true">PLUGINS_ODF_CONFIG_OUTPUT_FOLDER</label>
+	            <description i18n="true">PLUGINS_ODF_CONFIG_OUTPUT_FOLDER_DESC</description>
+	            <category i18n="true">PLUGINS_ODF_CONFIG_CATEGORY</category>
+	            <group i18n="true">PLUGINS_ODF_CONFIG_GROUP_OUTPUT_FOLDER</group>
+			</param>
+		</config>
+    </feature>
+    
     <!-- Synchronisation avec un serveur distant -->
     <feature name="workflow.sendcdmfr.onvalidation">
         <components>
Index: main/plugin-odf/src/org/ametys/odf/cdmfr/DepositCDMFRFunction.java
===================================================================
--- main/plugin-odf/src/org/ametys/odf/cdmfr/DepositCDMFRFunction.java	(revision 0)
+++ main/plugin-odf/src/org/ametys/odf/cdmfr/DepositCDMFRFunction.java	(revision 0)
@@ -0,0 +1,115 @@
+/*
+ *  Copyright 2012 Anyware Services
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.ametys.odf.cdmfr;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Map;
+
+import org.apache.avalon.framework.activity.Initializable;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceResolver;
+
+import org.ametys.cms.repository.WorkflowAwareContent;
+import org.ametys.cms.workflow.AbstractContentWorkflowComponent;
+import org.ametys.odf.program.Program;
+import org.ametys.plugins.repository.AmetysRepositoryException;
+import org.ametys.runtime.config.Config;
+
+import com.opensymphony.module.propertyset.PropertySet;
+import com.opensymphony.workflow.FunctionProvider;
+import com.opensymphony.workflow.WorkflowException;
+
+/**
+ * Send CDM-fr to distant server
+ *
+ */
+public class DepositCDMFRFunction extends AbstractContentWorkflowComponent implements FunctionProvider, Initializable
+{
+    private String _outputFolder;
+    private SourceResolver _sourceResolver;
+    
+    @Override
+    public void service(ServiceManager manager) throws ServiceException
+    {
+        super.service(manager);
+        _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
+    }
+    
+    @Override
+    public void initialize() throws Exception
+    {
+        // Récupérer l'adresse d'envoi en config
+        _outputFolder = Config.getInstance().getValueAsString("odf.publish.output.folder");
+    }
+
+    @Override
+    public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException
+    {
+        if (StringUtils.isNotEmpty(_outputFolder))
+        {
+            // Retrieve current content
+            WorkflowAwareContent content = getContent(transientVars);
+            
+            OutputStream os = null;
+            InputStream is = null;
+            try
+            {
+                // Generate CDM-FR file
+                Source cdmfrSource = _sourceResolver.resolveURI("cocoon://_plugins/odf/export-cdmfr.xml?id=" + content.getId());
+    
+                // Save file
+                is = cdmfrSource.getInputStream();
+                String filename = ((Program) content).getCode() + ".xml";
+                File file = new File(_outputFolder, filename);
+                if (file.exists())
+                {
+                    file.delete();
+                }
+                file.createNewFile();
+                os = new FileOutputStream(file);
+                byte[] bytes = new byte[1024];
+                int l;
+                while ((l = is.read(bytes)) > 0)
+                {
+                    os.write(bytes, 0, l);
+                }
+            }
+            catch (AmetysRepositoryException e)
+            {
+                _logger.error("Unable to get content id", e);
+                throw new WorkflowException("Unable to get content id", e);
+            }
+            catch (IOException e)
+            {
+                _logger.error("Unable to get front url", e);
+                transientVars.put("portalError", true);
+            }
+            finally
+            {
+                IOUtils.closeQuietly(is);
+                IOUtils.closeQuietly(os);
+            }
+        }
+    }
+}
Index: main/plugin-odf/src/org/ametys/odf/cdmfr/SendCDMFRFunction.java
===================================================================
--- main/plugin-odf/src/org/ametys/odf/cdmfr/SendCDMFRFunction.java	(revision 16258)
+++ main/plugin-odf/src/org/ametys/odf/cdmfr/SendCDMFRFunction.java	(working copy)
@@ -27,6 +27,7 @@
 import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
 import org.apache.excalibur.source.Source;
 import org.apache.excalibur.source.SourceResolver;
 import org.apache.http.HttpEntity;
@@ -75,37 +76,40 @@
     @Override
     public void execute(Map transientVars, Map args, PropertySet ps) throws WorkflowException
     {
-        // Retrieve current content
-        WorkflowAwareContent content = getContent(transientVars);
-        
-        InputStream is = null;
-        try
+        if (StringUtils.isNotEmpty(_serverUrl))
         {
-            // Generate CDM-FR file
-            Source cdmfrSource = _sourceResolver.resolveURI("cocoon://_plugins/odf/export-cdmfr.xml?id=" + content.getId());
-
-            // Send to remote server
-            is = cdmfrSource.getInputStream();
+            // Retrieve current content
+            WorkflowAwareContent content = getContent(transientVars);
             
-            if (!callWS("plugins/odf-sync/upload-cdm", is))
+            InputStream is = null;
+            try
+            {
+                // Generate CDM-FR file
+                Source cdmfrSource = _sourceResolver.resolveURI("cocoon://_plugins/odf/export-cdmfr.xml?id=" + content.getId());
+    
+                // Send to remote server
+                is = cdmfrSource.getInputStream();
+                
+                if (!callWS("plugins/odf-sync/upload-cdm", is))
+                {
+                    transientVars.put("portalError", true);
+                    _logger.error("The program " + content.getId() + " can't be synchronized with portal " + _serverUrl);
+                }
+            }
+            catch (AmetysRepositoryException e)
+            {
+                _logger.error("Unable to get content id", e);
+                throw new WorkflowException("Unable to get content id", e);
+            }
+            catch (IOException e)
             {
+                _logger.error("Unable to get front url", e);
                 transientVars.put("portalError", true);
-                _logger.error("The program " + content.getId() + " can't be synchronized with portal " + _serverUrl);
             }
-        }
-        catch (AmetysRepositoryException e)
-        {
-            _logger.error("Unable to get content id", e);
-            throw new WorkflowException("Unable to get content id", e);
-        }
-        catch (IOException e)
-        {
-            _logger.error("Unable to get front url", e);
-            transientVars.put("portalError", true);
-        }
-        finally
-        {
-            IOUtils.closeQuietly(is);
+            finally
+            {
+                IOUtils.closeQuietly(is);
+            }
         }
     }
     
Index: main/plugin-odf/i18n/messages_en.xml
===================================================================
--- main/plugin-odf/i18n/messages_en.xml	(revision 16258)
+++ main/plugin-odf/i18n/messages_en.xml	(working copy)
@@ -167,6 +167,13 @@
 	<message key="PLUGINS_ODF_CONFIG_REMOTE_PASSWORD_DESC">Mot de passe pour se connecter au serveur distant</message>
 	
 	<!-- +
+		 | DEPOT
+	 	 + -->
+	<message key="PLUGINS_ODF_CONFIG_GROUP_OUTPUT_FOLDER">Dépôt dans un dossier</message>
+	<message key="PLUGINS_ODF_CONFIG_OUTPUT_FOLDER">Dossier de dépôt</message>
+	<message key="PLUGINS_ODF_CONFIG_OUTPUT_FOLDER_DESC">Chemin du dossier vers lequel les formations validées seront exportées.</message>
+	
+	<!-- +
 		 | RIBBON ODF
 		 + -->
     <message key="RIBBON_TABS_TAB_ODF_LABEL">Training offer</message>
Index: main/plugin-odf/i18n/messages_fr.xml
===================================================================
--- main/plugin-odf/i18n/messages_fr.xml	(revision 16258)
+++ main/plugin-odf/i18n/messages_fr.xml	(working copy)
@@ -165,7 +165,14 @@
 	<message key="PLUGINS_ODF_CONFIG_REMOTE_LOGIN_DESC">Login du serveur distant</message>
 	<message key="PLUGINS_ODF_CONFIG_REMOTE_PASSWORD">Mot de passe</message>
 	<message key="PLUGINS_ODF_CONFIG_REMOTE_PASSWORD_DESC">Mot de passe pour se connecter au serveur distant</message>
-
+	
+	<!-- +
+		 | DEPOT
+	 	 + -->
+	<message key="PLUGINS_ODF_CONFIG_GROUP_OUTPUT_FOLDER">Dépôt dans un dossier</message>
+	<message key="PLUGINS_ODF_CONFIG_OUTPUT_FOLDER">Dossier de dépôt</message>
+	<message key="PLUGINS_ODF_CONFIG_OUTPUT_FOLDER_DESC">Chemin du dossier vers lequel les formations validées seront exportées.</message>
+	
 	<!-- +
 		 | RIBBON ODF
 		 + -->
#P Ametys - Template ODFWEB
Index: webapp/cms/WEB-INF/param/workflow-program.xml
===================================================================
--- webapp/cms/WEB-INF/param/workflow-program.xml	(revision 16250)
+++ webapp/cms/WEB-INF/param/workflow-program.xml	(working copy)
@@ -78,6 +78,9 @@
 					<condition type="avalon">
 						<arg name="role">org.ametys.cms.workflow.LockCondition</arg>
 					</condition>
+					<condition type="avalon">
+						<arg name="role">org.ametys.odf.workflow.MandatoryProgramMetadataCondition</arg>
+					</condition>
 				</conditions>
 			</restrict-to>
 			<pre-functions>
@@ -293,6 +296,14 @@
 					<results>
 						<unconditional-result old-status=" " status=" " step="3" />
 					</results>
+		            <post-functions>
+		                <function type="avalon">
+		                    <arg name="role">org.ametys.odf.cdmfr.DepositCDMFRFunction</arg>
+		                </function>
+		                <function type="avalon">
+		                    <arg name="role">org.ametys.odf.cdmfr.SendCDMFRFunction</arg>
+		                </function>
+		            </post-functions>
 				</action>
 				<action id="900" name="plugin.odf:WORKFLOW_ACTION_GLOBAL_VALIDATION">
 					<restrict-to>
@@ -314,6 +325,14 @@
 					<results>
 						<unconditional-result old-status=" " status=" " step="3" />
 					</results>
+		            <post-functions>
+		                <function type="avalon">
+		                    <arg name="role">org.ametys.odf.cdmfr.DepositCDMFRFunction</arg>
+		                </function>
+		                <function type="avalon">
+		                    <arg name="role">org.ametys.odf.cdmfr.SendCDMFRFunction</arg>
+		                </function>
+		            </post-functions>
 				</action>
 				<action id="7" name="plugin.web:WORKFLOW_ACTION_REFUSE">
 					<restrict-to>
@@ -381,11 +400,19 @@
 					<results>
 						<unconditional-result old-status=" " status=" " step="3" />
 					</results>
+		            <post-functions>
+		                <function type="avalon">
+		                    <arg name="role">org.ametys.odf.cdmfr.DepositCDMFRFunction</arg>
+		                </function>
+		                <function type="avalon">
+		                    <arg name="role">org.ametys.odf.cdmfr.SendCDMFRFunction</arg>
+		                </function>
+		            </post-functions>
 				</action>		
 			</actions>
             <post-functions>
                 <function type="avalon">
-                    <arg name="role">org.ametys.web.workflow.ValidationStepFunction</arg>
+                    <arg name="role">org.ametys.cms.workflow.ValidationStepFunction</arg>
                 </function>
                 <function type="avalon">
                     <arg name="role">org.ametys.cms.workflow.CommentStepFunction</arg>