Chatter Api Access to create Feed via Platform Trigger - salesforce

I am trying to Create A chatter feed using Chatter API(As I need mention user in the post) from A platform event trigger.
But I am getting an error:- "Insufficient Privileges: The Connect API is not enabled for this user type." in Debug Logs
and the user that's shown on debug log is Automated Process and not the Authenticated user creating a post request.
So my question is Do I need to Authenticate to Chatter API inside the trigger? If yes How I can do that.
Or am I missing any chatter Configuration?
Trigger Code
trigger SampleEventsTrigger on Sample_Events__e (after insert) {
System.debug('Event Log');
for (Sample_Events__e event : Trigger.New) {
System.debug('Event: ' + event);
//postFeedForSmartwinnr.PostFeedMethod(event.CreatedById, event.userId__c, event.Notification_message__c); // Call function to Create Chatter
ConnectApi.FeedItemInput feedItemInput = new ConnectApi.FeedItemInput();
ConnectApi.MentionSegmentInput mentionSegmentInput = new ConnectApi.MentionSegmentInput();
ConnectApi.MessageBodyInput messageBodyInput = new ConnectApi.MessageBodyInput();
ConnectApi.TextSegmentInput textSegmentInput = new ConnectApi.TextSegmentInput();
System.debug('feedItemInput: ' );
System.debug(feedItemInput);
messageBodyInput.messageSegments = new List<ConnectApi.MessageSegmentInput>();
mentionSegmentInput.id = event.userId__c;
messageBodyInput.messageSegments.add(mentionSegmentInput);
textSegmentInput.text = event.Notification_message__c;
messageBodyInput.messageSegments.add(textSegmentInput);
System.debug(feedItemInput);
feedItemInput.body = messageBodyInput;
feedItemInput.feedElementType = ConnectApi.FeedElementType.FeedItem;
//feedItemInput.subjectId = '0F9RR0000004CPw';
System.debug(feedItemInput);
ConnectApi.FeedElement feedElement = ConnectApi.ChatterFeeds.postFeedElement( Network.getNetworkId(), feedItemInput); // Error is on this line
System.debug('feedElement');
System.debug(feedElement);
}
}
Thanks in Advance...

As per my knowledge, the user present at that point is Automated Process who is able to post feed using class but, don't have access to chatter REST API

Related

Detecting on the browser when user switches Phantom wallet accounts

So I have a react app with nextjs where I'd need to get an event trigger when the user uses the Phantom wallet extension and switches accounts. I cannot find anything relevant on their docs: https://docs.phantom.app/
I was wondering if anyone encounter this issue. Basically I have the window.solana object but it does not have a trigger for when the user siwtches accounts
So Phantom itself does not expose any account switching specific API on their window.solana object.
There are some tricks you can do to find out when the account switches though.
You can continuously poll for the currently connected account and set the publicKey to some variable. When the publicKey changes, you can trigger your event.
Example psuedocode:
let currentKey = '';
poll(() => {
if (/* wallet available and connected */) {
await /* Action that updates publicKey */
if (currentKey !== wallet.publicKey.toBase58()) {
currentKey = wallet.publicKey.toBase58();
this.publicKey = wallet.publicKey;
this.emit('change')
}
}
})
You can find a writeup and PR we currently have on wallet-adapter going over this flow here
Phantom now emits accountChanged event: https://docs.phantom.app/integrating/extension-and-in-app-browser-web-apps/establishing-a-connection#changing-accounts

How to update NetSuite through Salesforce?

