{"id":27343,"date":"2024-04-25T11:00:00","date_gmt":"2024-04-25T09:00:00","guid":{"rendered":"https:\/\/help.qualiware.it\/qw-help\/?p=27343"},"modified":"2025-07-16T11:42:42","modified_gmt":"2025-07-16T09:42:42","slug":"qwntsec_actionlink_cfgform","status":"publish","type":"post","link":"https:\/\/help.qualiware.it\/qw-help\/qwntsec_actionlink_cfgform\/","title":{"rendered":"Action Link"},"content":{"rendered":"<p>La funzionalit\u00e0 <strong>Action Link<\/strong>, introdotta nella release 2021.06+, ha lo scopo di consentire la definizione di link che consentono, quando attivati da un utente o da un applicativo esterno, l&#8217;esecuzione di azioni in risposta che possono essere:<\/p>\n<ul>\n<li>la visualizzazione di una pagina di risposta;<\/li>\n<li>la restituzione di dati in formato json;<\/li>\n<li>la ridirezione ad un&#8217;altra pagina;<\/li>\n<li>la restituzione di un calendario.<\/li>\n<\/ul>\n<p>Il tutto governato da uno script definito dal programmatore, che pu\u00f2 valutare i parametri passati nel link stesso, arbitrariamente definiti dal programmatore stesso, eventualmente aggiornare il database e compiere l&#8217;azione richiesta fra quelle sopra indicate.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/help.qualiware.it\/qw-help\/wp-content\/uploads\/Pasted-2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-27346\" src=\"https:\/\/help.qualiware.it\/qw-help\/wp-content\/uploads\/Pasted-2.png\" alt=\"\" width=\"700\" height=\"615\" srcset=\"https:\/\/help.qualiware.it\/qw-help\/wp-content\/uploads\/Pasted-2.png 1082w, https:\/\/help.qualiware.it\/qw-help\/wp-content\/uploads\/Pasted-2-768x674.png 768w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><\/a><\/p>\n<p>La scheda di configurazione si presenta come nella figura seguente:<\/p>\n<p><a href=\"https:\/\/help.qualiware.it\/qw-help\/wp-content\/uploads\/image-50.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-37920\" src=\"https:\/\/help.qualiware.it\/qw-help\/wp-content\/uploads\/image-50.png\" alt=\"\" width=\"600\" height=\"547\" srcset=\"https:\/\/help.qualiware.it\/qw-help\/wp-content\/uploads\/image-50.png 970w, https:\/\/help.qualiware.it\/qw-help\/wp-content\/uploads\/image-50-768x700.png 768w\" sizes=\"(max-width: 600px) 100vw, 600px\" \/><\/a><\/p>\n<p>L&#8217;<strong><span style=\"color: #900000;\">Action Link ID<\/span><\/strong> \u00e8 un valore univoco che viene generato dal sistema, ma pu\u00f2 essere modificato, e che identificata in maniera univoca il link. Deve essere sempre passato nel parametro ACTIONID del link, oppure nella propriet\u00e0 &#8220;ActionID&#8221; del payload.<br \/>\nLa lista a discesa <strong><span style=\"color: #900000;\">Tipo<\/span><\/strong> consente di definire il tipo di risposta, e presenta le seguenti opzioni:<\/p>\n<ul>\n<li>JSON: la risposta sar\u00e0 di tipo &#8220;application\/json&#8221;, e, quindi, un flusso JSON.<\/li>\n<li>Pagina Web: la risposta sar\u00e0 una pagina web<\/li>\n<li>iCalendar: la risposta sar\u00e0 di tipo &#8220;text\/calendar&#8221; secondo la specifica <a href=\"https:\/\/icalendar.org\/\" target=\"_blank\" rel=\"noopener\">iCalendar<\/a>, consentendo di utilizzare l&#8217;action link per configurare un &#8220;calendario internet&#8221; su Microsoft Outlook. &nbsp;<\/li>\n<\/ul>\n<p>Il flag <span style=\"color: #900000;\"><b>Richiedi Token<\/b><\/span>, disponibile nella release 2025.00.13 o successiva, se attivato, consente di proteggere la chiamata con la specifica di un token, deve essere preventivamente richiesto dal chiamante utilizzando il Web Service Rest &#8220;GetUserToken&#8221; dell&#8217;SDK di QualiWare, e passato all&#8217;action link o nel parametro &#8220;TOKEN&#8221; o nel payload nella propriet\u00e0 &#8220;Token&#8221;.&nbsp;<\/p>\n<p>Lo <strong><span style=\"color: #900000;\">Script <\/span><\/strong>consente di definire l&#8217;azione che verr\u00e0 eseguita in risposta all&#8217;esecuzione del link. Pu\u00f2 essere scritto in VB.NET, C# o Python. Al suo interno si possono utilizzare le variabili &#8220;DB&#8221;, oggetto di tipo <a href=\"https:\/\/help.qualiware.it\/qw-help\/classi-di-supporto\/\" target=\"_blank\" rel=\"noopener\">QWDatabase<\/a> che rappresenta un riferimento al database di QualiWare, e &#8220;Params&#8221;, che contiene, sotto forma di array associativo (<a href=\"https:\/\/help.qualiware.it\/qw-help\/classi-di-supporto\/\" target=\"_blank\" rel=\"noopener\">AssocArray<\/a>) tutti i parametri passati nella URL. Lo script deve ritornare, tramite l&#8217;istruzione &#8220;Return&#8221;, una stringa che pu\u00f2 essere:<\/p>\n<ul>\n<li>nel caso il tipo <strong>non<\/strong> sia &#8220;JSON&#8221;<strong><span style=\"color: #900000;\">, <\/span><\/strong>&nbsp;un testo in formato HTML che verr\u00e0 visualizzato in una pagina di risposta standard;<\/li>\n<li>nel caso il tipo sia &#8220;JSON&#8221;<strong><span style=\"color: #900000;\">, <\/span><\/strong>&nbsp;un testo in formato JSON che verr\u00e0 utilizzato da un altro applicativo per acquisire informazioni.<\/li>\n<\/ul>\n<p>Il secondo caso \u00e8 particolarmente interessante in quanto d\u00e0 la possibilit\u00e0 di creare Web Service REST che possono essere utilizzati da altri applicativi per integrarsi con QualiWare.<\/p>\n<p>NOTA: nel primo caso, la pagina di risposta viene visualizzata in modalit\u00e0 <strong>non autenticata<\/strong>, senza, cio\u00e8, un utente corrente, a meno che il link non venga richiamato all&#8217;interno di una sessione di QualiWare, nel qual caso ne eredita la sessione.<\/p>\n<p>Le chiamate ad Action Link vengono registrate sulla tabella LOGDOC con IDDOC=&#8217;**&#8217; e CODDOC=&#8217;ACTIONLINK&#8217;. Nel campo &#8220;NOTE&#8221; vengono registrati l&#8217;indirizzo IP del chiamante, i parametri della chiamata (ad esclusione dell&#8217;eventuale payload) e la risposta restituita al chiamante.<\/p>\n<p>E&#8217; inoltre possibile aggiungere, sia come parametri che nel payload, i valori &#8220;OTLP_TraceId&#8221; e &#8220;OTLP_SpanID&#8221;, che vengono registrati su LOGDOC e possono essere utilizzati per effettuare una traccia globale di un flusso. Si veda l&#8217;apposita <a href=\"https:\/\/help.qualiware.it\/qw-help\/monitoraggio-dei-flussi-applicativi-e-dello-stato-dei-servizi\/\">pagina di approfondimento<\/a>.<\/p>\n<p>Di seguito riportiamo alcuni esempi di script riferiti alle varie possibilit\u00e0.<\/p>\n<h3>Visualizzazione di un messaggio<\/h3>\n<p>Il seguente script restituisce, nella pagina di risposta, tutti i parametri del link. Pu\u00f2 essere utilizzato come punto di partenza per utilizzare i parametri stessi per effettuare altri tipi di azione, come ad esempio l&#8217;aggiornamento di informazioni sul database, e restituirne l&#8217;esito nella pagina di risposta.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"visualbasic\">dim k as string=PARAMS.firstkey()\r\n\r\ndim html as string=\"\"\r\nwhile not empty(k)\r\n   html+=k+\"=\"+PARAMS(k)+\"&lt;BR&gt;\"\r\n   k=PARAMS.nextkey(k)\r\nend while\r\n\r\nreturn html<\/pre>\n<h3>Restituzione di un flusso JSON&nbsp;<\/h3>\n<p>Il seguente script restituisce un flusso json che rappresenta l&#8217;oggetto &#8220;obj&#8221;, che pu\u00f2 essere definito dinamicamente in base alle esigenze. Fra i valori restituiti vi \u00e8 anche quello del parametro &#8220;PARAMETRO1&#8221; assegnato nel link.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"visualbasic\">dim obj=New With {.valore1 = \"campo1\", .valore2 = 100.24, .valore3 = true, .valore4=now(), .parametro1=Params(\"PARAMETRO1\")}\r\n\r\nreturn newtonsoft.Json.jsonconvert.SerializeObject(obj)<\/pre>\n<h3>Restituzione di un flusso JSON a partire da un flusso JSON nel payload<\/h3>\n<p>Il seguente script restituisce un flusso json a partire da un flusso json inviato nel payload della richiesta. Questa modalit\u00e0 \u00e8 tipica dei Web Service Rest.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"visualbasic\">Dim obj As Newtonsoft.Json.linq.JObject\r\nDim jsonr as string\r\n\r\nPage.Request.InputStream.Seek(0,System.IO.SeekOrigin.Begin)\r\nUsing receiveStream As System.IO.Stream = Page.Request.InputStream\r\n   Using readStream As System.IO.StreamReader = New System.IO.StreamReader(receiveStream, System.Text.Encoding.UTF8)\r\n      jsonr = readStream.ReadToEnd()\r\n   End Using\r\nEnd Using\r\n\r\nobj=Newtonsoft.Json.linq.JObject.Parse(jsonr)  \r\n\r\ndim ret_obj=New With {.output1 = ctype(obj(\"input1\"),Newtonsoft.Json.Linq.JValue).Value, .output2 = ctype(obj(\"input2\"),Newtonsoft.Json.Linq.JValue).Value   }\r\n\r\nreturn newtonsoft.Json.jsonconvert.SerializeObject(ret_obj)<\/pre>\n<p>Richiamando il link e specificando il seguente payload:<\/p>\n<div>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\">{\r\n    \"input1\": \"valore1\",\r\n    \"input2\": \"valore2\"\r\n}<\/pre>\n<\/div>\n<p>verr\u00e0 restituito il seguente flusso.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\">{\r\n    \"output1\": \"valore1\",\r\n    \"output2\": \"valore2\"\r\n}<\/pre>\n<h3>Ridirezione ad un&#8217;altra pagina<\/h3>\n<p>Il seguente script rimanda ad un&#8217;altra pagina.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"visualbasic\">Page.Response.Redirect(\"GEMANOCO2.ASPX\")<\/pre>\n<h3>Restituzione di un calendario iCalendar<\/h3>\n<p>Il seguente script mostra come sia possibile restituire un calendario internet, configurabile in Microsoft Outlook, con la possibilit\u00e0 di definire tutte le propriet\u00e0 degli eventi in esso inclusi, compreso il colore. Si faccia riferimento ai commenti nel codice per le opportune spiegazioni.<br \/>\nIl link dell&#8217;Action Link pu\u00f2 essere inserito in Outlook per configurare un calendario che si aggiorna automaticamente in base ai dati contenuti in QualiWare e restituiti dall&#8217;Action Link stesso. La frequenza di aggiornamento pu\u00f2 essere stabilita nello script assegnando la propriet\u00e0 &#8220;X-PUBLISHED-TTL&#8221;.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"visualbasic\">' Creazione di un calendario utilizzando l'oggetto DDay.Ical.Calendar, che consente di assegnare le propriet\u00e0 degli eventi come propriet\u00e0\r\n' di oggetti contenuti in una collection\r\n' N.B. non tutte le propriet\u00e0 contenute nello standard sono disponibili come propriet\u00e0 dell'oggetto, ma \u00e8 possibile ugualmente assegnarle\r\n' utilizzando il metodo AddProperty dell'evento\r\n' Tutte le propriet\u00e0 disponibili sono visibili qui: https:\/\/icalendar.org\/\r\n\r\ndim resp as string\r\n\r\nDim iCal As DDay.iCal.iCalendar = New DDay.iCal.iCalendar()\r\n\r\niCal.Method = \"PUBLISH\"\r\niCal.Version = \"2.0\"\r\niCal.AddProperty(\"X-WR-CALNAME\", \"Calendario di prova Action link\")\r\niCal.AddProperty(\"PRODID\", \"QualiWare\")\r\niCal.AddProperty(\"X-PUBLISHED-TTL\", \"PT1H\")       ' Tempo di refresh di Outlook: 1H=1 ora\r\niCal.AddProperty(\"X-WR-TIMEZONE\", TimeZone.CurrentTimeZone.StandardName)\r\n\r\nDim evt As DDay.iCal.Components.Event \r\n\r\n' **** Evento 1\r\nevt = iCal.Create(Of DDay.iCal.Components.Event)()\r\nevt.Summary = \"Evento di prova 1\"\r\nevt.Start = New DDay.iCal.DataTypes.iCalDateTime(new date(2022,01,30,12,00,00).ToUniversalTime)\r\nevt.Start.HasTime = True\r\nevt.Start.IsUniversalTime = True\r\nevt.End = New DDay.iCal.DataTypes.iCalDateTime(new date(2022,01,30,15,00,00).ToUniversalTime)\r\nevt.End.HasTime = True\r\nevt.End.IsUniversalTime = True\r\nevt.Duration=TimeSpan.FromHours(3) ' durata in ore\r\nevt.Description = \"Descrizione dell'evento 1 (corpo)\"\r\nevt.Location = \"Locazione dell'evento\"\r\nevt.IsAllDay = false ' mettere true se l'evento occupa tutto il giorno\r\nevt.UID = \"001\" ' Codice univoco dell'evento\r\nevt.Organizer = New DDay.iCal.DataTypes.Cal_Address(\"pguidotti@qualiware.it\") ' Mail dell'organizzatore\r\nevt.Status = DDay.iCal.DataTypes.EventStatus.Confirmed\r\n\r\n' aggiunge l'allarme esplicitamente\r\nevt.AddProperty(\"BEGIN\", \"VALARM\")\r\nevt.AddProperty(\"ACTION\", \"DISPLAY\")\r\nevt.AddProperty(\"DESCRIPTION\", \"Evento di prova 1\")\r\nevt.AddProperty(\"TRIGGER\", \"-PT15M\")\r\nevt.AddProperty(\"END\", \"VALARM\")\r\n\r\n' aggiunge il colore\r\nevt.AddProperty(\"CATEGORIES\",\"Categoria Blu\") ' N.B. la descrizione della categoria deve essere quella presente nell'Outlook del destinatario\r\n\r\n' **** Evento 2\r\nevt = iCal.Create(Of DDay.iCal.Components.Event)()\r\nevt.Summary = \"Evento di prova 2\"\r\nevt.Start = New DDay.iCal.DataTypes.iCalDateTime(DateAdd(DateInterval.Day,1,now()).ToUniversalTime) ' Piazza l'evento ad un giorno da oggi\r\nevt.Start.HasTime = True\r\nevt.Start.IsUniversalTime = True\r\nevt.End = New DDay.iCal.DataTypes.iCalDateTime(DateAdd(DateInterval.Hour,1,DateAdd(DateInterval.Day,1,now())).ToUniversalTime)\r\nevt.End.HasTime = True\r\nevt.End.IsUniversalTime = True\r\nevt.Duration=TimeSpan.FromHours(1) ' durata in ore\r\nevt.Description = \"Descrizione dell'evento 2 (corpo)\"\r\nevt.Location = \"Locazione dell'evento\"\r\nevt.IsAllDay = false ' mettere true se l'evento occupa tutto il giorno\r\nevt.UID = \"002\" ' Codice univoco dell'evento\r\nevt.Organizer = New DDay.iCal.DataTypes.Cal_Address(\"pguidotti@qualiware.it\") ' Mail dell'organizzatore\r\nevt.Status = DDay.iCal.DataTypes.EventStatus.Confirmed\r\n\r\n' aggiunge l'allarme esplicitamente\r\nevt.AddProperty(\"BEGIN\", \"VALARM\")\r\nevt.AddProperty(\"ACTION\", \"DISPLAY\")\r\nevt.AddProperty(\"DESCRIPTION\", \"Evento di prova 2\")\r\nevt.AddProperty(\"TRIGGER\", \"-PT15M\")\r\nevt.AddProperty(\"END\", \"VALARM\")\r\n\r\n' aggiunge il colore\r\nevt.AddProperty(\"CATEGORIES\",\"Categoria Verde\") ' N.B. la descrizione della categoria deve essere quella presente nell'Outlook del destinatario\r\n\r\nDim serializer As DDay.iCal.Serialization.iCalendarSerializer = New DDay.iCal.Serialization.iCalendarSerializer(iCal)\r\nreturn serializer.SerializeToString()  ' ritorno del calendario serializzato<\/pre>\n<h3>Protezione di un Action link tramite token (per versioni precedenti alla 2025.00.13)<\/h3>\n<p>E&#8217; possibile proteggere tramite token un action link che restituisce dati in formato JSon. Per farlo, si pu\u00f2 utilizzare il seguente codice:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"visualbasic\">dim ok as boolean=true\r\ndim msg as string=\"\"\r\ndim emmsg as string=\"\"\r\ndim errcode as integer = 0\r\n\r\ntry\t\r\n        ' Verifica il Token, che \u00e8 nel payload della richiesta, propriet\u00e0 \"Token\"\r\n  Dim jsonr as string\r\n  Page.Request.InputStream.Seek(0,System.IO.SeekOrigin.Begin)\r\n\r\n  Using receiveStream As System.IO.Stream = Page.Request.InputStream\r\n    Using readStream As System.IO.StreamReader = New System.IO.StreamReader(receiveStream, System.Text.Encoding.UTF8)\r\n      jsonr = readStream.ReadToEnd()\r\n    End Using\r\n  End Using\r\n\r\n  objtmp = Newtonsoft.Json.Linq.JObject.Parse(jsonr)\r\n  \r\n  dim token as string\r\n  token = ctype(objtmp(\"Token\"), Newtonsoft.Json.Linq.JValue).value\r\n  \r\n  dim valid_token as boolean = QWLib.Webutils.CheckToken2(token)\r\n  \r\n  if valid_token \r\n    ' Inserire qui l'elaborazioen dell'Action Link\r\n  else\r\n    errcode = 1\r\n    msg += \" Token non valido!\"\r\n  end if\r\ncatch e as exception\r\n   errcode= -1\r\n   writelog(\"ERRORE ACTION LINK : \" &amp; e.message+vbcr+e.stacktrace.tostring())\r\n   msg= \"Errore nell'elaborazione della richiesta.\"\r\n   emmsg = e.message+vbcr+e.stacktrace.tostring() \r\nEnd try\r\n\r\ndim ret_obj=New With {.ResultCode = errcode, .Result = ..... , .ResultMessage = msg, .ErrorMsg = emmsg  }\r\nreturn newtonsoft.Json.jsonconvert.SerializeObject(ret_obj)<\/pre>\n<p>Il token deve essere preventivamente richiesto dal chiamante utilizzando il Web Service Rest &#8220;GetUserToken&#8221; dell&#8217;SDK di QualiWare, e passato all&#8217;action link nel payload nella propriet\u00e0 &#8220;Token&#8221;.&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>La funzionalit\u00e0 Action Link, introdotta nella release 2021.06+, ha lo scopo di consentire la definizione di link che consentono, quando attivati da un utente o da un applicativo esterno, l&#8217;esecuzione di azioni in risposta che possono essere: la visualizzazione di una pagina di risposta; la restituzione di dati in formato json; la ridirezione ad un&#8217;altra&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"ngg_post_thumbnail":0,"footnotes":""},"categories":[60],"tags":[],"acf":[],"_links":{"self":[{"href":"https:\/\/help.qualiware.it\/qw-help\/wp-json\/wp\/v2\/posts\/27343"}],"collection":[{"href":"https:\/\/help.qualiware.it\/qw-help\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/help.qualiware.it\/qw-help\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/help.qualiware.it\/qw-help\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/help.qualiware.it\/qw-help\/wp-json\/wp\/v2\/comments?post=27343"}],"version-history":[{"count":7,"href":"https:\/\/help.qualiware.it\/qw-help\/wp-json\/wp\/v2\/posts\/27343\/revisions"}],"predecessor-version":[{"id":37924,"href":"https:\/\/help.qualiware.it\/qw-help\/wp-json\/wp\/v2\/posts\/27343\/revisions\/37924"}],"wp:attachment":[{"href":"https:\/\/help.qualiware.it\/qw-help\/wp-json\/wp\/v2\/media?parent=27343"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/help.qualiware.it\/qw-help\/wp-json\/wp\/v2\/categories?post=27343"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/help.qualiware.it\/qw-help\/wp-json\/wp\/v2\/tags?post=27343"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}