예제 #1
0
    /// <summary>
    /// Get a page's worth of Data Sources
    /// </summary>
    /// <param name="onlineDatasources"></param>
    /// <param name="pageToRequest">Page # we are requesting (1 based)</param>
    /// <param name="totalNumberPages">Total # of pages of data that Server can return us</param>
    private void ExecuteRequest_ForPage(List <SiteDatasource> onlineDatasources, int pageToRequest, out int totalNumberPages)
    {
        int pageSize = _onlineUrls.PageSize;
        //Create a web request, in including the users logged-in auth information in the request headers
        var urlQuery = _onlineUrls.Url_DatasourcesList(_onlineSession, pageSize, pageToRequest);

        _onlineSession.StatusLog.AddStatus("Web request: " + urlQuery, -10);
        var xmlDoc = ResourceSafe_PerformWebRequest_GetXmlDocument(urlQuery, "get datasources list");

        //Get all the workbook nodes
        var nsManager   = XmlHelper.CreateTableauXmlNamespaceManager("iwsOnline");
        var datasources = xmlDoc.SelectNodes("//iwsOnline:datasource", nsManager);

        //Get information for each of the data sources
        foreach (XmlNode itemXml in datasources)
        {
            try
            {
                var ds = new SiteDatasource(itemXml);
                onlineDatasources.Add(ds);
            }
            catch
            {
                AppDiagnostics.Assert(false, "Datasource parse error");
                _onlineSession.StatusLog.AddError("Error parsing datasource: " + itemXml.InnerXml);
            }
        } //end: foreach

        //-------------------------------------------------------------------
        //Get the updated page-count
        //-------------------------------------------------------------------
        totalNumberPages = DownloadPaginationHelper.GetNumberOfPagesFromPagination(
            xmlDoc.SelectSingleNode("//iwsOnline:pagination", nsManager),
            pageSize);
    }
예제 #2
0
        /// <summary>
        /// Attempts to upload a single file a Tableau Server, and then make it a published data source
        /// </summary>
        /// <param name="localFilePath"></param>
        /// <param name="projectId"></param>
        /// <param name="dbCredentials">If not NULL, then these are the DB credentials we want to associate with the content we are uploading</param>
        /// <returns></returns>
        private bool AttemptUploadSingleFile(
            string localFilePath,
            string projectId,
            CredentialManager.Credential dbCredentials,
            DatasourcePublishSettings publishSettings)
        {
            string uploadSessionId;

            try
            {
                var fileUploader = new UploadFile(Urls, Login, localFilePath, HttpClientFactory, UploadChunkSizeBytes, UploadChunkDelaySeconds);
                uploadSessionId = fileUploader.ExecuteRequest();
            }
            catch (Exception exFileUpload)
            {
                Login.Logger.Error("Unexpected error attempting to upload file " + localFilePath + ", " + exFileUpload.Message);
                throw exFileUpload;
            }

            SiteDatasource dataSource = null;

            Login.Logger.Information("File chunks upload successful. Next step, make it a published datasource");
            try
            {
                string fileName   = Path.GetFileNameWithoutExtension(localFilePath);
                string uploadType = RemoveFileExtensionDot(Path.GetExtension(localFilePath).ToLower());
                dataSource = FinalizePublish(
                    uploadSessionId,
                    FileIOHelper.Undo_GenerateWindowsSafeFilename(fileName), //[2016-05-06] If the name has escapted characters, unescape them
                    uploadType,
                    projectId,
                    dbCredentials);
                UploadeDatasources.Add(dataSource);
                Login.Logger.Information("Upload content details: " + dataSource.ToString());
                Login.Logger.Information("Success! Uploaded datasource " + Path.GetFileName(localFilePath));
            }
            catch (Exception exPublishFinalize)
            {
                Login.Logger.Error("Unexpected error finalizing publish of file " + localFilePath + ", " + exPublishFinalize.Message);
                throw exPublishFinalize;;
            }

            //See if we want to reassign ownership of the datasource
            if (AttemptOwnershipAssignment)
            {
                try
                {
                    AttemptOwnerReassignment(dataSource, publishSettings, SiteUsers);
                }
                catch (Exception exOwnershipAssignment)
                {
                    Login.Logger.Error("Unexpected error reassigning ownership of published datasource " + dataSource.Name + ", " + exOwnershipAssignment.Message);
                    LogManualAction_ReassignOwnership(dataSource.Name);
                    throw exOwnershipAssignment;
                }
            }

            return(true);     //Success
        }
