How to console log value from an asset? in hyperledger composer? - hyperledger

I am writing a network by hyperledger composer playground.
Here i have an asset called patient, and patient has list of hospitals,
i have a transaction named GetPatientHospitals which is used to call the function getPatientHospitals, I want this function to print out a list of the ids (the thing like resource:org.acme.patientchain.PatientHospital#5wyjftthjr when i test),
but when i test my function, it only told me my transaction has been submitted, no where i could see the output, is there any way to do it? or I need another asset to store these messages?
My getPatientHospitals function:
function getPatientHospitals(gethospitals){
return getAssetRegistry('org.acme.patientchain.Patient')
.then(function (PatientAssetRegistry) {
// Get the patient asset
return PatientAssetRegistry.get(gethospitals.patient.pubKeyPatient);
})
.then(function (patienthospital) {
return patienthospital.hospitals;
})
} //list of hospitals
My GetPatientHospitals transaction and Patient asset:
transaction GetPatientHospitals {
--> Patient patient
}
asset Patient identified by pubKeyPatient {
o String pubKeyPatient
--> PatientHospital[] hospitals
}
This is the hospitals in a patient I tested:
{
"$class": "org.acme.patientchain.Patient",
"pubKeyPatient": "1652",
"hospitals": [
"resource:org.acme.patientchain.PatientHospital#5wyjftthjr",
"resource:org.acme.patientchain.PatientHospital#mgnl6ag4vh",
"resource:org.acme.patientchain.PatientHospital#5wyjftthjr"
]
}
I want to print those recourses or just the id after the #
but there was no anywhere i could see the output, can I do "print" in this playground?

You can use console.log() inside your js file. Then you can see the output in the browser developer console. For Firefox and Chrome you can show the developer console with CTRL-SHIFT-I.
This works only if you are using Playground with a 'Web' profile, then you will see console.log output in the Browser Console. If you use Playground connected to a local Fabric instance, then the console.log output will be in the log of the Chaincode container.
Try with console.log(patienthospital.hospitals) and check the output in the developer console.

For print the value you need to make one transaction in cto file.
Hyperledger composer provides Transaction processor functions. It can optionally return data to client applications. This can be useful for returning a receipt to the submitter of the transaction or returning an asset modified by the transaction to avoid a separate lookup of the asset after the transaction has been committed. Data can also be returned to the client application via a transaction REST API for the business network.
I recommend you to follow the below links :
returning data from transaction processor function
composer github
Hope it will help you :)

Related

Autodesk Simple Viewer - "Could not list models. "

I'm trying to implement the code example in this repo:
https://github.com/autodesk-platform-services/aps-simple-viewer-dotnet
While launching in debugging mode, I get an error in the AuthController.cs says:
Could not list models. See the console for more details
I didn't make any significant changes to the original code, I only changed the env vars (client id, secret etc..)
The error is on the below function:
async function setupModelSelection(viewer, selectedUrn) {
const dropdown = document.getElementById('models');
dropdown.innerHTML = '';
try {
const resp = await fetch('/api/models');
if (!resp.ok) {
throw new Error(await resp.text());
}
const models = await resp.json();
dropdown.innerHTML = models.map(model => `<option value=${model.urn} ${model.urn === selectedUrn ? 'selected' : ''}>${model.name}</option>`).join('\n');
dropdown.onchange = () => onModelSelected(viewer, dropdown.value);
if (dropdown.value) {
onModelSelected(viewer, dropdown.value);
}
} catch (err) {
alert('Could not list models. See the console for more details.');
console.error(err);
}
}
I get an access token so my client id and secret are probably correct, I also added the app to the cloud hub, what could be the problem, why the app can't find the projects in the hub?
I can only repeat what AlexAR said - the given sample is not for accessing files from user hubs like ACC/BIM 360 Docs - for that follow this: https://tutorials.autodesk.io/tutorials/hubs-browser/
To address the specific error. One way I can reproduce that is if I set the APS_BUCKET variable to something simple that has likely been used by someone else already, e.g. "mybucket", and so I'll get an error when trying to access the files in it, since it's not my bucket. Bucket names need to be globally unique. If you don't want to come up with a unique name yourself, then just do not declare the APS_BUCKET environment variable and the sample will generate a bucket name for you based on the client id of your app.

Twilio "Unable to create Room" error comes up in JS API

For some reason I'm unable to create a room directly out of JS API like this:
TwillioVideo.connect(twillioToken, {name: 'my-name'})
.then(room => {
....
}, error => {
console.error('Unable to connect to Room: ' + error.message);
})
.connect method only works for me if the room was previously created, for instance:
I create the room first with C# like this:
public string CreateRoom(string roomName) {
TwilioClient.Init(_twilioSettings.AccountSid, _twilioSettings.AuthToken);
RoomResource room = RoomResource.Create(uniqueName: roomName);
return room.Sid;
}
then after it is created i can connect to it no problem.
So I'm forced to create a room in C# api and then use it in JS API. But i would rather avoid this step.
Also I did not find a way to determine if the room with the unique name already exist prior to calling RoomResource.Create(uniqueName: roomName) because if it does exist this method throws an exception. But i would rather return an SID of existing room in that case
Please advise
Twilio developer evangelist here.
In order to create rooms via the JS SDK, you need to have to have Client-side room creation enabled in your video settings in the Twilio console.

