justicenation / slashclock

/clock concept as a new Slack app
GNU General Public License v3.0
0 stars 0 forks source link

User-specific time zone #9

Closed martyychang closed 7 years ago

martyychang commented 7 years ago

As a Slack user, I want to specify a time zone, so my time entries are accurately reported for the correct days of the week.

Solution design

Time entries should be linked to standard Contact records, based on the SlackUserId__c value. Every contact will have a custom TimeZoneSidKey__c picklist field that stores the same values as what would be expected of User.TimeZoneSidKey.

martyychang commented 7 years ago

My guess is that Java's TimeZone.getAvailableIDs() function will give the master list of recognized IDs. The list that I took from Salesforce is just fine, though, and I just need to create some kind of documentation page to explain all of the values.

martyychang commented 7 years ago

I'm thinking about the /clock zone command I'm planning to create. For user experience, I think the optimal steps would be as follows.

  1. User types /clock zone to see current time zone. The response instructs the user to types /clock help zone to get more info on the "zone" operation.
  2. User types /clock help zone. All available time zone IDs are listed along with the current offset, ordered by the current offset and then alphabetically.
  3. User types /clock zone America/New_York to select her new time zone

Although Slack does offer other ways of interacting with users, which may be worth exploring for a better UX with less code complexity.

martyychang commented 7 years ago

Or better yet, the user's time zone should simply be set to match the user's configuration in Slack. How easy is that? For an interactive UX, I think perhaps a message menu would be best. But I want to see whether I can simply find the user's time zone with an API call to Slack.

martyychang commented 7 years ago

The users.info method seems to be exactly what I want... but I need to figure out how to make the necessary calls. Also, it seems the UX for a user installing an app from the public App Directory vs. installing an unlisted Slack app is different. Installing an app from the public directory does not redirect the user to the redirect_uri as in the OAuth 2.0 flow.

martyychang commented 7 years ago

The steps below are the high-level steps in the process.

  1. User authorizes slashClock
  2. User is redirected to slashClock callback page
  3. Server exchanges authorization code for access token by calling oauth.access
  4. Server uses access token to get user's time zone by calling users.info
  5. Server sends a simple HTTP 200 response
martyychang commented 7 years ago

Very cool... with Postman I was able to get the access token in a response body that looks like this.

{
    "ok": true,
    "access_token": "...",
    "scope": "identify,commands",
    "user_id": "...",
    "team_name": "...",
    "team_id": "..."
}
martyychang commented 7 years ago

It appears that upon exchanging the authorization code for an access token, the app is considered to be "installed" and the commands become available to users in the workspace

martyychang commented 7 years ago

The cURL command illustrating the simple command I need to use to get the access token is below. However... I'm left in a strange place where I don't know how to take the user back to Slack...? I may need help from Slack here.

curl -X GET \
  'https://slack.com/api/oauth.access?client_id=...&client_secret=...&code=...' \
  -H 'cache-control: no-cache' \
  -H 'postman-token: bd6547b4-4f74-8bb4-091c-9a6ad1df189f'
martyychang commented 7 years ago

The following works in the action action method to take the user to another page after the controller does its thing.

        // Redirect to https://api.slack.com
        PageReference nextPage = new PageReference('https://api.slack.com');

        // Use Slack to get the 
        return nextPage;
martyychang commented 7 years ago

/api/team.info to get the team's domain for constructing the final URL

martyychang commented 7 years ago

I need a better strategy for handling HTTP errors, timeouts and other error conditions when invoking the API

martyychang commented 7 years ago

Interesting... looks like the problem is that I am making DML operations while still making web service callouts.

System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out

My current order of operations is as follows.

  1. Call oauth.access
  2. Store the access token on the account
  3. Call users.info
martyychang commented 7 years ago

Looks like the /team.info call is failing, coming back with "ok": false. Trying the call out in Postman, it seems the problem is that I need to request the "team:read" scope.

{
    "ok": false,
    "error": "missing_scope",
    "needed": "team:read",
    "provided": "identify,commands"
}
martyychang commented 7 years ago

Interesting... the scope request in the app currently is driven by the installation URL's scope parameter. When I change the requested scopes in the app configuration, it changes the URL. But until I started using the new URL vs. my bookmarked URL, the scope requests never changed.

martyychang commented 7 years ago

Hmm... how can I smartly look up the user's time zone without expending an API call on every single command???

martyychang commented 7 years ago

From the user's perspective, the UX should be as follows.

  1. I'm working in the America/New_York time zone
  2. I clock in, clock out, etc.
  3. I fly to Paris
  4. I change my time zone in Slack
  5. I clock in, clock out, etc. These new actions should be contextual in the new time zone.

I confirmed based on the Slack docs that the time zone looks to require manual management by the user.

martyychang commented 7 years ago

I can't think of a better way to handle this right now except to check the time zone every time the user invokes a command that uses an implicit time. Right now this means /clock in and /clock out would be impacted.