<< Previous | Home | Next >>

Salesforce week 13

Last week I spent two days at the customer site in Stockholm and 3 days at home in the home office. I think. Cannot really remember. Maybe I was in the office one of the days. Oh well :) It's starting to become normal to go to Stockholm and family life and work life is starting to work out. It seems like it will work for us. Customer project wise I almost finished the Lightning Component I've been working on for the customer and even made small changes to also make it work in Salesforce1. With both the web UI and the mobile UI being based off the same technologies make that pretty easy to do. Of course there are still things to address but they are mainly to do with the inherit difference in how users work on mobile vs on a desktop.

I actually thought I was done with the component last week but then I realized that writing test cases are required to deploy code into Salesforce. An org code coverage percentage of 75% is required. So this week I'm going to write the test cases for the server side controllers (written in Apex). One of the things which has been fun is that it's very different writing code for production release than writing for the sandboxes or exercises I've been doing otherwise. For one normal coding practices like documentation and comments are way more important but also things which is less obvious start rearing its head. Security for one... I suddenly had to stop and consider object and record access for the custom objects I use for the solution. For this solution it wasn't a big issue but one of those things that isn't necessarily required for a PoC / sandbox implementation.

I've also started to figure out how to bundle up my solution into "something" I can deploy easily across the various orgs we use at the customer. For now it's a bit of a kludge using the Apache Ant functionality by Salesforce. It will lukily become way better soon then new Salesforce DX approach become publicly available. If you do not know what Salesforce DX is stay tuned but in short it will turn the whole Salesforce development experience on its head. From the org being the source of truth to being based on a source-first approach so that your source repository becomes the source of truth and all development and deployment runs from the source to the org and not the other way. It looks very promising.

What did I learn

  • The Salesforce Ant extensions are fine to work with but still feels like a bit of a kludge
  • There are CLI extensions for Salesforce but they are not really ready for production use
  • Salesforce DX looks to be the solution I've been looking for
  • There is a difference between developing for a sandbox and a production org - remember to write those test cases

Status after this week

Trailhead points: 71150
Trailhead badges: 72
Certifications: 4 (Salesforce Certified Administrator, Salesforce Certified Platform App Builder, Salesforce Certified Advanced Administrator, Salesforce Certified Sales Cloud Consultant)

Tags :

Salesforce for Newcomers - Introduction to orgs, sandboxes, API login and Salesforce security

As I venture into the Salesforce Universe myself there are many areas that I would have wished had been easier to figure out. So what better than remedying that with a series of blog posts. Maybe there will be one post and maybe more. We'll see... This first instalment is on some of the basics in Salesforce namely the org, sandboxes and some of the security implications of logging in. I'm pretty technical so some of this will be from a technical angle so please forgive me and stay with me.

"Org"

When you get provisioned a Salesforce instance - or an org as we like to call them - you get your own slice of the Salesforce infrastructure. Depending on the amount of data you add to the org the slice may be VERY small or VERY big but the core concept is the same. Every org has an identifier (the "org id") and that is what identifies it and the associated data throughout the Salesforce infrastructure. Everything you do in your org - data and customizations belongs to your org due to being coupled to your org id.

Boom! That's it.

Sandboxes

A sandbox is something you may or may not get depending on the license types you buy and depending on the type of licenses you may even get more than one. Sandboxes are play areas that are connected to your org and allows you to develop and test customizations and - maybe - eventually move these customizations to your production org. Sandboxes come in different flavours and may contain no actual production data, some data or all of your production data. We call these empty, partial and full sandboxes. A sandbox always contains the customizations from the org it was generated from.

Besides the customizations a sandbox also gets a copy of all the users from the "source org" although the email addresses of users are changed in the process by removing the @-sign and appending @example.com. Bringing all the users across means that users may log into the sandbox using their existing username and password - the only change they need to do is to append a period and the name of the sandbox. So if my username is jdoe@acme.com and I'm logging into a sandbox called "uat" I simply use the username jdoe@acme.com.uat and my password.

Customizations may be moved between a sandbox and an org using a "change set" which basically is our way to move customizations between environments. There are other ways as well for more advanced uses but let us keep it simple for now.

