1 2 Previous Next 15 Replies Latest reply on Nov 8, 2015 6:02 PM by Brendan Lee

    documentation clarification - sample doesn't behave properly

    Chris Harrington

      The documentation has these samples

       

      On page Custom Initialization and Shutdown Code

       

      Code is

       

      myConnector.init = function() {

         tableau.initCallback();

         if(tableau.phase == tableau.phaseEnum.interactivePhase || tableau.phase == tableau.phaseEnum.authPhase) {

              tableau.submit();

          }

      };

       

      On page Web Data Connector API Reference

      code is

       

      myConnector.init = function() {

          if (tableau.phase == tableau.phaseEnum.interactivePhase){

              // Show full UI, including the UI to let the user sign in via OAuth

          }

          else if (tableau.phase === tableau.phaseEnum.authPhase) {

              // Get the auth token from the tableau.password property and

              // check that it is still valid.

              // If it isn't, display ONLY the UI that lets the

              // user sign in again.

          }

          tableau.initCallback();

          // Don't call the submit() function if the connector is in data-gathering phase

          if(tableau.phase == tableau.phaseEnum.interactivePhase || tableau.phase == tableau.phaseEnum.authPhase) {

              tableau.submit();

          }

      };

       

      But what I observe is that if this code is present, specifically

       

        if (tableau.phase == tableau.phaseEnum.interactivePhase || tableau.phase == tableau.phaseEnum.authPhase) {

              tableau.submit();

      }

       

      then the data gathering phase never occurs.

       

      As there are no samples in the "Examples" folder which use this pattern, and the pattern doesn't appear to work, I'd like to ask if this documentation is indeed correct.

        • 1. Re: documentation clarification - sample doesn't behave properly
          Mike Pope

          Hi,  Chris. Sorry for the delay in getting back to you on this. I'm not able to repro your issue exactly, but I might be misunderstanding it. I've got a kind of silly WDC below whose primary function is to spit out messages to the browser console. In this example, the code listed in the Custom Initialization and Shutdown Code seems to work--both phases are invoked and data is "returned" properly. However, as I say, I might not be understanding the issue that you're encountering.

           

          <html>
          <meta http-equiv="Cache-Control" content="no-store" />
          <head>
          
          <!-- Latest WDC Library -->
          <script src="https://public.tableau.com/javascripts/api/tableauwdc-1.1.0.js" type="text/javascript"></script>
          
          <script type="text/javascript">
          console.log("ready to create connector");
          console.log("phase = " + tableau.phase);
          var myConnector = tableau.makeConnector();
          console.log("connector created");
          
          myConnector.init = function() {
             console.log("init");
             console.log("Phase = " + tableau.phase);
             tableau.initCallback();
             if(tableau.phase == tableau.phaseEnum.interactivePhase || tableau.phase == tableau.phaseEnum.authPhase) {
                  tableau.submit();
              }
          };
          
          myConnector.getColumnHeaders = function() {
              console.log("getColumnHeaders");
              console.log("phase = " + tableau.phase);
              var columnNames = ['Month', 'LowTemp', 'HighTemp'];
              var columnTypes = ['string', 'int', 'int'];
              tableau.headersCallback(columnNames, columnTypes);
          }
          
          myConnector.getTableData = function(lastRecordNumber){
              console.log("getTableData");
              console.log("phase = " + tableau.phase);
              dataToReturn = [];
              isMoreData = false;
              dataToReturn.push({'Month':'Jan', 'LowTemp':37, 'HighTemp':49});
              dataToReturn.push({'Month':'Feb', 'LowTemp':37, 'HighTemp':51});
              dataToReturn.push({'Month':'Mar', 'LowTemp':40, 'HighTemp':55});
              dataToReturn.push({'Month':'Apr', 'LowTemp':43, 'HighTemp':60});
              dataToReturn.push({'Month':'May', 'LowTemp':49, 'HighTemp':66});
              dataToReturn.push({'Month':'Jun', 'LowTemp':53, 'HighTemp':71});
              dataToReturn.push({'Month':'Jul', 'LowTemp':57, 'HighTemp':76});
              dataToReturn.push({'Month':'Aug', 'LowTemp':57, 'HighTemp':76});
              dataToReturn.push({'Month':'Sep', 'LowTemp':53, 'HighTemp':71});
              dataToReturn.push({'Month':'Oct', 'LowTemp':47, 'HighTemp':61});
              dataToReturn.push({'Month':'Nov', 'LowTemp':41, 'HighTemp':52});
              dataToReturn.push({'Month':'Dec', 'LowTemp':36, 'HighTemp':47});
              tableau.dataCallback(dataToReturn, lastRecordNumber, isMoreData);
          }
          
          myConnector.shutdown = function() {
              console.log("shutdown");
              console.log("phase = " + tableau.phase);
              tableau.shutdownCallback();
          }
          
          tableau.registerConnector(myConnector);
          console.log("Connector registered");
          </script>
          </head>
          <body>
          <p>Test WDC Phases</p>
          </body>
          </html>
          
          • 2. Re: documentation clarification - sample doesn't behave properly
            Chris Harrington

            Hi Mike,

            One difference I see is that your sample doesn't have any UI actions. In my UI, the user clicks a "get data" button which invokes tableau.submit().  If a user action invokes tabeau.submit(), then is it incorrect (and perhaps why I found it not to work) to call it in the connector init()?

            - Chris

            • 3. Re: documentation clarification - sample doesn't behave properly
              Mike Pope

              Probably. :-) If you're calling tableau.submit from your UI code, it's possible you don't need a custom init function at all. Are you implementing code for an auth phase? For example, are you using OAuth in your connector? (This is just for my own curiosity.)

               

              Anyway, your original point is probably correct--the example code in the Custom Initialization topic should probably be fixed up for the case that tableau.submit has been called in UI code. I'm not 100% clear from your original post, but does the second example--the one with the more extensive phase checking--work for you?

               

              Thx,

               

              Mike

              • 4. Re: documentation clarification - sample doesn't behave properly
                Chris Harrington

                Hi Mike,

                 

                No, the one with the more extensive phase checking also doesn't work.

                I do have an init() because that's where I repopulate my UI if the user edits a connection. But that isn't fully working for me. As I explained in another support thread, the value of tableau.password is empty even when it's the same session. And more importantly it's empty in the data gathering phase so editing a connection always fails since it needs the authentication info to make the AJAX call. see Re: How should "edit" work?

                 

                I read this documentation more than once:  onlinehelp.tableau.com/current/api/wdc/en-us/help.htm#WDC/wdc_authentication.htm?Highlight=password

                but it doesn't really explain how passwords are managed, and there is no code sample using passwords to call a web service which requires an API key or basic authentication. The doc says "Tableau prompts user for credentials". In what phase? How do I get the username and password so that I can invoke my web service? An example would be most helpful.

                 

                Thanks,

                Chris

                 

                http://onlinehelp.tableau.com/current/api/wdc/en-us/help.htm#WDC/wdc_authentication.htm?Highlight=password

                • 5. Re: documentation clarification - sample doesn't behave properly
                  Mike Pope

                  Thanks for the clarification. I'm going to have to ping one of our developers to look at this. But I will take your observation that the docs aren't sufficiently clear and get those updated when we have an answer here. Thanks for your patience and I'm sorry that I can't immediately answer your question.

                   

                  Mike

                  • 6. Re: documentation clarification - sample doesn't behave properly
                    Brendan Lee

                    So the special OAuth phase is called only when refreshing an extract in the case where there are no credentials available.

                     

                    For example, try the following:

                    1. Connect to this connector Foursquare Connector in Tableau.   (You'll need a Foursquare account)
                    2. Extract the data
                    3. Make and save the workbook.
                    4. Close Tableau.
                    5. Open Tableau and the saved workbook.
                    6. Refresh the extract.


                    Since the password object will have been cleared when you exited Tableau, this is when you will see the special Auth phase.  You should see a similar WDC UI, but there is no get data button any longer.  Since this is just the auth phase, I hide that UI and just prompt for credentials.  When the credentials come back, I automatically call the tableau.submit() method to refresh the extract.

                     

                    You can check this out here: lbrendanl/TableauFoursquareHostedWDC · GitHub

                     

                    In general, if you need to collect username/password from a user, you can collect those in the first interactive phase (and any following interactive phase).   The auth phase is specifically designed to get around the problem of refreshing an extract if the credentials have dissapeared.


                    Thanks for the feedback, we are working on improving the documentation and samples so this will be easier in the future.

                    • 7. Re: documentation clarification - sample doesn't behave properly
                      Chris Harrington

                      Hi Brendan,

                       

                      I'll attempt to make a simple basic auth example based upon what I see in your Foursquare example.

                       

                      Thanks,

                      Chris

                      • 8. Re: documentation clarification - sample doesn't behave properly
                        Chris Harrington

                        Hi Brendan,

                        I am not getting anywhere. What I observe in looking at the tabprotosrv_1.txt log is that init() is never invoked in auth phase. Hopefully you can provide a sample which uses basic authentication against the backend web service. 

                        • 9. Re: documentation clarification - sample doesn't behave properly
                          Brendan Lee

                          Hey Chris,

                           

                          Thanks for the feedback, a basic auth sample sounds like it would be pretty useful. 

                           

                          But the init phase not running is troubling, that should always run in every phase of the WDC.  Are you able to share a sample that reproduces the issue?  That would be very helpful, I would love to help diagnose the problem.

                           

                          -Brendan

                          • 10. Re: documentation clarification - sample doesn't behave properly
                            Chris Harrington

                            init() is running, but never with tableau.phase == tableau.phaseEnum.authPhase

                             

                            I figured you might ask for a sample But I wanted to wait and see if perhaps you already had one. I can get one together next week.

                             

                            - Chris

                            • 11. Re: documentation clarification - sample doesn't behave properly
                              Brendan Lee

                              Hey Chris,

                               

                              Ah I see the problem now, and my apologies I should've caught on to this sooner.  It appears that with basic auth, the "Auth" phase never runs (and thus no init function).  The WDC doesn't get loaded with basic auth (as opposed to OAuth, where the WDC needs to show custom UI).  So a WDC that uses basic auth will only ever have two phases (interactive and data gathering). Thanks for helping to clarify this, we should add a doc note about this

                               

                              I wrote up a quick test connector that should showcase all this: password_repro_test_WDC/basicauth.html at master · lbrendanl/password_repro_test_WDC · GitHub

                               

                              Try that connector out.  It's just another hack of the stock quotes connector, but try the following workflow:

                              1. Connect to the basicauth.html
                              2. Enter a ticker, random username, and password 'asdf'.
                              3. Save the workbook.
                              4. Close Tableau.
                              5. Reopoen the workbook.
                              6. Right click the data source and do extract -> refresh.

                               

                              Then you should see the Tableau UI for password/username prompt.  I an logging the username and password in the data gathering phase as well so you will be able to access those values there.

                               

                              The top of this docs page has the details on when http://onlinehelp.tableau.com/current/api/wdc/en-us/help.htm#WDC/wdc_authentication.htm%3FTocPath%3DAdditional%2520Concepts%7C_____4this Tableau UI shows (basically just: if tableau.username is set and tableau.alwaysShowAuthUI is false): http://onlinehelp.tableau.com/current/api/wdc/en-us/help.htm#WDC/wdc_authentication.htm%3FTocPath%3DAdditional%2520Concepts%7C_____4http://onlinehelp.tableau.com/current/api/wdc/en-us/help.htm#WDC/wdc_authentication.htm%3FTocPath%3DAdditional%2520Concepts%7C_____4http://onlinehelp.tableau.com/current/api/wdc/en-us/help.htm#WDC/wdc_authentication.htm%3FTocPath%3DAdditional%2520Concepts%7C_____4 http://onlinehelp.tableau.com/current/api/wdc/en-us/help.htm#WDC/wdc_authentication.htm%3FTocPath%3DAdditional%2520Concepts%7C_____4

                               

                              ------

                               

                              So, I think this answers your initial question (and once again I apologize for the goose chase): no you can't access the Tableau password/username from the init phase during the Auth phase if you are doing basic auth.  This is because the auth phase only exists in an OAuth environment.  I suppose a workaround would be pretend like you are doing OAuth (set tableau.alwayShowAuthUI to true), and then create your own custom UI for collecting the username and password. 

                               

                              We'll work on making this clearer in our docs.  We would like to improve this portion of the API in a future release as well, so if you have any feedback please feel free to send it my way.

                               

                              The follow up question I would have: is there a reason you need to access username/password during the init function as opposed to later during the getTableaData function? 

                               

                              -Brendan

                              • 12. Re: documentation clarification - sample doesn't behave properly
                                Chris Harrington

                                Hi Brendan,

                                Thank you for sharing your investigation and findings.

                                 

                                I am using the password to set the value of an API key. I am saving it in the password so that the security around that key gets handled like any other Tableau credential. The user might need to edit this key - hence my desire to be able to edit it during the interactive phase.

                                 

                                Would there be any downside to "pretend like you are doing OAuth"? Would it have any effect on the behaviour of the WDC in the context of Tableau Server?


                                And speaking of Tableau Server, I've read the WDC documentation on that topic a couple times and still don't understand what would be the flow? I know they are a pain to create and maintain, but flow diagrams would really help here.  But until then, could you at least state with bullet points what is the operational flow of a WDC in the context of Server?

                                 

                                Here's an example. The doc says "The first exception is if the extract was created by a web data connector that was not previously imported into the server." I read that and it sounds like "you can't come to the department of motor vehicles to renew your license unless you've already come to the DMV to renew your license" .  It would be better to tell us the steps that WILL work to have things automatically refresh instead of just telling us what won't work.

                                 

                                - Chris

                                • 13. Re: documentation clarification - sample doesn't behave properly
                                  Mike Pope

                                  Hi, Chris. You can blame me for the unclear documentation about using WDCs on the server. :-) It's simpler than the docs seem to indicate, and it really boils down to this: Tableau Server won't invoke a web data connector to refresh an extract unless the WDC was imported using the tabadmin import_webdataconnectors command. Although we don't use this terminology (because it isn't entirely accurate), an imported WDC is a trusted WDC, so to speak. But once a WDC has been imported, any extracts created by the WDC can be refreshed "like normal," as the docs don't quite say.

                                   

                                  However, even then, Tableau Server can't invoke the WDC for a refresh if the WDC requires credentials before it can go through its data-gathering phase again. This is a practical limitation: it's not practical to have the WDC suddenly pop up and prompt for credentials. This is because the refresh can be occurring on a schedule or in some other background-type context, where the server wouldn't even know who to display the WDC UI to.

                                   

                                  Does this help? Obviously, we could state this more clearly in the docs, and I'll take a bug to revise this. If this isn't clear, please do let me/us know. And apologies for the unclear docs.

                                   

                                  Mike

                                  • 14. Re: documentation clarification - sample doesn't behave properly
                                    Chris Harrington

                                    Hi Brendan,

                                    I'm looking at your sample now.  One thing that I don't understand is the existing of the function myConnector.setTicker(). Why not just do this:

                                     

                                          if (tickerSymbol) {

                                            tableau.connectionData = tickerSymbol;

                                            tableau.connectionName = 'Stock quote: ' + tickerSymbol;

                                            tableau.username = username;

                                            tableau.password = password;

                                            tableau.submit();

                                          }

                                     

                                    Is that any different?

                                     

                                    Next issue: your sample doesn't support editing a connection, which is the issue I'm struggling with. 

                                     

                                    Should I boil down my connector into a sample that we can then jointly get working through the full workflow?

                                     

                                    Thanks,

                                    Chris

                                    1 2 Previous Next