#apexcode
Explore tagged Tumblr posts
proskillshub · 10 days ago
Text
Tumblr media
Get introduced to Apex, Salesforce’s proprietary programming language. Understand its capabilities in customizing applications and automating processes, and examine simple code snippets demonstrating Apex functionalities. #Apex
ApexDevelopment
SalesforceApex
ApexProgramming
ApexCode
ApexTrailhead
SalesforceDevelopment
ApexProgrammingLanguage
CloudDevelopment
ApexDevelopers #ProSkillsHub
0 notes
cssmonster · 1 year ago
Text
Explore 35+ CSS Login Forms
Tumblr media
In the dynamic realm of online interactions, the login form serves as the gateway to user engagement, making its design crucial for leaving a lasting impression. At CSS Monster, we recognize the significance of an effective and visually appealing login form on your website or application. To empower your digital journey, we've meticulously curated a collection of over 35 stylish and highly functional CSS login forms sourced from esteemed platforms like CodePen, GitHub, and other reputable resources. As we embrace the future of web design, our latest update in June 2023 introduces eight new items to our collection. Each addition is a testament to our commitment to continually elevate your website's user experience and streamline the login process. In a landscape where digital interactions reign supreme, the importance of a well-designed login form cannot be overstated. It serves as the initial point of contact between users and your platform, influencing their decision to engage or move on. A user-friendly login form must embody qualities of intuitiveness, responsiveness, and visual appeal, while upholding the paramount principles of security. Within this collection, we invite you to explore a showcase of the finest pure CSS login forms available for free on the web. Each entry not only captivates with its visual aesthetics but is also meticulously crafted with functionality and user experience at the forefront. From imaginative animations to thoughtful error handling, these login forms offer a spectrum of features and benefits that redefine the login experience. Embark on a journey through our collection, experiment with the diverse designs, and witness your login forms ascend to new heights. Your users will undoubtedly appreciate the seamless and visually engaging login experience you create. Dive into the world of CSS login forms at CSS Monster—where every login is an invitation to an exceptional user experience. Happy coding!
Tumblr media
Author ApexCoder June 10, 2023 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML / CSS About a code HACKER LOGIN FORM Compatible browsers:Chrome, Edge, Firefox, Opera, Safari Responsive:no Dependencies:-
Tumblr media
Author Sowjanya October 28, 2021 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML (Pug) / CSS (SCSS) About a code FINANCE MOBILE APPLICATION-UX/UI DESIGN SCREEN ONE Compatible browsers:Chrome, Edge, Firefox, Opera, Safari Responsive:no Dependencies:ionicons.js
Tumblr media
Author Mohithpoojary September 21, 2021 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML / CSS About a code LOGIN FORM Compatible browsers:Chrome, Edge, Firefox, Opera, Safari Responsive:no Dependencies:font-awesome.css
Tumblr media
Author Foolish Developer September 13, 2021 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML / CSS About a code GLASSMORPHISM LOGIN FORM Compatible browsers:Chrome, Edge, Firefox, Opera, Safari Responsive:no Dependencies:font-awesome.css Author slimen mami September 13, 2021 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML / CSS About a code SIGN UP / LOGIN FORM Compatible browsers:Chrome, Edge, Firefox, Opera, Safari Responsive:yes Dependencies:-
Tumblr media
Author Rok Krivec April 2, 2021 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML / CSS About a code CREATIVE AND CUSTOMIZABLE REGISTRATION FORM Compatible browsers:Chrome, Edge, Firefox, Opera, Safari Responsive:yes Dependencies:material-design-iconic-font.css
Tumblr media
Author Rok Krivec April 1, 2021 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML / CSS About a code ECOMMERCE REGISTRAION FORM Compatible browsers:Chrome, Edge, Firefox, Opera, Safari Responsive:yes Dependencies:material-design-iconic-font.css
Tumblr media
Author Rok Krivec April 1, 2021 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML / CSS About a code REGISTRATION FORM #18 Compatible browsers:Chrome, Edge, Firefox, Opera, Safari Responsive:yes Dependencies:material-design-iconic-font.css
Tumblr media
Author Rok Krivec April 1, 2021 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML / CSS About a code SIGN UP FORM #26 Compatible browsers:Chrome, Edge, Firefox, Opera, Safari Responsive:yes Dependencies:-
Tumblr media
Author Rok Krivec April 1, 2021 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML / CSS About a code SIGN UP FORM #7 Compatible browsers:Chrome, Edge, Firefox, Opera, Safari Responsive:yes Dependencies:material-design-iconic-font.css
Tumblr media
Author HiCoders January 25, 2021 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML / CSS About a code GLASSMORPHISM LOGIN FORM Compatible browsers:Chrome, Edge, Firefox, Opera, Safari Responsive:no Dependencies:- Author Larissa Rabello April 22, 2019 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML / CSS About a code SIGN UP MODAL Compatible browsers:Chrome, Edge, Firefox, Opera, Safari Responsive:no Dependencies:bootstrap.css, jquery.js, bootstrap.js, popper.js Author Florin Pop March 4, 2019 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML / CSS / JS About a code DOUBLE SLIDER SIGN IN/UP FORM Compatible browsers:Chrome, Edge, Firefox, Opera, Safari Responsive:no Dependencies:font-awesome.css Author Tony Banik October 24, 2018 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML (Pug) / CSS (SCSS) About a code LOGIN FORM Compatible browsers:Chrome, Edge, Firefox, Opera, Safari Responsive:no Dependencies:- Author bertdida October 17, 2018 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML / CSS (SCSS) About a code SIMPLE REGISTRATION FORM Compatible browsers:Chrome, Firefox, Opera, Safari Responsive:no Dependencies:- Author Mert Cukuren October 1, 2018 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML / CSS (SCSS) / JS (Babel) About a code LOGIN MODAL FORM Compatible browsers:Chrome, Edge, Firefox, Opera, Safari Responsive:yes Dependencies:-
Tumblr media
Author Marko October 3, 2018 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML (Haml) / CSS (SCSS) About a code CUBE LOGIN FORM Compatible browsers:Chrome, Edge, Firefox, Opera, Safari Dependencies:-
Tumblr media
Author Pablo Eugenio Lujambio Martinez May 23, 2018 Links Just Get The Demo Link How To Download - Article How To Download - Video Made with HTML / CSS (SCSS) Read the full article
0 notes
kids-worldfun · 2 years ago
Photo
Tumblr media
Using Custom Settings in Salesforce. Salesforce provides a powerful set of tools for managing your data and settings. This article describes how to create and use custom settings. 
0 notes
emizentechblog · 4 years ago
Photo
Tumblr media
Want to know how to avoid recursive triggers in apex code in Salesforce? If so, read this blog, and learn how to avoid the recursive triggers in apex code.
0 notes
Photo
Tumblr media
... - Fortnite Battle Royale V-Bucks free - Fortnite V-Bucks generator (on Wattpad) https://my.w.tt/e1cnyocF31
0 notes
salesforcecodex · 3 years ago
Link
2 notes · View notes
tak4hir0 · 5 years ago
Link
This document provides a testing solution for the Apex Continuations implemented in a static-context (commonly used in Aura and Lightning Web Components). All the source code displayed below is also available in this repository Please, note that this is not an official Salesforce solution but just a custom workaround What is an Apex continuation? Apex Continuations are a mechanism provided by the Salesforce platform that allow you to make asynchronously, long-running requests to an external Web Service. The service supports callouts to a SOAP or REST Web Service, with a maximum timeout of 120 seconds (versus 10 seconds in a standard synchronous callout). To give a more visual description of this concept, look at the diagram below: (1) A user invokes an action that requests some information from a Web Service (2 – 3) The app server sends the request to the Continuation Server and returns to the client-side, creating then an asynchronous situation / context (4 – 5) From the Continuation Server, a request is sent to the external Web Service (6 – 7) The Web Service processes a response that is sent back to the Continuation Server (8) This response is processed back to the App Server (9) And finally, sent back to the client-side to be displayed to the user To get into technical details of implementation, this is possible thanks to the definition of two different functions: The first one is responsible of creating, initializing and firing the Continuation (in the code examples of this document defined as startConinuation() function. It can receive parameters from the component) The second one is the callback: once the response has been processed and returned, we might want to work with the received data before displaying it to the user or to handle undesired exceptions from the External Service (in the code examples of this document this is defined as continuationCallback() function Why Apex continuations? So probably at this point, you are asking yourself: what’s the point of using these long-running asynchronous callouts, called Continuations, versus other asynchronous alternatives like for example, Queueable jobs? Well, you could use a Queueable job to perform a callout that will be executed asynchronously in the future, but you will lose the context of the execution. Even if you get the jobId, your component won’t have a callback to be executed once the job has finished. The Queueable jobs fit better in situations where the user don’t need to wait to see the results of the callout. Implementing + testing Apex continuations If you have already gone through the Salesforce Developer documentation, you might have seen that the implementation of Apex Continuation is not something new. Even more, there are already different official guides (very well explained), so let’s not reinvent the wheel! You can find below the official documentation for each context: Apex Continuation + Visualforce (Implementation + Testing) → Non-static methods Apex Continuation.+ Aura Components (Only implementation) → Static methods Apex Continuation + Lightning Web Components (Only implementation) → Static methods What’s the main difference between these three points above? The implementation in Visualforce Pages is done by using non-static methods (instances), while for Aura and LWC, the Continuations are executed from static methods (required when using the @AuraEnabled annotation). Apex Continuations were developed to be used through instances: making it possible to maintain individual references in an asynchronous context. When it comes to testing, the Test class implements a method invokeContinuationMethod(Object controller, Continuation request) that allows you to synchronously test your Apex Continuation by invoking the callback method for the specified controller. The first parameter of this function expects an instance of the controller class that implements the continuation and the second one is the continuation object that is returned by an action method in the controller class. When calling an Apex function from a LWC or an Aura Component, the Apex method must include the @AuraEnabled annotation and all the @AuraEnabled methods should always be static. When combined with the previous points… we can see that there is a problem: @AuraEnabled methods should always be static For Aura and LWC: our Continuation method will be a static function called from the component (because it will be implemented with the @AuraEnabled annotation). The Test.invokeContinuationMethod(controller, request) function is expecting an instance of the controller (non-static), but our class will be static with static methods PROBLEM: it is not possible to test the Apex Continuation implemented in a static context Another reason why this is not possible is because, in a testing context, all of the normally asynchronous functionality is executed synchronously (we don’t want to wait an undefined time to finish running our tests) and we don’t have stored anywhere a reference to the Continuation that was fired. SOLUTION: Nothing to worry about! I found a workaround to test the Apex Continuations by just implementing @TestVisible variables that will store relevant information to be used from the test methods, and replacing the Test.invokeContinuationMethod directly by your callback function. Also, as you might know, there are multiple ways to work with Apex Continuations: from one to multiple callouts within the same Continuation, to different implementations of the callback function. Here, the list of the examples is given below: Simple Continuation: one HttpCallout and callback(Object state) function Simple Continuation: one HttpCallout and labels, Object state) function Multiple Continuation: two HttpCallouts and labels, Object state) function   Simple Apex continuation Only one Http callout One parameter in the callback: callback(Object state). There IS NO data being passed from the function that fired the continuation to the callback function ApexContinuation.cls '; // The function to be called to fire the continuation @AuraEnabled(continuation=true cacheable=true) public static Object startConinuation(){ // Create the callout Request HttpRequest req = new HttpRequest(); req.setMethod('GET'); req.setEndpoint(HTTP_REQUEST_ENDPOINT); // Create the continuation Continuation con = new Continuation(CONTINUATION_TIMEOUT_IN_SECONDS); con.ContinuationMethod = 'continuationCallback'; continuationState = con.addHttpRequest(req); // Store the HttRequest and make it accessible for a testing-context con.state = continuationState; return con; } // The function that will process the callback of the Continuation = 2000){ // Error codes available in: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_class_System_Continuation.htm // Continuation error throw new AuraHandledException('Continuation Error: ' + statusCode + ' - ' + response.getBody() ); }else{ // Http Request error throw new AuraHandledException('HTTP Request Error: ' + statusCode + ' - ' + response.getBody() ); } } } ApexContinuation_Test.cls @IsTest private class ApexContinuation_Test { // Case 1: Valid HttpRequest using a Continuation @IsTest private static void testApexContinuation(){ String mockResponseBody = 'TestBodyResponse'; Test.startTest(); requests = con.getRequests(); System.assertEquals(1, requests.size(), 'The number of requests associated to the Continuation is not correct'); // Create a mock response HttpResponse response = new HttpResponse(); response.setStatusCode(200); response.setBody(mockResponseBody); // Assign the Mock response to the variable created for testing - for keeping the reference to the correct Continuation Test.setContinuationResponse(ApexContinuation.continuationState, response); String result = (String)ApexContinuation.continuationCallback(ApexContinuation.continuationState); Test.stopTest(); System.assertEquals(mockResponseBody, result, 'Continuation failed: response body not valid'); } // Case 2: Exception caused by a problem with the continuation requests = con.getRequests(); System.assertEquals(1, requests.size(), 'The number of requests associated to the Continuation is not correct'); // Create a mock response HttpResponse response = new HttpResponse(); response.setStatusCode(2000); Test.setContinuationResponse(ApexContinuation.continuationState, response); Boolean exceptionThrown = false; try{ Object result = ApexContinuation.continuationCallback(ApexContinuation.continuationState); }catch(AuraHandledException e){ exceptionThrown = true; } Test.stopTest(); System.assertEquals(true, exceptionThrown, 'Failed to catch Continuation Exception'); } // Case 3: Exception caused by a bad Http Response requests = con.getRequests(); System.assertEquals(1, requests.size(), 'The number of requests associated to the Continuation is not correct'); // Create a mock response HttpResponse response = new HttpResponse(); response.setStatusCode(400); Test.setContinuationResponse(ApexContinuation.continuationState, response); Boolean exceptionThrown = false; try{ Object result = ApexContinuation.continuationCallback(ApexContinuation.continuationState); }catch(AuraHandledException e){ exceptionThrown = true; } Test.stopTest(); System.assertEquals(true, exceptionThrown, 'Failed to catch Http Request Exception'); } }   Simple Apex continuation, passing data to the callback function Only one Http callout Two parameters in the callback: labels, Object state) There is data being passed from the function initiating the Continuation to the callback function ApexSimpleContinuationPassingData.cls public with sharing class ApexSimpleContinuationPassingData { @TestVisible private static String continuationLabel; // IMPORTANT: Variable used for testing, containing a reference to the Continuation Request @TestVisible private static String continuationState; // IMPORTANT: Variable used for testing, containing the value of the Continuation.state attribute private final static Integer CONTINUATION_TIMEOUT_IN_SECONDS = 40; private final static String HTTP_REQUEST_ENDPOINT = 'callout:TestEndpoint'; // The function to be called to fire the continuation @AuraEnabled(continuation=true cacheable=true) public static Object startConinuation(){ // Create the callout Request HttpRequest req = new HttpRequest(); req.setMethod('GET'); req.setEndpoint(HTTP_REQUEST_ENDPOINT); // Create the continuation Continuation con = new Continuation(CONTINUATION_TIMEOUT_IN_SECONDS); con.ContinuationMethod = 'continuationCallback'; continuationLabel = con.addHttpRequest(req); // Store the reference to the HttRequest and make it accessible for a test-context continuationState = 'Some data here...'; // Store data to be sent to the callback function con.state = continuationState; return con; } // The function that will process the callback of the Continuation= 2000){ // Continuation error throw new AuraHandledException('Continuation Error: ' + statusCode + ' - ' + response.getBody() ); }else{ // Http Request error throw new AuraHandledException('HTTP Request Error: ' + statusCode + ' - ' + response.getBody() ); } } } ApexSimpleContinuationPassingData_Test.cls @IsTest private class ApexSimpleContinuationPassingData_Test { // Case 1: Valid HttpRequest using a Continuation{ApexSimpleContinuationPassingData.continuationLabel}; String result = (String)ApexSimpleContinuationPassingData.continuationCallback(labels, ApexSimpleContinuationPassingData.continuationState); System.assertEquals(true, result.contains(mockResponseBody), 'Continuation failed: response body not valid'); System.assertEquals(true, result.contains('Some data here...')); } // Case 2: Exception caused by a problem with the continuation{ApexSimpleContinuationPassingData.continuationLabel}; Boolean exceptionThrown = false; try{ String result = (String)ApexSimpleContinuationPassingData.continuationCallback(labels, ApexSimpleContinuationPassingData.continuationState); }catch(AuraHandledException e){ exceptionThrown = true; } System.assertEquals(true, exceptionThrown, 'Failed to catch Continuation Exception'); } // Case 3: Exception caused by a bad Http Response{ApexSimpleContinuationPassingData.continuationLabel}; Boolean exceptionThrown = false; try{ String result = (String)ApexSimpleContinuationPassingData.continuationCallback(labels, ApexSimpleContinuationPassingData.continuationState); }catch(AuraHandledException e){ exceptionThrown = true; } System.assertEquals(true, exceptionThrown, 'Failed to catch Http Request Exception'); } } Multiple Apex continuation Two Http callouts (or more) Two parameters in the callback: labels, Object state) There might be data being passed from the function initiating the Continuation to the callback function ApexMultipleContinuation.cls public with sharing class ApexMultipleContinuation { // IMPORTANT: Variables used for testing, containing the values of the Continuation.state requests @TestVisible private static String continuationLabel1; @TestVisible private static String continuationLabel2; private final static Integer CONTINUATION_TIMEOUT_IN_SECONDS = 40; private final static String HTTP_REQUEST_ENDPOINT = 'callout:TestEndpoint'; // The function to be called to fire the continuation @AuraEnabled(continuation=true cacheable=true) public static Object startConinuation(){ // Create the callout Request HttpRequest req1 = new HttpRequest(); req1.setMethod('GET'); req1.setEndpoint(HTTP_REQUEST_ENDPOINT + '/2'); HttpRequest req2 = new HttpRequest(); req2.setMethod('GET'); req2.setEndpoint(HTTP_REQUEST_ENDPOINT + '/5'); // Create the continuation Continuation con = new Continuation(CONTINUATION_TIMEOUT_IN_SECONDS); con.ContinuationMethod = 'continuationCallback'; continuationLabel1 = con.addHttpRequest(req1); continuationLabel2 = con.addHttpRequest(req2); return con; } // The function that will process the callback of the Continuation{response1.getBody(), response2.getBody()}; } } ApexMultipleContinuation_Test.cls @IsTest private class ApexMultipleContinuation_Test { // Case 1: Valid HttpRequest using a Continuation)ApexMultipleContinuation.continuationCallback(labels, null); System.assertEquals(mockResponseBody1, result.get(0), 'Continuation failed: response body not valid for request 1'); System.assertEquals(mockResponseBody2, result.get(1), 'Continuation failed: response body not valid for request 2'); } // Case 2: Exception caused by a problem with the continuation) ApexMultipleContinuation.continuationCallback(labels, null); } catch (AuraHandledException e) { exceptionThrown = true; } System.assertEquals(true, exceptionThrown, 'Failed to catch Continuation Exception'); } // Case 3: Exception caused by a bad Http Response) ApexMultipleContinuation.continuationCallback(labels, null); } catch (AuraHandledException e) { exceptionThrown = true; } System.assertEquals(true, exceptionThrown, 'Failed to catch Http Request Exception'); } } Running the examples above in a LWC Do you want to try the examples above in a LWC? Here is the code: apexContinuation.js import { LightningElement } from 'lwc'; import startContinuation from '@salesforce/apexContinuation/'; import { ShowToastEvent } from 'lightning/platformShowToastEvent'; export default class ApexContinuation extends LightningElement { result; isLoading = true; // NOTE: The Continuation will be imperatively called after the component // is rendered. In your specific case, you might want to call at another // point of your code { this.displayErrorToast(error.body.message); this.isLoading = false; }); } displayErrorToast(message) { const evt = new ShowToastEvent({ message: message, variant: 'error', }); this.dispatchEvent(evt); } } apexContinuation.html   Personal recommendations Finally, here are some tips and advice from what I have learned by implementing Apex Continuations: labels, Object state). This will help you have a standard development style in your code (and it is easier to work with the testing variables). When implementing Apex Continuations with multiple callouts, from my point of view, it’s better to create multiple @TestVisible variables (continuationLabelX) instead of a list in the Controller class. This will help you to really identify which label is referencing which request in the testing-context. Want to contribute or have suggestions to improve this workaround? Then don’t hesitate to reach out to me! About the author Víctor García Zarco is a Technical Consultant at Salesforce France. He has an IT Engineering and Business background, helps customers to implement Salesforce adapted to their needs and is an innovation and technology enthusiast. Check his GitHub projects @victorgz References Apex Developer Guide: Continuation Class Apex Developer Guide: Make Long-Running Callouts from a Visualforce Page Apex Developer Guide: Execution Governors and Limits Lightning Aura Components Developer Guide: @AuraEnabled Annotations for Continuations Lightning Web Components Developer Guide: Continuations
0 notes
tak4hir0 · 5 years ago
Link
Discover Spring ’20 Release features! We are sharing release highlights for Developers (and Admins), curated and published by Salesforce product experts, as part of Learn MOAR. Complete the trailmix by March 31, 2020 to receive a special community badge and unlock a $10 contribution to FIRST®. Controlling access to data based on user permissions is critical for any application. On Salesforce, you can control who sees what using Sharing rules, field and object permissions. However, it is important to note that Apex generally runs in system context, therefore the current user’s permissions, field-level security, and sharing rules aren’t taken into account during code execution, which can compromise the integrity of your data. Using the with sharing keywords when declaring a class enforces Sharing Rules, but not object and field-level permissions. Below are some ways in which you can enforce object-level and field-level permissions in Apex. Using the with sharing keywords when declaring a class enforces Sharing Rules, but not object and field-level permissions. Below are some ways in which you can enforce object-level and field-level permissions in Apex. Using Schema Methods This way of determining field level access has been around for quite sometime now. You can call the isAccessible, isCreateable, or isUpdateable methods of Schema.DescribeFieldResult to verify whether the current user has read, create, or update access for a field. For example, if you want to check if the Email field on the Contact Object is accessible/readable by the logged in user, you enclose the SOQL query inside an if block that checks for field access using the Schema methods described above. if (Schema.sObjectType.Contact.fields.Email.isAccessible()) { Contact c = [SELECT Email FROM Contact WHERE Id= :Id]; } Imagine that you have a bunch of fields in your query, and you have inner queries. This if statement becomes complex to maintain, and increases the cyclomatic complexity of the code. Using WITH SECURITY_ENFORCED clause (Generally Available) Generally Available starting Spring ‘20, the WITH SECURITY_ENFORCED clause can be used in SOQL queries to enforce field and object level security permissions in Apex code, including subqueries and cross-object relationships. Field-level permissions are checked for all the fields that are retrieved in the SELECT clause(s) of the query. Since this clause only works inside an SOQL query, it’s only useful when you want to check for read access on a field. Here is an example: act1 = [SELECT Id, Name, (SELECT LastName FROM Contacts) FROM Account WHERE Name like 'Acme' WITH SECURITY_ENFORCED]; } catch(System.QueryException){ //TODO: Handle Errors } The above query will return the Id and Name of Accounts, and the LastName of the related contacts, only if the user has read access to all of these three fields. If the user doesn’t have access to at least one of these fields, the query throws a System.QueryException exception, and no results are returned. As a best practice, SOQL queries that use this clause, have to be enclosed in a try/catch block, so that errors can be gracefully handled. However, it is important to note that this clause doesn’t verify field-level security for fields used in the WHERE clause of the query. For example, if a user doesn’t have access a custom field called Picture_URL__c on the Contact object, the below query doesn’t throw an error, and the results are returned as usual. contacts = [SELECT Id, Name, BirthDate FROM Contact WHERE Picture_URL__c != null WITH SECURITY_ENFORCED]; Using stripInaccessible Method (Generally Available) Generally Available starting Spring ‘20, you can now use the stripInaccessible method from the new Security class to enforce field and object level security in Apex. Like the name suggests, this method can be used to strip the fields from sObject lists to which the user doesn’t have appropriate access, depending on the operation being performed. Here is the method signature: sourceRecords, [Boolean enforceRootObjectCRUD]) accessCheckType: This parameter defines the type of field-level access check to be performed. It accepts System.AccessType enum values: CREATABLE, READABLE, UPDATABLE, UPSERTABLE. sourceRecords: A list of sObjects to be checked for fields that aren’t accessible in the context of the current user’s operation. enforceRootObjectCRUD: An optional parameter that indicates whether object-level access check has to be performed. If set to true, and the user doesn’t have the necessary CRUD permissions on the object, this method throws an exception. It defaults to true. This method returns an object of type SObjectAccessDecision. You use the getRecords() method to access the list of sObjects which are stripped of fields that fail the field-level security checks for the current user. For error handling purposes, you can use the getRemovedFields() method to access a map of sObject types and their corresponding inaccessible fields. Here is an example of a DML operation, where the current user doesn’t have access to a custom field Picture_URL__c on the Contact Object: { new Contact(FirstName='Jane', LastName='Doe', Picture_URL__c='someurl'), new Contact(FirstName='John', LastName='Doe', Picture_URL__c='someurl'), }; // Strip fields that are not creatable SObjectAccessDecision decision = Security.stripInaccessible( AccessType.CREATABLE, contacts); //DML try{ insert decision.getRecords(); }catch(NoAccessException e){ //TODO: Handle Error if the user lacks create permission on the Object } // OPTIONAL: Print removed fields System.debug(decision.getRemovedFields()); The DML operation written above runs successfully without exceptions, but the Picture URL field on the inserted records would be blank because the current user doesn’t have appropriate permissions on it, therefore the value has been stripped off. However, if the user lacked the create permission on the Contact object itself, the DML statement would throw an exception. Here is another example of the method’s usage in a query operation, where the current user doesn’t have access to a custom field Picture_URL__c on the Contact Object. Security.SObjectAccessDecision securityDecision = Security.stripInaccessible( AccessType.READABLE, [SELECT Name, Picture_URL__c from Contact]; ); for (Contact c : securityDecision.getRecords()) { system.debug(c.Name); //Prints: Jane, John system.debug(c.Picture_URL__c); //Prints: null, null } Inaccessible fields are removed from the query result, therefore those fields would return a NULL value. If you are using the stripInaccessible method on a list of sObject records that have already been retrieved by a query, remember to use the getRecords() method to access the list of records with inaccessible fields removed. The original list of records is not updated by the stripInaccessible method and would still contain the values of inaccessible fields. contacts = [SELECT Name, Picture_URL__c from Contact]; Security.SObjectAccessDecision securityDecision = Security.stripInaccessible( AccessType.READABLE, contacts ); system.debug(contacts); //Insecure access system.debug(securityDecision.getRecords()); //Secure access To sum up, this method can be used to: Strip fields from query results that the user doesn’t have read access to. Remove inaccessible fields before a DML operation without causing an exception. Sanitize sObjects that have been deserialized from an untrusted source. Summary Even though ways to check and enforce field and object-level security were around for quite sometime, these new techniques make the code less verbose and more efficient. The WITH SECURITY_ENFORCED clause can be used directly in an SOQL query to check for read access on fields, and the query will throw an exception if a single field isn’t accessible. On the other hand stripInaccessible method can be used in read, create, update and upsert operations to strip the fields from sObject Lists that are inaccessible. Now that you’ve seen how easy it is to enforce Field Level Security in Apex, check out the rest of our documentation and get hands on today! https://developer.salesforce.com/docs/atlas.en-us.222.0.apexcode.meta/apexcode/apex_classes_with_security_stripInaccessible.htm https://developer.salesforce.com/docs/atlas.en-us.222.0.apexcode.meta/apexcode/apex_classes_with_security_enforced.htm https://developer.salesforce.com/docs/atlas.en-us.securityImplGuide.meta/securityImplGuide/security_data_access.htm   About the Author: Aditya Naag Topalli is a 10x Certified Senior Developer Evangelist at Salesforce. He focuses on Lightning Web Components, Einstein Platform Services, and integrations. He writes technical content and speaks frequently at webinars and conferences around the world. Follow him on Twitter @adityanaag
0 notes
tak4hir0 · 5 years ago
Link
最近数年ぶりに Salesforce を触る機会がありました。というかあります。 そこら辺については下記をご参照のほど、何卒よろしくお願いいたします。 prtimes.jp appexchangejp.salesforce.com みなさんテストデータってどうやって作ってますか? アルプの Salesforce 開発におけるセットとしましては、下記あたりを使ってます。 ApexCode Aura Component Lightning Web Component 他、既存機能色々 環境としましては、 Scratch組織 SFDX などを使っており、Scratch組織を作成したタイミングでSFDXを利用してプロビジョニング(プロビジョニングと言っていいの?)しているのですが、動作環境などに使うテストデータを毎回手でポチポチと登録するのがめんどくさかったんですよね。 例えば、Account と Contact をセットとしたとき、色々なバリエーションが必要で毎回手で入力していたのですが、これがもう腱鞘炎になるレベル。 こういう特に何も考えずに行う作業はやはり自動化したいということで、 force:data:tree:import を使いました。 これはおそらく誰でもやっていることだと思いますし、今さら使い方を書いてもし���うがない(上記のリンクからドキュメント読んだほうが早いし良い)ので、詳しい使い方は割愛します。 スクリプト化しよう 作成するテストデータによりバリエーションを持たせたいという欲求が生まれてくるのも自然でして、そこで Node.js を使ってサクッとスクリプトを作成したろうという話です。 一応仕事で作ったスクリプトなので全容は控えるのですが、ざっくり書いておくと const fs = require('fs') const dateFormat = require('dateformat') const { execSync } = require('child_process') const justNow = dateFormat(new Date(), 'hhMMss') fs.writeFileSync('./scripts/tmp/Accounts.json', fs.readFileSync('./scripts/testDataSources/Accounts.json', 'utf8').replace(/hhMMss/gi, justNow)) fs.writeFileSync('./scripts/tmp/Contacts.json', fs.readFileSync('./scripts/testDataSources/Contacts.json', 'utf8').replace(/hhMMss/gi, justNow)) execSync('cp -p scripts/testDataSources/Account-Contact-plan.json scripts/tmp/Account-Contact-plan.json') execSync(`sfdx force:data:tree:import -p scripts/tmp/Account-Contact-plan.json -u ${options.org}`) みたいな感じです。 解説 下記はテストデータの元として ./scripts/testDataSources/Accounts.json を読み込み、 hhMMss を現在時間に置換した後に ./scripts/tmp/Accounts.json に書き込みを行ってます。 fs.writeFileSync('./scripts/tmp/Accounts.json', fs.readFileSync('./scripts/testDataSources/Accounts.json', 'utf8').replace(/hhMMss/gi, justNow)) Account.json の中身はざっくりですが { "records": [ { "attributes": { "type": "Account", "referenceId": "hhMMss01_A" }, "Name": "hhMMss01_アカウント名" }, { "attributes": { "type": "Account", "referenceId": "hhMMss02_A" }, "Name": "hhMMss02_アカウント名" } ] } となっておりまして、 .replace(/hhMMss/gi, justNow) でID値などを現在時分秒に置換することでユニークな値を作成しています。 Contact.json は下記のような感じです。こちらも Account.json 同様、ID値を置換してユニークな値を作成しています。 { "records": [ { "attributes": { "type": "Contact", "referenceId": "hhMMss01_C" }, "LastName": "hhMMss01_名字", "FirstName": "太郎", "Email": "[email protected]", "AccountId": "@hhMMss01_A" }, { "attributes": { "type": "Contact", "referenceId": "hhMMss02_C" }, "LastName": "hhMMss02_名字", "FirstName": "次郎", "Email": "[email protected]", "AccountId": "@hhMMss02_A" }, ] } 次に、 execSync('cp -p scripts/testDataSources/Account-Contact-plan.json scripts/tmp/Account-Contact-plan.json') を実行してplanファイルをコピーし、 execSync(`sfdx force:data:tree:import -p scripts/tmp/Account-Contact-plan.json -u ${options.org}`) にてimportを実行しています。 本当はもっと色々してますが、まあこんな感じですかねえ。 ハマったところ Accountなどの referenceId に指定している hhMMss01_A ですが、初めは yyyymmddhhMMss01_A のようにして年月日時分秒を指定してました。 しかし、2回目以降どうしても下記エラーが出てしまいます。 { "hasErrors": true, "results": [ { "referenceId": "2020032707565901_A", "errors": [ { "statusCode": "DUPLICATES_DETECTED", "message": "Duplicate Alert", "fields": [] } ] } ] } 年月日時分秒なので秒単位でユニークになるハズなのと、エラーメッセージが DUPLICATES_DETECTED のみなので何も言っていない(本当に何も言っていない)に等しく、まったく原因が分から無いままおそらく丸1日ほどハマっていました。 が、ふと原因に気づきました。 おそらくですが、ID値が長すぎてどこかで末尾が欠落し、例えば 2020032707565901_A が 20200327 の様になってしまったのではないかなと思います。 そのため、 yyyymmddhhMMss01_A ではなく hhMMss01_A にしている次第です。 また、 Name 属性もユニークにする必要があるようです。 とまあ、Node.js が使えるので基本的になんでも出来るのは良いなあと思いました。 DUPLICATES_DETECTED は文献を漁っても原因が分からなかっただけに、気づいた時は心底安心するとともに、もし同様のエラーでハマっている方のお力に少しでもなればと思います。 その文字列を観た感じ重複しているというのはワカルのですが、そんなハズ無いという思い込みが捨てられたらというのと、もう少し丁寧なエラーメッセージがほしいなと言ったところですかね笑 SFDX所感 僕がSalesforceの開発案件に携わっていたのがもうかれこれ5年前だったりするのですが、当時は Eclipse にプラグインを入れて開発していました。 しかし、コードの補完が効きづらかったり、ソースコードのデプロイ速度が遅かったためローカルで書いたソースをブラウザにコピペして開発していたりと、お世辞にも良い開発体験ではなかったと思います。 SFDXはその頃の教訓をかなり活かせている気がします。 Visual Studio Code を基本として開発しているのですが、プラグインは良く出来ていますし、デプロイ速度も当時に比べて格段に向上しています。 コマンドも一通りそろってますし、開発する上でのストレスはかなり低減されていました。 Lightning Web Component Lightning Web Component は特にすんなり入りやすかったです。 HTML, Script, CSS が別れている点が Vue に少し似ていると思いました。 JavaScript は ECMAScript フレンドリーに記述できますし、HTML と JavaScript の連携もとても楽です。 CSS はあまり書かないです。理由としては Lightning Design System が提供するコンポーネントを使えば(今の所)事足りるからです。 ただ、 Lwc について一つ思うのが @wire を利用する際に fields にフィールド名を指定するのは嫌な気がします。 ココ( Understand the Wire Service )にある↓こういうやつ。 @wire(getRecord, { recordId: '$recordId', fields: [ACCOUNT_NAME_FIELD] }) record; 実装上楽になるかもしれませんが、これだとフロントがSOQLを書いているという意味にもなりますので、そこはフロントの責務から剥がしたい気持ちがありました。 そのため、下記のように画面で必要なデータは connectedCallback で ApexCode を呼びだして、SOQL は ApexCode 側に寄せるように実装してます。 ↓下記のイメージ { console.error(error) }) } しかし、そうするとやはり ApexCode はカオス化しやすい気がしますね。その点は設計思想などでカバーできればよいかな。 ただ、 @wire の存在を考えると、今後は Lwc の js 層が ApexCode に取って代わる未来にしたいのかなという考えもわかります(実際Salesforce社がどう考えているかまでは追っていません)。 おしまいに 久しぶりにSalesforceの開発へと戻ってきたのですが、かなり浦島太郎状態で、ちょっと辛かった当時と比べると思ったよりも楽しいです。 というわけで、アルプ株式会社では、絶賛 Salesforce エンジニアを探しております。 気になったそこのあなた、お気軽にお問い合わせください。Salesforce エンジニアに限らず採用は行っておりますので、併せてご確認ください! bosyu.me thealp.co.jp
0 notes
tak4hir0 · 5 years ago
Link
0 notes
tak4hir0 · 5 years ago
Link
In the new world of second generation packaging (2GP) capabilities such as Unlocked Packages mean the technical aspects of packaging are no longer a concern only for ISV developers but are now equally applicable to enterprise development. The Salesforce Developer Experience (SFDX) developer guide documentation provides a great reference for those getting started with packaging which covers all the main implementation considerations. One area that isn’t covered is the management of package versions in practice; I call this a package version scheme, an example of which is included below. Package Version Scheme: Convention [Major.Minor.Patch.Build] Pre-release development; 0.1.0-x .. 0.2.9-x First-release; 1.0.0-1 Post-initial-release bugfixes; 1.0.1-x .. 1.0.3-x (Patch number must increment per package version release) Post-initial-release internal builds; 1.1.0-x (Only the Build number must increment per package version release) Next-release (minor enhancement); 1.1.0-x (Release with the final build number) Post-minor-release bugfixes; 1.1.1-x .. 1.1.3-x (Patch number must increment per package version release) Post-minor-release internal builds; 1.2.0-x (Only the Build number must increment per package version release) Next-release (major enhancements); 2.0.0-1 Post-major-release bugfixes; 2.0.1-x .. 2.0.3-x (Patch number must increment per release) Post-major-release internal builds; 2.1.0-x (Only the Build number must increment per release) Additional references: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_manpkgs_package_versions.htm https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_intro.htm
0 notes