Logging in

At Salesforce our number one value is trust. The trust of our customers and the trust they place in us to keep the data they entrust with us safe. This means we spend a considerable amount of time and resources keeping data secure and ensuring that no two orgs get mixed up. It also means that Salesforce offers a number of ways to make sure only the right people may log in and do that at the right time of the day.

These security features come in a number of flavors including but not limited to:

  • Username and password (duh!) and being able to set the complexity required of passwords.
  • Whether two factor authentication is required using either the Salesforce Authenticator app, login codes texted to your cell phone or emailed to you.
  • Which users may log in from what IP ranges and at what time of the day. If a user is assigned to a call center chances are they should only login from the call center location between 9am and 6pm.
  • What IP ranges are deemed trusted. A login from a trusted IP range is special in that it doesn't require a second factor of authentication (that is besides username and password).

Besides these there are loads of other security mechanisms - way too many to dive into here in detail. If interested head over to Help & Training or get friendly with the security related pages under Setup in an org.

Security and the API's

Authenticating to the various API's for Salesforce is slightly different from logging in to the web UI or Salesforce1 (our mobile app). As a developer, you need to know the type of org (production or sandbox) you're working against If you need to authenticate using the API's. The main reason is due to any login IP restrictions you may have configured for your production org but really it's not important to know why. Simply remember that when using API's and you need to log into a production org you use login.salesforce.com and If logging in against a sandbox you use test.salesforce.com.

It's that simple. Use test.salesforce.com for - well - testing. So if using OAuth and logging in to a production org you use https://login.salesforce.com/services/oauth/token and If logging in against a sandbox use https://test.salesforce.com/services/oauth/token.

And really that's all there is to it.

Security Tokens

This is the final piece for this post but an important one. Remember those IP ranges that may have been set up as trusted in your org? If not go back and find that section and read it again... Salesforce uses the security token as a second factor of authentication if you are attempting to login from a source that Salesforce doesn't not quite trust. For interactive logins the second factor is either a code from Salesforce Authenticator or similar but for API logins the second factor is your "Security Token".

Think of the security token as:

  1. An extra password that Salesforce issues to you (you cannot set it manually)
  2. That gets reset whenever you change your password
  3. Which is only ever revealed to you once. If you lose it, you may reset it from your personal Settings at which point the new one gets revealed to you.
Using the security token is very easy - you just append it to your actual password and use the resulting string as you normally would the password. As a super password if you will.

If you are lucky enough to be a developer and log into Salesforce using the API's the security token is important to you as you may need to use your password/security token combo instead of your actual password. Again only if logging in from an untrusted network range such as when working from home without VPN or from Stackbucks.

For more information from the authoritative source of all things Salesforce I recommend reading through the posted titled Security and the API.

Lightning Components as Quick Actions in Salesforce1 and padding

Since Winter 17 we have had the option of using a Using Lightning Component as a Quick Action. In the Lightning Experience in a desktop browser the component is shown as a popup (actually a lightbox) in the UI and in Salesforce1 (the Salesforce mobile app) it's more of a modal fullscreen dialog. All this is great. Only thing you have to do is to make your component implement force:lightningQuickAction (all declaratively) and it can be added as a Quick Action. The resulting lightbox / dialog will have a header with the action name and a default Cancel button to close the dialog. Again great but what if you want to name the button something else? Or if you need a custom header? Well there is another interface for this called force:lightningQuickActionWithoutHeader. So far so good. The issue is that while this removes the default header and buttons it doesn't quite cut it in Salesforce1 as the container will still add a default margin around the component. Bummer...

The only way I found to fix this in the component I'm doing now is to add a negative martin on the component itself thereby hacking the UI. The added style is in bold - there is a negative margin to push the UI out of bounds to appear at 0,0 and a width and a height to make sure the header bar looks correctly. I've reported this internally and I hope someone will come up with a fix e.g. a new interface to add this explicitly.

