Cleaning an Access Team Record in CRM - plugins

I have to clean/to empty an access team record based on an Access team template.
How can I remove all users in the access team record in one shot? or Getting the list of users and then call RemoveUserFromRecordTeamRequest() for each user?

Here is the solution:
internal void CleanAccessTeam(IVisibilityService service, Guid recordId)
{
QueryExpression query = new QueryExpression(CrmTeam.EntityLogicalName);
FilterExpression filter = new FilterExpression();
filter.Conditions.Add(new ConditionExpression(CrmTeam.Lookups.RegardingObjectId, ConditionOperator.Equal, recordId));
query.Criteria.AddFilter(filter);
var teams = service.RetrieveMultipleRecord(query);
if (teams.Entities.Count > 0)
{
service.Delete(CrmTeam.EntityLogicalName, teams.Entities[0].Id);
}
}

Related

Leverage Groups for Workflow Approvals

We're implementing a new workflow (combined with staging task sync) on an existing website where we would like to notify all members that "own" that particular section/content to approve changes.
One of the options is to have multiple roles and their corresponding workflows configured for their role and scope, but this seems like overkill - at least for us, as currently one single role is set for approvals (and another for editors)
However I've recently come across this new page property:
And have a couple of questions:
Can regular CMS users (without membership) be part of a group?
Would we be able to leverage this group for the workflow's email notifications instead of the roles? E.g. email to everyone in the owner group when a page was sent for approval.
Is this option by default inherited from the parent page when a new one is created or does it need to be set individually for each page?
We have a Kentico 11 EMS license and working on an advanced workflow, therefore custom code is possible.
Can regular CMS users (without membership) be part of a group?
- why don't you use roles here?
Would we be able to leverage this group for the workflow's email
notifications instead of the roles? E.g. email to everyone in the
owner group when a page was sent for approval.
- you'll need to customize workflow manager class, but in general yes, it is possible. You could find an inspiration in this post
Is this option by default inherited from the parent page when a new
one is created or does it need to be set individually for each page?
- Use a macro to default the field. If you populate it with anything else then the new values will be saved.
Sample code snippet for Custom Global Event Handler for Workflow steps i.e., Reject and Approve steps.
using CMS;
using CMS.Base;
using CMS.DataEngine;
using CMS.DocumentEngine;
using CMS.EmailEngine;
using CMS.EventLog;
using CMS.Helpers;
using CMS.MacroEngine;
using CMS.SiteProvider;
using CMS.WorkflowEngine;
using System;
// Registers the custom module into the system
[assembly: RegisterModule(typeof(CustomWorkflowEvent))]
public class CustomWorkflowEvent : CMSModuleLoader
{
// Module class constructor, the system registers the module under the name "CustomInit"
public CustomWorkflowEvent()
: base("CustomInit")
{
}
// Contains initialization code that is executed when the application starts
protected override void OnInit()
{
base.OnInit();
// Assigns custom handlers to events
// WorkflowEvents.Approve.After += WorkFlow_Event_After();
WorkflowEvents.Reject.After += WorkFlow_Event_After;
WorkflowEvents.Approve.After += Approve_After;
// WorkflowEvents.Action.After += WorkFlowAction_Event_After;
}
private void Approve_After(object sender, WorkflowEventArgs e)
{
try
{
WorkflowStepInfo wsi = e.PreviousStep;
if (wsi != null)
{
CMS.WorkflowEngine.Definitions.SourcePoint s = wsi.GetSourcePoint(Guid.NewGuid());
//Make sure it was an approval (standard) step
var approvers = WorkflowStepInfoProvider.GetUsersWhoCanApprove(wsi, null, SiteContext.CurrentSiteID, "UserID = " + CMSActionContext.CurrentUser.UserID, "UserID", 0, "Email, FullName, Username");
EventLogProvider.LogInformation("Approvers Data", "Approvers Data", approvers.ToString());
if (approvers != null)
{
//Loop through the approvers
string siteName = null;
SiteInfo si = SiteInfoProvider.GetSiteInfo(SiteContext.CurrentSiteID);
if (si != null)
{
siteName = si.SiteName;
}
EmailTemplateInfo eti = EmailTemplateProvider.GetEmailTemplate("Workflow.Rejected", SiteContext.CurrentSiteName);
MacroResolver mcr = MacroResolver.GetInstance();
EmailMessage message = new EmailMessage();
// Get sender from settings
message.EmailFormat = EmailFormatEnum.Both;
message.From = eti.TemplateFrom;
// Do not send the e-mail if there is no sender specified
if (message.From != "")
{
// Initialize message
// message.Recipients = strRecipientEmail;
message.Subject = eti.TemplateSubject;
// Send email via Email engine API
// EmailSender.SendEmailWithTemplateText(SiteContext.CurrentSiteName, message, eti, mcr, true);
}
}
}
}
catch (Exception ex)
{
throw;
}
}
private void WorkFlow_Event_After(object sender, WorkflowEventArgs e)
{
try
{
WorkflowStepInfo wsi = e.PreviousStep;
if (wsi != null)
{
CMS.WorkflowEngine.Definitions.SourcePoint s = wsi.GetSourcePoint(Guid.NewGuid());
//Make sure it was an approval (standard) step
var approvers = WorkflowStepInfoProvider.GetUsersWhoCanApprove(wsi, null, SiteContext.CurrentSiteID, "UserID = " + CMSActionContext.CurrentUser.UserID, "UserID", 0, "Email, FullName, Username");
EventLogProvider.LogInformation("Approvers Data", "Approvers Data", approvers.ToString());
if (approvers != null)
{
//Loop through the approvers
string siteName = null;
SiteInfo si = SiteInfoProvider.GetSiteInfo(SiteContext.CurrentSiteID);
if (si != null)
{
siteName = si.SiteName;
}
EmailTemplateInfo eti = EmailTemplateProvider.GetEmailTemplate("Workflow.Rejected", SiteContext.CurrentSiteName);
MacroResolver mcr = MacroResolver.GetInstance();
EmailMessage message = new EmailMessage();
// Get sender from settings
message.EmailFormat = EmailFormatEnum.Both;
message.From = eti.TemplateFrom;
// Do not send the e-mail if there is no sender specified
if (message.From != "")
{
// Initialize message
// message.Recipients = strRecipientEmail;
message.Subject = eti.TemplateSubject;
// Send email via Email engine API
// EmailSender.SendEmailWithTemplateText(SiteContext.CurrentSiteName, message, eti, mcr, true);
}
}
}
}
catch (Exception ex)
{
throw;
}
}
}
Hope Helps you.
Can regular CMS users (without membership) be part of a group?
It is not part of CMS users. Groups are coming from Groups Application.
GROUP: Allows you to manage user groups. Groups are a social networking
feature enabling users to find information and communicate according
to shared interests.
Would we be able to leverage this group for the workflow's email notifications instead of the roles? E.g. email to everyone in the owner group when a page was sent for approval.
No
Is this option by default inherited from the parent page when a new one is created or does it need to be set individually for each page?
No

