Get customschema data - google-apps-script

I am new to this new world of programming with GAS, I have not programmed anything for a long time and the change of structure is a bit complicated to understand. I have an app-script that reads the data of the domain users and it works very well, but it doesn't bring me the customschema fields. I've searched quite a bit in the documentation, until I found something that seemed to work.
I created a function and tried to retrieve the fields I need and it works. What it does is look up a user and fetch the data.
Then I wanted to use that function but passing it the userkey of the user in question and then return one of the fields. But it stopped working, it only brought the normal data, but from the customschema, nothing.
My function is:
function LeeUser() {
var iuserEmail = "user#midominio.com";
var test = {
"name": {
"familyName": "",
"givenName": ""
},
"password": "",
"primaryEmail": "",
"orgUnitPath": "",
"emails":[{
"type": "work",
"address": "",
}],
"customSchemas": {
"Organizacion_Interna": {
"NombreFuncionario": "",
"FechaCaducidad": ""
}
},
};
try {
test = AdminDirectory.Users.get(iuserEmail,{"projection": "full"});
console.log(test.customSchemas.Organizacion_Interna.FechaCaducidad);
} catch (err) {
Logger.log('Failed with error %s', err.message);
}
}
But when I change
function LeeUser(userEmail) {
var iuserEmail = userEmail;
var test = {
"name": {
"familyName": "",
"givenName": ""
},
"password": "",
"primaryEmail": "",
"orgUnitPath": "",
"emails":[{
"type": "work",
"address": "",
}],
"customSchemas": {
"Organizacion_Interna": {
"NombreFuncionario": "",
"FechaCaducidad": ""
}
},
};
try {
test = AdminDirectory.Users.get(iuserEmail,{"projection": "full"});
return test.customSchemas.Organizacion_Interna.FechaCaducidad;
} catch (err) {
Logger.log('Failed with error %s', err.message);
}
}
It tells me that the field is not defined.
what's the problem?
Any suggestion
Thanks in advance.

Related

Creating an object with values of JSON path

I implemented i18n with useTranslation and tried to make it easier for json path to be written.
JSON
{
"userInfo":{
"name": "Name",
"lastname": "Last Name"
},
"sideMenu:{
"home":"Home"
}
}
So now when I try to access translated text I go
t("userInfo.name", "Name")
I tried to make a function that will recursively call it self and create the object like this
object = {
userInfo: {
name: {
key:"userInfo.name",
value:"Name"
},
lastname: {
key:"userInfo.lastname",
value:"Last name"
},
},
sideMenu: {
home: {
key:"sideMenu.home",
value:"Home"
}
}
}
so now I could access like this
t(object.userInfo.name.key, object.userInfo.name.value)
I tried using entries and fromEntries function but I simply cant get hold of the logic behind it.
I made it work with a recursive function so now, no matter the number of nested objects function will return a new object with key and value items.
You can see working snippet with json file i used for the project.
let en = {
"userInfo":{
"name": "Name",
"lastname": "Last Name",
"gender": "Gender",
"age": "Age",
"location": "Location",
"address": "Address",
"city": "City",
"login": "Login",
"about": "About"
},
"comboBox": {
"loading": "Loading...",
"loadmore": "Load More"
},
"error": {
"errormsg": "Ooops, it seems you are not authenticated to see this...",
"errormsgsub": "Get back and try again",
"errorbtn": "Back to Safety",
"alertmsg": "You should login first!"
},
"sideMenu": {
"home": "Home",
"logout": "Logout",
"croatian": "Croatian",
"english": "English",
"hello": "Hello"
},
"loadingPage": {
"load": "Loading...",
"loadsub": "Please wait"
}
}
function languageRecursion(data, key){
if (typeof data === 'object') {
return Object.fromEntries(
Object.entries(data).map(([ikey, value]) => {
return [ikey, languageRecursion(value, key ? `${key}.${ikey}` : ikey)];
})
);
}
return { key: key, value: data };
}
let locale = languageRecursion(en)
console.log("path",locale.userInfo.about.key)
console.log("value", locale.userInfo.about.value)
With this working now you can call languages with i18next useTranslation hook faster and easier.
t(locale.userInfo.name.key)

Mapping data that contains dots in React

