Exemplo n.º 1
0
    private SiteProject CreateProject(string projectName, string projectDescription)
    {
        //ref: http://onlinehelp.tableau.com/current/api/rest_api/en-us/help.htm#REST/rest_api_ref.htm#Create_Project%3FTocPath%3DAPI%2520Reference%7C_____12
        var sb        = new StringBuilder();
        var xmlWriter = XmlWriter.Create(sb, XmlHelper.XmlSettingsForWebRequests);

        xmlWriter.WriteStartElement("tsRequest");
        xmlWriter.WriteStartElement("project");
        xmlWriter.WriteAttributeString("name", projectName);
        xmlWriter.WriteAttributeString("description", projectDescription);
        xmlWriter.WriteEndElement(); //</project>
        xmlWriter.WriteEndElement(); // </tsRequest>
        xmlWriter.Close();

        var xmlText = sb.ToString(); //Get the XML text out

        //Generate the MIME message
        //var mimeGenerator = new OnlineMimeXmlPayload(xmlText);

        //Create a web request
        var urlCreateProject = _onlineUrls.Url_CreateProject(_onlineSession);
        var webRequest       = this.CreateLoggedInWebRequest(urlCreateProject, "POST");

        TableauServerRequestBase.SendPostContents(webRequest, xmlText);

        //Get the response
        var xmlDoc = GetWebReponseLogErrors_AsXmlDoc(webRequest, "create project");

        //Get all the workbook nodes
        var nsManager    = XmlHelper.CreateTableauXmlNamespaceManager("iwsOnline");
        var xNodeProject = xmlDoc.SelectSingleNode("//iwsOnline:project", nsManager);

        try
        {
            return(new SiteProject(xNodeProject));
        }
        catch (Exception parseXml)
        {
            StatusLog.AddError("Create project, error parsing XML response " + parseXml.Message + "\r\n" + xNodeProject.InnerXml);
            return(null);
        }
    }
    /// <summary>
    ///
    /// </summary>
    /// <param name="serverName"></param>
    public void ExecuteRequest()
    {
        var onlineUser  = new List <SiteUser>();
        int numberPages = 1; //Start with 1 page (we will get an updated value from server)

        //Get subsequent pages
        for (int thisPage = 1; thisPage <= numberPages; thisPage++)
        {
            try
            {
                ExecuteRequest_ForPage(onlineUser, thisPage, out numberPages);
            }
            catch (Exception exPageRequest)
            {
                StatusLog.AddError("Users list error during page request: " + exPageRequest.Message);
            }
        }

        _users = onlineUser;
    }
Exemplo n.º 3
0
    /// <summary>
    /// Sanity testing on whether the file being uploaded is worth uploading
    /// </summary>
    /// <param name="localFilePath"></param>
    /// <returns></returns>
    bool IsValidUploadFile(string localFilePath)
    {
        //Ignore temp files, since we know we don't want to upload them
        var fileExtension = Path.GetExtension(localFilePath).ToLower();

        if ((fileExtension == ".tmp") || (fileExtension == ".temp"))
        {
            StatusLog.AddStatus("Ignoring temp file, " + localFilePath, -10);
            return(false);
        }

        //These are the only kinds of data sources we know about...
        if ((fileExtension != ".twb") && (fileExtension != ".twbx"))
        {
            StatusLog.AddError("File is not a data source: " + localFilePath);
            return(false);
        }

        return(true);
    }
Exemplo n.º 4
0
        /// <summary>
        /// Execute the request for Groups
        /// </summary>
        public void ExecuteRequest()
        {
            var siteGroups = new List <SiteGroup>();

            int numberPages = 1; //Start with 1 page (we will get an updated value from server)

            //Get subsequent pages
            for (int thisPage = 1; thisPage <= numberPages; thisPage++)
            {
                try
                {
                    _ExecuteRequest_ForPage(siteGroups, thisPage, out numberPages);
                }
                catch (Exception exPageRequest)
                {
                    StatusLog.AddError("Groups error during page request: " + exPageRequest.Message);
                }
            }

            _groups = siteGroups;
        }