<aura:component implements="force:hasRecordId,force:lightningQuickActionWithoutHeader">
    <div class="slds-modal__header" style="margin: -20px 0 0 -20px; width: 120%; height: 50px">
        <a href="javascript:void(0)" class="slds-float--left" title="back" onclick="{!c.close}">
            <c:svg svgPath="{!'/resource/SLDS221/assets/icons/utility-sprite/svg/symbols.svg#back'}" 
                   category="standard" 
                   size="x-small" 
                   name="back" 
                   strokeColor="#0070D2" 
                   class="slds-icon-text-default" /><span class="slds-assistive-text">Back</span>
        </a>
        <span class="slds-text-heading--small slds-float--left slds-p-left--x-small">Contact Sync</span>
    </div>
    <div>
        UI body...
    </div>
</aura:component>

Salesforce Platform Cache

Stumbled over the Salesforce Platform Cache the other day and just discovered this nice Trailhead Module on it (Platform Cache Basics). Worth 30 minutes if you're developing on the platform.

Tags :

Salesforce week 12

Week 12 brought me to Stockholm for 3 days, had 1 day in our new shiny Salesforce office in Hellerup (closer to Copenhagen center) and 1 day working from home. I spent most of the week getting up to speed on Salesforce Lightning and developing mockups for a custom component for the customer. All in all it was a great week where I learned a lot and made significant contribution to the customer project although I'm not officially assigned and billable yet (I'm shadowing).

Salesforce Lightning components are very nice and the component framework is cool although it is also pretty obvious in some areas that it's new and there are round edges to be considered. Custom Lightning Components can be used in many places but unfortunately there are still areas where they cannot be used so workarounds are needed. Also building custom components can both be done from the supplied Lightning UI widgets and custom markup. For now most of what I'm doing resorts to combining custom markup with Salesforce Lightning Design System (SLDS) - I will have to see how much can and should be done using the built in components.

Much more to learn in the time to come.

Sunday it was time for Super Bowl and my New England Patriots came from behind to overcome a 25 deficit to win by 6 in overtime. What a great game!! Not much sleep but there is always coffee :)

What did I learn

  • Lots about Salesforce Lightning, Lightning Component and the Salesforce Lightning Design System (SLDS)
  • There are wicked many CSS classes in SLDS
  • Stockholm is a nice city
  • Patriots performed the biggest ever comeback in NFL history to close a 25 points gap to win by 6 in overtime

Status after this week

Trailhead points: 70400
Trailhead badges: 70
Certifications: 4 (Salesforce Certified Administrator, Salesforce Certified Platform App Builder, Salesforce Certified Advanced Administrator, Salesforce Certified Sales Cloud Consultant)

Tags :

Salesforce week 11

First week on "the job" brought me to the customer I'll most likely be assigned to in Stockholm. I spent Tuesday to Thursday there and have already delivered something that will go into production in a couple of weeks. Both exciting and scary... The week was basically spent learning about the project, the phases, deliverables and a whole slew of new terminology. All good stuff. Nothing much else to report for now besides Stockholm being a nice city.

What did I learn

  • Some customers actually use Salesforce Lightning
  • What's it's like being thrown in mid-project
  • That I will stay at 3 different hotels in Stockholm over the next weeks

Status after this week

Trailhead points: 70400
Trailhead badges: 70
Certifications: 4 (Salesforce Certified Administrator, Salesforce Certified Platform App Builder, Salesforce Certified Advanced Administrator, Salesforce Certified Sales Cloud Consultant)

Tags :

Salesforce username/password OAuth flow against a sandbox

We had issues today because our OAuth password flow wouldn't work against one of our sandboxes although the code worked against production. Instead we got this error:

{"error":"invalid_grant","error_description":"authentication failure"}
After Googling and finding this thread it turned out that when using the username/password flow against a sandbox you have to either relax IP restrictions for login or authenticate against test.salesforce.com instead of login.salesforce.com (which of course makes sense).

Below is curl commands for using the username/password flow against a sandbox:

