PuppeteerSharp - querySelectorAll + click - c#

I'm brand new to puppeteersharp. Can you please tell me where, in my thought process and code, I'm going wrong. I'm trying to grab reviews on this product:
https://www.newegg.com/gigabyte-geforce-rtx-2060-gv-n2060oc-6gd/p/N82E16814932115
All reviews load when you click the reviews tab which is retrieved from
document.querySelectorAll(".tab-nav")[4]
reviews is null after this code:
using (var browser = await Puppeteer.LaunchAsync(options))
{
using (var page = await browser.NewPageAsync().ConfigureAwait(false))
{
await page.GoToAsync("https://www.newegg.com/gigabyte-geforce-rtx-2060-gv-n2060oc-6gd/p/N82E16814932115");
var clickReviews = "document.querySelectorAll('.tab-nav')[4].click();";
var reviews = "Array.from(document.querySelectorAll('.comments-content'));";
await page.EvaluateExpressionAsync(clickReviews);
var reviews = await page.EvaluateExpressionAsync(reviews);
Console.WriteLine(reviews);

EvaluateExpressionAsync won't return DOM elements. You should build a serialized output. For instance, a string[] with the review text.
var reviews = "Array.from(document.querySelectorAll('.comments-content')).map(r => r.innerText);";
var reviews = await page.EvaluateExpressionAsync<string[]>(reviews);
Console.WriteLine(reviews);

Related

Bot mentions to meetings groups are blank on Desktop/Web chat view

We're developing a bot that proactively messages people in a group chat.
Bot mentions are showing blank on Desktop/Web chat view. Interestingly, on mobile and in the notification bar on the left, the full text does show correctly.
This issue may apply to other chats, but I have not tested.
I'm using similar code to the following Microsoft guide by constructing the mention object:
https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/conversations/channel-and-group-conversations?tabs=dotnet#add-mentions-to-your-messages
Yes, I have tried using XMLConvert on the name as in the example, however, that does not make a difference, in fact, it puts the XML verbatim into the message sent by the bot.
I've also submitted a bug report here, as I suspect it's a bug in Teams itself (although, I could not find any other mentions of this or other similar example code):
https://microsoftteams.uservoice.com/forums/555103-public/suggestions/43922577-bot-mentions-to-meetings-groups-are-blank-on-deskt
Relevant C# code:
...
using (ConnectorClient _client = new ConnectorClient(new Uri(groupChat.ServiceUrl), GetMicrosoftAppCredentials(), new HttpClient()))
{
var theMessage = Activity.CreateMessageActivity();
theMessage.Text = messageDto.Message;
// Process the message text for <at>mentions</at>
var textMentions = System.Text.RegularExpressions.Regex.Matches(theMessage.Text, "<at>(.*?)</at>");
var mentionObjects = new List<Entity>(); // For storing the mentions
foreach (var textMention in textMentions)
{
// The mentioned person should be between the tags
var theName = textMention.ToString().Split(new string[] { "<at>", "</at>" }, StringSplitOptions.RemoveEmptyEntries)[0];
if (!String.IsNullOrEmpty(theName))
{
// Find the teamsUser based on their name
var teamsUser = _botContext.Users.FirstOrDefault(u => u.Name.Equals(theName));
if (teamsUser != null)
{
var mention = new Mention
{
Mentioned = new ChannelAccount(teamsUser.TeamsUserId),
Text = textMention.ToString()
};
mentionObjects.Add(mention);
}
}
}
theMessage.Entities = mentionObjects;
try
{
var response = await _client.Conversations.SendToConversationAsync(groupChat.GroupChatId, (Activity)theMessage);
return Ok(response.Id);
}
catch (Exception e)
{}
}
...
Desktop Teams Chat:
Activity shows name OK:
Mobile app looks OK:
Images edited for privacy
Try passing "User Name" also in ChannelAccount() like below:
var mention = new Mention
{
Mentioned = new ChannelAccount(
turnContext.Activity.From.Id,
**turnContext.Activity.From.Name,**
role: null,
aadObjectId: null),
Text = textMention.ToString()
};
I tried above code and it's working for me.

TFS API: Request Review on Changeset in C#

In Visual Studio I usually open the Changeset via Source Control Explorer, open the Changeset via Go to Changeset and then select Actions->Request Review in the Team Explorer window where the Changeset is shown.
In C# I have code that lets me query all my changesets:
VersionControlServer vcs = tpc.GetService<VersionControlServer>();
vcs.QueryHistory(...)
Now I have a List of Changeset instances.
How can I implement the "Request Review" functionality?
I tried to create a Code Review Request like so:
Project teamProject = _workItemStore.Projects["XYZ"];
WorkItemType workItemType = teamProject.WorkItemTypes["Code Review Request"];
var request = new WorkItem(workItemType) { Title = "Testreview" };
request.Fields["Associated Context Type"].Value = "Changeset";
request.Fields["Associated Context"].Value = "5169";
request.Fields["Assigned To"].Value = "Joe Doe";
request.AreaPath = #"XYZ\Test";
request.IterationPath = #"XYZ\Test\1.5";
request.Save();
This creates a code review request very similar to the one in Visual Studio but Code Review can not be performed. What am I missing?
From what I see you are using the package Microsoft.TeamFoundationServer.ExtendedClient. You are on the right track, but you need one more work item called Code Review Response. For the creation of these two work items refer to the blog post Tfs Extensibility - Automatically Create Code Reviews on Checkin. This post helped me a lot regarding the work item field values. Here is the essential code section from the post:
var type = project.WorkItemTypes["Code Review Response"];
var workItem = new WorkItem(type) { Title = checkinNotification.Comment };
workItem.Fields["System.AssignedTo"].Value = "Betty"; //todo pick someone better
workItem.Fields["System.State"].Value = "Requested";
workItem.Fields["System.Reason"].Value = "New";
var result = workItem.Validate();
foreach (Field item in result)
{
//insert some form of logging here
}
workItem.Save();
var responseId = workItem.Id;
type = project.WorkItemTypes["Code Review Request"];
workItem = new WorkItem(type) { Title = checkinNotification.Comment };
workItem.Fields["System.AssignedTo"].Value = checkinNotification.ChangesetOwner.DisplayName;
workItem.Fields["Microsoft.VSTS.CodeReview.ContextType"].Value = "Changeset";
workItem.Fields["Microsoft.VSTS.CodeReview.Context"].Value = checkinNotification.Changeset;
workItem.Fields["System.AreaPath"].Value = project.Name; //todo: may want a better location from source path
workItem.Fields["System.IterationPath"].Value = project.Name;
workItem.Fields["System.State"].Value = "Requested";
workItem.Fields["System.Reason"].Value = "New";
WorkItemLinkTypeEnd linkTypeEnd = workitemStore.WorkItemLinkTypes.LinkTypeEnds["Child"];
workItem.Links.Add(new RelatedLink(linkTypeEnd, responseId));
workItem.Save();
The actual comments on the code review use the discussion service (see Creating code review request through API). Microsoft documentation on the disscusion service: Microsoft.TeamFoundation.Discussion.Client.
In this namespace take a look at the class DiscussionThread
I hope this helps.

Using VsConnection WorkItemTrackingHttpClient patch to add parent relation via VSTS client API

I am trying to programmatically add a parent-child relationship between two work items. I am using the Microsoft Team Foundation and Visual Studio Services libraries to export and import TFS 2015 and VSTS backlog objects.
https://learn.microsoft.com/en-us/vsts/integrate/concepts/dotnet-client-libraries
https://www.visualstudio.com/en-us/docs/integrate/api/wit/samples#migrating-work-items
I have worked through obtaining a VssConnection to my servers and getting a WorkItemTrackingHttpClient to execute Wiql queries and create work items. I also have a query to identify the parent of a target work item.
What I cannot figure out is how to add the link between child work items and their parent. I do not know the correct JsonPatchDocument item path to add the parent, or the correct property or method on an existing WorkItem to update it with a parent link. Does anyone have documentation links or specific information on adding a parent relationship to a work item using these libraries?
Here are some code excerpts for context:
using Microsoft.TeamFoundation.Core.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.Client;
using Microsoft.VisualStudio.Services.WebApi;
using Microsoft.VisualStudio.Services.WebApi.Patch;
using Microsoft.VisualStudio.Services.WebApi.Patch.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
// ...
var sourceConnection = new VssConnection(new Uri(_sourceTsUrl), new VssClientCredentials());
var targetConnection = new VssConnection(new Uri(_targetTsUrl), new VssClientCredentials());
var sourceClient = sourceConnection.GetClient<WorkItemTrackingHttpClient>();
var targetClient = targetConnection.GetClient<WorkItemTrackingHttpClient>();
// ...
var queryResults = sourceClient.QueryByWiqlAsync(query).Result;
var ids = queryResults.WorkItems.Select(x => x.Id).ToList();
var items = sourceClient.GetWorkItemsAsync(ids);
foreach (var item in items.Result)
{
// ...
var patchItem = new JsonPatchDocument();
foreach (var fieldName in item.Fields.Keys)
{ patchItem.Add(new JsonPatchOperation() { Path = $"/fields/{fieldName}", Value = item.Fields[fieldName], Operation = Operation.Add }); }
// TODO - add patch field(?) for parent relationship
var parentResults = sourceClient.QueryByWiqlAsync(parentQuery).Result;
// ...
var task = targetClient.CreateWorkItemAsync(patchItem, targetProject, itemType, validateOnly, bypassRules, suppressNotifications);
var newItem = task.Result;
// TODO - alternatively, add parent via the returned newly generated WorkItem
}
Addendum:
I've tried adding the following code, but the changes do not get committed to the remote object, it only exists in local memory, and I cannot find a method to push the changes/updates.
if (!string.IsNullOrWhiteSpace(mappedParentUrl))
{
if (newItem.Relations == null)
{ newItem.Relations = new List<WorkItemRelation>(); }
newItem.Relations.Add(new WorkItemRelation() { Rel = "Parent", Title = mappedParentTitle, Url = mappedParentUrl });
}
Refer to this code to create task work item with parent link (Update it to meet your requirement):
var url = new Uri("https://XXX.visualstudio.com");
var connection = new VssConnection(url, new VssClientCredentials());
var workitemClient = connection.GetClient<WorkItemTrackingHttpClient>();
string projectName = "[project name]";
int parentWITId = 771;//parent work item id
var patchDocument = new Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchDocument();
patchDocument.Add(new Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchOperation() {
Operation=Operation.Add,
Path= "/fields/System.Title",
Value="parentandchildWIT"
});
patchDocument.Add(new Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchOperation()
{
Operation = Operation.Add,
Path = "/relations/-",
Value = new
{
rel = "System.LinkTypes.Hierarchy-Reverse",
url = connection.Uri.AbsoluteUri+ projectName+ "/_apis/wit/workItems/"+parentWITId,
attributes = new
{
comment = "link parent WIT"
}
}
});
var createResult = workitemClient.CreateWorkItemAsync(patchDocument, projectName, "task").Result;

UWP - Exceptions thrown when Updating Or Deleting existing contact

I am working on a app to maintain contacts, but I haven't found a way to successfully retrieve a contact I have created and perform an update or delete on that contact. I have boiled it down to a simple example:
public async Task TestContact()
{
try
{
//Make a list
ContactStore store = await ContactManager.RequestStoreAsync(ContactStoreAccessType.AppContactsReadWrite);
var lists = await store.FindContactListsAsync();
ContactList list = lists.FirstOrDefault((x) => x.DisplayName == "Test List");
if (list == null)
{
list = await store.CreateContactListAsync("Test List");
list.OtherAppReadAccess = ContactListOtherAppReadAccess.Full;
list.OtherAppWriteAccess = ContactListOtherAppWriteAccess.SystemOnly;
await list.SaveAsync();
}
//Make a contact and save it
Contact contact = new Contact();
contact.FirstName = "Test";
contact.LastName = "Contact";
await list.SaveContactAsync(contact);
//Modify the existing one just to show that saving again works
ContactEmail email = new ContactEmail();
email.Address = "test#test.com";
contact.Emails.Add(email);
await list.SaveContactAsync(contact); //This line updates existing contact as desired.
//Now simulate finding that contact, modify it, and save it
store = await ContactManager.RequestStoreAsync(ContactStoreAccessType.AppContactsReadWrite);
var contacts = await store.FindContactsAsync("Test Contact");
contact = contacts[0];
contact.Emails[0].Address = "newemail#test.com"; //Change a value
lists = await store.FindContactListsAsync();
list = lists.FirstOrDefault((x) => x.DisplayName == "Test List");
if (list != null)
{
await list.SaveContactAsync(contact); //This line throws "The operation identifier is not valid"
await list.DeleteContactAsync(contact); //This line throws "Value does not fall within the expected range"
}
}
catch (Exception ex)
{
//exception thrown!
}
}
The code creates a new list as needed, adds a contact to it, and updates that contact in place. It then tries to retrieve that contact by searching for it and calling save (or delete). Both save and delete throw exceptions as noted in the comments.
Has anyone been able to update a contact after finding it through a search? Ultimately I really want to be able to update a contact in place. I'm only trying delete as work around for not being able to save (UPDATE = DELETE + ADD)
Note that I want an IN PLACE update - I am not interested in creating a second contact that is linked to the first when I save changes.
Thanks in advance!
The problem here is that the contacts returned from FindContactsAsync(String) method are "aggregate contacts" (even though they are not linked in People app). As they are not the raw contacts created by your app, you are not able to change or delete them directly and that's why you got errors when calling SaveContactAsync or DeleteContactAsync method.
To solve this issue, we need to get the raw contact according to the "aggregate contact" with using FindRawContactsAsync(Contact) method and then modify, save or delete the the raw contact. For example:
//Now simulate finding that contact, modify it, and save it
var store = await ContactManager.RequestStoreAsync(ContactStoreAccessType.AppContactsReadWrite);
var contacts = await store.FindContactsAsync("Test Contact");
//This contact is a "aggregate contact"
var contact = contacts[0];
//Get the raw contacts according to the "aggregate contact"
var allStore = await ContactManager.RequestStoreAsync(ContactStoreAccessType.AllContactsReadOnly);
var rawContacts = await allStore.AggregateContactManager.FindRawContactsAsync(contact);
foreach (var rawContact in rawContacts)
{
var contactList = await store.GetContactListAsync(rawContact.ContactListId);
if (contactList != null && contactList.DisplayName == "Test List")
{
rawContact.Emails[0].Address = "newemail#test.com"; //Change a value
await contactList.SaveContactAsync(rawContact);
//await contactList.DeleteContactAsync(rawContact);
}
}

How to get all the users in Zendesk

I have created users using CreateOrUpdateUser() method but i was unable to fetch all the users from zendesk. I am getting null for "oListUser" also I tried to fetch user list for Organization but for that also i am getting null.Any help would be appreciated. There is no issue with the connection.
Code:
ZenDeskApi.ZenDeskApi oZen = new ZenDeskApi.ZenDeskApi("https://waresolution.zendesk.com", "j#se.com", "87ggh76IO");
List<User> oListUser = oZen.GetUsers();
User oUsers = new ZenDeskApi.Model.User();
oUsers.Email = "r#se.com";
oUsers.IsVerified = true;
oUsers.Name = "R r";
oUsers..........// Other properties
int a = oZen.CreateOrUpdateUser(oUsers);
List<Organization> oOrg = oZen.GetOgranizations();
foreach (var orgItem in oOrg)
{
int orgId = orgItem.Id;
}
Take a look at this zendesk api client for C#.net on Github. See the JUSTEAT blog for more details. You can use this client to get all users like this:
Create a client:
IZendeskClient client = new ZendeskClient(
new Uri("my-zendesk-api-host-endpoint"),
"my-zendesk-username",
"my-zendesk-token"
);
Then you can use the Search resource to search all users:
var result = client.Search.Find(new ZendeskQuery<User>().WithCustomFilter("y", "x"));
You can download the code as a Nuget here
I am using ZendeskApi_v2 and I am able to get all the users using api as follows:
var userList = api.Users.GetAllUsers();
Here userList is GroupUserReponse.I doubt whether we have any method GetUsers().Atleast its not available in the version which I am using.Once you get the response you can iterate through it.
I see that this question is related to ZenDeskApi which is available at this location:
https://github.com/eneifert/ZenDeskApi.
Sorry,I have not worked on it and tried this.
Not sure if you got a response to this but for anyone else looking for info on the API:
Try instead of:
ZenDeskApi.ZenDeskApi oZen = new ZenDeskApi.ZenDeskApi("https://waresolution.zendesk.com", "j#se.com", "87ggh76IO");
ZenDeskApi.ZenDeskApi oZen = new ZenDeskApi("https://waresolution.zendesk.com", "j#se.com", "87ggh76IO");
Also, to get a paginated list of 100 users instead of the group response, just call:
var zendeskUsers = oZen.Users.GetAllUsers().Users;

Categories

Resources