예제 #3
0
 /// <summary>
 /// Create the request for to download Data sources from the Tableau REST API
 /// </summary>
 /// <param name="onlineUrls">Tableau Server Information</param>
 /// <param name="logInInfo">Tableau Sign In Information</param>
 /// <param name="datasource">List of Tableau Data sources to save to disk</param>
 /// <param name="localSavePath">File system location where data sources should be saved</param>
 /// <param name="project"></param>
 public DownloadDatasource(TableauServerUrls onlineUrls, TableauServerSignIn logInInfo, SiteDatasource datasource, string localSavePath, SiteProject project)
     : base(logInInfo)
 {
     _onlineUrls    = onlineUrls;
     _datasource    = datasource;
     _localSavePath = localSavePath;
     _downloadToProjectDirectory = project;
 }
예제 #4
0
        /// <summary>
        /// URL to download a datasource
        /// </summary>
        /// <param name="siteUrlSegment"></param>
        /// <returns></returns>
        public string Url_DatasourceDownload(TableauServerSignIn session, SiteDatasource contentInfo)
        {
            string workingText = UrlDownloadDatasourceTemplate;

            workingText = workingText.Replace("{{iwsSiteId}}", session.SiteId);
            workingText = workingText.Replace("{{iwsRepositoryId}}", contentInfo.Id);

            ValidateTemplateReplaceComplete(workingText);
            return(workingText);
        }
예제 #5
0
        /// <summary>
        /// URL to download a datasource
        /// </summary>
        /// <param name="logInInfo">Tableau Sign In Information</param>
        /// <param name="datasource">Tableau Data Source</param>
        /// <returns></returns>
        public string Url_DatasourceDownload(TableauServerSignIn logInInfo, SiteDatasource datasource)
        {
            string workingText = _urlDownloadDatasourceTemplate;

            workingText = workingText.Replace("{{iwsSiteId}}", logInInfo.SiteId);
            workingText = workingText.Replace("{{iwsRepositoryId}}", datasource.Id);

            _ValidateTemplateReplaceComplete(workingText);
            return(workingText);
        }
예제 #6
0
        public string UrlUpdateDatasourceConnection(TableauServerSignIn session, SiteDatasource datasourceToUpdate, SiteConnection connectionToUpdate)
        {
            string workingText = UrlUpdateDatasourceConnection_p;

            workingText = workingText.Replace("{{iwsSiteId}}", session.SiteId);
            workingText = workingText.Replace("{{iwsDatasourceId}}", datasourceToUpdate.Id);
            workingText = workingText.Replace("{{iwsConnectionId}}", connectionToUpdate.Id);

            ValidateTemplateReplaceComplete(workingText);
            return(workingText);
        }
