27 de diciembre de 2017

:: Javascript. Creando el juego de Piedra, Papel, Tijera

Únicamente y como prueba de concepto, crearemos el juego de Piedra, Papel, Tijera, que permita jugar varias partidas (por ejemplo 3) y que muestre el resultado de cada partida.

El código podría ser algo similar a este:
var juego=function(jugador1, jugador2){
  var jugadaJugador1=jugador1.jugar();
  var jugadaJugador2=jugador2.jugar();
  
  //Definimos las reglas del juego
  var reglasJuego={
    piedra:"tijera",papel:"piedra",tijera:"papel"
  }
  
  //Determina quien gana la partida
  if(jugadaJugador1===jugadaJugador2){
    return "Empate";
  }
  if (jugadaJugador1===reglasJuego[jugadaJugador2]){
    return jugador1.nombre+" gana";
  }else{
    return jugador2.nombre+" gana";
  }
}

function Jugador(nombreJugador){
  var valores=['piedra', 'papel', 'tijera'];
  this.nombre=nombreJugador;
  //Devuelve un valor aleatorio entre 0 y 2
  this.jugar= function(){
    return valores[Math.floor(Math.random()*valores.length)];
  }
}
  
var jugador1=new Jugador('Pablo');
var jugador2=new Jugador('Luis');

