moodle/webservice/amf/testclient/AMFTester.mxml

513 lines
17 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
backgroundColor="white"
layout="vertical"
creationPolicy="all"
height="100%" width="100%"
applicationComplete="init()"
xmlns:cv="customValidators.*"
defaultButton="{call}">
<mx:Script>
<![CDATA[
import mx.rpc.remoting.Operation;
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
import mx.messaging.Channel;
import mx.rpc.remoting.RemoteObject;
import mx.events.ValidationResultEvent;
import mx.validators.Validator;
/**
* Main class/dialog
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author Jamie Pratt <me@jamiep.org>
*/
import mx.controls.Label;
import mx.controls.Alert;
import mx.messaging.channels.AMFChannel;
import com.adobe.serialization.json.JSON;
// Import the debugger
// import nl.demonsters.debugger.MonsterDebugger;
protected var methods:Array;
protected var introspector:String;
public var rooturl:String;
[Bindable]
public var serviceurl:String;
public var channel:AMFChannel;
[Bindable]
public var argumentToolTip:String = "You can use JSON syntax for method arguments ie. an array is written like this [item1, item2, etc.] objects are written {\"propname\":value, \"propname2\":value2, etc}";
// Variable to hold the debugger
// private var debugger:MonsterDebugger;
/**
* restores the last settings if available
*/
public function init():void
{
// Init the debugger
// debugger = new MonsterDebugger(this);
// Send a simple trace
// MonsterDebugger.trace(this, "Hello World!");
var so:SharedObject = SharedObject.getLocal('AMFTester');
if (so.data.token) {
token.text = so.data.token;
}
if (so.data.username) {
username.text = so.data.username;
password.text = so.data.password;
}
if (so.data.mode == 'username'){
loginType.selectedIndex = 1;
}
this.rememberpassword.selected = so.data.rememberpassword;
this.remembertoken.selected = so.data.remembertoken;
this.rooturl = Application.application.parameters.rooturl;
this.urllabel1.text = 'Root URL :'+this.rooturl;
this.urllabel2.text = 'Root URL :'+this.rooturl;
}
public function doConnectToken():void
{
serviceurl = this.rooturl + '/webservice/amf/server.php?'+
'wstoken='+this.token.text;
this.doConnect();
// saving settings for next time
var so:SharedObject = SharedObject.getLocal('AMFTester');
if (this.rememberpassword.selected == true ){
so.setProperty('token', this.token.text);
} else {
so.setProperty('token', null);//delete shared obj prop
}
so.setProperty('remembertoken', this.remembertoken.selected);
so.setProperty('mode', 'token');
so.flush();
}
public function doConnectUsername():void
{
serviceurl = this.rooturl + '/webservice/amf/simpleserver.php?'+
'wsusername=' + this.username.text+
'&wspassword=' + this.password.text;
this.doConnect();
// saving settings for next time
var so:SharedObject = SharedObject.getLocal('AMFTester');
if (this.rememberpassword.selected == true ){
so.setProperty('username', this.username.text);
so.setProperty('password', this.password.text);
} else {
so.setProperty('username', null);//delete shared obj prop
so.setProperty('password', null);
}
so.setProperty('rememberpassword', this.rememberpassword.selected);
so.setProperty('mode', 'username');
so.flush();
}
/**
* initializes the connection
*/
private function doConnect():void
{
push("Connecting to "+serviceurl);
//api.source = 'MethodDescriptor';
api.setCredentials(this.username.text, this.password.text);
api.removeEventListener("result", outputResult);
api.addEventListener("result", handleConnection);
api.getOperation("MethodDescriptor.getMethods").send();
if (!api.hasEventListener("fault")) {
api.addEventListener("fault", faultHandler);
}
this.panelDebug.enabled = false;
}
/**
* initializes the debugger dialog with the method list and everything
*/
protected function handleConnection(event:ResultEvent):void
{
methods = [];
for (var cls:String in event.result) {
for (var meth:String in event.result[cls]['methods']) {
methods.push({label: cls+'.'+meth, docs: event.result[cls]['methods'][meth]['docs'], args: event.result[cls]['methods'][meth]['params']});
}
}
methods.sortOn('label', Array.CASEINSENSITIVE);
this.panelDebug.enabled = true;
this.maintabs.selectedIndex = 1;
func.dataProvider = methods;
api.removeEventListener("result", handleConnection);
api.addEventListener("result", outputResult);
reloadArgs();
}
/**
* outputs a response from the server
*/
protected function outputResult(event:ResultEvent):void
{
var keys:Array = new Array();
for (var key:String in event.result){
keys.push(key);
}
push("Result returned \n" + obj2string(event.result));
}
protected function obj2string(obj:Object, depth:Number=0):String{
var string:String = '';
if (obj==null){
return 'NULL';
}
switch (typeof(obj)){
case 'object':
if (obj is Array){
string += "Array\n";
} else {
string += "Object\n";
}
string += depth2string(depth+1)+"(\n";
for (var key:String in obj){
string += depth2string(depth+2)+'['+key+'] => '+obj2string(obj[key], depth+3);
}
string += depth2string(depth+1)+")\n";
break;
case 'string':
var formattedstring:String = obj.toString();
formattedstring = formattedstring.replace(/\r/g, "");
formattedstring = formattedstring.replace(/\n/g, "\n"+depth2string(depth+3));
string += '"'+formattedstring+'"'+"-("+typeof(obj)+")"+"\n";
break;
default :
string += obj.toString()+"-("+typeof(obj)+")"+"\n";
}
return string;
}
protected function depth2string(depth:Number):String{
var string:String = '';
var i:Number = 0;
while (i<depth){
string += ' ';
i++;
}
return string;
}
/**
* updates the display of arguments when the selected method changes
*
* it's hardly optimal to do it that way but it was faster to copy paste, I just hope nobody needs more than 7 args
*/
protected function reloadArgs():void
{
var i:int;
for (i = 1; i <= 7; i++) {
this['arg'+i].visible = false;
this['arg'+i].includeInLayout = false;
this['larg'+i].visible = false;
this['larg'+i].includeInLayout = false;
this['cbarg'+i].visible = false;
this['cbarg'+i].includeInLayout = false;
this['JSONV'+i].enabled = false;
}
i = 1;
for (var arg:String in func.selectedItem.args) {
(this['arg'+i] as TextInput).visible = true;
(this['arg'+i] as TextInput).includeInLayout = true;
if (func.selectedItem.args[arg]['required']){
(this['arg'+i] as TextInput).enabled = true;
this['cbarg'+i].selected = true;
}
(this['larg'+i] as Label).visible = true;
(this['larg'+i] as Label).includeInLayout = true;
this['cbarg'+i].visible = !func.selectedItem.args[arg]['required'];
this['cbarg'+i].includeInLayout = !func.selectedItem.args[arg]['required'];
this['JSONV'+i].enabled = this['cbarg'+i].selected;
this['JSONV'+i].required = true;
(this['larg'+i] as Label).text = func.selectedItem.args[arg]['name'] + (func.selectedItem.args[arg]['required'] ? "*":"");
i++;
}
while (i <= 7) {
this['cbarg'+i].selected = false;
i++;
}
if (func.selectedItem.docs == ""){
(this.methodDescription as TextArea).text = "";
(this.methodDescription as TextArea).visible = false;
(this.methodDescription as TextArea).includeInLayout = false;
} else {
(this.methodDescription as TextArea).text = func.selectedItem.docs.replace(/[\n\r\f]+/g, "\n");
(this.methodDescription as TextArea).visible = true;
(this.methodDescription as TextArea).includeInLayout = true;
}
}
public function toggleCheckBoxes(startAt:uint):void{
var i:uint= startAt;
if (this['cbarg'+i].selected){
i--;
while (i >= 1){
this['cbarg'+i].selected = true;
i--;
}
} else {
i++;
while (i <= 7){
this['cbarg'+i].selected = false;
i++;
}
}
}
/**
* calls a method on the server
*/
protected function execute():void
{
var input:TextInput;
var argumentArray:Array = [];
var argumentErrors:Array = Validator.validateAll(argumentValidators);
if (argumentErrors.length != 0){
// MonsterDebugger.trace(this, argumentErrors);
return;
}
for(var i:int = 1; i <= 7; i++)
{
input = this['arg' +i] as TextInput;
if(input && input.visible)
{
if (!this['cbarg' +i].selected){
break;
} else if (input.text.indexOf("\"") == 0 || input.text.indexOf("{") == 0 || input.text.indexOf("[") == 0)
try {
argumentArray.push(JSON.decode(input.text));
} catch (err:Error){
return;
}
else
argumentArray.push(input.text as String);
}
}
//no other way to pass arguments as array :
switch (argumentArray.length){
case 0:
api.getOperation(func.selectedLabel).send();
break;
case 1:
api.getOperation(func.selectedLabel).send(argumentArray[0]);
break;
case 2:
api.getOperation(func.selectedLabel).send(argumentArray[0], argumentArray[1]);
break;
case 3:
api.getOperation(func.selectedLabel).send(argumentArray[0], argumentArray[1], argumentArray[2]);
break;
case 4:
api.getOperation(func.selectedLabel).send(argumentArray[0], argumentArray[1], argumentArray[2], argumentArray[3]);
break;
case 5:
api.getOperation(func.selectedLabel).send(argumentArray[0], argumentArray[1], argumentArray[2], argumentArray[3], argumentArray[4]);
break;
case 6:
api.getOperation(func.selectedLabel).send(argumentArray[0], argumentArray[1], argumentArray[2], argumentArray[3], argumentArray[4], argumentArray[5]);
break;
case 7:
api.getOperation(func.selectedLabel).send(argumentArray[0], argumentArray[1], argumentArray[2], argumentArray[3], argumentArray[4], argumentArray[5], argumentArray[6]);
break;
}
// MonsterDebugger.trace(this, [func.selectedLabel, argumentArray[0], argumentArray[1], argumentArray[2], argumentArray[3], argumentArray[4], argumentArray[5], argumentArray[6]]);
push("Calling "+func.selectedLabel+" with arguments \n"+obj2string(argumentArray));
}
/**
* clears debug consoles
*/
protected function clear():void
{
output.text = output.text = "";
}
/**
* clears debug consoles
*/
protected function goBottom():void
{
output.verticalScrollPosition = output.maxVerticalScrollPosition;
}
/**
* refreshes the method list
*/
protected function refresh():void
{
api.removeEventListener("result", outputResult);
api.addEventListener("result", handleConnection);
api.exec(introspector);
}
/**
* returns timestamp string
*/
protected function time():String
{
var d:Date = new Date();
var ret:String = d.hours+":"+d.minutes+":"+d.seconds+"."+d.milliseconds;
return ret + "000000000000".substring(ret.length);
}
/**
* handler for specific net events
*/
public function faultHandler(event:FaultEvent):void
{
push("Error("+event.type+" - "+ event.fault.faultCode + "): "+event.fault.faultString+", "+event.fault.faultDetail);
}
/**
* pushes text into a console and scrolls it down automatically
*/
public function push(text:String):void
{
output.text += time() + ": "+ text + "\n";
output.verticalScrollPosition = output.maxVerticalScrollPosition;
}
]]>
</mx:Script>
<mx:RemoteObject id="api" destination="zend" endpoint="{serviceurl}" />
<mx:Array id="argumentValidators">
<cv:JSONValidator id="JSONV1" required="true" enabled="{cbarg1.selected}" source="{arg1}" property="text" />
<cv:JSONValidator id="JSONV2" required="true" enabled="{cbarg2.selected}" source="{arg2}" property="text" />
<cv:JSONValidator id="JSONV3" required="true" enabled="{cbarg3.selected}" source="{arg3}" property="text" />
<cv:JSONValidator id="JSONV4" required="true" enabled="{cbarg4.selected}" source="{arg4}" property="text" />
<cv:JSONValidator id="JSONV5" required="true" enabled="{cbarg5.selected}" source="{arg5}" property="text" />
<cv:JSONValidator id="JSONV6" required="true" enabled="{cbarg6.selected}" source="{arg6}" property="text" />
<cv:JSONValidator id="JSONV7" required="true" enabled="{cbarg7.selected}" source="{arg7}" property="text" />
</mx:Array>
<mx:HBox width="100%" height="550">
<mx:TabNavigator id="maintabs" height="100%" width="100%" >
<mx:TabNavigator label="Connect" id="loginType" borderStyle="solid" height="100%" width="100%">
<mx:Panel label="Use Token" id="panelConnectToken">
<mx:HBox width="100%">
<mx:Label text="Token"/>
<mx:TextInput id="token" text="" width="100%"/>
</mx:HBox>
<mx:HBox width="100%">
<mx:Label text="Remember"/>
<mx:CheckBox id="remembertoken" width="100%"/>
</mx:HBox>
<mx:Label id="urllabel1" text="URL :" />
<mx:HBox width="100%">
<mx:Spacer width="100%" />
<mx:Button label="Connect" click="doConnectToken()"/>
<mx:Spacer width="100%" />
</mx:HBox>
</mx:Panel>
<mx:Panel label="Use Username and Password" id="panelConnectUsername">
<mx:HBox width="100%">
<mx:Label text="Username"/>
<mx:TextInput id="username" text="" width="100%"/>
</mx:HBox>
<mx:HBox width="100%">
<mx:Label text="Password"/>
<mx:TextInput id="password" text="" displayAsPassword="true" width="100%"/>
</mx:HBox>
<mx:HBox width="100%">
<mx:Label text="Remember"/>
<mx:CheckBox id="rememberpassword" width="100%"/>
</mx:HBox>
<mx:Label id="urllabel2" text="URL :" />
<mx:HBox width="100%">
<mx:Spacer width="100%" />
<mx:Button label="Connect" click="doConnectUsername()"/>
<mx:Spacer width="100%" />
</mx:HBox>
</mx:Panel>
</mx:TabNavigator>
<mx:Panel label="Service Browser" width="100%" height="100%" layout="vertical" title="Moodle AMF Service Browser" enabled="false" id="panelDebug">
<mx:HBox width="100%">
<mx:Label text="Func "/>
<mx:ComboBox id="func" change="reloadArgs()">
</mx:ComboBox>
</mx:HBox>
<mx:TextArea id="methodDescription" text="" width="100%" height="150"/>
<mx:HBox width="100%">
<mx:Label id="larg1" text="Arg 1"/>
<mx:CheckBox id="cbarg1" click="toggleCheckBoxes(1)"/>
<mx:TextInput id="arg1" toolTip="{argumentToolTip}" width="100%" enabled="{cbarg1.selected}"/>
</mx:HBox>
<mx:HBox width="100%">
<mx:Label id="larg2" text="Arg 2"/>
<mx:CheckBox id="cbarg2" click="toggleCheckBoxes(2)"/>
<mx:TextInput id="arg2" toolTip="{argumentToolTip}" width="100%" enabled="{cbarg2.selected}"/>
</mx:HBox>
<mx:HBox width="100%">
<mx:Label id="larg3" text="Arg 3"/>
<mx:CheckBox id="cbarg3" click="toggleCheckBoxes(3)"/>
<mx:TextInput id="arg3" toolTip="{argumentToolTip}" width="100%" enabled="{cbarg3.selected}"/>
</mx:HBox>
<mx:HBox width="100%">
<mx:Label id="larg4" text="Arg 4"/>
<mx:CheckBox id="cbarg4" click="toggleCheckBoxes(4)"/>
<mx:TextInput id="arg4" toolTip="{argumentToolTip}" width="100%" enabled="{cbarg4.selected}"/>
</mx:HBox>
<mx:HBox width="100%">
<mx:Label id="larg5" text="Arg 5"/>
<mx:CheckBox id="cbarg5" click="toggleCheckBoxes(5)"/>
<mx:TextInput id="arg5" toolTip="{argumentToolTip}" width="100%" enabled="{cbarg5.selected}"/>
</mx:HBox>
<mx:HBox width="100%">
<mx:Label id="larg6" text="Arg 6"/>
<mx:CheckBox id="cbarg6" click="toggleCheckBoxes(6)"/>
<mx:TextInput id="arg6" toolTip="{argumentToolTip}" width="100%" enabled="{cbarg6.selected}"/>
</mx:HBox>
<mx:HBox width="100%">
<mx:Label id="larg7" text="Arg 7"/>
<mx:CheckBox id="cbarg7" click="toggleCheckBoxes(7)"/>
<mx:TextInput id="arg7" toolTip="{argumentToolTip}" width="100%" enabled="{cbarg7.selected}"/>
</mx:HBox>
<mx:HBox width="100%">
<mx:Button id="call" label="Call" click="execute()"/>
<mx:Button label="Clear" click="clear()"/>
<mx:Button label="Scroll to bottom of debug output" click="goBottom()"/>
</mx:HBox>
</mx:Panel>
</mx:TabNavigator>
</mx:HBox>
<mx:HBox width="100%" height="100%">
<mx:TextArea id="output" width="100%" height="100%"/>
</mx:HBox>
</mx:Application>