I am trying to map the data in React that is coming from the API but I am having problems mapping the object that contains dots for example this: name.en_US.
What is the proper way to map this object and keeping the data structure that I have?
I am getting the date in this format from the API:
{
"user": "User",
"employeeId": "0000",
"businessCustomer": "customer",
"endCustomer": {
"name": "",
"address": "",
"place": ""
},
"device": {
"shipmentIds": "23",
"name.en_US": "wasi",
"name.fi_FI": " masi"
},
"task": {
"time": "2019-02-10T16:55:46.188Z",
"duration": "00:00:24",
"sum": "75€"
}
},
And then I am trying to map it using the following code.
const {
user,
employeeId,
businessCustomer,
endCustomer,
device,
task
} = task;
const{
endCustomerName,
address,
place
} = endCustomer;
const {
shipmentIds,
names
} = device;
const{
en_US,
fi_FI
} = names;
const {
time,
duration,
summa
} = task;
const data = {
"user": "User",
"employeeId": "0000",
"businessCustomer": "customer",
"endCustomer": {
"name": "",
"address": "",
"place": ""
},
"device": {
"shipmentIds": "23",
"name.en_US": "wasi",
"name.fi_FI": " masi"
},
"task": {
"time": "2019-02-10T16:55:46.188Z",
"duration": "00:00:24",
"sum": "75€"
}
};
const { device } = data;
const {
shipmentIds,
'name.en_US': name_en_US,
'name.fi_FI': name_fi_FI
} = device;
const nameUS = device['name.en_US'];
console.log(name_en_US, nameUS);
Use [ ] notation like, device['name.en_US'] .
You can destructure your propery as #Vishnu mentioned, or you could also destructure it by providing a valid key name
const {
shipmentIds,
'name.en_US': name_en_US,
'name.fi_FI': name_fi_FI
} = device;
And then you could access your variable with name_en_US.

Meteor JSON Method and Call in template

I am trying to call a Meteor method with a parsed json doc to use in my template. None of my calls work and I then need advise on how to display (maybe I should save this part for another post - but any suggestions would be helpful) in template with helpers. I am new to meteor and javascript.
Json doc
{
"sports-content": {
"sport-event": [{
"event-metadata": {
"league": "NCAA Basketball",
"event-type": "0",
"league-details": "NCAAB",
"event-date-time": "12/18/2015 07:00 PM",
"eventNum": "3000460",
"status": "",
"off-the-board": "False"
},
"team": [{
"team-metadata": {
"alignment": "Home",
"nss": "526",
"openNum": "526",
"name": {
"full": "Clemson"
}
},
"wagering-stats": {
"wagering-straight-spread": {
"bookmaker-name": "BetOnline",
"active": "true",
"line": "1.5",
"money": "-110",
"context": "current"
}
},
"team-stats": {
"score": "0"
}
}, {
"team-metadata": {
"alignment": "Away",
"openNum": "525",
"nss": "525",
"name": {
"full": "South Carolina"
}
},
"wagering-stats": {
"wagering-straight-spread": {
"bookmaker-name": "BetOnline",
"active": "true",
"line": "-1.5",
"money": "-110",
"context": "current"
}
},
"team-stats": {
"score": "0"
}
}]
}],
"sports-meta-data": {
"doc-time": "42353.5979256944"
}
}
}
server.js
Meteor.startup(function () {
Meteor.methods({
sportsFeed:function(){
//console.log(JSON.parse(Assets.getText('ncaab.json')));
var feed = {};
var feed = JSON.parse(Assets.getText("ncaab.json"));
return feed;
}
});
});
Template.html
<template name="tabsOne">
<p>{{display}}</p>
</template>
Template.js
Template.tabsOne.helpers({
display: function(){
Meteor.call('sportsFeed', function(error, result){
if(error){
console.log("error", error);
}
if(result){
console.log('success');
}
});
}
});
If the json file is from your local, thinking about save it into Mongo and then publish it to the client
First, you need to create a collection called SportContent and on the server side, just make
SportContent.insert(JSON.parse(Assets.getText("ncaab.json")));
and then, do the normal publication to the client
If the json file is not on your local side (as in, you get it from rest call service), use wrapAsync to wrap the Http.call, then trigger the rest call and return the result. On your client side, you will get the response
Example on the server side to connect to the rest api
Meteor.methods({
'updateFeed': function () {
var httpCall = Meteor.wrapAsync(HTTP.call);
var result = httpCall('GET', url, {headers: headers});
....
}
});

