Google Apps Script Bulk Set Properties - properties

Another GAS question. I read the documentation on ScriptProperties and bulk-setting properties, as well as (again) the documentation on best practices. However, I'm not familiar with Javascript, and still new to GAS, and I keep running over the rate limit for API calls as a result.
Basically, I would like to 'get' all these properties from the Spreadsheet, put them in an Array or Object or something, then bulk set all of them. I have the keys and values correct, I just don't know how to temp store them in a JS Object or Array or some data type that will be accepted by the setProperties(Object) method.
Here is the current code (horrendous Sleep timer is the only thing that is working...):
function setSubsequentProperties(propertyRange, sheet) {
// Get the other Library Properties based on the new Range values.
// propertyRange is the 2-column 1-row Range for the key/value pairs
var tableRange = ScriptProperties.getProperty(propertyRange);
var dataRange = sheet.getRange(tableRange);
var data = dataRange.getValues();
// Create a 'properties' Object for bulk-setting to prevent overusing API calls
//var properties = new Array(data.length);
// Set a new Script Property for each row
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var propertyKey = row[0];
var propertyValue = row[1];
// var myObject = allMyPropertiesInOneObject
ScriptProperties.setProperty(propertyKey, propertyValue);
Utilities.sleep(1000);
}
// setProperties(myObject);
}
How might I go about adding propertyKey and propertyValue to an Object to bulk set them all at once? The pseudo-idea is commented out in the code block.

Since you say you are new to Javascript, I assume you are new to JSON as well. There is indeed a ScriptProperties.setProperties() method which takes a JSON object as argument.
Modifying just the setProperty() bit of your code, here is what you can do
function setSubsequentProperties(propertyRange, sheet) {
// Get the other Library Properties based on the new Range values.
// propertyRange is the 2-column 1-row Range for the key/value pairs
var tableRange = ScriptProperties.getProperty(propertyRange);
var dataRange = sheet.getRange(tableRange);
var data = dataRange.getValues();
// Create a 'properties' Object for bulk-setting to prevent overusing API calls
//var properties = new Array(data.length);
// Set a new Script Property for each row
var myObject = {} ;
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var propertyKey = row[0];
var propertyValue = row[1];
// var myObject = allMyPropertiesInOneObject
myObject[propertyKey] = propertyValue;
}
ScriptProperties.setProperties(myObject);
}

Just to update this answer, Google has deprecated ScriptProperties and replaced it with the PropertiesService. You can solve the same problem using setProperties() on a Properties object, except you have to choose which kind of store you want using a call to PropertiesService first:
var myObject = {} ;
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var propertyKey = row[0];
var propertyValue = row[1];
myObject[propertyKey] = propertyValue;
}
var myProperties = PropertiesService.getScriptProperties(); // or getUserProperties() or getDocumentProperties()
myProperties.setProperties(myObject);
See the documentation for details. Note: this only seems to work for simple key/value pairs. When I try to set and get more complex JSON objects, with keys set to arrays of values, I can retrieve the object but not the values inside it. I can't use JSON.parse() on it successfully, either. I'll post again if I can figure it out.

Related

Why can't I chain .sort() after .copyOf()?

I'll keep this very simple. Why does this work:
var heights = arrayOf(1,2,3,4,2,3,4)
var sortedHeights = heights.copyOf()
sortedHeights.sort()
for (i in 0..heights.size-1)
{
println(sortedHeights[i])
}
But this does not?
var heights = arrayOf(1,2,3,4,2,3,4)
var sortedHeights = heights.copyOf().sort()
for (i in 0..heights.size-1)
{
println(sortedHeights[i])
}
As you can see the only difference is the chaining with the sortedHeights array. If copyOf() returns an array, shouldn't I be able to chain it with sort()?
forpas answered why your code doesn't work in the comments, but you can use scope functions to allow chaining anyway:
var sortedHeights = heights.copyOf().apply { sort() }
or
var sortedHeights = heights.copyOf().also { it.sort() }
There is a builtin function performs both a copyOf() and a sorting: sortedArray()
You can change your line of code to:
var sortedHeights = heights.sortedArray()
(but you should really be using val instead of var unless you intend to change the value of the variable)

MS Dynamics CRM. Get users who current record shared with

