I would like to know an easy way to destruct a Parse.Object instance.
Lets say I have an Parse.Object instance with following attributes:
const Address = new Parse.Object<Address>("Address", {
address: "St. Nowhere",
zipCode: 33111,
timezoneOffset: -2,
dayLightSavingTime: true
})
I want to destruct Address to get is't properties values easily. Like:
const {
address,
zipCode,
...OtherAttributes
} = Address
Well I found that it is easy as:
const {
address,
zipCode,
...OtherAttributes
} = Address.toJSON()
Be advised that if you are using Typescript and Address is possible undefined you will get the error:
TS2339: Property 'address' does not exist on type '(ToJSON & JSONBaseAttributes) | undefined'.
One solution would be:
const {
address,
zipCode,
...OtherAttributes
} = Address.toJSON() ?? {}
Caution with Date attributes. They are transformed to { __type: 'Date'; iso: string; } where iso is the date in ISO 8601 format.
Related
I'm working in AppMaker to create a new employee/user provisioning workflow. I'm at the point where I am creating a new G Suite user, and I have a very weird problem with spaces in my JSON. It's leading to an error: GoogleJsonResponseException: API call to directory.users.insert failed with error:
Invalid Input at provisionUser (AdminDirectory:5)
I've been troubleshooting this for a while, and it seems that somewhere between AppMaker and the AdminDirectory call, some extra spaces and hard returns are inserted into my user data. Below I'm going to show:
The client-side code for gathering user information
The server-side user creation script
The console output of the user JSON
The output of the user JSON that comes to my email for troubleshooting
The emailed output as seen in Notepad++
Client-Side Code
...a bunch of data gathering from a form, then...
var user = {
primaryEmail: email,
name: {
givenName: firstName,
familyName: lastName
},
addresses: [{
type: 'work',
formatted: address
}],
organizations: [{
title: title,
department: department,
fullTimeEquivalent: ftpt
}],
phones: [{
type: 'work',
value: phone
}],
locations: [{
buildingId: building,
type: 'desk',
area: 'desk'
}],
password: 'xxxxxxxx',
changePasswordAtNextLogin: true,
orgUnitPath: orgUnit,
relations: [{
type: 'manager',
value: supervisor
}],
customSchemas: {
sclsnj: {
startDate: effective,
mls: mls,
location: location
}
}
};
google.script.run.provisionUser(user, grouparray);
Server-Side Code
function provisionUser(user, grouparray) {
user = JSON.stringify(user);
MailApp.sendEmail('lhoffman#xxxxxxxx.org', 'New Google User', user);
console.log(user);
user = AdminDirectory.Users.insert(user);
for (var g = 0; g < grouparray.length; g++) {
var groupEmail = grouparray[g] + '#xxxxxxxx.org';
var member = {
email: user,
role: 'MEMBER'
};
Logger.log(groupEmail);
AdminDirectory.Members.insert(member, groupEmail);
}
}
Console Output
{"primaryEmail":"jsmith#xxxxxxxx.org","name":{"givenName":"John","familyName":"Smith"},"addresses":[{"type":"work","formatted":"Bound Brook branch\n402 E High Street, Bound Brook, NJ 08805"}],"organizations":[{"title":"Library Technician","department":"Adult Services","fullTimeEquivalent":100000}],"phones":[{"type":"work","value":"908-458-8410"}],"locations":[{"buildingId":"BBROOK","type":"desk","area":"desk"}],"password":"xxxxxxxx","changePasswordAtNextLogin":true,"orgUnitPath":"/Branches/Bound Brook branch","relations":[{"type":"manager","value":"msmith#xxxxxxxx.org"}],"customSchemas":{"sclsnj":{"startDate":"2019-05-20T04:00:00.000Z","mls":false,"location":"Bound Brook branch"}}}
Email Output
{"primaryEmail":"jsmith#xxxxxxxx.org","name":{"givenName":"John","familyName":"Smith"},"addresses":[{"type":"work","formatted":"Bound
Brook
branch\n402 E High Street, Bound Brook, NJ
08805"}],"organizations":[{"title":"Library Technician","department":"Adult
Services","fullTimeEquivalent":100000}],"phones":[{"type":"work","value":"908-458-8410"}],"locations":[{"buildingId":"BBROOK","type":"desk","area":"desk"}],"password":"xxxxxxxx","changePasswordAtNextLogin":true,"orgUnitPath":"/Branches/Bound
Brook
branch","relations":[{"type":"manager","value":"msmith#xxxxxxxx.org"}],"customSchemas":{"sclsnj":{"startDate":"2019-05-20T04:00:00.000Z","mls":false,"location":"Bound
Brook branch"}}}
Email Output in Notepad++ (with control characters)
NOTE: I realize the JSON is actually represented in the image twice, but you can definitely see the extra space and left feed characters there.
I've confirmed that I can provision a user with the console output by using the Google API Explorer and copying and pasting it into the request body for the Directory API Users.insert.
I've also confirmed that the emailed version of the output does not work using the same method. When I paste that version into the request body in the API Explorer, I get an error alert and it's clear from the color-coding in the body field that it is not correct. Even when I don't email the output to myself, I get the same error behavior, so I'm pretty sure that the act of emailing isn't messing things up.
Help!!
The invalid input is a result of a specific field not correclty formatted. In your case, I see that you are using custom schemas. There is a specific filed in the custom schema that is not properly formatted, that is startDate. Instead of providing the value of 2019-05-20T04:00:00.000Z, just use 2019-05-20.
The reason for that is because the field is expecting a complete date only value instead of a complete date plus hours and minutes. As you can see on the ISO-8601 date format, the complete date format is YYYY-MM-DD.
Reference: https://developers.google.com/admin-sdk/directory/v1/reference/schemas/insert
What happens if you do it this way?
function provisionUser(user, grouparray) {
var user = JSON.stringify(user);
MailApp.sendEmail('lhoffman#xxxxxxxx.org', 'New Google User', user);
console.log(user);
AdminDirectory.Users.insert(user);
for (var g = 0; g < grouparray.length; g++) {
var groupEmail = grouparray[g] + '#xxxxxxxx.org';
var member = {
email: user,
role: 'MEMBER'
};
Logger.log(groupEmail);
AdminDirectory.Members.insert(member, groupEmail);
}
}
I'm trying to use Apps Script to change the owner of a Google Classroom course.
According to the documentation I can do it using .patch(). This is the relevant script:
var body = {
ownerId: owner
}
var mask={
mask:'ownerId'
}
var optArgs = (mask, body);
var course = {
name: classname,
courseState: state,
description: desc,
descriptionHeading: descHead,
room: room,
section: section
};
Classroom.Courses.patch(course, courseId, optArgs )
When I run it to update the owner I get the following error message
Could not be updated Invalid JSON payload received. Unknown name "ownerId": Cannot bind query parameter. Field 'ownerId' could not be found in request message.
Just to demonstrate a contrast, when I run .update() instead:
Classroom.Courses.update(course, courseId)
...the rest of the course details are updated perfectly, however .update() doesn't allow you to change the owner; it has to be a .patch() to do that.
Just had the same problem, the issue is the optArgs - you just want the mask in there, not your changed data.
var optArgs = { mask: 'ownerId' };
var course = {
name: classname,
courseState: state,
description: desc,
descriptionHeading: descHead,
room: room,
section: section,
ownerId: owner
};
Classroom.Courses.patch(course, courseId, optArgs );
I just tried this a few moments ago and it worked. Take into account that, for this to work, the user must already be a teacher in the specific class, and then this will make that teacher the owner.
function changeTeacherOwner() {
var course = { 'ownerId': "EMAIL OF TEACHER" };
Classroom.Courses.patch(course, "COURSE ID", {'updateMask':'ownerId'});
}
Based on documentation, this is working as intended.
courses.update has no ownerId parameters, only id.
But if you check courses.patch it has the updateMask parameter which accepts ownerId as a valid field.
For detailed information on this service, see the reference documentation for the Classroom API.
Ok I've got a list of objects, pretty standard.
const list = Immutable.List([{type:'thang',data:{id:'pants'}}]);
Now I want to change pants to shorts... so I'm thinking
list.setIn([0,'data','id'],'shorts');
Alas
Error: invalid keyPath
How is this done?
I can't even get this far despite messing around with this for a while :/ Once I know how to do this I'd like to know how to add a new element at a position
list.setIn([0,'data','length'],'short');
To add a new length attribute to the data object at position 0 in the list.
My bad. I was going wrong with the creation of the Immutable structure. If I change
const list = Immutable.List([{type:'thang',data:{id:'pants'}}]);
To
const list = Immutable.fromJS([{type:'thang',data:{id:'pants'}}]);
Then I can
list.setIn([0,'data','id'],'shorts');
Our nested structured data:
const state = {
Persons: [
{
fname: 'J.R.R',
lname: 'Tolkin',
},
{
fname: 'jack',
lname: 'London',
}
]
};
Requiring Immutable
const { fromJS } = require('immutable')
Turning simple object to Map
const stateMapped = fromJS(state);
Getting Data from nested structure
console.log(stateMapped.getIn(['Persons', 0, 'fname']))//output: J.R.R
setting data in nested structure
var objClone = stateMapped.setIn(['Persons', '0', 'fname'], 'John Ronald Reuel');
console.log('' + objClone.getIn(['Persons', 0, 'fname'])); //output: John Ronald Reuel
I am using https://github.com/felixge/node-mysql module with node.js.
Mysql table has a field of type POINT. The module requires to send array of arrays to insert bulk records. But It doesn't seem to have option to specify data type.
So naturally, the following gets enclosed in quotes
var loc = "GeomFromText('POINT(" + lat + "," + lon + ")')";
Has anybody tried this? How can I convince the query builder to treat this as an sql function?
Or do I have to make my own query builder?
There is a pull request from kevinhikaruevans that does it. You can do something like that to convert objects to points:
if (typeof val === 'object') {
if(val.hasOwnProperty('lat') && val.hasOwnProperty('long')) {
return 'POINT(' + [val.lat, val.long].map(parseFloat).join(',') + ')';
}
}
Supposing you have a table mytable with only the field point of type POINT, you would insert them like this:
var points = [
[{ lat: 1, long: 4}],
[{ lat: 23, long: -8.345}]
];
var query = connection.query('INSERT INTO mytable(point) VALUES ?', [points], your_callback_func);
console.log("Query: " + query.sql);
This will generate a query similar to:
INSERT INTO mytable(point)
VALUES (POINT(1,4)), (POINT(23,-8.345))
This would convert any object with both lat and long fields to a MySQL point. If this is not an intended behavior, you could create a Point class and use it instead of plain objects, and in lib/protocol/SqlString.js check if the value is an instance of Point.
Try constructing a query to handle POINT() and batch where site is an object with properties and values shown below. This approach works for me.
pool.query('INSERT INTO table SET geometryField = POINT(?,?), ?',[coords.lat,coords.lng,site], function(err, response) {
{ sitename: 'A Site',
customer: 'A Customer',
country: 'AL',
timezone: 'America/Los_Angeles',
address1: '123 My Street',
city: 'MyCity',
state: 'WA',
postalcode: '98110'}
I have a form that I need to populate with JSON data. The form contains select, textarea, and input elements that need to be populated. The JSON data is complex / hierarchical (i.e. many nested objects).
I am aware of http://www.keyframesandcode.com/code/development/javascript/jquery-populate-plugin/ but it uses square bracket notation to map to field names (e.g.
<input name="person[name][last]" ...
I need to use dot notation though (e.g.
<input name="person.name.last" ...
I'm using jQuery so a jQuery solution is fine. Thanks.
Here's a hacked together alternative to populate using a recursive function:
function populator(json, nodes){
$.each(json, function(key, value){
newNodes = nodes ? nodes.slice() : [];
newNodes.push(key);
if (typeof(value)=="object") {
populator(value, newNodes);
else
$('name["' + newNodes.join('.') + '"]').val(value);
}
});
}
With this you can do:
populator({
person: {
name: {
last: 'Doe',
first: 'John'
},
address: {
street: '123 Main Street',
city: 'Montgomery',
state: 'AL'
}
});