domoinc / domo-java-sdk

Java - Domo API SDK
https://developer.domo.com/
MIT License
24 stars 18 forks source link

Cannot export DataSet #11

Closed TokitsuMaitsuru closed 6 years ago

TokitsuMaitsuru commented 6 years ago

I want to export the dataset, such as https://api.domo.com/v1/datasets/317970a1-6a6e-4f70-8e09-44cf5f34cf44/data?includeHeader=true&fileName=data-dump.csv to a .csv file and using the dataSetId as follows:

    String dataSetId = "317970a1-6a6e-4f70-8e09-44cf5f34cf44";
    File f = File.createTempFile("sample-export", ".csv");
    dsClient.exportDataToFile(dataSetId, true, f);
    System.out.println("Wrote out file:"+f.getAbsolutePath());

by referencing the ExportDataExample.java:

But I still cannot export correct .csv file with data I want. I was afraid that I did not use the API in a right way since the link to Client Test File is broken. I wonder how I can export the dataset correctly by using Java.

Thank you very much.

Client Test File

checketts commented 6 years ago

What error do you see? Does the code throw an error or are you merely unable to fine the exported file?

Also could you please clarify which link to client test file is broken?

I see a client test file here: https://github.com/domoinc/domo-java-sdk/blob/master/domo-java-sdk-all/src/test/java/com/domo/sdk/datasets/ExportDataExample.java , but I'm happy to update any broken links you could point me to

TokitsuMaitsuru commented 6 years ago

Thank you very much for your reply. The code did not throw any error but I got the following html codes instead of my dataset in the csv file.

<!DOCTYPE html>
<html class="auth_index_html" ng-app="login" id="current-app">
<head>
  <title>Domo</title>
  <meta charset="utf-8">
  <meta name="referrer" content="same-origin" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="robots" content="noindex, nofollow" />
  <meta name="viewport" content="width=device-width, user-scalable=no">
  <base href="/">
  <link rel="apple-touch-icon" sizes="57x57"
        href="/m/public/favicons/apple-touch-icon-57x57.png">
  <link rel="apple-touch-icon" sizes="60x60"
        href="/m/public/favicons/apple-touch-icon-60x60.png">
  <link rel="apple-touch-icon" sizes="72x72"
        href="/m/public/favicons/apple-touch-icon-72x72.png">
  <link rel="apple-touch-icon" sizes="76x76"
        href="/m/public/favicons/apple-touch-icon-76x76.png">
  <link rel="apple-touch-icon" sizes="114x114"
        href="/m/public/favicons/apple-touch-icon-114x114.png">
  <link rel="apple-touch-icon" sizes="120x120"
        href="/m/public/favicons/apple-touch-icon-120x120.png">
  <link rel="apple-touch-icon" sizes="144x144"
        href="/m/public/favicons/apple-touch-icon-144x144.png">
  <link rel="apple-touch-icon" sizes="152x152"
        href="/m/public/favicons/apple-touch-icon-152x152.png">
  <link rel="apple-touch-icon" sizes="180x180"
        href="/m/public/favicons/apple-touch-icon-180x180.png">
  <link rel="icon" type="image/png" href="/m/public/favicons/favicon-32x32.png" sizes="32x32">
  <link rel="icon" type="image/png" href="/m/public/favicons/android-chrome-192x192.png"
        sizes="192x192">
  <link rel="icon" type="image/png" href="/m/public/favicons/favicon-96x96.png" sizes="96x96">
  <link rel="icon" type="image/png" href="/m/public/favicons/favicon-16x16.png" sizes="16x16">
  <link rel="manifest" href="/m/public/manifest.json">
  <meta name="msapplication-TileColor" content="#99ccee">
  <meta name="msapplication-TileImage" content="/m/public/favicons/mstile-144x144.png">
  <meta name="theme-color" content="#F6F6F6">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-itunes-app" content="app-id=553997239">
  <link rel="shortcut icon" type="image/png" href="/public/images/favicon.ico">
  <link href="//fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,400,600,700,300" rel="stylesheet" type="text/css">

  <style>
    /* Compatibility modal CSS here because older browsers can't load webpack-built/uglified CSS */
    body {
      background: #54585b;
    }

    a {
        color: #4b87b0;
        cursor: pointer;
        text-decoration: none;
    }

    a:hover {
        color: #43799e;
        text-decoration: underline;
    }

    .hidden-while-loading, [ng-cloak]{
      display:none !important;
    }

    .compatibility-modal-backdrop {
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      overflow: auto;
      text-align: center !important;
      z-index: 2000;
    }

    .compatibility-modal-container {
      position: absolute;
      top: 50%;
      left: 50%;
      margin-top: -150px;
      margin-left: -350px;
      padding: 40px;
      width: 700px;
      box-shadow: 0 0 0 6px rgba(85,85,85,0.25);
      border-radius: 5px;
      box-sizing: border-box;
      background: white;
      overflow: auto;
      display: inline-block;
      vertical-align: middle;
    }

    .compatibility-modal-header {
      margin-bottom: 15px;
    }

    .compatibility-modal-title {
      font-size: 18px;
    }

    .compatibility-modal-browser {
      display: inline-block;
      margin: 10px 10px 0 10px;
    }

    .browsers-chrome {
      background-image: url(/public/images/browsers/chrome.png);
      width: 142px;
      height: 132px;
    }

    .browsers-firefox {
      background-image: url(/public/images/browsers/firefox.png);
      width: 142px;
      height: 132px;
    }

    .browsers-ie {
      background-image: url(/public/images/browsers/ie.png);
      width: 142px;
      height: 132px;
    }
  </style>

  <link rel="stylesheet" type="text/css" href="/public/libsShared.built.css?v=1510195966" charset="utf-8" />  <link rel="stylesheet" type="text/css" href="/public/auth.built.css?v=1510195966" charset="utf-8" />
  <script src="/public/polyfills.built.js?v=1510195966"></script>  <script src="/public/i18n-ja.built.js?v=1510195966"></script>
    <link rel="prefetch" href="//assets.adobedtm.com/d9e9bb9d3d3e09e8b12f49d24b3325c0fdb6f998/satelliteLib-039a9c14f39837d1d9cd94e1943c468b85adb800.js">        <link rel="prefetch" href="/public/bootstrap.built.css?v=1510195966">    <link rel="prefetch" href="/public/next.built.css?v=1510195966">    <link rel="prefetch" href="/public/bootstrap.built.js?v=1510195966">    <link rel="prefetch" href="/public/next.built.js?v=1510195966">  
  <script type="text/javascript">
    function checkShowCompatabilityModal() {
      if(!document.addEventListener || (window.ActiveXObject != undefined && !("onpropertychange" in document && !!window.matchMedia))) { //First check is for old IE, second check is ie10
        document.getElementById('Cloak').removeAttribute('ng-cloak'); //IE8 needs this, cause Angular doesn't parse, so ng-cloak doesn't go away
        document.getElementById('CompatibilityModal').style.display = '';
        document.getElementById('CompatibilityModalTitle').innerText = window.i18n.authentication['browser-not-supported']();
        document.getElementById('login-wrapper').style.display = 'none';
      }
    }
  </script>

  <script>
    !function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
    n.callMethod.apply(n,arguments):n.queue.push(arguments);};if(!f._fbq)f._fbq=n;
    n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
    t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
    document,'script','//connect.facebook.net/en_US/fbevents.js');

    fbq('init', '288302794674604');
    fbq('track', "PageView");
  </script>
  <noscript>
    <img height="1" width="1" style="display:none"
    src="https://www.facebook.com/tr?id=288302794674604&ev=PageView&noscript=1" />
  </noscript>

  <script type="text/javascript">
    adroll_adv_id = "TEVG6YVUDVFV3J3FHTOCHT";
    adroll_pix_id = "35B3KTKHNFD7NDOADTBTRV";
    (function () {
        var _onload = function(){
            if (document.readyState && (!/loaded|complete/.test(document.readyState))){setTimeout(_onload, 10);return}
            if (!window.__adroll_loaded){__adroll_loaded=true;setTimeout(_onload, 50);return}
            var scr = document.createElement("script");
            var host = (("https:" == document.location.protocol) ? "https://s.adroll.com" : "http://a.adroll.com");
            scr.setAttribute('async', 'true');
            scr.type = "text/javascript";
            scr.src = host + "/j/roundtrip.js";
            ((document.getElementsByTagName('head') || [null])[0] ||
                document.getElementsByTagName('script')[0].parentNode).appendChild(scr);
        };
        if (window.addEventListener) {window.addEventListener('load', _onload, false);}
        else {window.attachEvent('onload', _onload)}
    }());
  </script>

  <script type="text/javascript">
    /* <![CDATA[ */
    var google_conversion_id = 1072736339;
    var google_custom_params = window.google_tag_params;
    var google_remarketing_only = true;
    /* ]]> */
  </script>
  <script type="text/javascript" src="//www.googleadservices.com/pagead/conversion.js">
  </script>
  <noscript>
    <div style="display:inline;">
    <img height="1" width="1" style="border-style:none;" alt="" src="//googleads.g.doubleclick.net/pagead/viewthroughconversion/1072736339/?value=0&amp;guid=ON&amp;script=0"/>
    </div>
  </noscript>