How would you go about updating NetSuite through Salesforce.
I know that you would use NetSuite's RESTlet and Salesforce Apex code to connect the two, but how would you actually go about doing this in a step by step process?
To send data from Salesforce to NetSuite (specifically customer/account data) you will need to do some preliminary setup in both.
In NetSuite:
Create a RESTlet Script that has at the bare minimum a get and post.
For instance I would create a javascript file on my desktop that contains:
/**
*#NApiVersion 2.x
*#NScriptType restlet
*/
//Use: Update NS customer with data (context) that is passed from SF
define(['N/record'], function(record) //use the record module
{
function postData(context)
{
//load the customer I'm gonna update
var cust = record.load({type:context.recordtype, id:context.id});
log.debug("postData","loaded the customer with NSID: " + context.id);
//set some body fields
cust.setValue("companyname", context.name);
cust.setValue("entityid", context.name + " (US LLC)");
cust.setValue("custentity12", context.formerName);
cust.setValue("phone",context.phone);
cust.setValue("fax",context.fax);
//remove all addresses
while(cust.getLineCount('addressbook') != 0)
cust.removeLine('addressbook',0);
//add default billing address
cust.insertLine('addressbook',0);
cust.setSublistValue('addressbook','defaultbilling',0,true);
cust.setSublistValue('addressbook','label',0,'BILL_TO');
var billingAddress=cust.getSublistSubrecord('addressbook','addressbookaddress',0);
billingAddress.setValue('country',context.billingCountry);
billingAddress.setValue('addr1', context.billingStreet);
billingAddress.setValue('city',context.billingCity);
billingAddress.setValue('state',context.billingState);
billingAddress.setValue('zip',context.billingZip);
//add default shipping address
cust.insertLine('addressbook',0);
cust.setSublistValue('addressbook','defaultshipping',0,true);
cust.setSublistValue('addressbook','label',0,'SHIP_TO');
var shippingAddress=cust.getSublistSubrecord('addressbook','addressbookaddress',0);
shippingAddress.setValue('country',context.shippingCountry);
shippingAddress.setValue('addr1',context.shippingStreet);
shippingAddress.setValue('city',context.shippingCity);
shippingAddress.setValue('state',context.shippingState);
shippingAddress.setValue('zip',context.shippingZip);
//save the record
var NSID = cust.save();
log.debug("postData","saved the record with NSID: " + NSID);
return NSID; //success return the ID to SF
}
//get and post both required, otherwise it doesn't work
return {
get : function (){return "get works";},
post : postData //this is where the sauce happens
};
});
After You've saved this file, go to NetSuite>Customization>Scripting>Scripts>New.
Select the new file that you've saved and create the script record. Your script record in NetSuite should have GET and POST checked under scripts.
Next, click deploy script and choose who will call this script, specifically the user that will login on the salesforce end into NetSuite.
On the deployment page you will need the External URL it goes something like:
https://1234567.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=123&deploy=1
Note: If any data that you are updating is critical for a process, I would highly recommond creating this in the sandbox first for testing, before moving to production.
In Salesforce sandbox:
Click YourName>Developer Console
In the developer console click File>New and create an Apex Class:
global class NetSuiteWebServiceCallout
{
#future (callout=true) //allow restlet callouts to run asynchronously
public static void UpdateNSCustomer(String body)
{
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndPoint('https://1234567.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=123&deploy=1'); //external URL
request.setMethod('POST');
request.setHeader('Authorization', 'NLAuth nlauth_account=1234567, nlauth_email=login#login.com, nlauth_signature=password'); //login to netsuite, this person must be included in the NS restlet deployment
request.setHeader('Content-Type','application/json');
request.setBody(body);
HttpResponse response = http.send(request);
System.debug(response);
System.debug(response.getBody());
}
}
You will have to set the endpoint here to the external url, the authorization nlauth_account=[your netsuite account number], and the header to your login email and password to a person who is on the deployment of the NS script, the body will be set in the trigger that calls this class.
Next create the trigger that will call this class. I made this script run every time I update the account in Salesforce.
trigger UpdateNSCustomer on Account (after update)
{
for(Account a: Trigger.new)
{
String data = ''; //what to send to NS
data = data + '{"recordtype":"customer","id":"'+a.Netsuite_Internal_ID__c+'","name":"'+a.Name+'","accountCode":"'+a.AccountCode__c+'",';
data = data + '"formerName":"'+a.Former_Company_Names__c+'","phone":"'+a.Phone+'","fax":"'+a.Fax+'","billingStreet":"'+a.Billing_Street__c+'",';
data = data + '"billingCity":"'+a.Billing_City__c+'","billingState":"'+a.Billing_State_Province__c+'","billingZip":"'+a.Billing_Zip_Postal_Code__c+'",';
data = data + '"billingCountry":"'+a.Billing_Country__c+'","shippingStreet":"'+a.Shipping_Street__c+'","shippingCity":"'+a.Shipping_City__c+'",';
data = data + '"shippingState":"'+a.Shipping_State_Province__c+'","shippingZip":"'+a.Shipping_Zip_Postal_Code__c+'","shippingCountry":"'+a.Shipping_Country__c+'"}';
data = data.replaceAll('null','').replaceAll('\n',',').replace('\r','');
System.debug(data);
NetSuiteWebServiceCallout.UpdateNSCustomer(data); //call restlet
}
}
In this script data is the body that you are sending to NetSuite.
Additionally, you will have to create an authorized endpoint for NetSuite in your remote site setings in salesforce (sandbox and production). Go to setup, and quickfind remote site settings which will be under security controls.
Create a new Remote site that has its remote site URL set to the first half of your external url: https://1234567.restlets.api.netsuite.com.
From here, do some testing in the sandbox.
If all looks well deploy the class and trigger to salesforce production.