Three-Way Relationship in Firebase

I've been learning a lot about denormalised data over the past few months, but I wanted to know if the following is possible in a flattened architecture world. I know how to handle two-way relationships in Firebase, but what about a three-way relationship. Let me explain...
I have 5 items in my database, services, providers, serviceAtProvider, reviews and users. I want to be able to add providers to services and vice versa.
I'd also like there to be a specific page for a provider inside a service, and for there to be reviews linked to the provider at that specific service. The page url might look like this (site.com/serviceId/providerId). The rating is unique to that providerId inside of that serviceId – you can't rate serviceIds or providerIds separately.
I'm not sure how to go about creating such a complex relationship. How would I join the serviceId and providerId in that serviceAtProvider item?
This is what I've got so far:
"services": {
"service1": {
"name": "Hernia Repair",
"providers": {
"provider1": true,
"provider2": true
}
}
},
"providers": {
"provider1": { "name": "The Whittington Hospital" },
"provider2": { "name": "Homerton Hospital" }
},
"serviceAtProvider": {
"service1AtProvider1": { "rating": 4 },
"service1AtProvider2": { "rating": 3 }
},
"reviews": {
"service1AtProvider1": {
"review1": {
"body": "A review from user 1",
"user": "user1"
}
},
"service1AtProvider2": {
"review1": {
"body": "A review from user 2",
"user": "user2"
}
}
},
"users": {
"user1": { "name": "Ben Thomas" },
"user2": { "name": "Beatrix Potter" }
}
I don't know how to create that serviceAtProviderjoin, or how would I go about accessing the service1.name, provider1.name, service1AtProvider1.rating, reviews.service1AtProvider1 on one page. Can anyone explain how to do this?
Also, are there any best practices I should follow?
Any help is appreciated. Thanks in advance!
UPDATE
{
"availableServices": {
"service1": { "name": "Hernia Repair" },
"service2": { "name": "Chemotherapy" }
},
"services": {
"provider": {
"name": "The Whittington Hospital",
"service": {
"service1": {
"rating": 4,
"reviewId1": true
},
"service2": {
"rating": 3,
"reviewId2": true
},
}
}
},
"reviews": {
"reviewId1": {
"review1": {
"rating": 4,
"body": "A review from user 1",
"user": "user1"
}
}
},
"users": {
"user1": { "name": "Raphael Essoo-Snowdon" },
"user2": { "name": "Sharlyne Slassi" }
}
}
I would start by making the data structure a bit simpler and more direct. It's hard to determine the correct data structure for your needs without a detailed use case. I'll do my best to make some generic assumptions here. You'll have to adapt as necessary.
{
"service": {
"service1": { "name": "Foo Service" },
...
},
"provider": {
"provider1": { name: "Foo Place" },
...
},
"ratings": {
"service1": { // service id
"provider1": { // provider id
"average_rating": 4
},
...
},
...
},
"reviews": {
"service1": { // service id
"provider1": { // provider id
"user": "user1",
"rating": 4
},
...
},
...
},
"user": {
"user1": { "name": "Foo Bar" },
...
}
}
Now, to look up the providers who offer a given service, and grab their reviews, I would do the following:
var ref = new Firebase(...);
ref.child('ratings/service1').on('child_added', function(reviewSnap) {
console.log(
'Provider ' + reviewSnap.key(),
'Average rating ' + reviewSnap.val().average_rating
);
});
Joining in the names of the services and providers could be done in several ways. Here's a manual technique:
var ref = new Firebase(...);
ref.child('ratings/service1').on('child_added', accumulateReview);
function accumulateReview(reviewSnap) {
var reviewData = reviewSnap.val();
var reviewid = reviewSnap.key();
fetchService(reviewSnap.parent().key(), function(serviceSnap) {
loadRec('provider', reviewSnap.key(), function(providerSnap) {
console.log('Provider: ', providerSnap.key(), providerSnap.val().name);
console.log('Service: ', serviceSnap.key(), serviceSnap.val().name);
console.log('Average rating: ', reviewData.average_rating);
});
});
}
var serviceCache = {};
function fetchService(serviceid, done) {
// demonstrates creating a local cache for things that will be
// looked up frequently
if( !serviceCache.hasOwnProperty(serviceid) ) {
cacheService(serviceid, done);
}
else {
done(serviceCache[serviceid]);
}
}
function cacheService(serviceid, done) {
loadRec('service', function(ss) {
serviceCache[serviceid] = ss;
fetchService(serviceid, done);
});
}
function loadRec(type, key, done) {
ref.child(type).child(key).once('value', done);
}
I could also automate some of this process with Firebase.util's NormalizedCollection:
var ref = new Firebase(...);
var nc = Firebase.util.NormalizedCollection(
[ref.child('reviews/service1'), 'review'],
ref.child('provider'),
ref.child('user')
)
.select('review.rating', {key: 'provider.name', alias: 'providerName'}, {key: 'user.name', alias: 'userName'})
.ref();
nc.on('child_added', function(snap) {
var data = snap.val();
console.log('Provider', data.providerName);
console.log('User', data.userName);
console.log('Rating', data.rating);
});
Note that nothing here is set in stone. This is how I would approach it. There are probably dozens of structures at least as good or better.