Exemplo n.º 5
0
    /*
     * /// <summary>
     * /// Constructor: Call when we want to query the Flows on behalf of an explicitly specified user
     * /// </summary>
     * /// <param name="onlineUrls"></param>
     * /// <param name="login"></param>
     * /// <param name="user"></param>
     * public DownloadFlowsList(TableauServerSignIn login, string userId, bool filterToOwnedBy, int maxNumberItems = int.MaxValue) : base(login)
     * {
     *  //Sanity test
     *  if(!RegExHelper.IsValidIdTableauContentId(userId))
     *  {
     *      throw new Exception("1030-139: Invalid user ID");
     *  }
     *
     *  _onlineUrls = login.ServerUrls;
     *  _maxNumberItemsReturned = maxNumberItems;
     *  _sort = DownloadFlowsList.Sort.NoSort; //[2019-10-29] This is currently the only option
     *  _userIdForContentQuery = userId;
     *  _filterToOwnedBy = filterToOwnedBy;
     * }
     */
    /// <summary>
    ///
    /// </summary>
    /// <param name="serverName"></param>
    public void ExecuteRequest()
    {
/*        //Sanity check
 *      if(string.IsNullOrWhiteSpace(_userIdForContentQuery))
 *      {
 *          _onlineSession.StatusLog.AddError("User ID required to query flows");
 *      }
 */
        var onlineFlows = new List <SiteFlow>();
        int numberPages = 1; //Start with 1 page (we will get an updated value from server)

        //Get subsequent pages
        for (int thisPage = 1; thisPage <= numberPages; thisPage++)
        {
            try
            {
                ExecuteRequest_ForPage(onlineFlows, thisPage, out numberPages);
            }
            catch (Exception exPageRequest)
            {
                StatusLog.AddError("Flows error during page request: " + exPageRequest.Message);
            }

            //See if we already have anough items
            if (onlineFlows.Count == _maxNumberItemsReturned)
            {
                goto exit_success;
            }
            else if (onlineFlows.Count > _maxNumberItemsReturned)
            {
                //Remove any excess
                onlineFlows.RemoveRange(_maxNumberItemsReturned, (onlineFlows.Count - _maxNumberItemsReturned));
                goto exit_success;
            }
        }

exit_success:
        _flows = onlineFlows;
    }
Exemplo n.º 6
0
        /// <summary>
        /// Execute request for Workbook Views
        /// </summary>
        public void ExecuteRequest()
        {
            if (string.IsNullOrWhiteSpace(_userId))
            {
                OnlineSession.StatusLog.AddError("User ID required to query workbooks");
            }

            try
            {
                var urlQuery   = _onlineUrls.Url_ViewsListForWorkbook(_workbookId, OnlineSession);
                var webRequest = CreateLoggedInWebRequest(urlQuery);
                webRequest.Method = "GET";
                OnlineSession.StatusLog.AddStatus($"Web request: {urlQuery}", -10);
                var response = GetWebResponseLogErrors(webRequest, "get views list");
                var xmlDoc   = GetWebResponseAsXml(response);

                var nsManager = XmlHelper.CreateTableauXmlNamespaceManager("iwsOnline");
                var workbooks = xmlDoc.SelectNodes("//iwsOnline:view", nsManager);
                _views = new List <SiteView>();
                foreach (XmlNode itemXml in workbooks)
                {
                    try
                    {
                        var ds = new SiteView(itemXml);
                        _views.Add(ds);
                    }
                    catch
                    {
                        AppDiagnostics.Assert(false, "View parse error");
                        OnlineSession.StatusLog.AddError("Error parsing view: " + itemXml.InnerXml);
                    }
                }
            }
            catch (Exception exPageRequest)
            {
                StatusLog.AddError($"Workbooks error during page request: {exPageRequest.Message}");
            }
        }
    /// <summary>
    /// Request the data from Online
    /// </summary>
    /// <param name="downloadMemberList"></param>
    /// <returns></returns>
    public bool ExecuteRequest(bool downloadMemberList = true)
    {
        var siteGroups = new List <SiteGroup>();

        int numberPages = 1; //Start with 1 page (we will get an updated value from server)

        //Get subsequent pages
        for (int thisPage = 1; thisPage <= numberPages; thisPage++)
        {
            try
            {
                ExecuteRequest_ForPage(siteGroups, thisPage, downloadMemberList, out numberPages);
            }
            catch (Exception exPageRequest)
            {
                StatusLog.AddError("Groups error during page request: " + exPageRequest.Message);
                return(false);
            }
        }

        _groups = siteGroups;
        return(true);
    }
        /// <summary>
        /// Execute the request for Site Views
        /// </summary>
        public void ExecuteRequest()
        {
            if (string.IsNullOrWhiteSpace(_userId))
            {
                OnlineSession.StatusLog.AddError("User ID required to query workbooks");
            }

            int numberPages = 1; //Start with 1 page (we will get an updated value from server)

            //Get subsequent pages
            _views = new List <SiteView>();
            for (int thisPage = 1; thisPage <= numberPages; thisPage++)
            {
                try
                {
                    _ExecuteRequest_ForPage(_views, thisPage, out numberPages);
                }
                catch (Exception exPageRequest)
                {
                    StatusLog.AddError($"Workbooks error during page request: {exPageRequest.Message}");
                }
            }
        }