<!-- include the basics -->

<script src="/public/libsShared.built.js?v=1510195966"></script><script src="/public/auth.built.js?v=1510195966"></script>
</head>
<body class="auth_index centered-container overflow-hidden" ng-class="{'ad-based-container': (true || false) && showAdBasedLogin}" onload="checkShowCompatabilityModal()" ng-controller="LoginController" ng-cloak>
<div id="Cloak" ng-show="view.visible" ng-cloak>
  <div id="login-wrapper" class="login-wrapper auth" ng-class="{'ad-based-login-wrapper': (true || false) && showAdBasedLogin}">
    <div class="login-form clearfix">
      <div class="form-container">
        <div class="header">
          <img ng-if="!view.isCustomerWhitelabeled" src="/public/images/logo-400.png" class="brand vertical-align-middle" width="100" height="100" alt="">

          <i class="icon-plus color-gray-10 margin-horizontal-small _24" style="vertical-align: -2px;" ng-if="(view.customerHash || view.easyInvite) && !view.isCustomerWhitelabeled"></i>
          <img
            ng-if="view.easyInvite && !view.isCustomerWhitelabeled"
            src="/public/images/buzz-logo-250.png"
            class="brand vertical-align-middle"
            width="100"
            height="100"
            alt="">
          <img class="cobrand vertical-align-middle" ng-src="/ext/companylogo/{{view.customerHash}}?cache={{cacheHash}}"
            title="" alt="" style="width: 100px; height: 100px;" ng-if="view.customerHash && !view.easyInvite" />
        </div>
        <div class="alert-area display-while-loading">
          <div class="alert-text red" >Please Enable JavaScript</div>
        </div>
        <div class="alert-area hidden-while-loading">
          <div class="alert-text red" ng-show="view.message && !view.notice">{{view.message}}</div>
          <div ng-show="view.message && view.notice">{{view.message}}</div>
          <div ng-show="!view.message">&nbsp;</div>        </div>
        <div class="domain-name-area show-when-electron">
          <div class="domain-name-text color-gray-6" style="font-size:16px;font-weight:500;">{{loggingInto}}</div>
        </div>
        <div class="body overflow-hidden hidden-while-loading" ng-switch on="view.active">

          <!-- login -->
          <form ng-switch-when="login" ng-submit="submit()" ng-disabled="verifying" autocomplete="on">
            <div ng-if="savedUser" class="saved-user-panel">
              <i class="close icon-x" ng-click="clearSavedUser()"></i>
              <img class="avatar" width="48" height="48" style="float: left;"
                ng-src="/avatar/thumb/{{savedUser.USER_ID}}" />
              <div style="margin-left: 60px;">
                <span class="name">{{savedUser.USER_FULLNAME}}</span><br/>
                <span class="email">{{savedUser.USER_NAME | extraWrap}}</span>
              </div>
            </div>
            <p ng-show="!savedUser">
              <i class="icon-envelope color-gray-6 form-field-icon"></i>
              <input type="text" name="username" class="input large with-icon" ng-disabled="verifying"
                  ng-model="creds.username" inputmode="email" autocorrect="off" autocapitalize="off" autocomplete="on" placeholder="{{i18n.authentication['email-placeholder']()}}" style="width: 100%;" dm-autofocus="{{!savedUser && !inIframe}}" />
            </p>
            <p>
              <i class="icon-key color-gray-6 form-field-icon"></i>
              <input type="password" name="password" class="input large with-icon" ng-disabled="verifying"
                  ng-model="creds.password" autocomplete="on" placeholder="{{i18n.authentication['password-placeholder']()}}" style="width: 100%;" dm-autofocus="{{!!savedUser}}" />
            </p>

            <div class="login-btn"><db-button theme="primary" size="large" name="submit" class="sign-in"
                ng-disabled="verifying" style="margin-right: 3px;">{{i18n.authentication['sign-in']()}}</db-button></div>
            <div class="margin-top-xsmall text-align-center" ng-show="view.showSSOBackButton">
              <a ng-click="setView('sso-signin'); showSSOBackButton(false);">{{i18n.authentication['back-to-single-sign-on']()}}</a>
            </div>

            <div class="footer">
              <div class="float-right" style="line-height: 33px;">
                <a ng-click="setView('forgot')" class="font-size-small">{{i18n.authentication['forgot-password']()}}</a>
              </div>
                              <db-checkbox ng-model="ctrls.rememberMe">{{i18n.authentication['remember-me']()}}</db-checkbox>
                          </div>
          </form>

          <!-- two-factor validation without phone -->
          <div ng-switch-when="two-factor-without-phone">
            <p style="font-size: 15px; margin-top: 8px;">{{i18n.authentication['two-factor-instructions']()}}</p>
            <div class="sign-in entry footer">
              <a ng-click="setView('login')" class="font-size-small">{{i18n.authentication['back-to-sign-in']()}}</a>
            </div>
          </div>

          <!-- two-factor code -->
          <form ng-switch-when="two-factor-validate" ng-submit="validateTwoFactor()" ng-disabled="verifying">
            <p>
              <i class="icon-key color-gray-6 form-field-icon"></i>
              <input type="text" name="code" class="input large with-icon" ng-disabled="verifying" dm-autofocus="true"
                  ng-model="twoFactor.code" autocomplete="off" placeholder="{{ :: i18n.authentication['enter-code']() }}" style="width: 100%;" />
            </p>
            <p style="font-size: 15px; margin-top: 8px;">
              {{textWithCodeSentText}}
            </p>
            <db-button theme="primary" size="large" style="width: 100%; margin-left: 0;"
              ng-disabled="!twoFactor.code || verifying">{{i18n.authentication['verify']()}}</db-button>

            <div class="sign-in entry footer">
              <input id="RememberDevice" class="input" type="checkbox" ng-model="twoFactor.remember">
              <label for="RememberDevice" class="remember-device">{{i18n.authentication['remember-device']()}}</label>
            </div>
            <div>
              <div>

                <a ng-click="send2FactorEmail()" class="font-size-small">
                  {{i18n.authentication['send-2factor-email']() || 'Send me the code in email'}}
                  <i class="icon-check" style="color: #00aa00; margin-left: 5px; font-size: 16px;" ng-if="send2FactorEmailSent"></i>
                </a>
                <div class="no-multifactor-code inline text-align-right">
                  <a href="#" ng-click="showTwoFactorFailureAlert()" class="font-size-small"> {{ i18n.authentication['two-factor-no-code']() }} </a>
                </div>
              </div>
              <a ng-click="usesSsoSignin ? setView('sso-signin') : setView('login')" class="font-size-small">{{i18n.authentication['back-to-sign-in']()}}</a>
            </div>
            <div ng-if="twoFactorFailure.showAlert">
              <div class="alert-banner">
                <i class="icon-x close" ng-click="hideTwoFactorFailureAlert()"></i>
                <strong>{{ i18n.authentication['two-factor-no-code-alert-head']() }}</strong> <br> {{ i18n.authentication['two-factor-no-code-text']() }}
              </div>
            </div>
          </form>

          <!-- two-factor failure -->
          <form ng-switch-when="two-factor-fail" ng-disabled="true">
            <db-button theme="primary" size="large" ng-click="usesSsoSignin ? setView('sso-signin') : setView('login')"  style="width: 100%; margin: 20px 0 0 0;">{{i18n.authentication['back-to-sign-in']()}}</db-button>
          </form>

          <!-- forgot my password -->
          <div ng-switch-when="forgot" class="password-reset">
            <form ng-submit="sendReset()">
              <p style="font-size: 15px; margin-top: 8px;">
                {{i18n.authentication['forgot-password-instructions']()}}</p>
              <p>
                <i class="icon-envelope color-gray-6 form-field-icon"></i>
                <input type="text" id="email" name="email" class="input large with-icon" ng-model="creds.username"
                  placeholder="{{i18n.authentication['email-placeholder']()}}" style="width: 100%;" />
              </p>

              <db-button theme="primary" size="large" style="width: 100%; margin-left: 0;">{{i18n.authentication['request-reset-link']()}}</db-button>

              <div class="sign-in entry footer">
                <a ng-click="setView('login')" class="font-size-small">{{i18n.authentication['back-to-sign-in']()}}</a>
              </div>
            </form>
          </div>

          <!-- reset password -->
          <div ng-switch-when="reset">
            <div class="password-reset" ng-if="view.active=='reset'" ng-controller="PasswordReset">

              <!-- show the user -->
              <div class="saved-user-panel" ng-if="resetUser">
                <img class="avatar" width="48" height="48" style="float: left;"
                  ng-src="/avatar/thumb/{{resetUser.USER_ID}}" />
                <div style="margin-left: 60px;">
                  <span class="name">{{resetUser.USER_FULLNAME}}</span><br/>
                  <span class="email">{{resetUser.USER_NAME}}</span>
                </div>
              </div>

              <!-- reset the password -->
              <form ng-submit="resetPassword()">
                <div class="password entry">
                  <p style="white-space: nowrap;">
                    <i class="icon-key color-gray-6 form-field-icon"></i>
                    <input type="password" ng-model="passwords.pass1" class="input large with-icon" ng-disabled="resetting"
                        placeholder="{{i18n.authentication['enter-password']()}}" style="width: 100%;" ng-blur="validatePasswords()"/>
                    <i class="icon-check" style="color: #00aa00; margin-left: 5px;" ng-if="passwordsValid"></i>
                  </p>
                </div>
                <div class="password entry">
                  <p style="white-space: nowrap;">
                    <i class="icon-key color-gray-6 form-field-icon"></i>
                    <input type="password" ng-model="passwords.pass2" class="input large with-icon" ng-disabled="resetting"
                        placeholder="{{i18n.authentication['confirm-password']()}}" style="width: 100%;"/>
                    <i class="icon-check" style="color: #00aa00; margin-left: 5px;" ng-if="passwordsValid"></i>
                  </p>
                </div>
                <div class="sign-in entry">
                  <db-button theme="primary" size="large" name="submit" style="width:100%" ng-disabled="resetting">
                    {{resetting ? i18n.authentication['updating-password']() : buText }}
                  </db-button>
                </div>
              </form>
            </div>
          </div>

          <div ng-switch-when="easy-invite">
            <form ng-submit="tryEasyInviteUserCreate()">
              <div class="easy-invite">
                <p style="white-space: nowrap;">
                  <input
                    type="text"
                    ng-disabled="easyInvite.verifying"
                    class="input large"
                    autocomplete="name"
                    dm-autofocus="true"
                    placeholder="{{i18n.authentication['name']()}}"
                    ng-model="easyInvite.fullName"
                    style="width: 100%;"/>
                </p>
                <p style="white-space: nowrap;">
                  <input
                    type="text"
                    ng-disabled="easyInvite.verifying"
                    class="input large"
                    autocomplete="email"
                    placeholder="{{i18n.authentication['email-placeholder']()}}"
                    ng-model="easyInvite.email"
                    style="width: 100%;"/>
                </p>
                <div class="login-btn">
                  <db-button
                    theme="primary"
                    size="large"
                    ng-click="tryEasyInviteUserCreate()"
                    class="sign-in"
                    style="margin-right: 3px;"
                    ng-disabled="easyInvite.verifying">
                      {{i18n.authentication['verify-email']()}}
                  </db-button>
                </div>
              </div>
            </form>
          </div>

          <!-- Easy invite success -->
          <div ng-switch-when="easy-invite-success">
            <form>
              <p style="font-size: 15px; margin-top: 8px;">
                {{ i18n.authentication['invite-incoming']() }}
              </p>
            </form>
          </div>

          <!-- expired invite link -->
          <div ng-switch-when="easy-invite-expired">
            <p style="font-size: 15px; margin-top: 8px; text-align: center">
              {{i18n.authentication['expired-invite-link']()}}
            </p>
          </div>

          <!-- reset an expired password -->
          <div ng-switch-when="resetExpired">
            <div class="password-reset" ng-if="view.active=='resetExpired'" ng-controller="ExpiredPasswordReset">

              <!-- reset the password -->
              <form ng-submit="resetExpiredPassword()">
                <div class="password entry">
                  <p>
                    <i class="icon-key color-gray-6 form-field-icon"></i>
                    <input type="password" ng-model="oldPass" class="input large with-icon" ng-disabled="resetting"
                           placeholder="{{i18n.authentication['current-password']()}}" style="width: 100%;"/>
                  </p>
                </div>
                <div class="password entry">
                  <p style="white-space: nowrap;">
                    <i class="icon-key color-gray-6 form-field-icon"></i>
                    <input type="password" ng-model="passwords.pass1" class="input large with-icon" ng-disabled="resetting"
                           placeholder="{{i18n.authentication['new-password']()}}" ng-blur="validatePasswords()" style="width: 100%;"/>
                    <i class="icon-check" style="color: #00aa00; margin-left: 5px;" ng-if="passwordsValid"></i>
                  </p>
                </div>
                <div class="password entry">
                  <p style="white-space: nowrap;">
                    <i class="icon-key color-gray-6 form-field-icon"></i>
                    <input type="password" ng-model="passwords.pass2" class="input large with-icon" ng-disabled="resetting"
                           placeholder="{{i18n.authentication['confirm-new-password']()}}" style="width: 100%;"/>
                    <i class="icon-check" style="color: #00aa00; margin-left: 5px;" ng-if="passwordsValid"></i>
                  </p>
                </div>
                <div class="sign-in entry">
                  <db-button theme="primary" size="large" name="submit" style="width:100%" ng-disabled="resetting">
                    {{resetting ? i18n.authentication['updating-password']() : buText }}
                  </db-button>
                </div>
              </form>
            </div>
          </div>

          <!-- signout -->
          <div ng-switch-when="signout">
            <h4>{{i18n.authentication['to-complete-signing-out']()}}</h4>
            <db-button theme="primary" size="large" onclick="window.location = '/';" style="width:100%;">{{i18n.authentication['go-to-sign-in']()}}</db-button>
          </div>

          <!-- sso sign in failure -->
          <div ng-show="notInvited">
              <div class="inset-container">{{i18n.authentication['sso-no-access']()}}</div>
              <div class="samlErrors clickable margin-top-xxsmall" ng-show="false" ng-click="showMessage = !showMessage" ng-class="{'in': showMessage}">
                {{i18n.authentication['show-more-saml-error-details']()}} <i class="icon-caret-down"></i>
              </div>
              <div class="samlErrors" ng-show="false && showMessage">
                  {{i18n.authentication['saml-error']()}}: null
              </div>
          </div>

          <div ng-show="(view.active === 'sso-signin' || view.active === 'sso-signout') && !notInvited">
            <div class="inset-container border-radius-medium margin-bottom-small" ng-show="view.active === 'sso-signout'">
              <span class="font-weight-bold">{{i18n.authentication['you-have-logged-out']()}}</span>
              <p class="margin-bottom-none">{{i18n.authentication['return-using-identity-provider']()}}</p>
            </div>
            <div>
              <db-button theme="primary" size="large" onclick="window.location = '/auth/sso-signin';" style="width:100%;">{{i18n.authentication['sign-in']()}}</db-button>
              <div class="margin-top-xsmall text-align-center" style="width: 100%;">
                <a ng-show="null" ng-click="setView('login'); showSSOBackButton(true);">{{i18n.authentication['use-direct-sign-on']()}}</a>
              </div>
            </div>
          </div>

          <div class="change-domain-btn margin-top-large show-when-electron">
            <button class="db-button" id="changeDomainBtn" style="margin-right: 3px; font-size: 13.4px; min-width: auto; padding: 12px 16px;">{{i18n.authentication['chose-another-domain']()}}</button>
          </div>
          <!-- service terms -->
          <div>
            <span ng-if="!((true || false) && showAdBasedLogin) || !isUserLocaleOn" class="font-size-small inline-block {{ twoFactorFailure.showAlert?'':'margin-top-large' }}" ng-bind-html="serviceAgreeementMarkup"></span>
            <div ng-if="isUserLocaleOn && view.active !== two-factor-validate" class="show-on-xsmall language-select" ng-class="{'margin-top-medium': !((true || false) && showAdBasedLogin)}" db-dropdown class="inline-block" items="bits.dropdownItems" selected-item="bits.dropdownSelectedItem" on-item-selected="bits.dropdownSelect(item)">
              <db-dropdown-button action-button="false" class="localization-button db-button" theme="alt"><i class="icon-webpage"></i><span>{{bits.dropdownSelectedItem.label}}</span></db-dropdown-button>
              <db-dropdown-basic-list></db-dropdown-basic-list>
            </div>
          </div>

        </div>
      </div> <!-- form-container -->
      <svg class="vertical-bar" ng-if="(true || false) && showAdBasedLogin" height="466px" width="1px">
        <rect height="466px" width="1px" fill="#D8D8D8"/>
      </sgv>
      <div class="marketing-container" ng-if="(true || false) && showAdBasedLogin">
        <a href="{{adBaseLink}}" target="_blank">
          <div class="marketing-content" style="background-size:contain;" background-image="adBaseImage">
          </div>
        </a>
      </div>
    </div>

    <div class="footer-wrapper text-align-center" ng-show="view.isCustomerWhitelabeled">
      <div>
        <span class="text-transform-uppercase color-gray-5 font-size-small">{{i18n.authentication['powered-by']()}}</span><br/>
        <img src="/public/images/logo-400.png" class="vertical-align-middle margin-top-xsmall" width="50" height="50" alt="">
      </div>
    </div>
  </div>
  <div class="outside-the-white white-text hide-on-xsmall flex" ng-if="isUserLocaleOn">
    <div class="language-select hide-on-xsmall" db-dropdown class="inline-block" items="bits.dropdownItems" selected-item="bits.dropdownSelectedItem" on-item-selected="bits.dropdownSelect(item)">
      <db-dropdown-button action-button="false" class="localization-button db-button" theme="inverse-alt"><i class="icon-webpage"></i><span>{{bits.dropdownSelectedItem.label}}</span></db-dropdown-button>
      <db-dropdown-basic-list></db-dropdown-basic-list>
    </div>
    <div ng-if="(true || false) && showAdBasedLogin" class="service-agreement">
      <span class="font-size-small inline-block" ng-bind-html="$parent.serviceAgreeementMarkup"></span>
    </div>
  </div>