예제 #7
0
        public void UpdateServerAddress(SiteDatasource datasourceToUpdate, SiteConnection connectionToUpdate, string serverAddress)
        {
            var sb        = new StringBuilder();
            var xmlWriter = XmlWriter.Create(sb, XmlHelper.XmlSettingsForWebRequests);

            xmlWriter.WriteStartElement("tsRequest");
            xmlWriter.WriteStartElement("connection");
            xmlWriter.WriteAttributeString("serverAddress", serverAddress);
            xmlWriter.WriteEndElement(); //</connection>
            xmlWriter.WriteEndElement(); // </tsRequest>
            xmlWriter.Dispose();

            var xmlText = sb.ToString();

            var urlQuery   = Urls.UrlUpdateDatasourceConnection(Login, datasourceToUpdate, connectionToUpdate);
            var webRequest = CreateLoggedInRequest(urlQuery, HttpMethod.Put);

            SendHttpRequest(webRequest, xmlText);
        }
    /// <summary>
    /// Save Datasource metadata in a XML file along-side the workbook file
    /// </summary>
    /// <param name="wb">Information about the workbook we have downloaded</param>
    /// <param name="localDatasourcePath">Local path to the twb/twbx of the workbook</param>
    /// <param name="userLookups">If non-NULL contains the mapping of users/ids so we can look up the owner</param>
    internal static void CreateSettingsFile(SiteDatasource ds, string localDatasourcePath, KeyedLookup<SiteUser> userLookups)
    {
        string contentOwnerName = null; //Start off assuming we have no content owner information
        if (userLookups != null)
        {
            contentOwnerName = WorkbookPublishSettings.helper_LookUpOwnerId(ds.OwnerId, userLookups);
        }

        var xml = System.Xml.XmlWriter.Create(PathForSettingsFile(localDatasourcePath));
        xml.WriteStartDocument();
            xml.WriteStartElement(XmlElement_DatasourceInfo);

                //If we have an owner name, write it out
                if (!string.IsNullOrWhiteSpace(contentOwnerName))
                {
                  XmlHelper.WriteValueElement(xml,  WorkbookPublishSettings.XmlElement_ContentOwner, contentOwnerName);
                }
            xml.WriteEndElement(); //end: WorkbookInfo
        xml.WriteEndDocument();
        xml.Close();
    }
    /// <summary>
    /// Save Datasource metadata in a XML file along-side the workbook file
    /// </summary>
    /// <param name="wb">Information about the workbook we have downloaded</param>
    /// <param name="localDatasourcePath">Local path to the twb/twbx of the workbook</param>
    /// <param name="userLookups">If non-NULL contains the mapping of users/ids so we can look up the owner</param>
    internal static void CreateSettingsFile(SiteDatasource ds, string localDatasourcePath, KeyedLookup <SiteUser> userLookups)
    {
        string contentOwnerName = null; //Start off assuming we have no content owner information

        if (userLookups != null)
        {
            contentOwnerName = WorkbookPublishSettings.helper_LookUpOwnerId(ds.OwnerId, userLookups);
        }

        var xml = System.Xml.XmlWriter.Create(PathForSettingsFile(localDatasourcePath));

        xml.WriteStartDocument();
        xml.WriteStartElement(XmlElement_DatasourceInfo);

        //If we have an owner name, write it out
        if (!string.IsNullOrWhiteSpace(contentOwnerName))
        {
            XmlHelper.WriteValueElement(xml, WorkbookPublishSettings.XmlElement_ContentOwner, contentOwnerName);
        }
        xml.WriteEndElement();     //end: WorkbookInfo
        xml.WriteEndDocument();
        xml.Close();
    }
예제 #10
0
        /// <summary>
        /// Get a page's worth of Data Sources
        /// </summary>
        /// <param name="onlineDatasources"></param>
        /// <param name="pageToRequest">Page # we are requesting (1 based)</param>
        /// <param name="totalNumberPages">Total # of pages of data that Server can return us</param>
        private void ExecuteRequest_ForPage(List <SiteDatasource> onlineDatasources, int pageToRequest, out int totalNumberPages)
        {
            int pageSize = Urls.PageSize;
            //Create a web request, in including the users logged-in auth information in the request headers
            var urlQuery = Urls.Url_DatasourcesList(Login, pageSize, pageToRequest);
            var request  = CreateLoggedInRequest(urlQuery, HttpMethod.Get);

            Login.Logger.Information("Web request: " + urlQuery);
            var response = SendHttpRequest(request);
            var xmlDoc   = GetHttpResponseAsXml(response);

            //Get all the nodes
            var xDoc        = xmlDoc.ToXDocument();
            var datasources = xDoc.Root.Descendants(XName.Get("datasource", XmlNamespace));

            //Get information for each of the data sources
            foreach (var itemXml in datasources)
            {
                try
                {
                    var itemXmlNode = itemXml.ToXmlNode();
                    var ds          = new SiteDatasource(itemXmlNode, XmlNamespace);
                    onlineDatasources.Add(ds);
                }
                catch
                {
                    Login.Logger.Error("Error parsing datasource: " + itemXml.ToXmlNode());
                }
            } //end: foreach

            //-------------------------------------------------------------------
            //Get the updated page-count
            //-------------------------------------------------------------------
            var paginationElement = xDoc.Root.Descendants(XName.Get("pagination", XmlNamespace)).FirstOrDefault();

            totalNumberPages = GetPageCount(paginationElement, pageSize);
        }
