User Tools

Site Tools


userspace:json-rpc_angularjs

This is an old revision of the document!


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 thus avoiding cross scripting complaints of modern browsers.

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 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

The Code

/usr/share/opsiconfd/static/AngularExample
  ├ index.html
  ├ angular.js
  ├ swinv.js
  └ swinv.css
 

index.html

Where all other is loaded from..

<!DOCTYPE html>
<html ng-app="opsi-swinv">
<head>
    <link rel="stylesheet" type="text/css" href="swinv.css" >
    <script type="text/javascript" src="angular.js"></script> <!-- chenge to angular-min for production -->
    <!-- script type="text/javascript" src="angular-resource.js"></script -->
    <script type="text/javascript" src="swinv.js"></script>
    <script type="text/javascript" src="swpattern.js"></script>
</head>
 
<body ng-controller="swinvController as sw">
 
<div class="swlist">
 
<input id="inputId" ng-model="sw.clientId"></input>
<button ng-click="sw.refresh(sw.clientId)">refresh list</button>
 
 
<table border >
  <tr><th>Name</th><th>Version</th><th>Lizenz</th><th>Installationsgrund</th></tr>
 
<tr ng-repeat="swp in sw.products" ng-show="sw.nonMS(swp.name)">
<td>{{swp.name}} </td>
<td> {{swp.version}}</td>
<td>{{sw.reason(swp.name)}}</td>
<td class={{sw.csswarn(swp.name)}}><span ng-show="!sw.isOpsi(swp.name)">{{sw.reason(swp.name)}} </span>{{sw.opsiProdId(swp.name)}}</td>
</tr>
</table>
 
<br/><label><input type="checkbox" ng-model="sw.showopsiinstalled" />installed OPSI products on this client <span>({{sw.clientId}})</span></label>
<div ng-show="sw.showopsiinstalled">
<table border>
  <tr><th>OpsiProduct</th></tr>
  <tr ng-repeat="inst in sw.installed">
    <td>{{inst}}</td>
  </tr>
</table>
</div>
 
<br/><label><input type="checkbox" ng-model="sw.showallprods" />available products</label>
<table ng-show="sw.showallprods" border width="100%">
  <tr><th>productInfo</th><th>productId</th><th>...............................................</th></tr>
  <tr ng-repeat="prod in sw.productinfos">
 
    <td>{{prod.productId}}</td>
    <td>{{prod.name}}</td>
    <td></td>
  </tr>
</table>
 
</div>
</body>
</html>

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"});
 
	opsiURL=baseurl+"?"+$filter('json')(this.auditParams);
 
	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":"<clientId>"}
		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<this.productinfos.length;i++){
		p=this.productinfos[i];
		if(p.name && name.match(p.name)||name.match(p.productId))
		    return p.productId;
	    }
	    return null;
	};
	// convenience: is this an OPSI product?
	this.isOpsi=function(name){
	    return (null != this.opsiProdId(name));
	};
 
	// mark rows w/o reason/license
	this.csswarn=function(name){
	    if(this.isOpsi(name) || this.reason(name))
		return "ng-binding";
	    else
		return "warn";
	};
 
 
    });
 
 
    var swpattern={'^Audacity':'OpenSource',
		   '^Java':'Oracle',
		   '^Mozilla ':'Mozilla Public',
		   '^OpenOff':'OpenSource',
		   '^Google':'Google Public',
		   '^Adobe Flash':'Adobe Public',
		   '^OpenSSL':'OpenSource',
		   '^Python':'OpenSource'
 
		  };
 
 
 
 
})();

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;
}
userspace/json-rpc_angularjs.1430489802.txt.gz · Last modified: 2021/08/23 08:37 (external edit)