I have a entity record which is shared with or more users. I would like to unshare this record when Deactivate it. I want to do that in Plugin. But I can't understand how to get all users from sharing list who have access to this record. How to do that?
Here is my code snippet:
protected void ExecutePostPersonSetStateDynamicEntity(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
var context = localContext.PluginExecutionContext;
var targetEntity = (Entity)context.InputParameters["EntityMoniker"];
var state = (OptionSetValue)context.InputParameters["State"];
var columns = new ColumnSet(new[] { "statecode" });
var retrivedEntity = localContext.OrganizationService.Retrieve(targetEntity.LogicalName, targetEntity.Id, columns);
if (state.Value == 1)
{
RevokeAccessRequest revokeRequest = new RevokeAccessRequest()
{
Target = new EntityReference(personEntity.LogicalName, personEntity.Id),
Revokee = new EntityReference(neededEntity.LogicalName, needed.Id)
};
// Execute the request.
}
}
As you can see, I need an entity "neededEntity", I don't know how to get it from "targetEntity" or "retrievedEntity".
You need to use a RetrieveSharedPrincipalsAndAccessRequest
http://msdn.microsoft.com/en-us/library/microsoft.crm.sdk.messages.retrievesharedprincipalsandaccessrequest.aspx
You can start from the included example, basically inside the foreach you call your RevokeAcessRequest

Creating new upshot js entities

I'm building a site as a Single Page Application using ASP.NET MVC 4 Beta .
The sample app talks about adding new entities and it uses a constructor function for it's product entity.
However I have many entity types and I'm not going to write a constructor function for each one. This is how I am creating a new entity (name is the name of the datasource and dataTarget.upshot.upshotData is the list of entities I get back from the GetEntities method
in coffeeScript...
newItem = {}
for field, def of upshot.metadata(upshot.dataSources[name]._entityType).fields
do (field, def) ->
if def.array
newItem[field] = new ko.observableArray()
else
newItem[field] = new ko.observable()
upshot.addEntityProperties newItem, upshot.dataSources[name]._entityType
dataTarget.upshot.upshotData.push newItem
my question is if this is the best way to do it or am I missing something? I'm surprised that upshot does not seem to have a createEntity method.
in javascript...
newItem = {};
_ref = upshot.metadata(upshot.dataSources[name]._entityType).fields;
_fn = function(field, def) {
if (def.array) {
return newItem[field] = new ko.observableArray();
} else {
return newItem[field] = new ko.observable();
}
};
for (field in _ref) {
def = _ref[field];
_fn(field, def);
}
upshot.addEntityProperties(newItem, upshot.dataSources[name]._entityType);
dataTarget.upshot.upshotData.push(newItem);
var newThing = {};
var typeName = "MyType:#MyNamespace";
upshot.map({ SomeProperty: "my value" }, typeName, newThing);
upshot.addEntityProperties(newThing, typeName);
This will create your object with the entity properties mapped to observables, and will allow you to set properties (see SomeProperty:"my value").