Exemplo n.º 9
0
    /// <summary>
    /// After a file has been uploaded in chunks, we need to make a call to COMMIT the file to server as a published Data Source
    /// </summary>
    /// <param name="uploadSessionId"></param>
    /// <param name="publishedContentName"></param>
    private SiteDatasource FinalizePublish(
        string uploadSessionId,
        string publishedContentName,
        string publishedContentType,
        string projectId,
        CredentialManager.Credential dbCredentials)
    {
        //See definition: http://onlinehelp.tableau.com/current/api/rest_api/en-us/help.htm#REST/rest_api_ref.htm#Publish_Datasource%3FTocPath%3DAPI%2520Reference%7C_____29
        var sb        = new StringBuilder();
        var xmlWriter = XmlWriter.Create(sb, XmlHelper.XmlSettingsForWebRequests);

        xmlWriter.WriteStartElement("tsRequest");
        xmlWriter.WriteStartElement("datasource");
        xmlWriter.WriteAttributeString("name", publishedContentName);

        //If we have an associated database credential, write it out
        if (dbCredentials != null)
        {
            CredentialXmlHelper.WriteCredential(
                xmlWriter,
                dbCredentials);
        }

        xmlWriter.WriteStartElement("project"); //<project>
        xmlWriter.WriteAttributeString("id", projectId);
        xmlWriter.WriteEndElement();            //</project>
        xmlWriter.WriteEndElement();            // </datasource>
        //Currently not supporting <connectionCredentials>
        xmlWriter.WriteEndElement();            // </tsRequest>
        xmlWriter.Close();

        var xmlText = sb.ToString(); //Get the XML text out

        //Generate the MIME message
        var mimeGenerator = new MimeWriterXml(xmlText);

        //Create a web request to push the
        var urlFinalizeUpload = _onlineUrls.Url_FinalizeDataSourcePublish(_onlineSession, uploadSessionId, publishedContentType);

        //NOTE: The publish finalization step can take several minutes, because server needs to unpack the uploaded ZIP and file it away.
        //      For this reason, we pass in a long timeout
        var webRequest = this.CreateAndSendMimeLoggedInRequest(urlFinalizeUpload, "POST", mimeGenerator, TableauServerWebClient.DefaultLongRequestTimeOutMs);
        var response   = GetWebReponseLogErrors(webRequest, "finalize datasource publish");

        using (response)
        {
            var xmlDoc = GetWebResponseAsXml(response);

            //Get all the datasource node from the response
            var nsManager     = XmlHelper.CreateTableauXmlNamespaceManager("iwsOnline");
            var dataSourceXml = xmlDoc.SelectSingleNode("//iwsOnline:datasource", nsManager);

            try
            {
                return(new SiteDatasource(dataSourceXml));
            }
            catch (Exception parseXml)
            {
                StatusLog.AddError("Data source upload, error parsing XML response " + parseXml.Message + "\r\n" + dataSourceXml.InnerXml);
                return(null);
            }
        }
    }