Get SharePoint group permissions level name based on group name Using SharePoint Rest API

I am trying to get SharePoint User group permissions (Ex: Read, Contribute) based on the group name using SharePoint Rest API. My goal is to get the permission level of the group and disable features on our custom app based on the permission levels. I have tried the below url to get the group properties but couldn't get the permission level of the group. Could anyone please guide me on how to get the User group permissions.
Options Tried:
URL = http://Servename/Site/api/web/SiteGroups/getByName('group name')
You won't be able to get this from the SiteGroup object alone. Your rest-call only retrieves group information (title, id, description and other metadata). To retrieve permission levels you will need to do a couple of more calls.
See https://msdn.microsoft.com/en-us/library/office/dn531432.aspx to read more about RoleAssignment and RoleDefinition
The function below returns Group Permission Level title and rest of the information:
function init() {
clientContext = new SP.ClientContext.get_current();
oWeb = clientContext.get_web();
currentUser = oWeb.get_currentUser();
allGroups = currentUser.get_groups();
clientContext.load(allGroups);
clientContext.executeQueryAsync(OnSuccess, OnFailure);
function OnSuccess() {
var grpsEnumerator = allGroups.getEnumerator();
while (grpsEnumerator.moveNext()) {
var group = grpsEnumerator.get_current();
var grpTitle = group.get_title();
var grpid = group.get_id();
console.log('Group Id :' + grpid);
console.log('Group Title :'+ grpTitle);
roleBindings = oWeb.get_roleAssignments().getByPrincipalId(grpid).get_roleDefinitionBindings();
clientContext.load(roleBindings);
clientContext.executeQueryAsync(function () {
var iterator = roleBindings.getEnumerator();
while (iterator.moveNext()) {
current = iterator.get_current();
console.log('Show Role Defination Title : '+ current.get_name());
}
});
}
}
function OnFailure(){
console.log('Process Failed');
}
}