</div>

<!-- Compatibility Modal -->
<div id="CompatibilityModal" class="compatibility-modal-backdrop" style="display: none;">
  <div class="compatibility-modal-container">
    <div class="compatibility-modal-header">
      <div class="compatibility-modal-title" id="CompatibilityModalTitle">This product does not support your browser. Upgrade!</div>
    </div>
    <div class="compatibility-modal-browser">
      <a href="https://www.google.com/chrome">
        <div class="browsers-chrome"></div>
      </a><br/>
      <a href="https://www.google.com/chrome">Chrome</a>
    </div>
    <div class="compatibility-modal-browser">
      <a href="https://www.mozilla.org/en-US/firefox/new/">
        <div class="browsers-firefox"></div>
      </a><br/>
      <a href="https://www.mozilla.org/en-US/firefox/new/">Firefox</a>
    </div>
    <div class="compatibility-modal-browser">
      <a href="https://www.microsoft.com/en-us/windows/microsoft-edge">
        <div class="browsers-ie"></div>
      </a><br/>
      <a href="https://www.microsoft.com/en-us/windows/microsoft-edge">IE 10+</a>
    </div>
  </div>
</div>
<!-- service terms -->
<script>
"use strict";
(function() {

  var locale = ('ja-JP' !== 'null') ? "ja-JP" : (window.navigator.userLanguage || window.navigator.language);
  var ngApp;
  var localStorage = getLocalStorage();
  var location = window.location;
  var redirectUrl = "/" || "/";
  var featureAdBasedLogin = true;
  var featureAdBasedLoginTest = false;
  var emailRegex = /^[^@(\s)]+@[^@(\s)]+\.[^@(\s)]{2,}$/;

  // enable custom backgrounds for whitelabeled customers
  if(locale && locale.toLowerCase() === 'en-us' && !/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) && location.host.search(/ccna|coca-cola/) > -1) {
    $('body').addClass('custom-bg');
  }

  //fix loading classes
  $('.display-while-loading').remove();
  $('.hidden-while-loading').removeClass('hidden-while-loading');

    function supports_history_api() {
        return !!(window.history && history.pushState);
    }

  ngApp = angular.module('login',['domobits']).config(function ($provide, $httpProvider, $locationProvider) {
    if(window.InteractionHelper) {
      window.InteractionHelper.registerAngularProviders('login', $provide, $httpProvider);
    }
    if (supports_history_api()) {
        $locationProvider.html5Mode(true);
    }

  }).run(function($rootScope, $location) {
      $rootScope.bits = {};
      $rootScope.isUserLocaleOn = true;
      if ($rootScope.isUserLocaleOn) {
        var locales = [{"name":"English","currentName":"英語","country":"United States","languageCode":"en","countryCode":"US","code":"en-US","betaTag":false}, {"name":"Deutsch","currentName":"ドイツ語","country":"Deutschland","languageCode":"de","countryCode":"DE","code":"de-DE","betaTag":true}, {"name":"français","currentName":"フランス語","country":"France","languageCode":"fr","countryCode":"FR","code":"fr-FR","betaTag":true}, {"name":"日本語","currentName":"日本語","country":"日本","languageCode":"ja","countryCode":"JP","code":"ja-JP","betaTag":false}, {"name":"中文","currentName":"中国語","country":"中国","languageCode":"zh","countryCode":"CN","code":"zh-CN","betaTag":true}];
        $rootScope.bits.dropdownItems = getLocales(locales);
        $rootScope.bits.dropdownSelectedItem = getSelectedLocale($rootScope.bits.dropdownItems);
        $rootScope.bits.dropdownSelect = function (e){
            $location.search('lang', e.code);
            window.location.reload();
        };
      }
  });
  function getLocales(locales) {
      var newLocales = [];
      locales.forEach(function(locale) {
        locale.name = locale.name.charAt(0).toUpperCase() + locale.name.slice(1);
        var label = locale.name;
        if (locale.betaTag) {
            label += ' [BETA]';
        }
        locale.label = label;
        newLocales.push(locale);
      });
      return newLocales;
  }
  function getSelectedLocale(locales) {
      var currentLocale = ('ja-JP' !== 'null') ? "ja-JP" : (window.navigator.userLanguage || window.navigator.language);
      for(var i = 0; i < locales.length; i++) {
          var locale = locales[i];
          if (locale.code.toLowerCase() === currentLocale.toLowerCase()) {
              return locale;
          }
      };
      return locales[0];
  }

  // set the 'justSignedIn' flag to false (not doing so can cause us to calculate incorrect durations that get sent
  // into the /clog endpoint).  Instead, set it to "true" after actually successfully authenticating just before
  // redirecting to the initial/requested page
  localStorage.setItem('justSignedIn', 'false');

  //Workaround for people using the app in safari Private Browsing Mode
  function getLocalStorage(){
    var LS;
    try{LS = window.localStorage}catch(e){LS = {};}
    var randomKey = Math.random().toString(36).substring(7);
    try{
      LS[randomKey] = "LS_TEST:"+randomKey;
      delete LS[randomKey];
    }catch(e){
      LS = {
        getItem: function(key){ return this[key]},
        setItem: function(key, val){ this[key] = val},
        removeItem: function(key){delete this[key]}
      };
    }
    return LS;
  }

  // We will read this time in interaction helper on the next page load to time the "first page load" experience
  function recordSignInStartTime() {
    localStorage.setItem('signInStartTime', new Date().getTime());
  }

  // parse the query string
  var urlParams = _.chain(location.search.substring(1).split('&')).map(function(pair) {
    var parts = pair.split('=');
    if ( parts[1] ) {
      parts[1] = decodeURIComponent(parts[1].replace(/\+/g," "));
      return parts;
    } else {
      return null;
    }
  }).compact().object().value();

  // #### LoginMain ####
  ngApp.controller('LoginController',function($scope,$http,$sce,i18n,$location,$timeout) {
    $scope.setView = setView;
    $scope.showSSOBackButton = showSSOBackButton;

    $scope.inIframe = window.parent !== window;
    $scope.cacheHash = Date.now();
    $scope.creds = {};
    $scope.twoFactor = {
      remember: true
    };
    $scope.view = {
      visible: true,
      customerHash: false,
      isCustomerWhitelabeled: false,
      showSSOBackButton: false,
      easyInvite: false,
      easyInviteSuccess: false
    };
    $scope.showAdBasedLogin = false;

    if (featureAdBasedLogin) {
      adobeTestAndTarget();
    } else if (featureAdBasedLoginTest) {
      adobeTestAndTarget(true);
    }
    doElectronStuff();

    $scope.notInvited = 'null' === 'true';
    $scope.i18n = i18n;
    $scope.locale = locale;
    var termsURL = 'https://www.domo.com/company/service-terms';

    $scope.twoFactorFailure = { showAlert: false};

    //Japanese TOS shipped with this URL already. Future lang TOS URL should be 'locale-lang' Ex: 'en-US'
    if ($scope.locale ==='ja-JP'){
      termsURL = 'https://www.domo.com/jp/company/service-terms';
    } else if ($scope.locale !=='en-US') {
      termsURL = 'https://www.domo.com/' + $scope.locale + '/company/service-terms'; //
    }
    var patentUrl = 'https://www.domo.com/company/patents';

    var serviceAgreeementMarkup = i18n.authentication['service-agreement']({
      startLink: '<a href="' + termsURL + '">',
      endLink: '</a>',
      startPatentLink: '<a href="' + patentUrl + '">',
      endPatentLink: '</a>',
    });
    $scope.serviceAgreeementMarkup = $sce.trustAsHtml(serviceAgreeementMarkup);
    $scope.usesSsoSignin = null;

    // this sets the above text to say "sign up" instead of "sign in"
    function resetServiceAgreementText() {
      var serviceAgreeementMarkup = i18n.authentication['service-agreement-signup']({
        startLink: '<a href="' + termsURL + '">',
        endLink: '</a>',
        startPatentLink: '<a href="' + patentUrl + '">',
        endPatentLink: '</a>',
      });
      $scope.serviceAgreeementMarkup = $sce.trustAsHtml(serviceAgreeementMarkup);
    }

    // read the current state from the local storage
    try {
      $scope.savedUser = JSON.parse(localStorage.getItem('RememberMe'));
      $scope.savedUser = _.isObject($scope.savedUser) ? $scope.savedUser : null;
    } catch(e) {}

    try {
      $scope.customerConfig = JSON.parse(localStorage.getItem('CustomerConfig'));
      $scope.customerConfig = _.isObject($scope.customerConfig) ? $scope.customerConfig : null;
    } catch(e) {}

    // remove the cloak because we know that angular is properly running at this point
    $("#Cloak").show();
    // set the initial active view
    if ( location.pathname.indexOf('/password/') == 0 ) {
      $scope.view.active = 'reset';
    } else if ( location.pathname.indexOf('/forgot') != -1 ) {
      $scope.view.active = 'forgot';
    } else if ( location.pathname.indexOf('/signout') != -1 ) {
      $scope.view.active = 'signout';
    } else if ( location.pathname.indexOf('/sso-signout') != -1 ) {
      $scope.view.active = 'sso-signout';
    } else if ( location.pathname.indexOf('/tfvalidate') != -1 ) {

      $scope.view.active = 'two-factor-validate';
      $scope.textMessageWithCodeSentText = i18n.authentication['we-sent-a-text-with-code']({ phoneNumber: $scope.twoFactor.phoneMask });
    } else if(null === true) {
      if (null && $scope.customerConfig && $scope.customerConfig.useDirectSignOn) {
        $scope.view.active = 'login';
        showSSOBackButton(true);
      } else {
        $scope.view.active = 'sso-signin';
      }
    } else if(location.pathname.indexOf('/invite') != -1){

      resetServiceAgreementText();

      validateEasyInvite().then(function(validEasyLink){
        if(validEasyLink === true){
          $scope.view.active = 'easy-invite';
          $scope.view.easyInvite = true;
          setupEasyInviteScope();
        }else{
          $scope.view.active = 'easy-invite-expired';
        }
      });
    }else{
      $scope.view.active = 'login';
    }

    $scope.ctrls = { rememberMe: !!$scope.savedUser };
    $scope.creds.username = $scope.savedUser && $scope.savedUser.USER_NAME || urlParams.username;

    $scope.view.customerHash = $scope.customerConfig && $scope.customerConfig.customerHash;
    $scope.view.isCustomerWhitelabeled = $scope.customerConfig && $scope.customerConfig.isCustomerWhitelabeled;

    if($scope.view.isCustomerWhitelabeled && $scope.customerConfig.whitelabeledProductName) {
      document.title = $scope.customerConfig.whitelabeledProductName;
    }

    var externalLoginFailure = 'null';
    if(externalLoginFailure.length && externalLoginFailure !== 'null') {
      var failure = JSON.parse(externalLoginFailure);
      $scope.creds.username = failure.username;
      handleLoginFailure({data: failure.data});
    }

    $scope.send2FactorEmail = function() {
      $scope.send2FactorEmailSent = false;

      var qs = _.pick(urlParams,'domoUserId','resetToken','role');
      var backupUserID = '';

      var body = undefined;
      var url = '/api/identity/v1/authentication/twoFactorEmail';

      if ($scope.creds.username) {
        body = $scope.creds.username;
      } else if ((qs.domoUserId !== null && qs.domoUserId !== undefined && qs.domoUserId) || backupUserID) {
        body = qs.domoUserId || backupUserID;
        url = '/api/identity/v1/authentication/twoFactorEmailByUserId'
      }
      $http.post(url, body, {

        headers: {
            'content-type': 'application/json'
        }
      }).then(function(resp) {
        $scope.$applyAsync(function() {
          $scope.send2FactorEmailSent = true;
        });
      });
    };

    $scope.showTwoFactorFailureAlert = function(){
      $scope.twoFactorFailure.showAlert = true;
    };

    $scope.hideTwoFactorFailureAlert = function(){
      $scope.twoFactorFailure.showAlert = false;
    };

    // clear the saved user
    $scope.clearSavedUser = function() {
      $scope.savedUser = null;
      $scope.creds.username = "";
      $scope.clearLocalStorageData();
    }

    $scope.clearLocalStorageData = function () {
      delete localStorage.RememberMe;
      delete localStorage.CustomerConfig;
    }

    $scope.validateTwoFactor = function() {
      if (!$scope.verifying) {
        recordSignInStartTime(); // Reset the start time again because we were waiting on user input

        $scope.view.message = null;
        $scope.failure = false;
        $scope.verifying = true;

        var body = {
          token: $scope.twoFactor.token,
          code: $scope.twoFactor.code,
          remember: $scope.twoFactor.remember
        };

        $http.post('/api/domoweb/auth/validateTwoFactor', body).then(function(resp) {
          completeLogin($scope, resp.data);

        }, function(resp) {
          $scope.verifying = false;

          if (resp.data.twoFactorInfo) {
            if (resp.data.twoFactorInfo.status == 'INVALID_CODE' ||
              resp.data.twoFactorInfo.status == 'REQUIRES_CODE') {
              $scope.view.message = i18n.authentication['verification-code-incorrect']();

            } else if (resp.data.twoFactorInfo.status == 'EXPIRED_CODE') {
              $scope.view.message = i18n.authentication['verification-code-expired']();
              $scope.view.active = 'two-factor-fail';
            }
          } else {
            $scope.view.message = i18n.authentication['verification-code-failed']();
            $scope.view.active = 'two-factor-fail';
          }
        });
      }
    };

    // attempt to login
    $scope.submit = function() {
      if ( !$scope.verifying ) {
        recordSignInStartTime();

        $scope.view.message = null;
        $scope.failure = false;
        $scope.verifying = true;

        // do not set the cookie if there is a redirect
        var body = _.clone($scope.creds);
        var redirectUrl = urlParams.url;
        if ( redirectUrl )
          body.nocookie = true;

        // base64 encode the password so it doesn't show in plaintext in the Network panel of
        // browser dev tools.  This should not be looked at as some sort of robust security measure
        if ( window.btoa ) {
          body.base64 = true;
          body.password = window.btoa(body.password);
        }
        var isUserLocaleOn = true;
        if (isUserLocaleOn) {
          body.locale = ('ja-JP' !== 'null') ? "ja-JP" : (window.navigator.userLanguage || window.navigator.language);
        }

        // login domo
        $http.post('/api/domoweb/auth/login', body).then(
          function(resp) {
            completeLogin($scope, resp.data);
          },
          handleLoginFailure
        );
      }
    }

    // clear the saved user if the username changes
    $scope.$watch('creds.username',function(val) {
      if ( $scope.savedUser && $scope.savedUser.USER_NAME != val ) {
        $scope.clearSavedUser();
        $scope.creds.username = val;
      }
    });

    // send a reset email
    $scope.sendReset = function() {
      if (!$scope.creds.username) {
        $scope.view.message = i18n.authentication['missing-email']();
      } else {
        $scope.view.message = null;
        $scope.setView('login', i18n.authentication['password-reset-email-sent'](), true);
        var locale = ('ja-JP' !== 'null') ? "ja-JP" : (window.navigator.userLanguage || window.navigator.language);
        $http.get('/api/domoweb/auth/sendReset',{params:{email:$scope.creds.username, locale: locale}});
      }
    };

    function isEmulatingElectron() {
      return location.search.indexOf('?_f=emulate-electron') > -1;
    }

    function isElectron() {
      return window.buzztron ||
        isEmulatingElectron() ||
        /* the following methods of testing for electron are deprecated */
        window.isBuzzDesktop ||
        window.process && window.process.versions && window.process.versions.electron != undefined;
    }

    function doElectronStuff(){
      if(isElectron()) {
        $scope.loggingInto = i18n.authentication['logging-into']({ domainName: $location.host() });
        redirectUrl = '/buzz';
        if(isEmulatingElectron()) {
          document.body.classList.add('electron');
        }
      }
    }

    function adobeTestAndTarget(isTest) {
      // don't load on smaller screens
      if (window.innerWidth >= 768) {
        window.adobe.target.getOffer({
          mbox: isTest === true ? 'loginPageEventBoardTest' : 'loginPageEventBoard',
          params: {'lang': locale},
          success: function(response) {
            if(response && response.length > 0 && response[0].content) {
              try {
                var json = JSON.parse(response[0].content);
                $scope.adBaseImage = json.imgUrl;
                $scope.adBaseLink = json.link;
                $scope.showAdBasedLogin = true;
              } catch(err) {
                $scope.showAdBasedLogin = false;
              }
            } else {
              $scope.showAdBasedLogin = false;
            }
            $scope.$apply();
          },
          error: function(status, response) {
            $scope.showAdBasedLogin = false;
            console.warn('error');
          }
        });
      } else {
        $scope.showAdBasedLogin = false;
      }
    }

    function showSSOBackButton(value) {
      $scope.view.showSSOBackButton = value;
    }

    // switch the active view
    function setView(view,message,notice) {
      $scope.view.visible = true;
      $scope.view.active = view || $scope.view.active;
      $scope.view.message = message;
      $scope.view.notice = notice;
    }

    function handleLoginFailure(resp) {
        if ( resp.data && resp.data.twoFactorInfo) {
          handleTwoFactorResponse($scope, resp.data.twoFactorInfo);

        } else if ( resp.data.reason && resp.data.reason === "passwordExpired" ) {
          $scope.view.active = 'resetExpired';

        } else {
          $scope.view.message = i18n.authentication['login-failed']();
        }
        $scope.verifying = false;
    }

    function easyInviteErrorsDefault(){
      $scope.easyInvite.errors = {
        invalidEmail: false,
        noEmail: false,
        invalidName: false,
        emailProvider: false,
        emailInUse: false
      }
    }

    function setupEasyInviteScope(){
      $scope.easyInvite = {
        fullName: '',
        email: '',
        errors: {},
        verifying: false
      };
      $scope.tryEasyInviteUserCreate = function(){
        easyInviteErrorsDefault();
        setEasyInviteErrorMessage();
        var params = {
          displayName: $scope.easyInvite.fullName,
          emailAddress: $scope.easyInvite.email,
          easyInviteGuid: urlParams['easy-invite']
        };
        if(urlParams['bz-channel']){
          params['bz-channel'] = urlParams['bz-channel'];
        }
        var tryInvite = false;
        var easyInviteGoUrl = '/auth/invite/go/'
                              + params.displayName+'/'
                              + params.emailAddress+'/'
                              + params.easyInviteGuid ;
        if(params['bz-channel']){
          easyInviteGoUrl += '/' + params['bz-channel'];
        }
        $scope.easyInvite.errors.invalidEmail = !validateEasyInviteEmail();
        $scope.easyInvite.errors.noEmail = !$scope.easyInvite.email.trim().length;
        $scope.easyInvite.errors.invalidName = !validateEasyInviteName();
        tryInvite = !($scope.easyInvite.errors.invalidEmail
                    || $scope.easyInvite.errors.invalidName);
        if(tryInvite){
          $http.post(easyInviteGoUrl).then(function(res){
            $scope.view.active = 'easy-invite-success';
          }).catch(function(err){
            if(err.status === 409){
              $scope.easyInvite.errors.emailInUse = true;
            }else if(err.status === 403){
              $scope.easyInvite.errors.emailProvider = true;
            }
          }).finally(function(){
            $scope.easyInvite.verifying = false;
            setEasyInviteErrorMessage();
          });
          $scope.easyInvite.verifying = true;
        }else{
          setEasyInviteErrorMessage();
        }
      };

    }

    function setEasyInviteErrorMessage(){
      var messageToShow;
      if($scope.easyInvite.errors.invalidName){
        messageToShow = i18n.authentication['name-required']();
      }else if($scope.easyInvite.errors.noEmail){
        messageToShow = i18n.authentication['email-required']();
      }else if($scope.easyInvite.errors.invalidEmail){
        messageToShow = i18n.authentication['invalid-email']();
      }
      if($scope.easyInvite.errors.emailInUse){
        messageToShow = i18n.authentication['invalid-email-address']();
      }
      if($scope.easyInvite.errors.emailProvider){
        messageToShow = i18n.authentication['invalid-email-address']();
      }
      $scope.view.message = messageToShow;
    }

    function validateEasyInviteEmail(){
      var isValid = emailRegex.test($scope.easyInvite.email);
      return isValid;
    }

    function validateEasyInviteName(){
      var isValid = !!$scope.easyInvite.fullName.trim().length;
      return isValid;
    }

    function validateEasyInvite(){
      var inviteGuid = urlParams['easy-invite'];
      if(!inviteGuid){
        window.location = '/';
        return null;
      }else{
        return $http.get('/auth/invite/'+inviteGuid)
          .then(function (resp){
            return resp.data === "true";
          }).catch(function(err){
            return false;
          });
      }
    }

  });

  ngApp.directive('backgroundImage', function() {
    return {
      restrict: 'A',
      scope: {
        bgImgUrl: '=backgroundImage',
      },
      link: function(scope, elem) {
        scope.$watch('bgImgUrl', function(_new, _old) {
          elem.css('background-image', 'url(' + _new + ')');
          elem.css('background-repeat', 'no-repeat');
        });
      }
    }
  });

  // #### PasswordReset ####
  ngApp.controller('PasswordReset',function($scope,$http, i18n) {
    $scope.buText = (location.pathname.indexOf('/reset') != -1) ? i18n.authentication['reset-your-password']() : i18n.authentication['create-your-account']();
    $scope.view.visible = false;
    $scope.passwords = {};
    $scope.passwords.pass1 = $scope.passwords.pass2 = "";

    // load the reset state
    var qs = _.pick(urlParams,'domoUserId','resetToken','role','login');

    if(qs.role == 'Social') {
      $scope.buText = i18n.authentication['lets-domo']();
    }
    $http.get('/api/domoweb/auth/verifyReset',{params:qs}).then(function(resp) {
      var viewText;
      if(qs.role != 'Social') {
        viewText = i18n.authentication['enter-and-confirm-password']();
      } else {
        viewText = i18n.authentication['youre-just-a-password-away']();
      }
      $scope.setView(null, viewText, true);
      $scope.view.showLogo = true;
      $scope.resetUser = resp.data;
    },function() {
      if (qs.login === 'true') {
        $scope.setView('login');
      } else {
        $scope.setView('forgot', i18n.authentication['reset-link-expired']());
      }
    });

    $scope.validatePasswords = function () {
      $scope.passwordsValid =  $scope.passwords.pass1 && $scope.passwords.pass2 &&
        $scope.passwords.pass1 === $scope.passwords.pass2;
    };

    $scope.$watch('passwords', $scope.validatePasswords, true);

    // send the password reset
    $scope.resetPassword = function() {
      if ( !$scope.resetting ) {

        // verify the inputs
        var password = $scope.passwords.pass1;
        if ( password != $scope.passwords.pass2 ) {
          $scope.setView(null, i18n.authentication['password-mismatched']());
        } else if ( !password ) {
          $scope.setView(null,null);

          // send the request
        } else {
          var body = _.defaults({password:password},qs);
          $scope.resetting = true;
          $http.post('/api/domoweb/auth/login',body).then(function(data) {
            completeLogin($scope, data.data);
          },function(resp) {
            if (resp.data.twoFactorInfo) {
              handleTwoFactorResponse($scope, resp.data.twoFactorInfo);

            } else {
              $scope.resetting = false;
              // if the description is paresable, we don't want to show it
              try {
                JSON.parse(resp.data.description);
                $scope.setView(null, i18n.authentication['password-reset-failed']());
              } catch (e) {
                $scope.setView(null, resp.data.description || i18n.authentication['password-reset-failed']());
              }
            }
          });
        }
      }
    }

  });

  ngApp.controller('ExpiredPasswordReset',function($scope,$http, i18n) {
    $scope.buText = i18n.authentication['reset-password']();
    $scope.view.message = i18n.authentication['password-expired']();
    $scope.oldPass = "";
    $scope.passwords = {};
    $scope.passwords.pass1 = $scope.passwords.pass2 = "";

    $scope.validatePasswords = function () {
      $scope.passwordsValid =  $scope.passwords.pass1 && $scope.passwords.pass2 &&
        $scope.passwords.pass1.trim() === $scope.passwords.pass2.trim();
    };

    $scope.$watch('passwords', $scope.validatePasswords, true);

    // send the expired reset request
    $scope.resetExpiredPassword = function () {
      if ( !$scope.resetting ) {

        // verify the inputs
        var password = $scope.passwords.pass1.trim();
        if ( password != $scope.passwords.pass2 ) {
          $scope.setView(null, i18n.authentication['password-mismatched']());
        } else if ( !password ) {
          $scope.setView(null,null);

          // send the request
        } else {

          $scope.resetting = true;

          var body = {
            emailAddress: $scope.creds.username,
            oldPassword: $scope.oldPass,
            password: password
          };

          $http.put('/api/domoweb/auth/reset-expired', body).then(function() {
            var loginBody = {
              username: $scope.creds.username,
              password: password
            };
            $http.post('/api/domoweb/auth/login',loginBody).then(function(resp) {
              completeLogin($scope, resp.data);

            },function(resp) {
              if (resp.data.twoFactorInfo) {
                handleTwoFactorResponse($scope, resp.data.twoFactorInfo);

              } else {
                $scope.view.message = i18n.authentication['login-failed']();
                $scope.verifying = false;
              }
            });

          }, function(resp) {
            $scope.resetting = false;
            $scope.setView(null, resp.data.description || i18n.authentication['password-reset-failed']());
          });
        }
      }

    }

  });

  function handleTwoFactorResponse($scope, twoFactorInfo) {
    $scope.twoFactor.token = twoFactorInfo.token;
    $scope.verifying = false;

    if (twoFactorInfo.status == 'REQUIRES_CODE') {
      $scope.twoFactor.phoneMask = twoFactorInfo.phoneMask;
      $scope.setView('two-factor-validate');

    } else if (twoFactorInfo.status == 'REQUIRES_PHONE') {
      $scope.setView('two-factor-without-phone')
    }
  }

  function completeLogin($scope, data) {
    if ( $scope.ctrls.rememberMe ) {
      localStorage.setItem('RememberMe' ,JSON.stringify(data.user));
      localStorage.setItem('CustomerConfig', JSON.stringify({
        customerHash: data.customerHash,
        isCustomerWhitelabeled: data.isCustomerWhitelabeled,
        whitelabeledProductName: data.whitelabeledProductName,
        useDirectSignOn: $scope.view.showSSOBackButton,
      }));
    } else {
      $scope.clearLocalStorageData();
    }

    // set the 'justSignedIn' flag
    localStorage.setItem('justSignedIn', 'true');
    if ( urlParams.url ) {
      window.location = redirectUrl + '?' + $.param({
        userId: data.user.USER_ID
      });
    } else if(urlParams['bz-channel']){
      window.location = '/buzz-link/'+urlParams['bz-channel'] + '?' + $.param({
        userId: data.user.USER_ID
      });
    }else{
      window.location = redirectUrl;
    }
  }

  ngApp.filter('extraWrap', function() {
    var zeroWidthSpace = '\u200b';
    return function(input) {
      return input.replace(/([A-Z]+|_|@|\.)/g, function (match) {
        return zeroWidthSpace + match;
      });
    };
  });

  ngApp.directive('dmAutofocus', function($timeout) {
    return function(scope, element, attrs) {
      if (attrs.dmAutofocus === 'true') {
        element[0].focus();
      }
    };
  });

  ngApp.constant('i18n', window.i18n);

})();
</script>
</body>
</html>

