Over the last couple of years I've received a number of requests to allow
Unauthenticated/Guest Users to be able to sign records like internal users.
Unfortunately this isn't something that isn't possible for a security reviewed
package. In order to be able to save a File/Attachment against a record, the
user must have Edit access to the record, and since the Spring '21 release of
Salesforce Guest Users can't have Edit access. The Experience Cloud Developer
Guide has a
handy workaround of executing in system context and without sharing. but if I change the BrightSIGN code to work this way it will fail the
security review, and rightly so - I'd be ignoring the security settings of the
org and allowing an unauthenticated user to carry out actions that should be
blocked.
While I can't publish a package that allows a Guest User to execute code in
system context without sharing, there's nothing to stop the owner of the org
adding this capability after installing the package. So in version 4.1 of
BrightSIGN, Guest Users can capture a signature as a File. There's a caveat to
this though - as I can't associate the File with a record, it will be
"orphaned".
Full details of how to configure BrightSIGN to allow Guest User access are
available in the Implementation Guide for V4, but the upshot is rather than the file detail having the following
sharing :
It just has the sharing for the Owner:
The admin can then create an Apex trigger on ContentVersion and take
appropriate action. This is a bit tricky though, as they'll need to find a way
to tie the ContentVersion back to the specific record. The other option is a
second component to handle the Signature Captured Event -
there's an example of using this to update a record when a signature is
captured, and this can easily be tweaked to insert a ContentDocumentLink record to
associate the File with the target record.
It's been a while since I've had the time to work on the BrightSIGN (formerly
known as Signature Capture), but I had a couple of days off this week and what
better way to spend them than a bit of front end coding.
The Problem
A feature requested by a user posting a review on the app exchange was the
ability to update a field on the record that the signature image is attached
to. There are a number of ways to achieve this, but one thing was for sure -
this wasn't going into the package. Dynamically generating update statements
to change records in the subscriber org is the kind of thing that really slows
down the security review!
The scenario I wanted to satisfy was a Lightning App Builder page that would
show a BrightSIGN component, and once the user had saved the signature image,
update the record and hide the BrightSIGN component so they weren't asked to
sign multiple times.
I was originally thinking that I'd go the route of a trigger on
Attachment/ContentDocument, depending on how the component was configured, but
I decided against this for a couple of reasons -
I'd have to make some assumptions about the name of the attachment/content
document in order to determine that it had been created by BrightSIGN, which
would lead to false positives if attachments/documents with the same name
were used elsewhere
I'd be detached from the front end and unable to signal to the container
that the record had been updated - this is key when I want to conditionally
render parts of the page depending on whether the record has been 'signed'
or not.
The Solution
I ended up writing very little code to satisfy this requirement, as I was able
to leverage the existing SignatureCaptured event and the force:recordData
standard component. In the example scenario I'm setting a field with the
API name 'Signature_Captured__c' on an Account record once the user has
'signed' it.
To start with, I created a Lightning App Builder record page for Accounts,
which I dropped a BrightSIGN component onto. This component is conditionally
rendered and only appears if the Signature_Captured__c checkbox is not set :
I then created a new local component - SigCapUpdateRecord - which retrieves
the field that I'm interested in for the current record using the
force:recordData component, thus saving me writing any Apex code :
Thus when the user saves the signature image, the handleCaptured method from
my component's controller is invoked. This sets the Signature_Captured__c
field and updates the record using the force:recordData component, again
avoiding me having to write any Apex code. Once the update is complete, the
view is refreshed to notify the container that it's changed and allow any
conditional rendering to be re-evaluated:
handleCaptured : function(component, event, helper)
{
component.get('v.theRecordFields').Signature_Captured__c=true;
component.find("recordUpdater").saveRecord(function(saveResult) {
var resultsToast = $A.get("e.force:showToast");
if (saveResult.state === "SUCCESS" || saveResult.state === "DRAFT") {
resultsToast.setParams({
"type":"success",
"title": "Record Signed",
"message": "The record whas been marked as signed."
});
resultsToast.fire();
$A.get("e.force:refreshView").fire();
}
// error handling
});
}
You can see a very brief video of this below :
The Code
You can find the code in the
BrightSIGN Samples repository - look for the SigCapUpdateRecord component. Note that you will need to
either deploy the samples or manually create a Signature_Captured__c field on
the Account sObject in order to try this out.