SharePoint O365 Get All Users With Certain Role

Is there a way to get all users who have "Full Control" permission at a site collection and subsite level and change their role to something else? PowerShell would be ideal but CSOM would be fine too if that's the only way to do it. I know I can get groups by role but I need a way to get explicitly added users.
I tried this older StackOverflow question: Get all the users based on a specific permission using CSOM in SharePoint 2013 but I keep getting a 403 forbidden error on the first ctx.ExecuteQuery(); for all sites even though I am a collection administrator. I also wonder if anyone had a PowerShell way to do it.
According the error message, I suspect that the credential is missing in your code.
Please try the code below and let me know whether it works on your side.
static void Main(string[] args)
{
var webUrl = "[your_site_url]";
var userEmailAddress = "[your_email_address]";
using (var context = new ClientContext(webUrl))
{
Console.WriteLine("input your password and click enter");
context.Credentials = new SharePointOnlineCredentials(userEmailAddress, GetPasswordFromConsoleInput());
context.Load(context.Web, w => w.Title);
context.ExecuteQuery();
Console.WriteLine("Your site title is: " + context.Web.Title);
//Retrieve site users
var users = context.LoadQuery(context.Web.SiteUsers);
context.ExecuteQuery();
foreach(var user in users)
{
Console.WriteLine(user.Email);
}
}
}
private static SecureString GetPasswordFromConsoleInput()
{
ConsoleKeyInfo info;
SecureString securePassword = new SecureString();
do
{
info = Console.ReadKey(true);
if (info.Key != ConsoleKey.Enter)
{
securePassword.AppendChar(info.KeyChar);
}
}
while (info.Key != ConsoleKey.Enter);
return securePassword;
}
}
You need the SharePoint Online Management shell to stand up a connection to O365 via Powershell.
Introduction to the SharePoint Online management shell

p_validate_txn - unable to find MBL customer REF id

I have added a customer to QuickBooks desktop using Intuit Anywhere. When I try and sync a Sales Receipt, I get this error:
p_validate_txn - unable to find MBL customer REF id = [number] idDomain = QB
My code for returning a customer id:
Customer customer = new Customer();
List<Customer> customersList = new List<Customer>();
string theName = GetCustId(ord);
CustomerQuery query = new CustomerQuery();
if (_qboSettings.CustomerID != "SingleName")
{
query.FirstLastName = ord.BillingAddress.FirstName + " " + ord.BillingAddress.LastName.Trim();
}
else
{
query.FirstLastName = theName.Trim();
}
customersList = query.ExecuteQuery<Customer>(dataServices.ServiceContext).ToList();
//for customers that do not exist, return the ID and add them
if (customersList.Count() == 0)
{
return BuildCustomerAddRq(ord).Id.Value;
}
return customersList.FirstOrDefault().Id.Value;
When I ran a customer query, here was the response:
http://pastebin.com/rtyA8KKL
It appears I am incorrectly querying my customers? When I run the Intuit Sync Manager, I see no new customers in my QuickBooks Desktop. Is this supposed to happen?
Here is the Rest Response when creating the Sales Receipt:
http://pastebin.com/QE5YwjVB
This issue happens with customers that already exist. I created John Smith in my QB and the item for the order. I ran the sync manager. I still get this error, even with an existing customer.
While creating the sales receipt, could you try passing the Customer id and customer name in the request ?