And sorry for the missing of the link, the broken link is https://github.com/domoinc/domo-java-sdk/blob/master/domo-java-sdk-all/src/test/java/com/domo/sdk/ClientTest.java Since I would like to export an existed dataset, I modified the ExportDataExample like this:

import java.io.File;
import java.io.IOException;
import com.domo.sdk.datasets.DataSetClient;
import com.domo.sdk.datasets.model.DataSet;

public class ExportDataExample extends ExampleBase{

  public void dataSetClient_smokeTest() throws IOException {
    setup();
    DataSetClient dsClient = client.dataSetClient();
//    String dataSetId = setupDataSet(dsClient);
    String dataSetId = "105d0c5a-2d4c-4200-8d19-80df4be25365";

    //Export to file
    File f = File.createTempFile("sample-export", ".csv");
    dsClient.exportDataToFile(dataSetId, true, f);
    System.out.println("Wrote out file:"+f.getAbsolutePath());
  }

  private String setupDataSet(DataSetClient dsClient) {
    //Create DS
    DataSet ds = CreateExample.create(dsClient);
    System.out.println("Created:"+ds);

    //Import DS
    String csvInput = "\"Pythagoras\"\n" +
            "\"Alan Turing\"\n" +
            "\"George Boole\"";
    dsClient.importData(ds.getId(), csvInput);

    return ds.getId();
  }

}