예제 #11
0
    /// <summary>
    /// Assign ownership
    /// </summary>
    /// <param name="datasource"></param>
    /// <param name="publishSettings"></param>
    /// <param name="siteUsers"></param>
    /// <returns>TRUE: The server content has the correct owner now.  FALSE: We were unable to give the server content the correct owner</returns>
    private bool AttemptOwnerReassignment(SiteDatasource datasource, DatasourcePublishSettings publishSettings, IEnumerable <SiteUser> siteUsers)
    {
        this.StatusLog.AddStatusHeader("Attempting ownership assignement for Datasource " + datasource.Name + "/" + datasource.Id);

        //Something went wrong if we don't have a set of site users to do the look up
        if (siteUsers == null)
        {
            throw new ArgumentException("No set of site users provided for lookup");
        }

        //Look the local meta data to see what the desired name is
        var desiredOwnerName = publishSettings.OwnerName;

        if (string.IsNullOrEmpty(desiredOwnerName))
        {
            this.StatusLog.AddStatus("Skipping owner assignment. The local file system has no metadata with an owner information for " + datasource.Name);
            LogManualAction_ReassignOwnership(datasource.Name, "none specified", "No client ownership information was specified");
            return(true); //Since there is no ownership preference stated locally, then ownership we assigned during upload was fine.
        }

        //Look on the list of users in the target site/server, and try to find a match
        //
        //NOTE: We are doing a CASE INSENSITIVE name comparison. We assume that there are not 2 users with the same name on server w/differet cases
        //      Because if this, we want to be flexible and allow that our source/destination servers may have the user name specified with a differnt
        //      case.  -- This is less secure than a case-sensitive comparison, but is almost always what we want when porting content between servers
        var desiredServerUser = SiteUser.FindUserWithName(siteUsers, desiredOwnerName, StringComparison.InvariantCultureIgnoreCase);

        if (desiredServerUser == null)
        {
            this.StatusLog.AddError("The local file has a workbook/user mapping: " + datasource.Name + "/" + desiredOwnerName + ", but this user does not exist on the target site");
            LogManualAction_ReassignOwnership(datasource.Name, desiredOwnerName, "The target site does not contain a user name that matches the owner specified by the local metadata");
            return(false); //Not a run time error, but we have manual steps to perform
        }

        //If the server content is already correct, then there is nothing to do
        if (desiredServerUser.Id == datasource.OwnerId)
        {
            this.StatusLog.AddStatus("Workbook " + datasource.Name + "/" + datasource.Id + ", already has correct ownership. No update requried");
            return(true);
        }

        //Lets tell server to update the owner
        var            changeOwnership = new SendUpdateDatasourceOwner(_onlineUrls, _onlineSession, datasource.Id, desiredServerUser.Id);
        SiteDatasource updatedDatasource;

        try
        {
            this.StatusLog.AddStatus("Server request to change Datasource ownership, ds: " + datasource.Name + "/" + datasource.Id + ", user:"******"/" + desiredServerUser.Id);
            updatedDatasource = changeOwnership.ExecuteRequest();
        }
        catch (Exception exChangeOnwnerhsip)
        {
            throw exChangeOnwnerhsip; //Unexpected error, send it upward
        }

        //Sanity check the result we got back: Double check to make sure we have the expected owner.
        if (updatedDatasource.OwnerId != desiredServerUser.Id)
        {
            this.StatusLog.AddError("Unexpected server error! Updated workbook Owner Id does not match expected. ds: "
                                    + datasource.Name + "/" + datasource.Id + ", "
                                    + "expected user: "******", "
                                    + "actual user: " + updatedDatasource.OwnerId
                                    );
        }

        return(true);
    }