$ curl -d "grant_type=password \
   &client_id=3MVG9X0_oZyBSzHrnzENlR...JSDz0_MiwxyieREuBhtgZJrF7Lzx8542TFpU_ \
   &client_secret=6235860963257688256 \
   &username=mikkel.heisterberg%40example.com.sandboxname \
   &password=Passw0rd.SecurityToken" https://test.salesforce.com/services/oauth2/token
{"access_token":"00D6E000000Cpmu!AQ0AQIj4...cGCRqmNnYc6dmgLT09VNoIFXJtHvsPGLqrBs0VlK",
   "instance_url":"https://someaddress.my.salesforce.com",
   "id":"https://test.salesforce.com/id/00D6E000000CpmuUAC/0056E000000OCcCQAW",
   "token_type":"Bearer","issued_at":"1485850119972","signature":"malODIaSULh1siHzdw...pHKjBpWoQcm66UQ="}

$curl -H 'Authorization: Bearer 00D6E000000Cpmu!AQ0AQIj4...cGCRqmNnYc6dmgLT09VNoIFXJtHvsPGLqrBs0VlK' \
   https://test.salesforce.com/id/00D6E000000CpmuUAC/0056E000000OCcCQAW
{"id":"https://test.salesforce.com/id/00D6E000000CpmuUAC/0056E000000OCcCQAW",
   "asserted_user":true,"user_id":"0056E000000OCcCQAW","organization_id":"00D6E000000CpmuUAC",
   "username":"mikkel.heisterberg@example.com.sandboxname","nick_name":"mheis",
   "display_name":"Mikkel Heisterberg","email":"mheisterberg@foo.com","email_verified":true,"first_name":"Mikkel",
   "last_name":"Heisterberg","timezone":"Europe/Paris","photos":{"picture":"https://someaddress.content.force.com/profilephoto/005/F",
   "thumbnail":"https://someaddress.content.force.com/profilephoto/005/T"},"addr_street":null,"addr_city":null,"addr_state":null,
   "addr_country":null,"addr_zip":null,"mobile_phone":"+45 12345678","mobile_phone_verified":true,"status":{"created_date":null,
   "body":null},"urls":{"enterprise":"https://someaddress.my.salesforce.com/services/Soap/c/{version}/00D6E000000Cpmu",
   "metadata":"https://someaddress.my.salesforce.com/services/Soap/m/{version}/00D6E000000Cpmu",
   "partner":"https://someaddress.my.salesforce.com/services/Soap/u/{version}/00D6E000000Cpmu",
   "rest":"https://someaddress.my.salesforce.com/services/data/v{version}/",
   "sobjects":"https://someaddress.my.salesforce.com/services/data/v{version}/sobjects/",
   "search":"https://someaddress.my.salesforce.com/services/data/v{version}/search/",
   "query":"https://someaddress.my.salesforce.com/services/data/v{version}/query/",
   "recent":"https://someaddress.my.salesforce.com/services/data/v{version}/recent/",
   "profile":"https://someaddress.my.salesforce.com/0056E000000OCcCQAW",
   "feeds":"https://someaddress.my.salesforce.com/services/data/v{version}/chatter/feeds",
   "groups":"https://someaddress.my.salesforce.com/services/data/v{version}/chatter/groups",
   "users":"https://someaddress.my.salesforce.com/services/data/v{version}/chatter/users",
   "feed_items":"https://someaddress.my.salesforce.com/services/data/v{version}/chatter/feed-items",
   "feed_elements":"https://someaddress.my.salesforce.com/services/data/v{version}/chatter/feed-elements",
   "custom_domain":"https://someaddress.my.salesforce.com"},"active":true,"user_type":"STANDARD","language":"en_US","locale":"en_US",
   "utcOffset":3600000,"last_modified_date":"2017-01-26T13:49:33.000+0000","is_app_installed":true}

Arlanda Express app

These weeks - and probably through the end of the year - I'm going quite a lot to Stockholm so like any respectable geek I'm trying my best to make my travels more productive and easier to manage. Flying is easy - booking is all online and trips, boarding cards and receipts are managed entirely mobile. Easy. Next was hotels - also easy using existing apps except for the actual check in process.

This Monday I found the Arlanda Express app. Excellent!! Tickets are bought and paid in the app using saved credentials unlocked using a pin code. Once bought a receipt is emailed to you and it can be easily added to Concur for expensing. The ticket and the return ticket is saved in the app so no more stubs to keep track of. Nice.

Arlanda Express by A-Train AB