Exemplo n.º 10
0
    /// <summary>
    /// Uploads the contents of a directory to server
    /// </summary>
    /// <param name="rootContentPath"></param>
    /// <param name="currentContentPath"></param>
    /// <param name="recurseDirectories"></param>
    private void UploadDirectoryToServer(
        string rootContentPath,
        string currentContentPath,
        ProjectFindCreateHelper projectsList,
        bool recurseDirectories,
        out int countSuccess,
        out int countFailure)
    {
        countSuccess = 0;
        countFailure = 0;

        //Look up the project name based on directory name, and creating a project on demand
        string projectName;

        if (rootContentPath == currentContentPath) //If we are in the root upload directory, then assume any content goes to the Default project
        {
            projectName = "";                      //Default project
        }
        else
        {
            projectName = FileIOHelper.Undo_GenerateWindowsSafeFilename(Path.GetFileName(currentContentPath));
        }


        //Start off with no project ID -- we'll look it up as needed
        string projectIdForUploads = null;

        //-------------------------------------------------------------------------------------
        //Upload the files from local directory to server
        //-------------------------------------------------------------------------------------
        foreach (var thisFilePath in Directory.GetFiles(currentContentPath))
        {
            bool isValidUploadFile = IsValidUploadFile(thisFilePath);

            if (isValidUploadFile)
            {
                //If we don't yet have a project ID, then get one
                if (string.IsNullOrWhiteSpace(projectIdForUploads))
                {
                    projectIdForUploads = projectsList.GetProjectIdForUploads(projectName);
                }

                try
                {
                    //See if there are any credentials we want to publish with the content
                    var dbCredentialsIfAny = helper_DetermineContentCredential(
                        Path.GetFileName(thisFilePath),
                        projectName);

                    //See what content specific settings there may be for this workbook
                    var publishSettings = DatasourcePublishSettings.GetSettingsForSavedDatasource(thisFilePath);

                    //Do the file upload
                    bool wasFileUploaded = AttemptUploadSingleFile(thisFilePath, projectIdForUploads, dbCredentialsIfAny, publishSettings);
                    if (wasFileUploaded)
                    {
                        countSuccess++;
                    }
                }
                catch (Exception ex)
                {
                    countFailure++;
                    StatusLog.AddError("Error uploading datasource " + thisFilePath + ". " + ex.Message);
                    LogManualAction_UploadDataSource(thisFilePath);
                }
            }
        }

        //If we are running recursive , then look in the subdirectories too
        if (recurseDirectories)
        {
            int subDirSuccess;
            int subDirFailure;
            foreach (var subDirectory in Directory.GetDirectories(currentContentPath))
            {
                UploadDirectoryToServer(rootContentPath, subDirectory, projectsList, true, out subDirSuccess, out subDirFailure);
                countSuccess += subDirSuccess;
                countFailure += subDirFailure;
            }
        }
    }
    /// <summary>
    /// Looks up the default project ID
    /// </summary>
    /// <returns></returns>
    public string GetProjectIdForUploads(string projectName)
    {
        //If the project name is empty - look for the default project
        if (string.IsNullOrEmpty(projectName))
        {
            goto find_default_project;
        }

        //Look for the matching project
        var project = _projectsList.FindProjectWithName(projectName);

        if (project != null)
        {
            return(project.Id);
        }

        //If the option is specified; attempt to create the project
        if (_uploadProjectBehavior.AttemptProjectCreate)
        {
            //Create the project name
            var createProject = new SendCreateProject(_onlineUrls, _onlineSession, projectName);
            try
            {
                var newProject = createProject.ExecuteRequest();
                _projectsList.AddProject(newProject);
                return(newProject.Id);
            }
            catch (Exception exCreateProject)
            {
                this.StatusLog.AddError("Failed attempting to create project '" + projectName + "', " + exCreateProject.Message);
            }
        }

        //If we are not allowed to fall back the default project then error
        if (!_uploadProjectBehavior.UseDefaultProjectIfNeeded)
        {
            throw new Exception("Not allowed to use default project");
        }

        this.StatusLog.AddStatus("Project name not found '" + projectName + "'. Reverting to default project", -10);

find_default_project:
        //If all else fails, fall back to using the default project
        var defaultProject = _projectsList.FindProjectWithName("default"); //Find the default project

        if (defaultProject != null)
        {
            return(defaultProject.Id);
        }

        defaultProject = _projectsList.FindProjectWithName("Default");
        if (defaultProject != null)
        {
            return(defaultProject.Id);
        }

        defaultProject = _projectsList.FindProjectWithName(""); //Try empty
        if (defaultProject != null)
        {
            return(defaultProject.Id);
        }

        //Default project not found. Choosing any project
        this.StatusLog.AddError("Default project not found. Reverting to any project");
        foreach (var thisProj in _projectsList.Projects)
        {
            return(thisProj.Id);
        }

        StatusLog.AddError("Upload could not find a project ID to use");
        throw new Exception("Aborting. Upload Datasources could not find a project ID to use");
    }
