CRM Late Bound - Cleaner Approach - console-application

I have the following code and I'm trying to find a more elegant approach to this. activityParty is a DataCollection. I am basically trying to get a list of recipients for an email, which can be of type users or contacts.
I am familiar with early bound but in this scenario must use late bound.
Is there a better approach to this?
var recipientParty = activityParty.Where(x => x.GetAliasedValueOrDefault<OptionSetValue>("ap.participationtypemask").Value == 2).ToList();
var recipientList = new List<string>();
foreach (var to in recipientParty)
{
if (to.Attributes.Contains("u.internalemailaddress"))
{
recipientList.Add(to.GetAliasedValueOrDefault<string>("u.internalemailaddress"));
}
if (to.Attributes.Contains("c.emailaddress1"))
{
recipientList.Add(to.GetAliasedValueOrDefault<string>("c.emailaddress1"));
}
}

Have a look at AddressUsed property of ActivityParty entity. It should contain email address, regardless which entity is source of party involved.
So, in your code you can use to.AddressUsed instead whole if {...} statement.

Try this:
using (var serviceContext = new OrganizationServiceContext(this.OrganizationService)) // if you are writing custom code activity
//using (var serviceContext = new OrganizationServiceContext(localContext.OrganizationService)) // if you are writing plugin
{
var activityPartySet = serviceContext.CreateQuery<ActivityParty>();
var activityParties = activityPartySet.Where(
ap => ap.PartyId != null &&
ap.ParticipationTypeMask != null &&
ap.ParticipationTypeMask.Value == 2).ToList();
var userSet = serviceContext.CreateQuery<SystemUser>();
var contactSet = serviceContext.CreateQuery<Contact>();
var recipientList = new List<string>();
foreach (var ap in activityParties)
{
var partyRef = ap.PartyId;
if (partyRef.LogicalName == SystemUser.EntityLogicalName)
{
var user = (from u in userSet
where u.Id == partyRef.Id
select new SystemUser
{
InternalEMailAddress = u.InternalEMailAddress
}).FirstOrDefault();
if (user != null)
recipientList.Add(user.InternalEMailAddress);
}
else if (partyRef.LogicalName == Contact.EntityLogicalName)
{
var contact = (from c in contactSet
where c.Id == partyRef.Id
select new Contact
{
EMailAddress1 = c.EMailAddress1
}).FirstOrDefault();
if (contact != null)
recipientList.Add(contact.EMailAddress1);
}
}
}
Hope it helps!

Related

how to mock a method of a class