EF SaveChanges() throws an exception 'The EntityKey property can only be set when the current value of the property is null'

I have been reading all similar posts I found regarding EF but I can't still manage to found a solution.
I'm very new to the EF and I have been reading some useful info about working with it but I think that I'm missing something.
The scenario is like this:
I want a user to be able to create an account in an ASP.NET webpage. So I have a table named 'Accounts'. The user must agree with the condition terms of the site, that may be updated in the futere, so I have also a table called 'ConditionTerms' that has 1 to many relation with the account (many accounts have an unique condition term).
I wanted to separete the specific personal user data from the data of the account so I also created a table called 'Persons' and I set the relation ship so that a person may have many accounts.
Now, when I want to save an account into the database, I retrieve the last conditionTerm available in the database and I attach it to the account entity. Then when I try to save the data via SaveChanges() I get the exception mentioned in the title of the post. The thing is that if all entities are new, when the associations are created, the EntityState for all the items is 'Detached' and it works, but when I retrieve the existing conditionTerm from the data base and I add it to the account.ConditionTerm, the account changes its state to 'Added' and then it throws the exception.
I read somewhere that when this happens, it means that all the entity tree is considered as already added by the context and I should only need to call SaveChanges() without the AddObject() method since it is already added. I tried this and then I get no exception and the code ends, but then if I check the database (SQL Server 2008 express) the account hasn't been added at all.
This is the code I'm trying and I think it should work but it's clear that I'm missing something:
[TestMethod]
public void TestCreateNewAccount()
{
try
{
AccountRepository accountRepository = new AccountRepository();
Account account = new Account()
{
Username = "TestUsername",
Password = "TestPassword",
Email = "TestEmail",
Nickname = "TestNickName",
Quote = "Test Quote",
AgreedToTermsDate = DateTime.Now,
CreationDate = DateTime.Now,
LastUpdateTime = DateTime.Now
};
// This works (all new entities!)
//ConditionTerm conditionTerm = new ConditionTerm()
//{
// Text = "This is some test condition term.",
// CreationDate = DateTime.Now,
// LastUpdateTime = DateTime.Now
//};
//This does not work (attaching an existing entity to a new one)
ConditionTerm conditionTerm = new ConditionTermsRepository().GetCurrentTerm();
Person person = new Person()
{
FirstName = "TestName",
Surname = "TestSurname",
CreationDate = DateTime.Now,
LastUpdateTime = DateTime.Now
};
account.ConditionTerm = conditionTerm;
account.Person = person;
using (ImproveEntities entities = Connection.GetModel())
{
if (account.ID > 0)
{
Account newAccount = new Account();
newAccount.ID = account.ID;
entities.Accounts.Attach(newAccount);
entities.Accounts.ApplyCurrentValues(account);
}
else
{
entities.Accounts.AddObject(account);
entities.SaveChanges();
}
}
}
catch (Exception)
{
}
}
Any help would be very much apreciated!
EDIT: This is the GetCurrentTerm() method:
public ConditionTerm GetCurrentTerm()
{
using (ImproveEntities entities = Connection.GetModel())
{
ConditionTerm conditionTerm = (from ct in entities.ConditionTerms
orderby ct.CreationDate descending
select ct).FirstOrDefault();
return conditionTerm;
}
}
If I understand correctly you want to insert a new account along with a new user into the database. But you don't want to create a new ConditionTerm but instead assign an existing ConditionTerm to the account.
The problem is that you fetch the existing ConditionTerm in another context (in your GetCurrentTerm) than the context you use for saving the new account. This second context doesn't know anything about the ConditionTerm, so you must EF explicitely tell that this conditionTerm already exists by attaching it to the second context:
// ...
using (ImproveEntities entities = Connection.GetModel())
{
entities.ConditionTerms.Attach(conditionTerm);
account.ConditionTerm = conditionTerm;
account.Person = person;
entities.Accounts.AddObject(account);
entities.SaveChanges();
}
// ...