Exemplo n.º 12
0
    /// <summary>
    /// Update the group
    /// </summary>
    /// <returns>TRUE: Success.  FALSE: failed/error</returns>
    private bool UpdateGroup()
    {
        AppDiagnostics.Assert(!string.IsNullOrWhiteSpace(this.GroupId), "920-1053: missing group id");
        AppDiagnostics.Assert(!string.IsNullOrWhiteSpace(this.UpdatedGroupName), "920-1054: missing role");

        //[2020-09-20] NOTE: Currently this function DOES NOT work for Active Directory syncronized groups (on premises Tableau Serer)

        //ref: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#update_group
        var sb        = new StringBuilder();
        var xmlWriter = XmlWriter.Create(sb, XmlHelper.XmlSettingsForWebRequests);

        xmlWriter.WriteStartElement("tsRequest");
        xmlWriter.WriteStartElement("group");
        xmlWriter.WriteAttributeString("name", this.UpdatedGroupName);

        //If we are updating the grant license parts, write these here
        //[2020-09-20] For (on premises Server) Active Directory sync, this would need to be different XML (inside an "import" node)
        if (this.PerformUpdateGrantLicense)
        {
            xmlWriter.WriteAttributeString("grantLicenseMode", this.UpdatedGrantLicenseMode);

            //If the Grant license mode is blank, set the license role to be UNLICENSED
            //This is required to remove the licensing mode: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#update_group
            string updateLicenseMode = this.UpdatedGrantLicenseSiteRole;
            if (string.IsNullOrEmpty(this.UpdatedGrantLicenseMode))
            {
                updateLicenseMode = "UNLICENSED";
            }
            xmlWriter.WriteAttributeString("minimumSiteRole", updateLicenseMode);
        }

        xmlWriter.WriteEndElement(); //</group>
        xmlWriter.WriteEndElement(); // </tsRequest>
        xmlWriter.Close();

        var xmlText = sb.ToString(); //Get the XML text out

        //Create a web request
        var urlUpdateGroup = this._onlineSession.ServerUrls.Url_UpdateSiteGroup(_onlineSession, this.GroupId);
        var webRequest     = this.CreateLoggedInWebRequest(urlUpdateGroup, "PUT");

        TableauServerRequestBase.SendPutContents(webRequest, xmlText);

        //Get the response
        var response = GetWebReponseLogErrors(webRequest, "update group (change name/grant-license)");

        using (response)
        {
            var xmlDoc = GetWebResponseAsXml(response);

            //Get all the group nodes
            var nsManager         = XmlHelper.CreateTableauXmlNamespaceManager("iwsOnline");
            var xNodeUpdatedGroup = xmlDoc.SelectSingleNode("//iwsOnline:group", nsManager);

            try
            {
                //Sanity check on the expected results
                var updatesGroupId      = xNodeUpdatedGroup.Attributes["id"].Value;
                var returnedMinSiteRole = XmlHelper.SafeParseXmlAttribute(xNodeUpdatedGroup, "minimumSiteRole", "");

                if (updatesGroupId != this.GroupId)
                {
                    IwsDiagnostics.Assert(false, "920-1102: Error. Updated groups returned mismatching group id: " + this.GroupId + "/" + updatesGroupId);
                    StatusLog.AddError("920-1102: Error. Updated groups returned mismatching group id: " + this.GroupId + "/" + updatesGroupId);
                    return(false);
                }

                //See if the returned role matches
                if (this.PerformUpdateGrantLicense)
                {
                    if (!CompareGrantLicenseRoles(returnedMinSiteRole, this.UpdatedGrantLicenseSiteRole))
                    {
                        string errorText = "920-1206: Error. Updated Grant License role for group does not match expected role: "
                                           + NullSafeText(returnedMinSiteRole) + "/" + NullSafeText(this.UpdatedGrantLicenseSiteRole);
                        StatusLog.AddError(errorText);
                        return(false);
                    }
                }
            }
            catch (Exception parseXml)
            {
                StatusLog.AddError("920-1105: Update group, error parsing XML response " + parseXml.Message + "\r\n" + xmlDoc.InnerXml);
                return(false);
            }
        }
        return(true); //Success
    }