for(var i=0;i<10 code="" console.log="" i="" juego="" jugador1="" jugador2="">

La salida de este pequeño ejemplo podría ser algo similar a esto:
"Pablo gana"
"Luis gana"
"Luis gana"
"Empate"
"Empate"
"Empate"
"Pablo gana"
"Pablo gana"
"Luis gana"
"Pablo gana"

22 de diciembre de 2017

:: Alfresco. Deshabilitar CSRF (Tip)

El filtro Cross-Site Request Forgery (CSRF) viene por defecto habilitado en Alfresco, pero en ocasiones puede que necesitemos deshabilitarlo.

Para ello, debemos quitar los comentarios a unas líneas en nuestro fichero: "share-config-custom.xml" ubicado en: "shared/classes/alfresco/web-extension/"; en concreto, las líneas son las siguientes:
< config condition="CSRFPolicy" evaluator="string-compare" replace="true" >
      < filter >
   < /filter >
< /config >

Más información: http://docs.alfresco.com/5.2/concepts/csrf-policy.html

17 de diciembre de 2017

:: Alfresco. Cómo desplegar un workflow

Tras le desarrollo de un workflow en Activity, podemos llevar a cabo el despliegue de este de distintas maneras.
Describiremos a continuación cómo tenemos estructurado el workflow.

En la ruta "shared/classes/alfresco/extension/" tenemos el fichero de contexto.
Fichero: activiti-adhoc-timer-workflow-context.xml

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>

<beans>
    <bean id="lifecycle.workflowBootstrap" parent="workflowDeployer">
  <property name="workflowDefinitions">
   <list>
    <props>
     <prop key="engineId">activiti</prop>
     <prop key="location">alfresco/extension/activiti-adhoc-timer.bpmn20.xml</prop>
     <prop key="mimetype">text/xml</prop>
     <prop key="redeploy">false</prop>
    </props>
   </list>
  </property>
  <property name="labels">
   <list>
                <value>alfresco/extension/activiti-adhoc-timer-messages</value>
   </list>
  </property>
 </bean>
</beans>

Tendremos un fichero con los literales utilizados, en la siguiente ruta: "shared/classes/alfresco/web-extension/messages/".
Fichero: activiti-adhoc-timer-messages.properties

# For Activiti Timer Workflow Example
activitiAdhocTimer.workflow.title=Activiti Adhoc Timer 
activitiAdhocTimer.workflow.description=Activiti Adhoc Timer Sample Process 

La propia definición del workflow la hemos ubicado en la siguiente carpeta, referenciada desde el fichero de contexto: "shared/classes/alfresco/extension/workflow/".
Fichero: activiti-adhoc-timer.bpmn20.xml

<?xml version="1.0" encoding="UTF-8" ?>

<definitions id="adhoc-definitions"
             typeLanguage="http://www.w3.org/2001/XMLSchema"
             expressionLanguage="http://www.w3.org/1999/XPath"
             targetNamespace="http://activiti.org/bpmn20" 
             xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:activiti="http://activiti.org/bpmn">

    <process id="activitiAdhocTimer" name="Activiti Timer Adhoc">

        <startEvent id="start"
            activiti:formKey="wf:submitAdhocTask" />

        <sequenceFlow id='flow1' 
            sourceRef='start'
            targetRef='adhocTask' />

        <userTask id="adhocTask" name="Urgent task"
            activiti:formKey="wf:adhocTask">
           <extensionElements>
               <activiti:taskListener event="create" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
                  <activiti:field name="script">
                     <activiti:string>
                      if (typeof bpm_workflowDueDate != 'undefined') task.setVariableLocal('bpm_dueDate', bpm_workflowDueDate);
                      if (typeof bpm_workflowPriority != 'undefined') task.priority = bpm_workflowPriority;
                     </activiti:string>
                  </activiti:field>
               </activiti:taskListener>
           </extensionElements>
            <humanPerformer>
                <resourceAssignmentExpression>
                    <formalExpression>${bpm_assignee.properties.userName}</formalExpression>
                </resourceAssignmentExpression>
            </humanPerformer>
        </userTask>
        
        <!-- Boundry event attached to 'adhocTask', which will end the task after 1 minute -->
        <boundaryEvent id="timer" cancelActivity="true" attachedToRef="adhocTask" name="testTimer">
     <timerEventDefinition>
      <!-- ISO-8601 durations of one hour-->
      <timeDuration>PT1H</timeDuration>
    </timerEventDefinition>
  </boundaryEvent>   

        <sequenceFlow id='flow2' 
        sourceRef='adhocTask'
            targetRef='taskDone' />

        <userTask id="taskDone" name="Urgent task completed on time"
            activiti:formKey="wf:completedAdhocTask" >
            <documentation>
                The urgent task was completed on time by ${bpm_assignee.properties.userName}.
            </documentation>
            <extensionElements>
               <activiti:taskListener event="create" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
                  <activiti:field name="script">
                     <activiti:string>
                        if (typeof bpm_workflowDueDate != 'undefined') task.setVariableLocal('bpm_dueDate', bpm_workflowDueDate);
                        if (typeof bpm_workflowPriority != 'undefined') task.priority = bpm_workflowPriority;
                     </activiti:string>
                  </activiti:field>
               </activiti:taskListener>
           </extensionElements>
            <humanPerformer>
                <resourceAssignmentExpression>
                    <formalExpression>${initiator.properties.userName}</formalExpression>
                </resourceAssignmentExpression>
            </humanPerformer>
        </userTask>
        
        <userTask id="taskExpired" name="Urgent task expired"
            activiti:formKey="wf:completedAdhocTask" >
            <documentation>
                The urgent task was NOT completed on time by ${bpm_assignee.properties.userName}.
            </documentation>
            <extensionElements>
               <activiti:taskListener event="create" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
                  <activiti:field name="script">
                     <activiti:string>
                        if (typeof bpm_workflowDueDate != 'undefined') task.setVariableLocal('bpm_dueDate', bpm_workflowDueDate);
                        if (typeof bpm_workflowPriority != 'undefined') task.priority = bpm_workflowPriority;
                     </activiti:string>
                  </activiti:field>
               </activiti:taskListener>
           </extensionElements>
            <humanPerformer>
                <resourceAssignmentExpression>
                    <formalExpression>${initiator.properties.userName}</formalExpression>
                </resourceAssignmentExpression>
            </humanPerformer>
        </userTask>

        <sequenceFlow id='flow3' sourceRef='taskDone'
            targetRef='theEnd' /> 
        
        <sequenceFlow id='flow4' sourceRef='timer'
            targetRef='taskExpired' />
        
         <sequenceFlow id='veryLongTimer' sourceRef='taskExpired'
            targetRef='theEnd' />

        <endEvent id="theEnd" />
    </process>
</definitions>

Una opción sería que ante cualquier reinicio del servicio se volviera a re-desplegar el workflow, para lo que tendríamos que modificar la propiedades del fichero de contexto "activiti-adhoc-timer-workflow-context.xml":
< prop key="redeploy" >true< /prop >
Otra opción posible sería hacer uso de la consola de administración de flujos de trabajo. Inicialmente podemos ver los workflows desplegados mediante la intrucción:
show definitions


El acceso a esta consola se realiza por medio de la url siguiente: http://servidor:puerto/alfresco/s/admin/admin-communitysummary
O bien: http://localhost:8181/alfresco/
Seleccionar la entrada: Alfresco Administration Console

Para proceder al despliegue, la instrucción sería:
deploy activiti alfresco/extension/workflow/activiti-adhoc-timer.bpmn20.xml


Por defecto el motor activiti viene habilitado, pero en el caso de que necesitásemos otro motor, podríamos añadir las siguientes líneas en el fichero "alfresco-global.properties"
## Activity
system.workflow.engine.activiti.enabled=true
system.workflow.engine.activiti.definitions.visible=true

En el caso de utilizar JBPM, las entradas a definir serían:
### JBPM
system.workflow.engine.jbpm.enabled=true
system.workflow.engine.jbpm.definitions.visible=true


12 de diciembre de 2017

:: Alfresco. Importación masiva de documentos

Alfresco dispone de una utilidad para llevar a cabo la importación masiva de documentos, esta está accesible en la siguiente url:


http://localhost:8383/alfresco/service/bulkfsimport


Los campos que deberemos cumplimentar son los siguientes:

Import directory
Directorio desde el que realizaremos la importación (ficheros a importar en nuestro Alfresco)

Por ejemplo: d:\software
Target space
Path
Ruta -dentro de nuestro Alfresco- al nodo (carpeta) sobre la que se realizará la importación

Por ejemplo: /Espacio de empresa/Sitios/netic360/documentLibrary/Inicio
NodeRef
Referencia al nodo sobre el que queremos importar (por ejemplo carpeta dentro de nuestro Alfresco) 
Por ejemplo: workspace://SpacesStore/844bc038-53f5-4a79-b06e-941c1b8302c1
Disable rules
Nos permitirá - si es necesario - habilitar/deshabilitar la ejecución de reglas, lo que podría ralentizar la carga masiva

Replace existing files
Marcando esta opción reemplazará los ficheros existentes con los que están siendo importados

Batch size
Es el nº de directorio y ficheros que serán importados de una sola vez
Por ejemplo: 10
Number of threads
Número de hilos de ejecución
Por ejemplo: 5

Para comprobar el estado de importación podemos acceder a la url:

http://localhost:8383/alfresco/service/bulkfsimport/status

Para obtener el path o el NodeRef es útil hacer uso de las "Herramientas de administración" > "Navegador de Nodos".

7 de diciembre de 2017

:: Alfresco. Creación de una lista de datos

En este caso, la prueba de concepto será la creación de un tipo personalizado, en concreto una lista de datos. Para ello, seguiremos los siguientes pasos:


.- Seleccionaremos la opción: "Herramientas administrativas" > "Gestor de modelos" (disponible en la versión 5.2)

.- Crearemos un nuevo modelo, cumplimentando los datos del formulario:
Espacio de nombres: http://www.alfresco.org/model/publicaciones2/1.0
Prefijo: publi2
Nombre: Publicaciones2

.- Tras cumplimentar los datos, crearemos los distintos campos a contemplar en la lista. Desde el gestor de modelos no permite la creación heredando del padre "dlListItem" por lo que una vez creado el modelo, lo exportaremos (.zip) y modificaremos los ficheros oportunos con los valores orrespondientes.


 .- Importaremos el modelo con las modificaciones, y ya tendremos a nuestra disposición la nueva lista de datos

El tipo de datos definido está compuesto por dos ficheros cuyo contenido es el siguiente:
Fichero: publicaciones2.xml
< ?xml version="1.0" encoding="UTF-8" ?>
< model xmlns="http://www.alfresco.org/model/dictionary/1.0" name="publi2:Publicaciones2" >
< description >Gestionar publicaciones< /description >
< author >neTIC360< /author >
< imports >
< import uri="http://www.alfresco.org/model/datalist/1.0" prefix="dl" />
< import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d" />
< /imports>
< namespaces>
< namespace uri="http://www.alfresco.org/model/publicaciones2/1.0" prefix="publi2" />
< /namespaces >
< data-types />
< constraints />
< types >
< type name="publi2:Publicaciones2" >
< title >Publicaciones neTIC360< /title >
< description >Listas de datos de Publicaciones< /description >
< parent >dl:dataListItem< /parent >
< properties >
< property name="publi2:titulo" >
< title >Título< /title >
< type >d:text< /type >
< mandatory >true< /mandatory >
< index enabled="true" >
< tokenised >TRUE< /tokenised >
< facetable >true< /facetable >
< /index >
< /property >
< property name="publi2:autor" >
< title >Autor< /title >
< type >d:text< /type >
< mandatory >false< /mandatory >
< index enabled="true" >
< tokenised >TRUE< /tokenised >
< facetable >false< /facetable >
< /index >
< /property >
< property name="publi2:isbn" >
< title >ISBN
< type >d:text< /type >
< mandatory >false< /mandatory >
< index enabled="true" >
< tokenised >TRUE< /tokenised >
< facetable >false< /facetable >
< /index >
< /property >
< /properties >
< associations />
< overrides />
< mandatory-aspects />
< /type >
< /types >
< aspects />
< /model >



Fichero: CMM_publicaciones2_Model.xml
< ?xml version="1.0" encoding="UTF-8"? >< module >
< id >CMM_Publicaciones2< /id >
< auto-deploy >true< /auto-deploy >
< configurations >


< config condition="DocumentLibrary" evaluator="string-compare" replace="false" >
< types >
< type name="dl:dataListItem" >
< subtype label="" name="publi2:Publicaciones2" />

< /types >
< /config >


< config condition="publi2:Publicaciones2" evaluator="node-type" >
< forms >
< form >
< field-visibility >
< show force="true" id="dl:title" />
< /field-visibility >
< appearance >
< set appearance="whitespace" id="publi2:Publicaciones2_cmm_set0" />
< field id="dl:title" set="publi2:Publicaciones2_cmm_set0" >
< /field >
< /appearance >
< /form >


< form id="doclib-simple-metadata" >
< edit-form template="../documentlibrary/forms/doclib-simple-metadata.ftl" />
< field-visibility >
< show force="true" id="dl:title" />
< /field-visibility >
< appearance >
< set appearance="whitespace" id="publi2:Publicaciones2_cmm_set0" />
< field id="dl:title" set="publi2:Publicaciones2_cmm_set0" >
< /field >
< /appearance >
< /form >


< form id="doclib-inline-edit" >
< field-visibility>
< show id="dl:name" />
< show force="true" id="dl:content" />
< show force="true" id="dl:title" />
< show force="true" id="dl:description" />
< /field-visibility >
< appearance >
< field id="dl:name" >
< control >
< control-param name="maxLength" >255< /control-param >
< /control >
< /field >
< field id="dl:title" >
< control template="/org/alfresco/components/form/controls/textfield.ftl" />
< /field >
< field id="dl:content" label-id="" >
< control>
< control-param name="editorAppearance" >explorer< /control-param >
< control-param name="forceEditor" >true< /control-param >
< /control >
< /field >
< /appearance >
< /form >
< /forms >
< /config >




< config condition="FormDefinition" evaluator="string-compare" >
< form-definition id="Publicaciones2">[{"elementconfig":{"label":"","appearance":"bordered-panel"},"pseudonym":"cmm/editor/layout/1cols","label":"cmm.form-editor.palette.one-column","type":["layout"],"column":[{"pseudonym":"cmm/editor/property/text","id":"cm:title","elementconfig":{"infoname":"cm:title","infolabel":"Título","infotype":"d:text","force":true},"label":"Título [cm:title]","type":["property"]}]}]< /form-definition >
< /config >
< /configurations >
< /module >

:: Cookies de nuestra página web. ¿Para qué sirve cada una?

A menudo una pregunta que nos hacen es qué cookies se están utilizando en mi página y para qué sirven. Para ver las cookies, podemos selecci...