Generate parameter list with userdefined types at runtime (using C#)

As part of my project, I am trying to build a web UI where user will select a method and pass the values. My program should be able to call the method dynamically and build a parameter list on runtime to pass it to the method.
I have created a comma separated list (string) of key and value pairs. This key/value pair is nothing but the parameter name and value of my method (methodname stored in a variable). Example: string params = "ID:123;Name:Garry;Address:addressObject;AddressLine:108 Plaza Lane;City:Avenel;State:NJ;Zip:07001;". Where ID and Name are simple string varaibles while Address is user defined type. What follows after Address i.e. AddressLine, City, State and Zip is elements of Address object. And my method definition is
public string GetInfo(string ID, string Name, Address addressObject)
{
//return something;
}
I am dynamically calling the method (GetInfo) that is stored in sMethodName variable using DynamicProxy like :
string sMethodName = "GetInfo";
object result = (object) proxy.CallMethod(sMethodName, arguments);
Challenge is how to pass the argument list dynamically? Till now I am just able to extract the values from the csv variable into NamedValueCollection. Here is the code:
public static void StoreParameterValues(string param)
{
nvc = new NameValueCollection();
param = param.TrimEnd(';');
string[] parameters = param.Split(new char[] { ';' });
foreach (string val in parameters)
{
string[] keyValue = val.Split(new char[] { ':' });
nvc.Add(keyValue[0], keyValue[1]);
}
}
..and here is the code that tries to build the parameter:
string methodName = "GetInfo";
DynamicProxyFactory factory = new DynamicProxyFactory("http://../myservice.svc");
string sContract = "";
foreach (ServiceEndpoint endpoint in factory.Endpoints)
{
sContract = endpoint.Contract.Name;
}
DynamicProxy proxy = factory.CreateProxy(sContract);
string[] values = null;
// Create the parameter list
object[] arguments = new object[nvc.Count];
int i = -1;
foreach (string key in nvc.Keys)
{
values = nvc.GetValues(key);
foreach (string value in values)
{
arguments[++i] = value;
}
}
object result = (object) proxy.CallMethod(methodName, arguments);
The above code works if I have simple primitive types but not sure how can I build the logic for any other userdefined types. How can I create a object dynamically of type stored in a variable? Not sure if I was able to put my question correctly. I hope so :)
Edit: 01/19/2011: Applied the suggestion from Chris - using Reflection instead of ComponentModel.
I have converted the code to make it more generic. This works now for all primitive and custom types (resursion). Code snippet below:
private object BuildParameterList(Type type)
{
object item = new object();
item = Activator.CreateInstance(type);
PropertyInfo[] propArray = type.GetProperties(BindingFlags.Public|BindingFlags.Instance);
for (int i = 0; i < propArray.Length; i++)
{
PropertyInfo pi = (PropertyInfo)propArray[i];
////Check for custom type
if (IsCustomType(pi.PropertyType))
{
object item1 = BuildParameterList(pi.PropertyType);
pi.SetValue(item, item1, null);
}
else
{
if (property.ContainsKey(pi.Name))
{
pi.SetValue(item, Convert.ChangeType(property[pi.Name], pi.PropertyType), null);
}
}
}
return item;
}
But if one of the property is Color (I just tested with Color type, will fail with other system types aswell-i guess), then it fails at the following line. Not sure how to handle system types - Color or something similar.
pi.SetValue(item, Convert.ChangeType(property[pi.Name], pi.PropertyType), null);
Can you not find what types are expected by the method, by inspecting its ParameterInfos:
endpoint.Contract.ContractType.GetMethod(methodName).GetParameters();
and then instantiating the custom types using:
Activator.CreateInstance(parameterType);

Trouble defining method for Javascript class definition

I'm somewhat new to object oriented programming in Javascript and I'm trying to build a handler object and library for a list of items I get back from an API call. Ideally, I'd like the library functions to be members of the handler class. I'm having trouble getting my class method to work however. I defined as part of the class bcObject the method getModifiedDateTime, but when I try to echo the result of the objects call to this method, I get this error:
Error on line 44 position 26: Expected ';'
this.getModifiedDateTime: function(epochtime) {
which leads me to believe that I simply have a syntax issue with my method definition but I can't figure out where.
response(
{
"items":
[
{"id":711,"name":"Shuttle","lastModifiedDate":"1268426336727"},
{"id":754,"name":"Formula1","lastModifiedDate":"1270121717721"}
],
"extraListItemsAttr1":"blah",
"extraListItemsAttr2":"blah2"
});
function response(MyObject) {
bcObject = new bcObject(MyObject);
thing = bcObject.getModifiedDateTime(bcObject.videoItem[0].lastModifiedDate);
SOSE.Echo(thing);
}
function bcObject(listObject) {
// define class members
this.responseList = {};
this.videoCount = 0;
this.videoItem = [];
this.responseListError = "";
// instantiate members
this.responseList = listObject;
this.videoCount = listObject.items.length;
// populate videoItem array
for (i=0;i<this.videoCount;i++) {
this.videoItem[i] = listObject.items[i];
}
this.getModifiedDateTime: function(epochtime) {
var dateStringOutput = "";
var myDate = new Date(epochtime);
dateStringOutput = myDate.toLocaleString();
return dateStringOutput;
};
}
You use = to assign values in JS, not ::
this.getModifiedDateTime = function(epochtime) {
You should use the = operator for methods defined as you did there (this.<methodName> = function (...) {).
The colon notation is used when declaring object literals.