====== Angular JSON-RPC ====== Yet another method of reading the JSON-RPC interface. The example below reads the result of the latest softwareAudit and displays it as a table. Information about installed sw products are merged in. All needed files (.html, .js, .css) should be hosted below /usr/share/opsiconfd/static/AngularExample folder. This way no other Webserver is involved and cross scripting complaints by the browser are avoided. The location would then read https://opsi:4447/AngularExample. ====== Prerequisites ====== Of course its helpful to load the angular-min.js (or angular.js for development) from an appropriate location. The example uses a local copy. ====== Minor Obstacles ====== opsiconfd will currently answer /rpc? requests with Encoding "deflate", but will anounce it as "gzip". This currently prevents any browser from even reading the opsiconfd answer. The responsible Worker.py needs a small change to answer requests from a browser //and// Winst.exe (and other legacy opsi clients) as well. The issue is known and a patch is [[https://forum.opsi.org/viewtopic.php?f=6&t=7449|mentioned in the forums]]. Most requests require a logon, some even special rights. The script user should be member of a new group //opsireader// and the **acl.conf** file should be prepended with appropriate lines: getProducts_.* : sys_group(opsireader); sys_group(opsiadmin); opsi_depotserver; self; opsi_client productOnClient_get.* : sys_group(opsireader); sys_group(opsiadmin); opsi_depotserver;self; opsi_client auditSoftwareOnClient_get.* : sys_group(opsireader); sys_group(opsiadmin); opsi_depotserver; self; opsi_client product_get.* : sys_group(opsireader); sys_group(opsiadmin); opsi_depotserver; self; opsi_client ====== Calling Parameter ====== When called as /AngularExample/?{"dns":"clientID.domain.local"} the SoftwareAudit of the given clientId is displayed. OPSI client names may be entered in an input field at any time and are queried asynchronously. The strange format of the query string as json has its reason: it is needed for the AndroidApp named [[https://play.google.com/store/apps/details?id=eu.dirtyharry.opsiadmin|OPSI Admin]]. The App can read barcodes/QRcodes formatted this way in order to open the details of the identified client. Nice feature when the barcode sticks on the client. What if the barcode appears right on the client's screen? Try this Java app: [[https://github.com/GallusMax/opsi/tree/master/opsi-barcode|Opsi-Barcode]] ====== The Code ====== /usr/share/opsiconfd/static/AngularExample ├ index.html ├ angular.js ├ swinv.js └ swinv.css ======= index.html ======= Where all other is loaded from..
NameVersionLizenzInstallationsgrund
{{swp.name}} {{swp.version}} {{sw.reason(swp.name)}} {{sw.reason(swp.name)}} {{sw.opsiProdId(swp.name)}}

OpsiProduct
{{inst}}

productInfoproductId...............................................
{{prod.productId}} {{prod.name}}
======= swinv.js ======= The AngularJS mimic.. (function(){ var app = angular.module('opsi-swinv', []); app.controller('swinvController',function($http,$filter){ this.showallprods=0; this.showopsiinstalled=0; baseurl='/rpc'; logonurl='https://testerMemberOfGroupopsireader:unGuessablePassword@'+window.location.host+'/rpc'; this.clientId="defaultclient.domain.local"; this.auditParams={'id':'jsonrpc','method':'auditSoftwareOnClient_getObjects','params':[]}; this.auditParams.params.push([]); this.auditParams.params.push({"clientId":"defaultclient.domain.local"}); me=this; me['installed']=[]; me['productinfos']=[]; this.jsonParmDns=function(){ this.search=window.location.search; if (this.search.match(/dns/)){ // we believe in barcode like {"dns":""} var qsearch=decodeURIComponent(this.search).match(/{.+dns.+:.+}/); var jsonsearch=decodeURIComponent(qsearch); // get the json return angular.fromJson(jsonsearch).dns; // return JSON.parse(jsonsearch).dns; } return null; }; this.opsicall=function(field,method,arg){ Params={'id':'1','method':method,'params':[]}; if(arg)Params.params[0]=arg; $http.post(baseurl,Params) .success(function(response,stat,head,conf){ // alert("success: "+$filter('json')(response)); me.opsires="success: "+method; me.opsiconf=conf; if(response.error) alert(response.error.message); else me[field]=response.result; }) .error(function(err,stat,head,conf){ me.opsires="error"; alert("err: "+(err)+stat+head+$filter('json')(conf)); me.opsistat=stat; me.opsihead=head; me.opsiconf=conf; }); }; this.logon=function(){ $http.post(logonurl,this.logonParams) .success(function(response){ // alert("success: "+$filter('json')(response)); // call after logon success me.getproductinfos(); me.refresh(me.clientId); }) .error(function(response){ alert("err: "+(response)); }); }; this.getprods=function(id){ this.opsires="calling.. "+id; if(id)this.auditParams.params[1].clientId=id; $http.post(baseurl,this.auditParams) .success(function(response,stat,head,conf){ // alert("success: "+response); if(response.error)alert(response.error.message); me.products=response.result; me.opsistat=stat; me.opsihead=head; me.opsiconf=conf; }) .error(function(err,stat,head,conf){ me.opsires="error"; alert("err: "+(err)+stat+head+$filter('json')(conf)); me.opsistat=stat; me.opsihead=head; me.opsiconf=conf; }); }; // get products on Client with id this.getinstalled=function(id){ this.opsicall('installed','getInstalledLocalBootProductIds_list',id); }; // get all available OPSi products this.getproductinfos=function(){ this.opsicall('productinfos','getProducts_listOfHashes'); }; this.logon(); this.clientId=this.jsonParmDns(); // this.getproductinfos(); this.refresh=function(id){ if(null != id){ this.getprods(id); this.getinstalled(id); } }; this.nonMS=function(name){ // return true; if(name.match(/AddressBook/)) return false; if(name.match(/^Connection Manager/)) return false; if(name.match(/^DirectDrawEx/)) return false; if(name.match(/^DXM_Runtime/)) return false; if(name.match(/^Fontcore/)) return false; if(name.match(/KB[0-9]+/)) return false; if(name.match(/Microsoft/)) return false; if(name.match(/^MPlayer2/)) return false; if(name.match(/^Outlook/)) return false; if(name.match(/^[iI][Ee]/)) return false; if(name.match(/^Windows/)) return false; if(name.match(/^MobileOptionPack/)) return false; if(name.match(/^SchedulingAgent/)) return false; if(name.match(/^WIC/)) return false; return true; } this.pattern=swpattern; this.reason=function(name){ for(p in this.pattern){ if(name.match(p)) return this.pattern[p]; } }; // guess the corresponding OPSI productId from the Windows Product name this.opsiProdId=function(name){ for(i=0; i ======= swinv.css ======= some tweaking of the appearance - anything goes.. body { font-family: "Comic Sans M$", Arial, Helvetica, sans-serif; } table{ width: 100%; border-collapse: collapse; } td, th { font-size: 1em; border: 1px solid #aa0093; padding: 3px 7px 2px 7px; } th { font-size: 1.1em; text-align: left; padding-top: 5px; padding-bottom: 4px; background-color: #d30c6b; color: #ffffff; } label{ background-color: #d30c6b; color: #ffffff; } td.warn { /* enhance unlicensed products*/ color: #000000; background-color: yellow; } .ng-binding{ // background-color: blue; font-family: Courier; }