예제 #12
0
    /// <summary>
    /// URL to download a datasource
    /// </summary>
    /// <param name="siteUrlSegment"></param>
    /// <returns></returns>
    public string Url_DatasourceDownload(TableauServerSignIn session, SiteDatasource contentInfo)
    {
        string workingText = _urlDownloadDatasourceTemplate;
        workingText = workingText.Replace("{{iwsSiteId}}", session.SiteId);
        workingText = workingText.Replace("{{iwsRepositoryId}}", contentInfo.Id);

        ValidateTemplateReplaceComplete(workingText);
        return workingText;
    }
예제 #13
0
    /// <summary>
    /// Update the owner of a single datasource
    /// </summary>
    /// <param name="siteSignIn"></param>
    /// <param name="contentItem"></param>
    /// <param name="userOldOwner"></param>
    /// <param name="userNewOwner"></param>
    private void Execute_ProvisionOwnership_SingleUserChange_SingleDatasource_inner(TableauServerSignIn siteSignIn, SiteDatasource contentItem, SiteUser userOldOwner, SiteUser userNewOwner)
    {
        var updateContentOwner = new SendUpdateDatasourceOwner(siteSignIn, contentItem.Id, userNewOwner.Id);

        updateContentOwner.ExecuteRequest();

        CSVRecord_ContentOwnershipModified("datasource", contentItem.Name, userOldOwner.Name, userNewOwner.Name);
    }
예제 #14
0
    /// <summary>
    /// Change the ownership for a single Datasource
    /// </summary>
    /// <param name="contentItem"></param>
    /// <param name="userOldOwner"></param>
    /// <param name="userNewOwner"></param>
    private void Execute_ProvisionOwnership_SingleUserChange_SingleDatasource(TableauServerSignIn siteSignIn, SiteDatasource contentItem, SiteUser userOldOwner, SiteUser userNewOwner)
    {
        try
        {
            Execute_ProvisionOwnership_SingleUserChange_SingleDatasource_inner(siteSignIn, contentItem, userOldOwner, userNewOwner);
        }
        catch (Exception ex)
        {
            _statusLogs.AddError("Error attempting to change content ownership, "
                                 + "datasource: " + contentItem.Name
                                 + "from: " + userOldOwner.Name
                                 + ", to:" + userNewOwner.Name
                                 + ", error: " + ex.ToString());

            CSVRecord_ErrorUpdatingContentOwnership("datasource", contentItem.Name, userOldOwner.Name, userNewOwner.Name, ex.Message);
        }
    }
    /// <summary>
    /// Get a page's worth of Data Sources
    /// </summary>
    /// <param name="onlineDatasources"></param>
    /// <param name="pageToRequest">Page # we are requesting (1 based)</param>
    /// <param name="totalNumberPages">Total # of pages of data that Server can return us</param>
    private void ExecuteRequest_ForPage(List<SiteDatasource> onlineDatasources, int pageToRequest, out int totalNumberPages)
    {
        int pageSize =_onlineUrls.PageSize; 
        //Create a web request, in including the users logged-in auth information in the request headers
        var urlQuery = _onlineUrls.Url_DatasourcesList(_onlineSession, pageSize, pageToRequest);
        var webRequest = CreateLoggedInWebRequest(urlQuery);
        webRequest.Method = "GET";

        _onlineSession.StatusLog.AddStatus("Web request: " + urlQuery, -10);
        var response = GetWebReponseLogErrors(webRequest, "get datasources list");
        var xmlDoc = GetWebResponseAsXml(response);

        //Get all the workbook nodes
        var nsManager = XmlHelper.CreateTableauXmlNamespaceManager("iwsOnline");
        var datasources = xmlDoc.SelectNodes("//iwsOnline:datasource", nsManager);

        //Get information for each of the data sources
        foreach (XmlNode itemXml in datasources)
        {
            try
            {
                var ds = new SiteDatasource(itemXml);
                onlineDatasources.Add(ds);
            }
            catch
            {
                AppDiagnostics.Assert(false, "Datasource parse error");
                _onlineSession.StatusLog.AddError("Error parsing datasource: " + itemXml.InnerXml);
            }
        } //end: foreach

        //-------------------------------------------------------------------
        //Get the updated page-count
        //-------------------------------------------------------------------
        totalNumberPages  =DownloadPaginationHelper.GetNumberOfPagesFromPagination(
            xmlDoc.SelectSingleNode("//iwsOnline:pagination", nsManager),
            pageSize);
    }