$batch request resulting in error "Default changeset implementation allows only one operation"

I am making a worklist application using SAPUI5. The problem is that when I create an entry and then create another one right after that, I get the following error:
Default changeset implementation allows only one operation.
I checked the $batch header and I see that there is a MERGE and a POST, with the MERGE updating the previous entry for some reason. Can anyone shed some light? Could it be a backend error and not a UI5 error?
Creating the new entry:
_onMetadataLoaded: function() {
var oModel = this.getView().getModel();
var that = this;
// ...
oModel.read("/USERS_SET", {
success: function(oData) {
var oProperties = {
Qmnum: "0",
Otherstuff: "cool"
};
that._oContext = that._oView.getModel().createEntry("/ENTITYSET", {
properties: oProperties
});
that.getView().setBindingContext(that._oContext);
// ...
}
});
},
handleSavePress: function(oEvent) {
// ...
this.getView().getModel().submitChanges({
success: function(oData) {
// ...
},
error: function(oError) {
// ...
}
});
},
tl-dr: Apparently you must be using the SAP Gateway. If you do not need to process those requests in one transaction then send them in different changesets. If you do not need batch calls at all consider turning it off by supplying your model with "useBatch": false upon instantiation. However if you need to process the requests together in one transaction then you have to read the details below.
In order to understand the problem you have to understand how the gateway and the batch and changeset requests work.
Batch requests consist of multiple requests bundled together. The purpose is to open only one connection and group together relevant requests so that the overhead is minimalized. Changesets form smaller blocks inside batch requests, where modification requests can be bundled and processed together in order to ensure an all-or-nothing characteristic.
So on the gateway side: there are two relevant classes for your OData service, assuming that you have used the SAP Gateway Service Builder (SEGW transaction). There is one with the ending ...DPC and one with ...DPC_EXT. Don't touch the former, it will be always regenerated when you update your service in the service builder. The latter is the one that we will need in this example. You will have to redefine at least two methods:
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_PROCESS
By default the changeset_begin method will only allow changeset processing for changesets where the number of requests equals to one. This can be handled automatically that's why a limitation exists. If there were more requests one could not ensure their processing automatically as they could have a business dependency on each other.
So make sure to allow a bundled (deferred mode) processing of changesets under the desired conditions:
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN: first call the super->/iwbep/if_mgw_appl_srv_runtime~changeset_begin method in a try catch block, then loop at it_operation_info to decide and narrow down processing only in selected cases and then allow cv_defer_mode only for the selected cases, otherwise throw a /iwbep/cx_mgw_tech_exception=>changeset_not_supported exception.
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_PROCESS: all requests will be available in the it_changeset_request. Make sure to fill the ct_changeset_response table with the responses.
METHOD /iwbep/if_mgw_appl_srv_runtime~changeset_process.
DATA:
lv_operation_counter TYPE i VALUE 0,
lr_context TYPE REF TO /iwbep/cl_mgw_request,
lr_entry_provider TYPE REF TO /iwbep/if_mgw_entry_provider,
lr_message_container TYPE REF TO /iwbep/if_message_container,
lr_entity_data TYPE REF TO data,
ls_context_details TYPE /iwbep/if_mgw_core_srv_runtime=>ty_s_mgw_request_context,
ls_changeset_response LIKE LINE OF ct_changeset_response.
FIELD-SYMBOLS:
<fs_ls_changeset_request> LIKE LINE OF it_changeset_request.
LOOP AT it_changeset_request ASSIGNING <fs_ls_changeset_request>.
lr_context ?= <fs_ls_changeset_request>-request_context.
lr_entry_provider = <fs_ls_changeset_request>-entry_provider.
lr_message_container = <fs_ls_changeset_request>-msg_container.
ls_context_details = lr_context->get_request_details( ).
CASE ls_context_details-target_entity.
WHEN 'SomeEntity'.
"Do the processing here
WHEN OTHERS.
ENDCASE.
ENDLOOP.
ENDMETHOD.
From the error I can tell you must be using SAP GW :-) This happens only for batch requests containing more than one create/delete/update calls and it's related to transaction security ("all or nothing"). What you have to do is redefining the corresponding GW method, I think it was CHANGESET_BEGIN. See https://archive.sap.com/discussions/thread/3562720 for some details (can't offer more for now...).

Quickbooks Online - Cannot get LinkedTxn detail