This is my controller code and I need to mock GetTokenDetails() method to conduct XUnit test on DecodeToken function. Am I doing in right way or not?
[HttpGet]
[Authorize(Roles = "Admin")]
[Route("DecodeToken")]
public IActionResult DecodeToken()
{
if (ModelState.IsValid)
{
var tokenResult = GetTokenDetails();
var result = _employeeService.ServiceDecodeToken(tokenResult.UserName, tokenResult.Role);
if (result.Httpcode == 200)
{
return Ok(result);
}
else
{
return StatusCode(500, result);
}
}
else
return BadRequest();
}
public GetTokenDetailsDto GetTokenDetails()
{
var token = HttpContext.Request.Headers["Authorization"].ToString();
var tokenbearer = token.Split(' ');
var handler = new JwtSecurityTokenHandler();
var decodedtoken = handler.ReadJwtToken(tokenbearer[1]);
string user = decodedtoken.Claims.Where(x => x.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name").FirstOrDefault().ToString();
string role = decodedtoken.Claims.Where(x => x.Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/role").FirstOrDefault().ToString();
var usr = user.Split(":");
var rol = role.Split(":");
string userName = usr[2].Trim();
string userRole = rol[2].Trim();
GetTokenDetailsDto getTokenDetailsDto = new GetTokenDetailsDto()
{
UserName = userName,
Role = userRole,
};
return getTokenDetailsDto;
}
First, Generally, I don't think there is a right way to do something.
There are multiple right ways to do it :). You just need to pick one or create one.
Second, I suggest you to create a new Dotnet standard Project under the same Solution and separate the logic from controllers. This way, you can create a Unit test project and import only the logic project.
Third, I see some points in your code that you are reading some value from the context( which is not avaiable in testing environment). For example, HttpContext.Request.Headers["Authorization"]. these kind of data should be in the input arguments of the function GetTokenDetails, so you can provide some sample data to test in your UnitTestProject. Something like this:
public GetTokenDetailsDto GetTokenDetails(string token)
{
var tokenbearer = token.Split(' ');
var handler = new JwtSecurityTokenHandler();
var decodedtoken = handler.ReadJwtToken(tokenbearer[1]);
string user = decodedtoken.Claims.Where(x => x.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name").FirstOrDefault().ToString();
string role = decodedtoken.Claims.Where(x => x.Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/role").FirstOrDefault().ToString();
var usr = user.Split(":");
var rol = role.Split(":");
string userName = usr[2].Trim();
string userRole = rol[2].Trim();
GetTokenDetailsDto getTokenDetailsDto = new GetTokenDetailsDto()
{
UserName = userName,
Role = userRole,
};
return getTokenDetailsDto;
}

How do I get an alert prompt when an "if" statement returns no 'finds' in Google Apps Script?

//Invoice find and transfer to Warehouse Sheet
function searchInvoiceWhSh() {
var ss = SpreadsheetApp.getActiveSpreadsheet()
var shUserForm = ss.getSheetByName("Warehouse Form")
var shSalesSheet = ss.getSheetByName("Sales")
var sValue = shUserForm.getRange("G5").getValue();
var sData = shSalesSheet.getDataRange().getValues();
var currentRow = 9
for (var i=0; i<sData.length; i++) {
var row = sData[i];
if (row[0] == sValue) { //do something}
currentRow += 2
}}
I've used this to search for an "Invoice number" from the "Sales" worksheet and when found to transfer the data back to the user form.
If, for example, the invoice number is typed incorrectly into the "sValue" cell, then no data will be transferred.
How do I code a prompt message to ask the user to check the invoice number as no records were found?
Try:
function searchInvoiceWhSh() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const shUserForm = ss.getSheetByName("Warehouse Form")
const shSalesSheet = ss.getSheetByName("Sales")
const sValue = shUserForm.getRange("G5").getValue()
const sData = shSalesSheet.getDataRange().getValues()
const targetData = sData.filter(row => row[0] === sValue)
if (targetData.length) {
// Value(s) found
targetData.forEach(row => {
Logger.log(row)
})
} else {
SpreadsheetApp.getUi().alert(`No match found.`)
}
}
This will search for the sValue provided as in your code, but will store the row in a variable once found. If it's not found, it will create an alert pop-up with your specified message.
Alternatively, you can check out UI Class for other pop-up options.
Try it like this:
function myfunk() {
var ss = SpreadsheetApp.getActive()
var fsh = ss.getSheetByName("Warehouse Form")
var ssh = ss.getSheetByName("Sales")
var fv = fsh.getRange("G5").getValue();
var svs = ssh.getDataRange().getValues();
let m = 0;
svs.forEach((r, i) => {
if (r[0] == fv) {
m++;
}
SpreadsheetApp.getUi().alert(`${m} matches found`)
});
}
Always provides a result

How to add dynamic values to field injections list with custom trigger to camunda properties panel?

I have two questions here
Is it possible to add dynamic lists values to field injection list input ?
Can I create a trigger for this so this can be initiated from any other input selection say a class selection will populate all fields
I was just looking into FieldInjection.js whether that can be extented for the same
Can someone please provide a hint or direction for this ?
Thanks.
For anyone interested in the answer, I was able to achieve the above goal by changing the set function of the Java Class select input as folllowing
few imports
var extensionElementsHelper = require('../../../../helper/ExtensionElementsHelper'),
elementHelper = require('../../../../helper/ElementHelper')
var CAMUNDA_FIELD_EXTENSION_ELEMENT = 'camunda:Field';
function getExtensionFields(bo) {
return bo && extensionElementsHelper.getExtensionElements(bo, CAMUNDA_FIELD_EXTENSION_ELEMENT) || [];
}
then changing the set function to create extension element and push the field values as :
set: function(element, values, node) {
var bo = getBusinessObject(element);
var type = getImplementationType(element);
var attr = getAttribute(type);
var prop = {}
var commands = [];
prop[attr] = values.delegate || '';
var extensionElements = getExtensionFields(bo);
//remove any extension elements existing before
extensionElements.forEach(function(ele){
commands.push(extensionElementsHelper.removeEntry(getBusinessObject(element), element, ele));
});
if(prop[attr] !== ""){
var extensionElements = elementHelper.createElement('bpmn:ExtensionElements', { values: [] }, bo, bpmnFactory);
commands.push(cmdHelper.updateBusinessObject(element, bo, { extensionElements: extensionElements }));
var arrProperties = ["private org.camunda.bpm.engine.delegate.Expression com.cfe.extensions.SampleJavaDelegate.varOne","private org.camunda.bpm.engine.delegate.Expression com.cfe.extensions.SampleJavaDelegate.varTwo"]
var newFieldElem = "";
arrProperties.forEach(function(prop){
var eachProp = {
name:"",
string:"",
expression:""
}
var type = prop.split(" ")[1].split(".").reverse()[0];
var val = prop.split(" ")[2].split(".").reverse()[0];
eachProp.name = val;
if( type == "String"){
eachProp.string = "${" + val +" }"
}else if( type == "Expression"){
eachProp.expression = "${" + val +" }"
}
newFieldElem = elementHelper.createElement(CAMUNDA_FIELD_EXTENSION_ELEMENT, eachProp, extensionElements, bpmnFactory);
commands.push(cmdHelper.addElementsTolist(element, extensionElements, 'values', [ newFieldElem ]));
});
}
commands.push(cmdHelper.updateBusinessObject(element, bo, prop));
return commands;
}
Cheers !.

SPAlert.Filter not working

Can anybody help with SPAlert filters on Sharepoint 2013?
If I set Filter property on SPAlert instance the alert has not been sent
SPAlert newAlert = user.Alerts.Add();
SPAlertTemplateCollection alertTemplates = new SPAlertTemplateCollection(
(SPWebService)(SPContext.Current.Site.WebApplication.Parent));
newAlert.AlertType = SPAlertType.List;
newAlert.List = list;
newAlert.Title = alertTitle;
newAlert.DeliveryChannels = SPAlertDeliveryChannels.Email;
newAlert.EventType = eventType;
newAlert.AlertFrequency = SPAlertFrequency.Immediate;
newAlert.AlertTemplate = alertTemplates[Constants.AlertTemplates.GenericListCustom];
var wsm = new WorkflowServicesManager(web);
var wss = wsm.GetWorkflowSubscriptionService();
var subscriptions = wss.EnumerateSubscriptionsByList(list.ID);
bool assotiationExist = false;
var guid = Constants.Workflows.ApprovalWF.Guid;
foreach (var subs in subscriptions)
{
assotiationExist = subs.DefinitionId == guid;
if (assotiationExist)
{
newAlert.Filter = "<Query><Eq><FieldRef Name=\"ApprovalStatus\"/><Value type=\"string\">Approved</Value></Eq></Query>";
}
}
newAlert.Update(false);
If I set Filter property on SPAlert instance the alert has not been sent
What do you need exactly ?
If you just want to change the filter (alert condition), did you simply try :
newAlert.AlertType = SPAlertType.List;
newAlert.List = list;
newAlert.Title = alertTitle;
newAlert.DeliveryChannels = SPAlertDeliveryChannels.Email;
newAlert.EventType = eventType;
newAlert.AlertFrequency = SPAlertFrequency.Immediate;
newAlert.AlertTemplate = alertTemplates[Constants.AlertTemplates.GenericListCustom];
newAlert.Filter = "<Query><Eq><FieldRef Name=\"ApprovalStatus/New\"/><Value type=\"string\">Approved</Value></Eq></Query>";
newAlert.Update(false);
I have just added a /New in your filter query. Query filter in alert need to get a /New or a /Old in your field.
If your alert still doesn't work, it might be something else than the filter.
The problem was in line newAlert.EventType = eventType. eventType was SPEventType.Add. That was the reason of not sending alert after Workflow set the ApprovalStatus field to «Approved».
I’ve modified algourithm. Now eventType is SPEventType.Modify and I added new field "IsNewAlertSent" to list. When event fires the first time then I send email and set the "IsNewAlertSent" field
Final code is shown below.
class UserAlertManager:
..
newAlert.EventType = (eventType == SPEventType.Add? SPEventType.Modify: eventType);
newAlert.AlertFrequency = SPAlertFrequency.Immediate;
newAlert.AlertTemplate = alertTemplates[Constants.AlertTemplates.GenericListCustom];
..
if (assotiationExist)
{
newAlert.Filter = "<Query><Eq><FieldRef name=\"ApprovalStatus\"/><Value type=\"Text\">Approved</Value></Eq></Query>";
newAlert.Properties.Add("grcustomalert", "1");
}
..
newAlert.Update(false);
class GRCustomAlertHandler:
...
string subject = string.Empty;
string body = string.Empty;
bool grCustomAlert = Utils.IsSPAlertCustom(ahp.a);
if (ahp.eventData[0].eventType == (int)SPEventType.Modify && grCustomAlert)
{
SPListItem item = list.GetItemById(ahp.eventData[0].itemId);
var isNewAlertSentField = item.Fields.GetFieldByInternalName(Constants.Fields.IsNewAlertSent);
if (isNewAlertSentField != null && (item[Constants.Fields.IsNewAlertSent] == null || !(bool)item[Constants.Fields.IsNewAlertSent]))
{
...
Utils.SendMail(web, new List<string> { ahp.headers["to"].ToString() }, subject, body);
item[Constants.Fields.IsNewAlertSent] = true;
using (new DisabledItemEventScope())
{
item.SystemUpdate(false);
}
}
}
...

Extract info from email body with Google Scripts

I am trying to extract specific info from email in one of my labels in Gmail. I've hacked (my scripting knowledge is very limited) the following together based on a script from https://gist.github.com/Ferrari/9678772. I am getting an error though: "Cannot convert Array to Gmail Thread - Line 5"
Any help will be greatly appreciated.
/* Based on https://gist.github.com/Ferrari/9678772 */
function parseEmailMessages(start) {
/* var threads = GmailApp.getInboxThreads(start, 100); */
var threads = GmailApp.getMessagesForThread(GmailApp.search("label:labelname"));
var sheet = SpreadsheetApp.getActiveSheet();
var tmp, result = [];
for (var i = 0; i < threads.length; i++) {
// Get the first email message of a threads
var message = threads[i].getMessages()[0];
// Get the plain text body of the email message
// You may also use getRawContent() for parsing HTML
var content = messages[0].getPlainBody();
// Implement Parsing rules using regular expressions
if (content) {
tmp = content.match(/Name and Surname:\n([A-Za-z0-9\s]+)(\r?\n)/);
var username = (tmp && tmp[1]) ? tmp[1].trim() : 'No username';
tmp = content.match(/Phone Number:\n([\s\S]+)/);
var phone = (tmp && tmp[1]) ? tmp[1] : 'No phone';
tmp = content.match(/Email Address:\n([A-Za-z0-9#.]+)/);
var email = (tmp && tmp[1]) ? tmp[1].trim() : 'No email';
tmp = content.match(/Prefered contact office:\n([\s\S]+)/);
var comment = (tmp && tmp[1]) ? tmp[1] : 'No office';
sheet.appendRow([username, phone, email, comment]);
}
}
};
Thanks folks.. This did the trick:
// Adapted from https://gist.github.com/Ferrari/9678772
function processInboxToSheet() {
// Have to get data separate to avoid google app script limit!
var start = 0;
var label = GmailApp.getUserLabelByName("yourLabelName");
var threads = label.getThreads();
var sheet = SpreadsheetApp.getActiveSheet();
var result = [];
for (var i = 0; i < threads.length; i++) {
var messages = threads[i].getMessages();
var content = messages[0].getPlainBody();
// implement your own parsing rule inside
if (content) {
var tmp;
tmp = content.match(/Name and Surname:\n([A-Za-z0-9\s]+)(\r?\n)/);
var username = (tmp && tmp[1]) ? tmp[1].trim() : 'No username';
tmp = content.match(/Phone Number:\n([\s\S]+)/);
var phone = (tmp && tmp[1]) ? tmp[1] : 'No phone';
tmp = content.match(/Email Address:\n([A-Za-z0-9#.]+)/);
var email = (tmp && tmp[1]) ? tmp[1].trim() : 'No email';
tmp = content.match(/Prefered contact office:\n([\s\S]+)/);
var comment = (tmp && tmp[1]) ? tmp[1] : 'No office';
sheet.appendRow([username, phone, email, comment]);
Utilities.sleep(500);
}
}
};
var threads = GmailApp.getMessagesForThread(GmailApp.search("label:labelname"));
should include an array index since GmailApp.search returns an array, even if only one item is found.
var threads = GmailApp.getMessagesForThread(GmailApp.search("label:labelname")[0]);
would work but is wordy.
var thread_list = GmailApp.search("label:labelname");
var threads = GmailApp.getMessagesForThread(thread_list[0]);
IMO, the above is clearer in meaning.