Thank you very much.

checketts commented 6 years ago

Something is very wrong here. Can you post a snippet of the code you are using (excluding your ids and secrets of course)? It is almost as though you set your customer domain as your API host.

TokitsuMaitsuru commented 6 years ago

Thank you very much for your reply. Here are my codes: test.java:

import java.io.IOException;
public class test {
    public static void main(String[] args) throws IOException{
        ExportDataExample exData = new ExportDataExample();
        exData.dataSetClient_smokeTest();
    }
}

ExampleBase.java:

import static com.domo.sdk.request.Scope.*;

import org.junit.Before;

import com.domo.sdk.DomoClient;
import com.domo.sdk.request.Config;

import okhttp3.logging.HttpLoggingInterceptor;

public class ExampleBase {

  public DomoClient client;
  public static final String MY_CLIENT_ID = "";
  public static final String MY_CLIENT_SECRET = "";
  public static final String MY_DOMO_PAGE = "";

  @Before
  public void setup() {
    Config config = Config.with()
            .clientId(MY_CLIENT_ID)
            .clientSecret(MY_CLIENT_SECRET )
            .apiHost(MY_DOMO_PAGE)
            .useHttps(true)
            .scope(USER, DATA)
            .httpLoggingLevel(HttpLoggingInterceptor.Level.BODY)
            .build();

    client = DomoClient.create(config);

  }