EWS API calendar - Impersonating to update raise an error "Access is denied. Check credentials and try again."

I am new to using EWS managed APIs.
Following is the issue I am facing with EWS APIs:
EWS API - Impersonating to update a calendar item created by any other user than a service account, raise an error "Access is denied. Check credentials and try again."
Details:
1. I am using a service account e.g. abc#xyz.onmicrosoft.com. This user is a global administrator and also has ApplicationImpersonation role assigned. (Sign into Online Office 365 account -> Admin -> select "Exchange" tab- > select Permissions on the left panel -> create an impersonation role -> assign ApplicationImpersonation in Roles: and abc#xyz.onmicrosoft.com in Members: -> Click on save)
Create a calendar item by other user for e.g. pqr#xyz.onmicrosoft.com, and invite an attendee - abc#xyz.onmicrosoft.com.
In a c# program, I connect to EWS service using a service account - abc#xyz.onmicrosoft.com, fetch its calendar events. If organizer of an event is some other user - pqr#xyz.onmicrosoft.com then I use impersonation in the following way to update the calendar event/item properties- subject, body text etc.
private static void Impersonate(string organizer)
{
string impersonatedUserSMTPAddress = organizer;
ImpersonatedUserId impersonatedUserId =
new ImpersonatedUserId(ConnectingIdType.SmtpAddress, impersonatedUserSMTPAddress);
service.ImpersonatedUserId = impersonatedUserId;
}
It was working fine till yesterday afternoon. Suddenly, it started throwing an exception "Access is denied. Check credentials and try again." Whenever I try to update that event.
private static void FindAndUpdate(ExchangeService service)
{
CalendarView cv = new CalendarView(DateTime.Now, DateTime.Now.AddDays(30));
cv.MaxItemsReturned = 25;
try
{
FindItemsResults masterResults = service.FindItems(WellKnownFolderName.Calendar, cv);
foreach (Appointment item in masterResults.Items)
{
if (item is Appointment)
{
Appointment masterItem = item as Appointment;
if (!masterRecurEventIDs.Contains(masterItem.ICalUid.ToString()))
{
masterItem.Load();
if (!masterItem.Subject.Contains(" (Updated content)"))
{
//impersonate organizer to update and save for further use
Impersonate(masterItem.Organizer.Address.ToString());
// Update the subject and body
masterItem.Subject = masterItem.Subject + " (Updated content)";
string currentBodyType = masterItem.Body.BodyType.ToString();
masterItem.Body = masterItem.Body.Text + "\nUpdated Body Info: xxxxxxxxxxxx";
// This results in an UpdateItem operation call to EWS.
masterItem.Update(ConflictResolutionMode.AutoResolve);
// Send updated notification to organizer of an appointment
CreateAndSendEmail(masterItem.Organizer.Address.ToString(), masterItem.Subject);
masterRecurEventIDs.Add(masterItem.ICalUid.ToString());
}
else
{
Console.WriteLine("Event is already updated. No need to update again.:\r\n");
Console.WriteLine("Subject: " + masterItem.Subject);
Console.WriteLine("Description: " + masterItem.Body.Text);
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
What could be an issue here? Initially I thought may be its a throttling policy which is stopping same user after making certain API call limits for the day, but I am still seeing this issue today.
Any help is appreciated.
Thanks
Found the solution:
Only adding impersonated ID to the existing service instance doesn't work. You also need to re-validate the auto-discover url.
I was investigating an Impersonation + Calendar issue, and found this forum post.
I am sure your problem lies in the way you are trying to get and then update the calendar item (appointment).
You are getting the calendar item using a credentials (mailbox A). Then later on, on following line
Impersonate(masterItem.Organizer.Address.ToString());
you are instructing the Ews Service object to work as the Impersonated Identity (credentials of Mailbox B).
Since you already had grabbed the appointment from Mailbox A, and now trying to update that appointment in Mailbox A, using the credentials of Mailbox B, that should not work IMHO if Mailbox B doesn't have permission on Mailbox A calendar.
So here, actually, you are trying to update the calendar item of Mailbox A, using the impersonated credentials of Mailbox B, and as Mailbox B doesn't have permission on Mailbox A credentials, so the Access Denied error is occurring.
Hope this help someone else too.
Thanks

How to get notify for new message using TweetSharp ListDirectMessageReceived() method?

I am using TweetSharp for making a small demo desktop application for twitter and I am using the below code for getting all the messages of a login user:-
TwitterService service = new TwitterService("ConsumerKey", "ConsumerSecretKey");
// Step 1 - Retrieve an OAuth Request Token
OAuthRequestToken requestToken = service.GetRequestToken();
// Step 2 - Redirect to the OAuth Authorization URL
Uri uri = service.GetAuthorizationUri(requestToken);
Process.Start(uri.ToString());
// Step 3 - Exchange the Request Token for an Access Token
Console.Write("Enter Pin:: ");
string verifier = Console.ReadLine(); // <-- This is input into your application by your user
OAuthAccessToken access = service.GetAccessToken(requestToken, verifier);
// Step 4 - User authenticates using the Access Token
service.AuthenticateWith(access.Token, access.TokenSecret);
string message = null;
List<string> messages = new List<string>();
IEnumerable<TwitterDirectMessage> directMessages = service.ListDirectMessagesReceived(new ListDirectMessagesReceivedOptions());
//Fetch all current direct message:
foreach (TwitterDirectMessage directMessage in directMessages)
{
//Write All Messages in Console
Console.WriteLine(directMessage.Text);
}
Above foreach loop will show all the messages but my problem is that when any other user send me new message then how can notifying me for new message.
Please help me!
Any Help Appreciated!
Thanx!
This TweetSharp code defines the library methods.

Has anyone created a DNN 7 user with the services framework?

I'm trying to create a user with the DNN 7 services framework. I've taken my working code from my custom registration module and modified to work within a DNN webapi function.
When I get to the UserController.CreateUser call in the code below I receive a
"\"There was an error generating the XML document.\""
exception. My user makes it into the aspnet_Users table and the DNN users table but does not make it into the DNN userportals table. Any ideas would be appreciated.
private void CreateUser()
{
//Update DisplayName to conform to Format
UpdateDisplayName();
User.Membership.Approved = PortalSettings.UserRegistration == (int)Globals.PortalRegistrationType.PublicRegistration;
var user = User;
CreateStatus = UserController.CreateUser(ref user);
I finally found the issue. I was not setting the portal ID for my new users and DNN was excepting out when it was adding them to a portal. All it took was User.PortalId = 0 before the CreateUser call.
I have found by trial and error that the minimum needed to create a viable DNN user is:
UserInfo uiNewUser = new UserInfo();
uiNewUser.Username = "<myUsername>";
uiNewUser.Displayname = "<myDisplayname>";
uiNewUser.Email = "<myUserEmail>";
UserMembership newMembership = new UserMembership(uiNewUser);
newMembership.Password = "<myUserPassword>";
uiNewUser.Membership = newMembership;
uiNewUser.PortalID = <myPortalID>;
DotNetNuke.Security.Membership.UserCreateStatus uStatus;
uStatus = DotNetNuke.Security.Membership.MembershipProvider.Instance().CreateUser(ref uiNewUser);
RoleInfo newRole = RoleController.Instance.GetRoleByName(uiNewUser.PortalID, "Registered Users");
RoleController.Instance.AddUserRole(uiNewUser.PortalID, uiNewUser.UserID, newRole.RoleID, (RoleStatus)1, false, DateTime.MinValue, DateTime.MaxValue);
If any of these are missed out, parts of the user are created in the database, but the user may not be visible in the Admin list of users, or an Exception may be generated. Other details can be added later.

Resources