Get sheets belonging to a specific group - smartsheet-api

How do I tell if a sheet belongs to a certain group?
For example, we have a group called RPR and when we create sheets we share them with other users in our organization applying the group to the sheet.
// Get all sheets modified within last day
SmartSheetList = smartsheet
.SheetResources
.ListSheets(new SheetInclusion[] { SheetInclusion.OWNER_INFO }, new PaginationParameters(true, null, null))
.Data
.Where(d => d.ModifiedAt.Value.Date >= DateTime.Now.AddDays(-1).Date)
.ToList();
// Get organization sheets
var orgUserSheets = smartsheet.UserResources.SheetResources.ListSheets(true).Data.ToList();
// get specific group
var group = smartsheet.GroupResources.ListGroups(null).Data.Where(grp => grp.Id == some-id-here).First();
With the code above I can see if a sheet belongs to an organization but I can't tell if that sheet belongs to a certain group. Any help would be appreciated.

You need one more API Request for each sheet to retrieve the list of shares on the sheet. Keep in mind, sheets can be shared directly on the sheet or via a workspace.
To get sheets that are shared with a specific group directly or via a workspace, you can use code something like the below (relying on LINQ for this sample).
SmartsheetClient cl = new SmartsheetBuilder()
.SetAccessToken(ACCESS_TOKEN)
.Build();
var includeAll = new PaginationParameters(true, null, null);
Console.WriteLine("Looking for group " + SOUGHT_GROUP_NAME);
var groups = cl.GroupResources.ListGroups(includeAll);
var soughtGroup = groups.Data.Single((group) => group.Name == SOUGHT_GROUP_NAME);
Console.WriteLine("Found group ID {0} for group {1}.", soughtGroup != null ? soughtGroup.Id.ToString() : "NULL", SOUGHT_GROUP_NAME);
if (soughtGroup == null)
throw new ArgumentException("Group not found");
var sheets = cl.SheetResources.ListSheets(null, includeAll);
Console.WriteLine("Querying through {0} sheets...", sheets.Data.Count);
var sheetsSharedWithGroup = from sheet in sheets.Data
from share in cl.SheetResources.ShareResources.ListShares(sheet.Id.Value, includeAll, ShareScope.Workspace).Data
where share.GroupId == soughtGroup.Id
select new { Sheet = sheet, Share = share };
var found = sheetsSharedWithGroup.ToList();
Console.WriteLine("Found {0} sheets shared with group {1}.", found.Count, SOUGHT_GROUP_NAME);
found.ForEach(foundSheet => Console.WriteLine("Sheet {0} shared with {1} ({2})", foundSheet.Sheet.Name, foundSheet.Share.Name, foundSheet.Share.Type));
NOTE: I submitted a pull request to add support for the specific ListShares overload that returns workspace shares too. This is available in the REST API but wasn't yet in the C# SDK.
NOTE: The above code does not take into account Smartsheet Sights yet. It should be possible using the corresponding REST API for Sights (i.e. List Sights, List Sight Shares, but I don't think that's in the C# SDK yet.

Related

I have a question on apex trigger when an account zip code is changed then change the account owner to the sales representative to the new zip code

When an Account’s BillingPostalCode (aka Zip Code), is changed,
Change the Account Owner to the sales representative assigned to the new zip code
Change the Owner field of all the Account’s Contacts to the same sales rep
Change the Owner field of all the Account’s Open Opportunities to the same sales rep
Note:
● The logic should run only when the Account’s zip code is changed or populated for the
first time
● If no matching Territories are found, do nothing
Requirement #3: Multiple sales representatives can be assigned to the same zip code territory.
If this is the case, use a random function to select one of the assigned sales representatives.
Requirement #4: Three sales representatives at most can be assigned to a single zip code.
Display an error if a user attempts to associate another sales representative to a zip code
trigger FireBolt on Account (before insert,before update)
{
Map<Id,String> oldZip = new Map<Id,String>();
Map<Id,String> newZip = new Map<Id,String>();
Territory1__c t = new Territory1__c();
Set ZipCodes = new Set();
List <Territory1__c> trlist= new List<Territory1__c>();
trlist = [SELECT Id,Name,OwnerId,Zip_Code__c,Sales_Representative__c FROM Territory1__c Where Zip_Code__c IN : ZipCodes];
for(Account a : Trigger.New)
{
ZipCodes.add(a.id);
}
if(Trigger.IsUpdate && Trigger.IsInsert)
{
for(Account a:Trigger.New)
{
//checking if the Account BillingPostalCode Zip code value has changed during update
String newZipCode = Trigger.newMap.get(a.id).BillingPostalCode;
String oldZipCode = Trigger.oldMap.get(a.id).BillingPostalCode;
if(newZipCode != oldZipCode)
{
oldZip.put(a.Id, Trigger.oldMap.get(a.Id).BillingPostalCode);
newZip.put(a.Id, a.OwnerId);
ZipCodes.add(a.Id);
newZipCode= t.Sales_Representative__c;
a.OwnerId= t.Sales_Representative__c;
}
}
}
}
please guide me I am new to salesforce

Need to change Access Control of Published Items though api

In Smartsheet I have downloaded Published Items list from user management. Using this list I need to change the Access control (Public/Organization) value through api. Please help. Thanks
Depending on the type of object you're updating (Sheet, Report, or Dashboard), the operations you'll use are as follows:
Set Sheet Publish Status
Set Report Publish Status
Set Dashboad (Sight) Publish Status
I've included some code examples below (taken nearly verbatim from those you'll find in the docs I've linked to above.)
One additional note: You'll notice that the values written to the Published Items list that you manually export from Smartsheet differ from the values used by the API. For example, the Access Control column of exported data contains values like Organization and Public -- where as the corresponding values used by the API are ORG and ALL.
Example #1: SHEET --> Set ReadOnlyFullAccessibleBy to ALL, ReadWriteAccessibleBy to ORG
SheetPublish sheetPublish = new SheetPublish();
sheetPublish.ReadOnlyLiteEnabled = false;
sheetPublish.ReadOnlyFullEnabled = true;
sheetPublish.ReadOnlyFullAccessibleBy = "ALL";
sheetPublish.ReadWriteEnabled = true;
sheetPublish.ReadWriteAccessibleBy = "ORG";
sheetPublish.IcalEnabled = false;
smartsheet.SheetResources.UpdatePublishStatus(
4583614634583940, // sheetId
sheetPublish
);
Example #2: Report --> Set ReadOnlyFullAccessibleBy to ORG
ReportPublish reportPublish = new ReportPublish();
reportPublish.ReadOnlyFullEnabled = true;
reportPublish.ReadOnlyFullAccessibleBy = "ORG";
smartsheet.ReportResources.UpdatePublishStatus(
1653087851556740, // reportId
reportPublish
);
Example #3: Dashboard (Sight) --> Set ReadOnlyFullAccessibleBy to ALL
SightPublish publish = new SightPublish();
publish.ReadOnlyFullEnabled = true;
publish.ReadOnlyFullAccessibleBy = "ALL";
smartsheet.SightResources.SetPublishStatus(
5363568917931908, // sightId
publish
);

Copy selection from Google Sheets into a Google Doc (using REST API?)

I have a Google Sheet whose contents I update with a python script that utilizes Google's REST API.
I want to copy a section of that Sheet into a given Google Doc automatically. (E.g. I want columns A:G of that sheet to appear in my Doc and get updated whenever the sheet does.) There are other elements (e.g. paragraphs) in the Doc, so it's important that the section appears in the location I specify each time (either by updating itself or by deleting the old section and inserting a new one).
Is that possible? How would I do it?
AFAIK, this is possible using Apps Script - Extending Google Docs and Extending Google Sheets.
You can create a Container-bound Scripts that have a onChange() trigger to get the updated value.
Write to Docs
//This can be openById() Open a document by ID.
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
// Append a paragraph and a page break to the document body section directly.
body.appendParagraph("A paragraph.");
body.appendPageBreak();
Getting data from Sheets
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// This represents ALL the data
var range = sheet.getDataRange();
var values = range.getValues();
// This logs the spreadsheet in CSV format with a trailing comma
for (var i = 0; i < values.length; i++) {
var row = "";
for (var j = 0; j < values[i].length; j++) {
if (values[i][j]) {
row = row + values[i][j];
}
row = row + ",";
}
Logger.log(row);
}
For implementation purposes, check the link. This shows how to create Google Docs and pass a value from Google Sheets using Apps Script.
Hope this helps.

Manipulate google form associated with a google sheet from app script in that sheet

I have a google spreadsheet which contains multiple sheets (or tabs) within it. Each sheet is populated from its own unique form. None of the forms are embedded in the spreadsheet.
Periodically, I need to delete all the data in the sheets, and also delete all the old responses which are saved in each of the forms. I can do this using a .gs script which resides in the spreadsheet. It accesses the form by its ID (the long string which appears in its URI). This requires the ID string to be hardcoded in my .gs script.
Ideally, I would like to access each form from the sheet object (i.e. the destination for each forms entries). Mock up code would look like this...
var ss = SpreadSheedApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var form = sheet.getMyAssociatedSourceForm(); // my dream method :-)
form.deleteAllResponses() // this method already exists
Does anyone know if this is possible? Or will I have to continue to use the ID (which is currently working)?
rgds...
I think you can do this without literally typing in ID's into your script. But, you would need to get every Form in your drive, loop through them all and get the destinationId() of every Form.
Google Documentation
Then compare the destinationId with the current spreadsheets ID, which you can get without needing to "hard code" it:
function deleteAllResponses() {
var thisSS_ID = SpreadsheetApp.getActiveSpreadsheet().getId();
var allForms = DriveApp.getFilesByType(MimeType.GOOGLE_FORMS);
var thisFormFile, thisFormFileID = "", thisForm, theDestID = "";
while (allForms.hasNext()) {
thisFormFile = allForms.next();
thisFormFileID = thisFormFile.getId();
thisForm = FormApp.openById(thisFormFileID);
try {
theDestID = thisForm.getDestinationId();
} catch(err) {
continue;
};
if (theDestID === "" || theDestID === undefined) {
continue;
};
if (theDestID === thisFormFileID) {
thisForm.deleteAllResponses();
};
};
};
I have not tested this, so don't know if it works. If it does, let me know in the comments section.

Crm 2011 - How to set a default form depending on attribute value (without using Javascript)?

I have a little requirement that is making me crazy:
We have 8 different forms for the Contact Entity.
We also have a pick list with 8 options.
The idea is that based on the option selected we could open that Contact record showing by default a particular form WITHOUT USING JAVASCRIPT in order to avoid performance problems (each record has to be loaded twice). Example:
Forms:
Form 1
Form 2
Form 3
Pick List Values - Default Form:
Form 1
Form 2
Form 3
If Form 3(pick list value) is selected then, the next time I open that record, Form 3 should be displayed by default.
If Form 1(pick list value) is selected then, the next time I open that record, Form 1 should be displayed by default.
I've trayed registering a plugin at the systemform entity, in RetrieveFilteredForms message, updating the userentityuisettings table and I've been able to set a "DEFAULT" that is displayed every time the records is opened regardless the last opened form.
I've trayed registering a plugin at the contact entity, in Retrieve message, updating the userentityuisettings table but I found that Crm only consults the table Once if there is no attribute updated, the following times Crm take the the default form to open value from the cache.
This is an old question but since it's coming up in my searches for this problem I wanted to add my solution.
We use Dynamics CRM 2013. To my knowledge, later versions of 2011 also support this technique.
The form that is displayed when an entity is opened is determined by a few things - the default form, the security roles and fallback settings for a form and the last form used by the current user for that entity. We had a similar problem to the asker where we wanted a different account form displayed based on the value of a form. We were also tired of the constant reload/refresh that javascript techniques are subject to.
I found some blog posts (in particular this one: http://gonzaloruizcrm.blogspot.com/2014/11/avoiding-form-reload-when-switching-crm.html) which mentioned that it is possible to write a plugin to the Retrieve of the entity that allows you to read out the value (LastViewedFormXml) from UserEntityUISettings that stores which form was last used. If it's not the form you want, you can write in the desired value. This avoids the javascript form refreshing.
I had to modify some code from the samples I found to get it to work, but I'm happy with the results. You need to generate an entity class using CrmSvcUtil and include it in the project. You can get your form guids from the url of the form editor.
using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Client;
namespace CRM.Plugin.AccountFormSwitcher
{
public class Plugin : IPlugin
{
public enum accountType
{
Customer = 100000000,
Vendor = 100000001,
Partner = 100000002,
Other = 100000003
}
public const string CustomerAccountFormId = "00000000-E53C-4DF4-BC99-93856EDD168C";
public const string VendorAccountFormId = "00000000-E49E-4197-AB5E-F353EF0E806E";
public const string PartnerAccountFormId = "00000000-B8C6-4E2B-B84E-729AA11ABE61";
public const string GenericAccountFormId = "00000000-8F42-454E-8E2A-F8196B0419AF";
public const string AccountTypeAttributeName = "cf_accounttype";
public void Execute(IServiceProvider serviceProvider)
{
if (serviceProvider == null)
{
throw new ArgumentNullException("serviceProvider");
}
// Obtain the execution context from the service provider.
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
var pluginContext = (IPluginExecutionContext)context;
if (pluginContext.Stage == 20) //pre-operation stage
{
var columns = (ColumnSet)pluginContext.InputParameters["ColumnSet"];
if (!columns.Columns.Contains(AccountTypeAttributeName))
columns.AddColumn(AccountTypeAttributeName);
}
else if (pluginContext.Stage == 40) //post-operation stage
{
EntityReference currentEntity = (EntityReference)context.InputParameters["Target"];
if (currentEntity == null)
return;
var query = new QueryExpression(Account.EntityLogicalName);
query.Criteria.AddCondition("accountid", ConditionOperator.Equal, currentEntity.Id);
query.ColumnSet = new ColumnSet(AccountTypeAttributeName);
var accounts = service.RetrieveMultiple(query).Entities;
Account currentAccount = (Account)accounts[0];
SetForm(currentAccount, service, context.UserId);
}
}
private void SetForm(Account account, IOrganizationService service, Guid userId)
{
var query = new QueryExpression(UserEntityUISettings.EntityLogicalName);
query.Criteria.AddCondition("ownerid", ConditionOperator.Equal, userId);
query.Criteria.AddCondition("objecttypecode", ConditionOperator.Equal, Account.EntityTypeCode);
query.ColumnSet = new ColumnSet("lastviewedformxml");
var settings = service.RetrieveMultiple(query).Entities;
// Some users such as SYSTEM have no UserEntityUISettings, so skip.
if (settings == null || settings.Count != 1 || account.cf_AccountType == null) return;
var setting = settings[0].ToEntity<UserEntityUISettings>();
string formToUse;
switch ((accountType)account.cf_AccountType.Value)
{
case accountType.Customer:
formToUse = String.Format("<MRUForm><Form Type=\"Main\" Id=\"{0}\" /></MRUForm>", CustomerAccountFormId);
break;
case accountType.Vendor:
formToUse = String.Format("<MRUForm><Form Type=\"Main\" Id=\"{0}\" /></MRUForm>", VendorAccountFormId);
break;
case accountType.Partner:
formToUse = String.Format("<MRUForm><Form Type=\"Main\" Id=\"{0}\" /></MRUForm>", PartnerAccountFormId);
break;
case accountType.Other:
formToUse = String.Format("<MRUForm><Form Type=\"Main\" Id=\"{0}\" /></MRUForm>", GenericAccountFormId);
break;
default:
formToUse = String.Format("<MRUForm><Form Type=\"Main\" Id=\"{0}\" /></MRUForm>", GenericAccountFormId);
return;
}
// Only update if the last viewed form is not the one required for the given opportunity type
if (!formToUse.Equals(setting.LastViewedFormXml, StringComparison.InvariantCultureIgnoreCase))
{
var s = new UserEntityUISettings { Id = setting.Id, LastViewedFormXml = formToUse };
service.Update(s);
}
}
}
}
And to address the asker's issue with it only consulting the UserEntityUISettings once, I'm not sure why that's happening. But why not use javascript to change the form when the triggering attribute is changed? That what I do and I haven't ran into any problems with the plugin not displaying the desired for.
EDIT: the OP specified after that he needs a solution without javascript, I leave this reply for future references.
You can use javascript, inside the OnLoad event you check the picklist value and navigate to the desired form. Check this code as example
var value = Xrm.Page.getAttribute("new_optionset").getValue();
switch(value) {
case 100000000:
Xrm.Page.ui.formSelector.items.get(0).navigate();
break;
case 100000001:
Xrm.Page.ui.formSelector.items.get(1).navigate();
break;
case 100000002:
Xrm.Page.ui.formSelector.items.get(2).navigate();
break;
/// ... other cases here
default:
// default form to open when there is no value
Xrm.Page.ui.formSelector.items.get(0).navigate();
}
This is an oldy but a goody... I use CRM Rules to generate Hide Tab and Show Tab actions that essentially show each user role a different form.
Steps:
Create one, massive form with all of the fields you want to display (if you already have many forms, this would include all fields across all forms).
Organize the form into TABS, with each tab showing 'one form' worth of data. (You can also have many TABS for each user group). Typically, I create one 'General' tab that has the key option set that will set the rest of the form up, and any fields that are common across roles / user groups / forms, like status, name, etc...
3) Hide all of the tabs except the General tab by unchecking the visible box on those tab form property forms in the Admin UI.
4) Using CRM Rules (crm-rules.com), you can then bring in the metadata, with the form, and all of the tabs and sections in there. Then you just have to write one rule for each 'form' you are trying to show... Each rule is of this format:
IF User_Role contains 'Sales' THEN Show Tab: Sales
IF User_Role contains 'Marketing' THEN Show Tab: Marketing
You can also do this, of course, with an option set, or any field on the form as the condition... One of the benefits of this approach is that if users cross role boundaries (or some users were part of security roles that could access multiple forms), this technique shows them both forms at once...
HTH somebody, CRM Rules (www.crm-rules.com) generates the JavaScript to make this happen...