I created an Expense record and linked to an Invoice. When i import Invoice object through API, it has linked transaction as below.
"LinkedTxn":[{
"TxnId":"1356", //Id of Expense
"TxnType":"ReimburseCharge" //Type showing as ReimburseCharge
}]
In Quickbooks online docs, it is mentiond as
Links to expenses incurred on behalf of the customer are returned in
the response with LinkedTxn.TxnType set to ReimbCharge, ChargeCredit
or StatementCharge corresponding to billable customer expenses of type
Cash, Delayed Credit, and Delayed Charge, respectively. Links to these
types of transactions are established within the QuickBooks UI, only,
and are available as read-only at the API level.
Use LinkedTxn.TxnLineId as the ID in a separate read request for the
specific resource to retrieve details of the linked object.
In response it is showing TxnType as ReimburseCharge, but I didn't see any object like that in api explorer or docs. I don't know what type of object to request with id. I tried with Purchase, PurchaseOrder, Bill etc. but not of the request returned expected expense record.
Please help on how to access this Expense record with linked transaction id through api.
Invoice JSON:
Invoice line with description Printing paper is the expense linked in this invoice.
{
"Invoice":{
"Id":"1358",
"LinkedTxn":[
{
"TxnId":"1356",
"TxnType":"ReimburseCharge"
}
],
"Line":[
{
"Id":"1",
"LineNum":1,
"Description":"Printing paper",
"DetailType":"DescriptionOnly",
"DescriptionLineDetail":{
}
},
{
"Id":"3",
"LineNum":2,
"Description":"Magazine Monthly",
"Amount":100.0,
"DetailType":"SalesItemLineDetail",
"SalesItemLineDetail":{
"ItemRef":{
"value":"19",
"name":"Publications:Magazine Monthly"
},
"UnitPrice":100,
"Qty":1,
"TaxCodeRef":{
"value":"NON"
}
}
},
{
"Amount":250.0,
"DetailType":"SubTotalLineDetail",
"SubTotalLineDetail":{
}
}
],
"Balance":250.0
}
}
The docs are a little confusing on this point - unfortunately, the second paragraph
Use LinkedTxn.TxnLineId as the ID in a separate read request for the specific resource to retrieve details of the linked object.
is a generic paragraph that appears for docs on every Ref type, but shouldn't appear here. It's impossible to access these transactions via the API. More detail available here.

How do you switch from SQL to Table Storage in Azure Mobile Services?

I've signed up for the free month trial of Azure, and I have created a Mobile Service. I'm using iOS, so I downloaded the model Todo app for iOS.
I am now trying to use Table Storage in the back end instead of a MSSQL store; I have found instructions on using Table Storage here: http://azure.microsoft.com/en-us/documentation/articles/storage-nodejs-how-to-use-table-storage/
However, my app is still storing todo items in the MSSQL storage. I've been told that I don't need to do anything in the client to make the switch, so I assume everything I need to do must be done in the node.js scripts. But I'm clearly missing something.
One thing that confuses me is that after I downloaded the generated node.js script for the Todo app, I didn't see anything in it that seemed to be explicitly talking to the MSSQL database.
Any pointers would be greatly appreciated.
EDIT:
here's my todoitem.insert.js:
var azure = require('azure-storage');
var tableSvc = azure.createTableService();
function insert(item, user, request) {
// request.execute();
console.log('Request received');
console.log(request);
var entGen = azure.TableUtilities.entityGenerator;
var task = {
PartitionKey: entGen.String('learningazure'),
RowKey: entGen.String('1'),
description: entGen.String('add something to TS'),
dueDate: entGen.DateTime(new Date(Date.UTC(2014, 11, 5))),
};
tableSvc.insertEntity('codedelphi',task, {echoContent: true}, function (error, result, response) {
if(!error){
// Entity inserted
console.log('No error on table insert: task created.');
request.respond(statusCodes.SUCCESS, 'OK.');
} else {
console.log('Houston, we have a problem. Entity not added to table.');
console.log(error);
}
});
console.log(JSON.stringify(item, null, 4));
}
tableSvc.createTableIfNotExists('codedelphi', function(error, result, response){
if(!error){
// Table exists or created
console.log('No error, table should exist');
} else {
console.log('We have a problem.');
console.log(error);
}
});
Mobile Services has the built in capability to handle talking to your SQL Database for you. When your script calls "request.execute()" that triggers whatever the request is (insert, update, delete, select) to be ran against the SQL database. Talking to Table Storage instead of SQL requires you to edit those scripts to explicitly talk to Table Storage (i.e. perform your insert, update, deletes, and reads). Today there is no magic switch which will change your "request.execute" from talking to SQL to talk to Table Storage. If you've already edited your scripts to talk to Table Storage and it's not working / you still see data stored in your SQL database, I would suspect that you are either still calling "request.execute" in your scripts, or you haven't pushed them to your Mobile Service (if you've pulled them down locally and then need to push them back to your service). If you've done all of the above, update your question with the Node.js script in question so we can see it.
As Chris pointed out, you are most likely still calling request.execute() from your table scripts. By design, this will explicitly talk to the MSSQL database you configured your application with. You will have to edit your table scripts to not perform "request.execute()" and instead interact with the TableService object.
If you follow the tutorial, and do the following:
1. Import the package.
2. Create the table service object.
3. Create an entity (and modify the variables to store the data you need)
4. Write the entity to your table service.
You should see data being written to table storage rather than SQL database.
Give it a shot and ping back, we'll help you out.

Resources