La funzionalità 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’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’altra pagina.
Il tutto governato da uno script definito dal programmatore, che può valutare i parametri passati nel link stesso, arbitrariamente definiti dal programmatore stesso, eventualmente aggiornare il database e compiere l’azione richiesta fra quelle sopra indicate.
La scheda di configurazione si presenta come nella figura seguente:
L’Action Link ID è un valore univoco che viene generato dal sistema, ma può essere modificato, e che identificata in maniera univoca il link. Deve essere sempre passato nel parametro ACTIONID del link.
Il flag Restituisci flusso JSON, se attivato, definisce che la risposta al link sarà di tipo “application/json” anzichè una pagina HTML. Lo script dovrà quindi comportarsi di conseguenza, come specificato più di seguito.
Analogamente, il flag Restituisci flusso iCalendar, se attivato, definisce che la risposta al link sarà di tipo “text/calendar” secondo la specifica iCalendar, consentendo di utilizzare l’action link per configurare un “calendario internet” su Microsoft Outlook.
Lo Script consente di definire l’azione che verrà eseguita in risposta all’esecuzione del link. Può essere scritto in VB.NET, C# o Python. Al suo interno si possono utilizzare le variabili “DB”, oggetto di tipo QWDatabase che rappresenta un riferimento al database di QualiWare, e “Params”, che contiene, sotto forma di array associativo (AssocArray) tutti i parametri passati nella URL. Lo script deve ritornare, tramite l’istruzione “Return”, una stringa che può essere:
- nel caso non sia spuntato il flag Restituisci flusso JSON, un testo in formato HTML che verrà visualizzato in una pagina di risposta standard;
- nel caso sia spuntato il flag Restituisci flusso JSON, un testo in formato JSON che verrà utilizzato da un altro applicativo per acquisire informazioni.
Il secondo caso è particolarmente interessante in quanto dà la possibilità di creare Web Service REST che possono essere utilizzati da altri applicativi per integrarsi con QualiWare.
NOTA: nel primo caso, la pagina di risposta viene visualizzata in modalità non autenticata, senza, cioè, un utente corrente, a meno che il link non venga richiamato all’interno di una sessione di QualiWare, nel qual caso ne eredita la sessione.
Le chiamate ad Action Link vengono registrate sulla tabella LOGDOC con IDDOC=’**’ e CODDOC=’ACTIONLINK’. Nel campo “NOTE” vengono registrati l’indirizzo IP del chiamante, i parametri della chiamata (ad esclusione dell’eventuale payload) e la risposta restituita al chiamante.
E’ inoltre possibile aggiungere, alla chiamata, i parametri OTLP_TraceId e OTLP_SpanID, che vengono registrati su LOGDOC e possono essere utilizzati per effettuare una traccia globale di un flusso. Si veda l’apposita pagina di approfondimento.
Di seguito riportiamo alcuni esempi di script riferiti alle varie possibilità.
Visualizzazione di un messaggio
Il seguente script restituisce, nella pagina di risposta, tutti i parametri del link. Può essere utilizzato come punto di partenza per utilizzare i parametri stessi per effettuare altri tipi di azione, come ad esempio l’aggiornamento di informazioni sul database, e restituirne l’esito nella pagina di risposta.
dim k as string=PARAMS.firstkey() dim html as string="" while not empty(k) html+=k+"="+PARAMS(k)+"<BR>" k=PARAMS.nextkey(k) end while return html
Restituzione di un flusso JSON
Il seguente script restituisce un flusso json che rappresenta l’oggetto “obj”, che può essere definito dinamicamente in base alle esigenze. Fra i valori restituiti vi è anche quello del parametro “PARAMETRO1” assegnato nel link.
dim obj=New With {.valore1 = "campo1", .valore2 = 100.24, .valore3 = true, .valore4=now(), .parametro1=Params("PARAMETRO1")} return newtonsoft.Json.jsonconvert.SerializeObject(obj)
Restituzione di un flusso JSON a partire da un flusso JSON nel payload
Il seguente script restituisce un flusso json a partire da un flusso json inviato nel payload della richiesta. Questa modalità è tipica dei Web Service Rest.
Dim obj As Newtonsoft.Json.linq.JObject Dim jsonr as string Page.Request.InputStream.Seek(0,System.IO.SeekOrigin.Begin) Using receiveStream As System.IO.Stream = Page.Request.InputStream Using readStream As System.IO.StreamReader = New System.IO.StreamReader(receiveStream, System.Text.Encoding.UTF8) jsonr = readStream.ReadToEnd() End Using End Using obj=Newtonsoft.Json.linq.JObject.Parse(jsonr) dim ret_obj=New With {.output1 = ctype(obj("input1"),Newtonsoft.Json.Linq.JValue).Value, .output2 = ctype(obj("input2"),Newtonsoft.Json.Linq.JValue).Value } return newtonsoft.Json.jsonconvert.SerializeObject(ret_obj)
Richiamando il link e specificando il seguente payload:
{ "input1": "valore1", "input2": "valore2" }
verrà restituito il seguente flusso.
{ "output1": "valore1", "output2": "valore2" }
Ridirezione ad un’altra pagina
Il seguente script rimanda ad un’altra pagina.
Page.Response.Redirect("GEMANOCO2.ASPX")
Restituzione di un calendario iCalendar
Il seguente script mostra come sia possibile restituire un calendario internet, configurabile in Microsoft Outlook, con la possibilità di definire tutte le proprietà degli eventi in esso inclusi, compreso il colore. Si faccia riferimento ai commenti nel codice per le opportune spiegazioni.
Il link dell’Action Link può essere inserito in Outlook per configurare un calendario che si aggiorna automaticamente in base ai dati contenuti in QualiWare e restituiti dall’Action Link stesso. La frequenza di aggiornamento può essere stabilita nello script assegnando la proprietà “X-PUBLISHED-TTL”.
' Creazione di un calendario utilizzando l'oggetto DDay.Ical.Calendar, che consente di assegnare le proprietà degli eventi come proprietà ' di oggetti contenuti in una collection ' N.B. non tutte le proprietà contenute nello standard sono disponibili come proprietà dell'oggetto, ma è possibile ugualmente assegnarle ' utilizzando il metodo AddProperty dell'evento ' Tutte le proprietà disponibili sono visibili qui: https://icalendar.org/ dim resp as string Dim iCal As DDay.iCal.iCalendar = New DDay.iCal.iCalendar() iCal.Method = "PUBLISH" iCal.Version = "2.0" iCal.AddProperty("X-WR-CALNAME", "Calendario di prova Action link") iCal.AddProperty("PRODID", "QualiWare") iCal.AddProperty("X-PUBLISHED-TTL", "PT1H") ' Tempo di refresh di Outlook: 1H=1 ora iCal.AddProperty("X-WR-TIMEZONE", TimeZone.CurrentTimeZone.StandardName) Dim evt As DDay.iCal.Components.Event ' **** Evento 1 evt = iCal.Create(Of DDay.iCal.Components.Event)() evt.Summary = "Evento di prova 1" evt.Start = New DDay.iCal.DataTypes.iCalDateTime(new date(2022,01,30,12,00,00).ToUniversalTime) evt.Start.HasTime = True evt.Start.IsUniversalTime = True evt.End = New DDay.iCal.DataTypes.iCalDateTime(new date(2022,01,30,15,00,00).ToUniversalTime) evt.End.HasTime = True evt.End.IsUniversalTime = True evt.Duration=TimeSpan.FromHours(3) ' durata in ore evt.Description = "Descrizione dell'evento 1 (corpo)" evt.Location = "Locazione dell'evento" evt.IsAllDay = false ' mettere true se l'evento occupa tutto il giorno evt.UID = "001" ' Codice univoco dell'evento evt.Organizer = New DDay.iCal.DataTypes.Cal_Address("[email protected]") ' Mail dell'organizzatore evt.Status = DDay.iCal.DataTypes.EventStatus.Confirmed ' aggiunge l'allarme esplicitamente evt.AddProperty("BEGIN", "VALARM") evt.AddProperty("ACTION", "DISPLAY") evt.AddProperty("DESCRIPTION", "Evento di prova 1") evt.AddProperty("TRIGGER", "-PT15M") evt.AddProperty("END", "VALARM") ' aggiunge il colore evt.AddProperty("CATEGORIES","Categoria Blu") ' N.B. la descrizione della categoria deve essere quella presente nell'Outlook del destinatario ' **** Evento 2 evt = iCal.Create(Of DDay.iCal.Components.Event)() evt.Summary = "Evento di prova 2" evt.Start = New DDay.iCal.DataTypes.iCalDateTime(DateAdd(DateInterval.Day,1,now()).ToUniversalTime) ' Piazza l'evento ad un giorno da oggi evt.Start.HasTime = True evt.Start.IsUniversalTime = True evt.End = New DDay.iCal.DataTypes.iCalDateTime(DateAdd(DateInterval.Hour,1,DateAdd(DateInterval.Day,1,now())).ToUniversalTime) evt.End.HasTime = True evt.End.IsUniversalTime = True evt.Duration=TimeSpan.FromHours(1) ' durata in ore evt.Description = "Descrizione dell'evento 2 (corpo)" evt.Location = "Locazione dell'evento" evt.IsAllDay = false ' mettere true se l'evento occupa tutto il giorno evt.UID = "002" ' Codice univoco dell'evento evt.Organizer = New DDay.iCal.DataTypes.Cal_Address("[email protected]") ' Mail dell'organizzatore evt.Status = DDay.iCal.DataTypes.EventStatus.Confirmed ' aggiunge l'allarme esplicitamente evt.AddProperty("BEGIN", "VALARM") evt.AddProperty("ACTION", "DISPLAY") evt.AddProperty("DESCRIPTION", "Evento di prova 2") evt.AddProperty("TRIGGER", "-PT15M") evt.AddProperty("END", "VALARM") ' aggiunge il colore evt.AddProperty("CATEGORIES","Categoria Verde") ' N.B. la descrizione della categoria deve essere quella presente nell'Outlook del destinatario Dim serializer As DDay.iCal.Serialization.iCalendarSerializer = New DDay.iCal.Serialization.iCalendarSerializer(iCal) return serializer.SerializeToString() ' ritorno del calendario serializzato
Protezione di un Action link tramite token
E’ possibile proteggere tramite token un action link che restituisce dati in formato JSon. Per farlo, si può utilizzare il seguente codice:
dim ok as boolean=true dim msg as string="" dim emmsg as string="" dim errcode as integer = 0 try ' Verifica il Token, che è nel payload della richiesta, proprietà "Token" Dim jsonr as string Page.Request.InputStream.Seek(0,System.IO.SeekOrigin.Begin) Using receiveStream As System.IO.Stream = Page.Request.InputStream Using readStream As System.IO.StreamReader = New System.IO.StreamReader(receiveStream, System.Text.Encoding.UTF8) jsonr = readStream.ReadToEnd() End Using End Using objtmp = Newtonsoft.Json.Linq.JObject.Parse(jsonr) dim token as string token = ctype(objtmp("Token"), Newtonsoft.Json.Linq.JValue).value dim valid_token as boolean = QWLib.Webutils.CheckToken2(token) if valid_token ' Inserire qui l'elaborazioen dell'Action Link else errcode = 1 msg += " Token non valido!" end if catch e as exception errcode= -1 writelog("ERRORE ACTION LINK : " & e.message+vbcr+e.stacktrace.tostring()) msg= "Errore nell'elaborazione della richiesta." emmsg = e.message+vbcr+e.stacktrace.tostring() End try dim ret_obj=New With {.ResultCode = errcode, .Result = ..... , .ResultMessage = msg, .ErrorMsg = emmsg } return newtonsoft.Json.jsonconvert.SerializeObject(ret_obj)
Il token deve essere preventivamente richiesto dal chiamante utilizzando il Web Service Rest “GetUserToken” dell’SDK di QualiWare, e passato all’action link nel payload nella proprietà “Token”.