  public static String convertStreamToString(java.io.InputStream is) {
    @SuppressWarnings("resource")
    java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
    return s.hasNext() ? s.next() : "";
  }
}

ExportDataExample.java:

import java.io.File;
import java.io.IOException;

import com.domo.sdk.datasets.DataSetClient;

public class ExportDataExample extends ExampleBase{

  public void dataSetClient_smokeTest() throws IOException {
    setup();
    DataSetClient dsClient = client.dataSetClient();
//    String dataSetId = setupDataSet(dsClient);
    String dataSetId = "105d0c5a-2d4c-4200-8d19-80df4be25365";

    //Export to file
    File f = File.createTempFile("sample-export", ".csv");
    dsClient.exportDataToFile(dataSetId, true, f);
    System.out.println("Wrote out file:"+f.getAbsolutePath());
  }
}
checketts commented 6 years ago

Remove the .apiHost(MY_DOMO_PAGE) line. That should be api.domo.com (which is the default) Its purpose is if you need to call an alternative api endpoint (ie for testing or other needs)

TokitsuMaitsuru commented 6 years ago

Thank you very much. When I change the apiHost to api.domo.com, an error message comes out like this:


Logout
Exception in thread "main" com.domo.sdk.request.RequestException: Error making request url:https://api.domo.com/v1/datasets/105d0c5a-2d4c-4200-8d19-80df4be25365/data?includeHeader=true responseBody:<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Error 406 Not Acceptable</title>
</head>
<body><h2>HTTP ERROR 406</h2>
<p>Problem accessing /error. Reason:
<pre>    Not Acceptable</pre></p><h3>Caused by:</h3><pre>com.domo.bedrock.service.exception.UnauthorizedException: Full authentication is required to access this resource
    at com.domo.gateway.config.security.OAuthAuthenticationProvider.values(OAuthAuthenticationProvider.java:39)
    at com.domo.gateway.config.security.OAuthAuthenticationProvider.getCustomer(OAuthAuthenticationProvider.java:48)
    at com.domo.gateway.config.security.OAuthLoggingRequestFilter.doFilterInternal(OAuthLoggingRequestFilter.java:50)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter.doFilter(OAuth2AuthenticationProcessingFilter.java:176)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
    at com.domo.bedrock.maestro.web.ServiceLogFilter.doFilterInternal(ServiceLogFilter.java:141)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
    at com.domo.gateway.config.security.HttpRedirectionDetectionFilter.doFilterInternal(HttpRedirectionDetectionFilter.java:61)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
    at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:103)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
    at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
    at com.codahale.metrics.jetty9.InstrumentedHandler.handle(InstrumentedHandler.java:240)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
    at org.eclipse.jetty.server.handler.StatisticsHandler.handle(StatisticsHandler.java:159)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
    at org.eclipse.jetty.server.Server.handle(Server.java:499)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)
    at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)
    at java.lang.Thread.run(Thread.java:748)
