In my hyperledger-composer app, I have a transaction processor:
async function doSomething(transaction) {
//some code
// the following line results in error message:
const connection = new BusinessNetworkConnection();
await connection.connect('admin#tmy-network');
const result = await connection.query(selectPatientByEmail, { inputValue: email });
//some more code
}
However, the line
const connection = new BusinessNetworkConnection();
causes the following error messsage:
ReferenceError: BusinessNetworkConnection is not defined
How can I define the BusinessNetworkConnection?
*******************************UPDATE**************************************
Following the comment by Paul O'Mahony, I used the following line of code in my transaction processor function (in order to get the patient with the email address 'adam#gmail.com'):
let result = await query('selectPatientByEmail', {
"email": "adam#gmail.com"
});
The query is defined in the queries.qry file as follows:
query selectPatientByEmail {
description: "Select the patient with the given email address"
statement:
SELECT org.comp.app.Patient
WHERE (email == _$email)
}
However, the query returns "undefined" (i.e. variable "result" is undefined) .
What for god's sake is wrong with the code? I just can't see what might be the causing this behaviour.
***************************Update2*****************************************
I have to correct myself ... the query returns something ... but when I want to access the id of the returned patient, this is not possible. That is,
result.id is "undefined"
How can I access the id of the patient returned?
this is because you are (above) writing client code inside a native transaction function - you don't need to set these. Transaction processor functions are automatically invoked by the runtime when transactions are submitted (eg using the BusinessNetworkConnection API under the covers, but it is already part of the transaction - you don't need to specify) . See https://hyperledger.github.io/composer/latest/reference/js_scripts for more info - and the sample networks for common use cases and examples -> https://github.com/hyperledger/composer-sample-networks/tree/master/packages/
Related
I have a question regarding a small issue that I'm having. I've created a widget that will live on the Service Portal to allow an admin to Accept or Reject requests.
The data for the widget is pulling from the Approvals (approval_approver) table. Under my GlideRecord, I have a query that checks for the state as requested. (Ex. addQuery('state', 'requested'))
To narrow down the search, I tried entering addQuery('sys_id', current.sys_id). When I use this query, my script breaks and I get an error on the Service Portal end.
Here's a sample of the GlideRecord script I've written to Accept.
[//Accept Request
if(input && input.action=="acceptApproval") {
var inRec1 = new GlideRecord('sysapproval_approver');
inRec1.addQuery('state', 'requested');
//inRec1.get('sys_id', current.sys_id);
inRec1.query();
if(inRec1.next()) {
inRec1.setValue('state', 'Approved');
inRec1.setValue('approver', gs.getUserID());
gs.addInfoMessage("Accept Approval Processed");
inRec1.update();
}
}][1]
I've research the web, tried using $sp.getParameter() as a work-around and no change.
I would really appreciate any help or insight on what I can do different to get script to work and filter the right records.
If I understand your question correctly, you are asking how to get the sysId of the sysapproval_approver record from the client-side in a widget.
Unless you have defined current elsewhere in your server script, current is undefined. Secondly, $sp.getParameter() is used to retrieve URL parameters. So unless you've included the sysId as a URL parameter, that will not get you what you are looking for.
One pattern that I've used is to pass an object to the client after the initial query that gets the list of requests.
When you're ready to send input to the server from the client, you can add relevant information to the input object. See the simplified example below. For the sake of brevity, the code below does not include error handling.
// Client-side function
approveRequest = function(sysId) {
$scope.server.get({
action: "requestApproval",
sysId: sysId
})
.then(function(response) {
console.log("Request approved");
});
};
// Server-side
var requestGr = new GlideRecord();
requestGr.addQuery("SOME_QUERY");
requestGr.query(); // Retrieve initial list of requests to display in the template
data.requests = []; // Add array of requests to data object to be passed to the client via the controller
while(requestsGr.next()) {
data.requests.push({
"number": requestsGr.getValue("number");
"state" : requestsGr.getValue("state");
"sysId" : requestsGr.getValue("sys_id");
});
}
if(input && input.action=="acceptApproval") {
var sysapprovalGr = new GlideRecord('sysapproval_approver');
if(sysapprovalGr.get(input.sysId)) {
sysapprovalGr.setValue('state', 'Approved');
sysapprovalGr.setValue('approver', gs.getUserID());
sysapprovalGr.update();
gs.addInfoMessage("Accept Approval Processed");
}
...
I want to return assignments in Google Classrom using
service().courseWork().studentSubmissions().return_(courseId=PASS_HERE_THE_COURSEID, courseWorkId=PASS_HERE_THE_COURSEWORDID, id=PASS_HERE_THE_SUBMISSION_ID)
I have the courseId and the courseWorkId, but don´t know how to get the id=PASS_HERE_THE_SUBMISSION_ID for each student.
Hope someone can help me.
You can use courses.courseWork.studentSubmissions.list to get a list of student submissions. You just need to provide the courseId and courseWorkId as a path parameter. You may also include additional query parameters in your request.
For example, you want to restrict returned student work to those owned by the student with the specified identifier. You need to set a specific identifier to userId as part of your query parameters
Note: You may also loop all the list of student submission to process each submission before returing it using courses.courseWork.studentSubmissions.return
The numeric identifier for the user
The email address of the user
The string literal "me", indicating the requesting user
Sample Response Body (JSON):
{
"studentSubmissions": [
{
object (StudentSubmission)
}
],
"nextPageToken": string
}
StudentSubmission contains all the information related to the student submission for the course work including the courseId, courseWorkId, id and userId.
StudentSubmission Resource (JSON):
{
"courseId": string,
"courseWorkId": string,
"id": string,
"userId": string,
"creationTime": string,
"updateTime": string,
"state": enum (SubmissionState),
"late": boolean,
"draftGrade": number,
"assignedGrade": number,
"alternateLink": string,
"courseWorkType": enum (CourseWorkType),
"associatedWithDeveloper": boolean,
"submissionHistory": [
{
object (SubmissionHistory)
}
],
// Union field content can be only one of the following:
"assignmentSubmission": {
object (AssignmentSubmission)
},
"shortAnswerSubmission": {
object (ShortAnswerSubmission)
},
"multipleChoiceSubmission": {
object (MultipleChoiceSubmission)
}
// End of list of possible types for union field content.
}
(UPDATE)
Regarding the error you have encountered when using courses.courseWork.studentSubmissions.return in Apps Script,
GoogleJsonResponseException: API call to classroom.courses.courseWork.studentSubmissions.return failed with error: #ProjectPermissionDenied The Developer Console project is not permitted to make this request.
It occurred because you are trying to modify a course work which is not created on a Developer Console project. Please refer here.
Sample Code:
var courseId = '2491255xxxxxx';
var courseWorkId = '2524434xxxxx'; // manually created in classroom.google.com
//1st TRY with error
var studentSubmissions = Classroom.Courses.CourseWork.StudentSubmissions.list(courseId, courseWorkId);
Logger.log(studentSubmissions.studentSubmissions[0].id);
//var ret = Classroom.Courses.CourseWork.StudentSubmissions.return({},courseId, courseWorkId, studentSubmissions.studentSubmissions[0].id);
//Logger.log(ret);
var assignment = {
title: "Test Assignment 3",
state: "DRAFT",
assigneeMode: "ALL_STUDENTS",
workType: "ASSIGNMENT"
};
//var newCourseWork = Classroom.Courses.CourseWork.create(assignment, courseId);
//2nd TRY without error
var newCourseWorkId = '2618921xxxxx';
var studentSubmissions2 = Classroom.Courses.CourseWork.StudentSubmissions.list(courseId, newCourseWorkId);
var ret = Classroom.Courses.CourseWork.StudentSubmissions.return({},courseId, newCourseWorkId, studentSubmissions2.studentSubmissions[0].id);
Logger.log(studentSubmissions2);
Logger.log(ret);
Logger.log(Classroom.Courses.CourseWork.get(courseId,newCourseWorkId));
Explanation:
During the first try, I tried to return a student submission course work which was created in https://classroom.google.com/. This case will encounter an error, since I am trying to modify a course work that is not associated with a developer console project. You can check if a course work has an associated developer console project using Classroom.Courses.CourseWork.get(), associatedWithDeveloper property should be true.
On the 2nd try, I created a draft course work first, then modify the created course work in https://classroom.google.com/. Once I finalized the changes and published the course work. I tried to return the student submission course work and it was successful (return should be null/empty). The reason why it succeed is because a developer console project is associated with the course work since I created the course work using Apps Script, hence I could also modify the student submission using Apps Script.
I am trying to get a Reservation object which contains a pointer to Restaurant.
In Parse Cloud code, i am able to get the restaurants objects associated with Reservations via query.include('Restaurant') in log just before response.success. However, the Restaurants reverted back to pointer when i receive the response on client app.
I tried reverted JSSDK version to 1.4.2 & 1.6.7 as suggested in some answers, but it doesn't work for me.
Parse.Cloud.define('getreservationsforuser', function(request, response) {
var user = request.user
console.log(user)
var query = new Parse.Query('Reservations')
query.equalTo('User', user)
query.include('Restaurant')
query.find({
success : function(results) {
console.log(JSON.stringify(results))
response.success(results)
},
error : function (error) {
response.error(error)
}
})
})
response :
..."restaurant":{"__type":"Pointer",
"className":"Restaurants",
"objectId":"kIIYe7Z0tD"},...
You can't directly send the pointer objects back from cloud code even though you have included it. You need to manually copy the content of that pointer object to a javascript object. Like below:
var restaurant = {}
restaurant["id"] = YOUR_POINTER_OBJECT.id;
restaurant["createdAt"] = YOUR_POINTER_OBJECT.createdAt;
restaurant["custom_field"] = YOUR_POINTER_OBJECT.get("custom_field");
ps: in your code you seem do nothing else other than directly send the response back. I think parse REST api might be a better choice in that case.
It turned out that my code implementation was correct.
I am trying to figure out how Dynamic Websites on Parse work.
I have followed the instructions here: https://parse.com/docs/hosting_guide#webapp to set up a basic example.
Beside cloud/views/hello.ejs, I have made cloud/views/mything.ejs and used that from app.js and it all works.
Now I would like to show for example the number of records in MyClass on Parse.
In other words, inside my Dynamic Website I want to display information related to the contents of the DB on Parse.
How can I do that? Obviously I need to include some DB query at some point, but is there any sample?
Here's an example snippet
This handles a GET request to /mypage, on execution it creates a Parse Query but returns a result count instead of a record set matching the query. On completion of the query we then set a count or error on the response using res.set(). You can then use ejs to display the count or error.
app.get('/mypage', function(req, res) {
var query = new Parse.Query('My Class');
query.equalTo("name", "Joe Blogs");
query.count({
success: function(count) {
res.set('count', count);
},
error: function(error) {
res.set('error', error);
}
});
});
I have a servicestack service which when called via the browser (restful) Url ex:http://localhost:1616/myproducts, it works fine.
The service method has RedisCaching enabled. So first time it hits the data repository and caches it for subsequent use.
My problem is when I try calling it from a c# client via Soap12ServiceClient. It returns the below error:
Error in line 1 position 183. Expecting element '<target response>'
from namespace 'http://schemas.datacontract.org/2004/07/<target namespace>'..
Encountered 'Element' with name 'base64Binary',
namespace 'http://schemas.microsoft.com/2003/10/Serialization/'.
Below is my Client code:
var endpointURI = "http://mydevelopmentapi.serverhostingservices.com:1616/";
using (IServiceClient client = new Soap12ServiceClient(endpointURI))
{
var request = new ProductRequest { Param1 = "xy23432"};
client.Send<ProductResponse>(request);
}
It seems that the soapwsdl used is giving the problem, but I appear to have used the defaults as generated by servicestack..
Any help will be much appreciated.
Update
I was able over come this error by changing the cache code at the service end:
Code that returned error at client end:
return RequestContext.ToOptimizedResultUsingCache(this.CacheClient, cacheKey,
() =>
new ProductResponse(){CreateDate = DateTime.UtcNow,
products = new productRepository().Getproducts(request)
});
Code that works now:
var result = this.CacheClient.Get<ProductResponse>(cacheKey);
if (result == null)
{
this.CacheClient.Set<ProductResponse>(cacheKey, productResult);
result = productResult;
}
return result;
But I am still curious to know why the first method (RequestContext.ToOptimizedResultUsingCache) returned error at c# client?
But I am still curious to know why the first method (RequestContext.ToOptimizedResultUsingCache) returned error at c# client?
From what I can tell, the ToOptimizedResultUsingCache is trying to pull a specific format (xml, html, json, etc) out of the cache based on the RequestContext's ResponseContentType (see code here and here). When using the Soap12ServiceClient the ResponseContentType is text/html (not sure if this is correct/intentional within ServiceStack). So what ToOptimizedResultUsingCache is pulling out of the cache is a string of html. The html string is being returned to the Soap12ServiceClient and causing an exception.
By pulling directly out of the cache you are bypassing ToOptimizedResultUsingCache's 'format check' and returning something the Soap12ServiceClient can handle.
** If you are using Redis and creating your key with UrnId.Create method you should see a key like urn:ProductResponse:{yourkey}.html
Thanks for your response paaschpa.
I revisited the code and I was able to fix it. Since your response gave me the direction, I have accepted your answer. Below is my fix.
I moved the return statement from RequestContext to the response DTO.
Code which throws error when used via c# client (code was returning entire requestcontext):
return RequestContext.ToOptimizedResultUsingCache(this.CacheClient, cacheKey,
() =>
new ProductResponse(){CreateDate = DateTime.UtcNow,
products = new productRepository().Getproducts(request)
});
Fixed Code (return moved to response DTO):
RequestContext.ToOptimizedResultUsingCache(this.CacheClient, cacheKey,
() => {
return new ProductResponse(){CreateDate = DateTime.UtcNow,
products = new productRepository().Getproducts(request)
}
});