Validate Json Schema

I'm getting an error when using json-schema-validator API v4.
I try to do :
final JsonValidator validator = new JsonValidator(JsonLoader.fromPath("schema.json"));
ValidationReport report = validator.validate(data);
but every time I get an error : # [schema]: unknown keyword contacts
schema.json :
{
"contacts": {
"description": "The list of contacts",
"type": "array",
"optional": true,
"items": {
"description": "A contact",
"type": "object",
"properties": {
"givenName": {
"description": "Person's first name",
"type": "string",
"maxLength": 64,
"optional": true
},
"familyName": {
"description": "A person's last name",
"type": "string",
"maxLength": 64,
"optional": true
}
}
}
}
}
Regards
As far as I can intuit, your data looks like this-> json_data={"contacts":array}. If this is true, basically your outermost thing is an object (basically the full json object itself), for which you "might" need to define the schema starting from the "top level root" of your json as->
schema.json:
{
"description": "the outer json",
"type": "object",
"properties": {
"contacts": {
"description": "The list of contacts",
"type": "array",
"optional": true,
"items": {
"description": "A contact",
"type": "object",
"properties": {
"givenName": {
etc.....
Forgive me for rough indentations. Also, I have not tested this, please see if it works, if it does not, I would suggest you to provide your json_data (example at least) and the API's examples so that one can try to locate where what is wrong.
Use AVJ. Instead of having your data validation and sanitization logic written as lengthy code, you can declare the requirements to your data with concise, easy to read and cross-platform JSON Schema or JSON Type Definition specifications and validate the data as soon as it arrives to your application.
// validationSchema.js
import Ajv from "ajv";
import addFormats from "ajv-formats";
import ajvErrors from "ajv-errors";
const schemas = {
newUser: {
{
type: "object",
properties: {
lastName: {
type: "string",
minLength: 1,
maxLength: 255
},
firstName: {
type: "string",
minLength: 1,
maxLength: 255
},
description: {
type: "string"
},
birthday: {
type: "string",
format: "date-time"
},
status: {
type: "string",
enum: ["ACTIVE", "DELETED"]
},
},
required: ["name"]
}
}
};
const ajv = new Ajv({ allErrors: true });
addFormats(ajv);
ajvErrors(ajv /*, {singleError: true} */);
const mapErrors = (errorsEntry = []) => {
const errors = errorsEntry.reduce(
(
acc,
{ instancePath = "", message = "", params: { missingProperty = "" } = {} }
) => {
const key = (instancePath || missingProperty).replace("/", "");
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(`${key} ${message}`);
return acc;
},
[]
);
return errors;
};
const validate = (schemaName, data) => {
const v = ajv.compile(schemas[schemaName]);
let valid = false,
errors = [];
valid = v(data);
if (!valid) {
errors = mapErrors(v.errors);
}
return { valid, errors };
};
export default { validate };
You can validate it like this:
import validationSchema from "your_path/validationSchema.js"
const user = {
firstName: "",
lastName: "",
....
};
const { valid, errors = [] } = validationSchema.validate("newUser", user);
if(valid){
console.log("Data is valid!");
} else {
console.log("Data is not valid!");
console.log(errors);
}