</pre>
<hr><i><small>Powered by Jetty://</small></i><hr/>

</body>
</html>

    at com.domo.sdk.request.Transport.getCsv(Transport.java:110)
    at com.domo.sdk.datasets.DataSetClient.exportData(DataSetClient.java:151)
    at ExportDataExample.dataSetClient_smokeTest(ExportDataExample.java:18)
    at test.main(test.java:11)

And after I tried

dsClient.get(dataSetId)
dsClient.exportDataToFile(dataSetId,true, f);

the error message is like this:

Exception in thread "main" Logout
com.domo.sdk.request.RequestException: Error making request url:https://api.domo.com/v1/datasets/105d0c5a-2d4c-4200-8d19-80df4be25365 reponseBody:{"status":401,"statusReason":"Internal Server Error","path":"/v1/datasets/105d0c5a-2d4c-4200-8d19-80df4be25365","message":"com.domo.bedrock.service.exception.UnauthorizedException: Full authentication is required to access this resource","toe":"E03EECB7UF-G667I-N2F49"}
    at com.domo.sdk.request.Transport.getJson(Transport.java:41)
    at com.domo.sdk.datasets.DataSetClient.get(DataSetClient.java:61)
    at ExportDataExample.dataSetClient_smokeTest(ExportDataExample.java:19)
    at test.main(test.java:11)
checketts commented 6 years ago

Now it sounds like you might being using incorrect credentials. Keep in mind that API calls use OAuth and not your personal username/passord for Domo.

You should be able to access/create your credentials here: https://developer.domo.com/manage-clients

TokitsuMaitsuru commented 6 years ago

I see... I did use my personal username and password for Domo. Thank you very much for your kind help.