Exemplo n.º 13
0
    private SiteUser UpdateUser(string userId, string newRole, bool updateAuthentication, SiteUserAuth newAuthentication)
    {
        AppDiagnostics.Assert(!string.IsNullOrWhiteSpace(userId), "missing user id");
        AppDiagnostics.Assert(!string.IsNullOrWhiteSpace(newRole), "missing role");


        //ref: https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm#update_user
        var sb        = new StringBuilder();
        var xmlWriter = XmlWriter.Create(sb, XmlHelper.XmlSettingsForWebRequests);

        xmlWriter.WriteStartElement("tsRequest");
        xmlWriter.WriteStartElement("user");
        xmlWriter.WriteAttributeString("siteRole", newRole);

        //Only if we are updating the user's authentication method do we need to update this
        if (updateAuthentication)
        {
            string newAuthenticationText = SendCreateUser.SiteUserAuthToAttributeText(newAuthentication);
            xmlWriter.WriteAttributeString("authSetting", newAuthenticationText);
        }
        xmlWriter.WriteEndElement(); //</user>
        xmlWriter.WriteEndElement(); // </tsRequest>
        xmlWriter.Close();

        var xmlText = sb.ToString(); //Get the XML text out

        //Create a web request
        var urlUpdateUser = _onlineUrls.Url_UpdateSiteUser(_onlineSession, userId);
        var webRequest    = this.CreateLoggedInWebRequest(urlUpdateUser, "PUT");

        TableauServerRequestBase.SendPutContents(webRequest, xmlText);

        //Get the response
        var response = GetWebReponseLogErrors(webRequest, "update user (change auth or role)");

        using (response)
        {
            var xmlDoc = GetWebResponseAsXml(response);


            //Get all the user nodes
            var nsManager = XmlHelper.CreateTableauXmlNamespaceManager("iwsOnline");
            var xNodeUser = xmlDoc.SelectSingleNode("//iwsOnline:user", nsManager);

            try
            {
                if (updateAuthentication)
                {
                    return(SiteUser.FromUserXMLWithoutUserId(xNodeUser, userId));
                }
                else
                {
                    //Use the passed in authentication
                    return(SiteUser.FromUserXMLWithoutUserIdOrAuthRole(xNodeUser, userId, newAuthentication));
                }
            }
            catch (Exception parseXml)
            {
                StatusLog.AddError("Update user, error parsing XML response " + parseXml.Message + "\r\n" + xNodeUser.InnerXml);
                return(null);
            }
        }
    }