예제 #16
0
    /// <summary>
    /// Assign ownership
    /// </summary>
    /// <param name="datasource"></param>
    /// <param name="publishSettings"></param>
    /// <param name="siteUsers"></param>
    /// <returns>TRUE: The server content has the correct owner now.  FALSE: We were unable to give the server content the correct owner</returns>
    private bool AttemptOwnerReassignment(SiteDatasource datasource, DatasourcePublishSettings publishSettings, IEnumerable<SiteUser> siteUsers)
    {
        this.StatusLog.AddStatusHeader("Attempting ownership assignement for Datasource " + datasource.Name + "/" + datasource.Id);

        //Something went wrong if we don't have a set of site users to do the look up
        if (siteUsers == null)
        {
            throw new ArgumentException("No set of site users provided for lookup");
        }

        //Look the local meta data to see what the desired name is
        var desiredOwnerName = publishSettings.OwnerName;
        if (string.IsNullOrEmpty(desiredOwnerName))
        {
            this.StatusLog.AddStatus("Skipping owner assignment. The local file system has no metadata with an owner information for " + datasource.Name);
            LogManualAction_ReassignOwnership(datasource.Name, "none specified", "No client ownership information was specified");
            return true; //Since there is no ownership preference stated locally, then ownership we assigned during upload was fine.
        }

        //Look on the list of users in the target site/server, and try to find a match
        //
        //NOTE: We are doing a CASE INSENSITIVE name comparison. We assume that there are not 2 users with the same name on server w/differet cases
        //      Because if this, we want to be flexible and allow that our source/destination servers may have the user name specified with a differnt
        //      case.  -- This is less secure than a case-sensitive comparison, but is almost always what we want when porting content between servers
        var desiredServerUser = SiteUser.FindUserWithName(siteUsers, desiredOwnerName, StringComparison.InvariantCultureIgnoreCase);

        if (desiredServerUser == null)
        {
            this.StatusLog.AddError("The local file has a workbook/user mapping: " + datasource.Name + "/" + desiredOwnerName + ", but this user does not exist on the target site");
            LogManualAction_ReassignOwnership(datasource.Name, desiredOwnerName, "The target site does not contain a user name that matches the owner specified by the local metadata");
            return false; //Not a run time error, but we have manual steps to perform
        }

        //If the server content is already correct, then there is nothing to do
        if (desiredServerUser.Id == datasource.OwnerId)
        {
            this.StatusLog.AddStatus("Workbook " + datasource.Name + "/" + datasource.Id + ", already has correct ownership. No update requried");
            return true;
        }

        //Lets tell server to update the owner
        var changeOwnership = new SendUpdateDatasourceOwner(_onlineUrls, _onlineSession, datasource.Id, desiredServerUser.Id);
        SiteDatasource updatedDatasource;
        try
        {
            this.StatusLog.AddStatus("Server request to change Datasource ownership, ds: " + datasource.Name + "/" + datasource.Id + ", user:"******"/" + desiredServerUser.Id);
            updatedDatasource = changeOwnership.ExecuteRequest();
        }
        catch (Exception exChangeOnwnerhsip)
        {
            throw exChangeOnwnerhsip; //Unexpected error, send it upward
        }

        //Sanity check the result we got back: Double check to make sure we have the expected owner.
        if (updatedDatasource.OwnerId != desiredServerUser.Id)
        {
            this.StatusLog.AddError("Unexpected server error! Updated workbook Owner Id does not match expected. ds: "
                + datasource.Name + "/" + datasource.Id + ", "
                + "expected user: "******", "
                + "actual user: " + updatedDatasource.OwnerId
                );
        }

        return true;
    }