private async Task GetHtmlContent()
        {
            var rawTopic = new TopicInformation {
                OriginalName = SelectedTopic.Title, Type = SelectedTopic.Type
            };

            ImageRootUrl = string.Empty;

            var normalizedLink = SelectedTopic.LinkPure.ToLowerInvariant();

            if (normalizedLink.StartsWith("https://") || normalizedLink.StartsWith("http://"))
            {
                // This is an absolute link, so we can just try to load it
                rawTopic.OriginalContent = await WebClientEx.GetStringAsync(SelectedTopic.Link);

                ImageRootUrl = StringHelper.JustPath(SelectedTopic.Link) + "/";
            }
            else if (!string.IsNullOrEmpty(normalizedLink))
            {
                var repositoryType = RepositoryTypeHelper.GetTypeFromTypeName(GetSetting <string>(SettingsEnum.RepositoryType));

                // Even if the overall repository type is something else, we will switch to different repository access for specific node types,
                // as they may point to other repositories or require different APIs even within the same repository
                if (TopicTypeHelper.IsVstsWorkItemType(rawTopic?.Type))
                {
                    repositoryType = RepositoryTypes.VstsWorkItemTracking;
                }

                switch (repositoryType)
                {
                case RepositoryTypes.GitHubRaw:
                    var fullGitHubRawUrl = GitHubMasterUrlRaw + SelectedTopic.Link;
                    if (string.IsNullOrEmpty(rawTopic.Type))
                    {
                        rawTopic.Type = TopicTypeHelper.GetTopicTypeFromLink(fullGitHubRawUrl);
                    }
                    if (TopicTypeHelper.IsMatch(rawTopic.Type, TopicBodyFormats.Markdown) || TopicTypeHelper.IsMatch(rawTopic.Type, TopicBodyFormats.Html))
                    {
                        rawTopic.OriginalContent = await WebClientEx.GetStringAsync(fullGitHubRawUrl);
                    }
                    else if (TopicTypeHelper.IsMatch(rawTopic.Type, TopicBodyFormats.ImageUrl))
                    {
                        rawTopic.OriginalContent = fullGitHubRawUrl;
                    }
                    ImageRootUrl = StringHelper.JustPath(fullGitHubRawUrl);
                    if (!string.IsNullOrEmpty(ImageRootUrl) && !ImageRootUrl.EndsWith("/"))
                    {
                        ImageRootUrl += "/";
                    }
                    break;

                case RepositoryTypes.GitHubApi:
                    if (TopicTypeHelper.IsMatch(rawTopic.Type, TopicBodyFormats.Markdown) || TopicTypeHelper.IsMatch(rawTopic.Type, TopicBodyFormats.Html))
                    {
                        var gitHubClient  = new GithubRepositoryParser(GitHubOwner, GitHubRepository, GitHubPat);
                        var gitHubContent = await gitHubClient.GetItemContent(SelectedTopic.Link);

                        rawTopic.OriginalContent = gitHubContent.Text;
                    }
                    // TODO: else if (TopicTypeHelper.IsMatch(rawTopic.Type, TopicBodyFormats.ImageUrl))
                    //    rawTopic.OriginalContent = fullGitHubRawUrl;
                    //ImageRootUrl = StringHelper.JustPath(fullGitHubRawUrl);
                    //if (!string.IsNullOrEmpty(ImageRootUrl) && !ImageRootUrl.EndsWith("/")) ImageRootUrl += "/";
                    break;

                case RepositoryTypes.VstsGit:
                    if (!string.IsNullOrEmpty(SelectedTopic.LinkPure))
                    {
                        rawTopic.OriginalContent = await VstsHelper.GetFileContents(SelectedTopic.LinkPure, GetSetting <string>(SettingsEnum.VstsInstance), GetSetting <string>(SettingsEnum.VstsProjectName), GetSetting <string>(SettingsEnum.VstsDocsFolder), GetSetting <string>(SettingsEnum.VstsPat), GetSetting <string>(SettingsEnum.VstsApiVersion));
                    }
                    ImageRootUrl = "/___FileProxy___?mode=" + RepositoryTypeNames.VstsGit + "&path=";
                    if (SelectedTopic.LinkPure.Contains("/"))
                    {
                        ImageRootUrl += StringHelper.JustPath(SelectedTopic.LinkPure) + "/";
                    }
                    break;

                case RepositoryTypes.VstsWorkItemTracking:
                    if ((TopicTypeHelper.IsMatch(rawTopic?.Type, TopicBodyFormats.VstsWorkItemQuery) || TopicTypeHelper.IsMatch(rawTopic?.Type, TopicBodyFormats.VstsWorkItemQueries)) && HttpContext.Request.Query.ContainsKey("workitemnumber"))
                    {
                        // The current node is a work item query, but we use it as a context to get the actual work item
                        var itemNumber = int.Parse(HttpContext.Request.Query["workitemnumber"]);
                        rawTopic.OriginalContent = await VstsHelper.GetWorkItemJson(itemNumber, GetSetting <string>(SettingsEnum.VstsInstance), GetSetting <string>(SettingsEnum.VstsPat), GetSetting <string>(SettingsEnum.VstsApiVersion));

                        rawTopic.Type = TopicBodyFormats.VstsWorkItem;
                    }
                    else if (TopicTypeHelper.IsMatch(rawTopic?.Type, TopicBodyFormats.VstsWorkItemQueries) && HttpContext.Request.Query.ContainsKey("queryid"))
                    {
                        // The current node is a list of work item queries, but we use it as a context to run the actual query
                        var queryId       = HttpContext.Request.Query["queryid"];
                        var queryInfoJson = await VstsHelper.GetWorkItemQueriesJson(queryId, GetSetting <string>(SettingsEnum.VstsInstance), GetSetting <string>(SettingsEnum.VstsProjectName), GetSetting <string>(SettingsEnum.VstsPat), GetSetting <string>(SettingsEnum.VstsApiVersion));

                        dynamic queryInfo = JObject.Parse(queryInfoJson);
                        if (queryInfo != null)
                        {
                            Title = "Query: " + queryInfo.name;
                        }
                        rawTopic.OriginalContent = await VstsHelper.RunWorkItemQueryJson(queryId, GetSetting <string>(SettingsEnum.VstsInstance), GetSetting <string>(SettingsEnum.VstsProjectName), GetSetting <string>(SettingsEnum.VstsPat), GetSetting <string>(SettingsEnum.VstsApiVersion));

                        if (rawTopic.OriginalContent.StartsWith("{"))
                        {
                            rawTopic.Type = TopicBodyFormats.VstsWorkItemQuery;
                        }
                        else
                        {
                            rawTopic.Type = TopicBodyFormats.Markdown;     // Something went wrong, but one way or another, we didn't end up with JSON
                        }
                    }
                    else if (TopicTypeHelper.IsMatch(rawTopic?.Type, TopicBodyFormats.VstsWorkItem))
                    {
                        // Plain work item node
                        var itemNumber = int.Parse(SelectedTopic.Link);
                        rawTopic.OriginalContent = await VstsHelper.GetWorkItemJson(itemNumber, GetSetting <string>(SettingsEnum.VstsInstance), GetSetting <string>(SettingsEnum.VstsPat), GetSetting <string>(SettingsEnum.VstsApiVersion));
                    }
                    else if (TopicTypeHelper.IsMatch(rawTopic?.Type, TopicBodyFormats.VstsWorkItemQueries))
                    {
                        // Plain work item queries
                        rawTopic.OriginalContent = await VstsHelper.GetWorkItemQueriesJson(SelectedTopic.Link, GetSetting <string>(SettingsEnum.VstsInstance), GetSetting <string>(SettingsEnum.VstsProjectName), GetSetting <string>(SettingsEnum.VstsPat), GetSetting <string>(SettingsEnum.VstsApiVersion));

                        Title = SelectedTopic.Title;
                    }
                    else if (TopicTypeHelper.IsMatch(rawTopic?.Type, TopicBodyFormats.VstsWorkItemQuery))
                    {
                        // Plain work item query
                        rawTopic.OriginalContent = await VstsHelper.RunWorkItemQueryJson(SelectedTopic.Link, GetSetting <string>(SettingsEnum.VstsInstance), GetSetting <string>(SettingsEnum.VstsProjectName), GetSetting <string>(SettingsEnum.VstsPat), GetSetting <string>(SettingsEnum.VstsApiVersion));

                        Title = SelectedTopic.Title;
                    }

                    Vsts.ImageLink = "/___FileProxy___?mode=" + RepositoryTypeNames.VstsWorkItemTracking + "&topic=" + CurrentSlug + "&path=";
                    break;
                }
            }

            var renderer = TopicRendererFactory.GetTopicRenderer(rawTopic);

            var intermediateHtml = renderer.RenderToHtml(rawTopic, ImageRootUrl, this);

            if (!string.IsNullOrEmpty(intermediateHtml))
            {
                intermediateHtml = await ProcessKavaTopic(intermediateHtml);

                intermediateHtml = AutoGenerateTitle(intermediateHtml);
                intermediateHtml = ProcessBrokenImageLinks(intermediateHtml, ImageRootUrl);
            }

            Html = intermediateHtml;

            Json         = renderer.RenderToJson(rawTopic, ImageRootUrl, this);
            TemplateName = renderer.GetTemplateName(rawTopic, TemplateName, this);

            if (string.IsNullOrEmpty(Html) && SelectedTopic != null)
            {
                var sb = new StringBuilder();
                sb.Append("<h1>" + SelectedTopic.Title + "</h1>");

                if (SelectedTopic.Topics.Count > 0)
                {
                    sb.Append("<ul>");
                    foreach (var topic in SelectedTopic.Topics)
                    {
                        sb.Append("<li class=\"kava-auto-link\">");
                        sb.Append("<a href=\"" + TopicHelper.GetNormalizedName(topic.Title) + "\">");
                        sb.Append(topic.Title);
                        sb.Append("</a>");
                        sb.Append("</li>");
                    }
                    sb.Append("</ul>");
                }

                Html = sb.ToString();
            }
        }
        private async Task BuildToc()
        {
            string tocJson = null;

            var repositoryType = RepositoryTypeHelper.GetTypeFromTypeName(GetSetting <string>(SettingsEnum.RepositoryType));

            var logoUrl           = GetSetting <string>(SettingsEnum.LogoPath);
            var logoUrlLower      = logoUrl.ToLowerInvariant();
            var logoUrlIsAbsolute = true;

            if (!logoUrl.StartsWith("http://") && !logoUrl.StartsWith("https://"))
            {
                logoUrlIsAbsolute = false;
            }
            LogoUrl = logoUrl;

            if (UseSqlServer) // SQL server *may* provide a local tabe of contents that would override all others
            {
                tocJson = await SqlDataAccess.GetRepositoryLocalTableOfContents(CurrentPrefix);
            }

            if (string.IsNullOrEmpty(tocJson))
            {
                switch (repositoryType)
                {
                case RepositoryTypes.GitHubRaw:
                    tocJson = await TableOfContentsHelper.GetTocJsonFromGitHubRaw(GitHubMasterUrlRaw);

                    if (!logoUrlIsAbsolute)
                    {
                        LogoUrl = GitHubMasterUrlRaw + logoUrl;
                    }
                    break;

                case RepositoryTypes.GitHubApi:
                    tocJson = await TableOfContentsHelper.GetTocJsonFromGitHubApi(GitHubOwner, GitHubRepository, GitHubPat);

                    // TODO: if (!logoUrlIsAbsolute)
                    //    LogoUrl = GitHubMasterUrlRaw + logoUrl;
                    break;

                case RepositoryTypes.VstsGit:
                    tocJson = await VstsHelper.GetTocJson(GetSetting <string>(SettingsEnum.VstsInstance), GetSetting <string>(SettingsEnum.VstsProjectName), GetSetting <string>(SettingsEnum.VstsDocsFolder), GetSetting <string>(SettingsEnum.VstsPat), GetSetting <string>(SettingsEnum.VstsApiVersion));

                    if (!logoUrlIsAbsolute)
                    {
                        LogoUrl = $"/___FileProxy___?mode=vstsgit&path={logoUrl}";
                    }
                    break;
                }
            }
            if (string.IsNullOrEmpty(tocJson))
            {
                return;
            }

            var dynamicToc = TableOfContentsHelper.GetDynamicTocFromJson(tocJson);

            if (dynamicToc.title != null)
            {
                RepositoryTitle = dynamicToc.title;
            }
            if (dynamicToc.owner != null)
            {
                Owner = dynamicToc.owner;
            }

            Topics     = TableOfContentsHelper.BuildTocFromDynamicToc(dynamicToc, this, CurrentSlug, out List <TableOfContentsItem> flatTopicList);
            FlatTopics = flatTopicList;
            MainMenu   = TableOfContentsHelper.BuildMainMenuStructureFromDynamicToc(dynamicToc);

            var matchingTopic = FlatTopics.FirstOrDefault(t => TopicHelper.SlugMatchesTopic(CurrentSlug, t));

            if (matchingTopic == null)
            {
                matchingTopic = FlatTopics.FirstOrDefault(t => TopicHelper.SlugMatchesTopic(CurrentSlug, t, true));
            }
            if (matchingTopic == null)
            {
                matchingTopic = FlatTopics.FirstOrDefault(t => TopicHelper.LinkMatchesTopic(CurrentSlug, t));
            }
            if (matchingTopic == null)
            {
                matchingTopic = Topics.FirstOrDefault();
            }

            SelectedTopic = matchingTopic;
            TableOfContentsHelper.EnsureExpanded(SelectedTopic);

            TocSettings          = dynamicToc.settings;
            CurrentTopicSettings = SelectedTopic?.SettingsDynamic;
        }
Exemple #3
0
        public async Task <IActionResult> FileProxy(string mode, string path, string topic = "", string fileName = "")
        {
            // Special processing for file retrieval of attachments to TFS work items. This is mainly used to return images in item descriptions.
            if (RepositoryTypeHelper.IsMatch(mode, RepositoryTypeNames.VstsWorkItemTracking))
            {
                var model = new TopicViewModel(topic, HttpContext);
                if (SqlDataAccess.CanUseSql)
                {
                    var prefix   = ControllerHelper.GetCurrentDomainPrefix(HttpContext.Request);
                    var settings = await SqlDataAccess.GetSqlRepositorySettingsDynamic(prefix);

                    if (settings == null)
                    {
                        return(NotFound($"Document repository {prefix} does not exist."));
                    }
                    model.SetRootSettingsForRequest(settings);
                }
                await model.LoadData(buildHtml : false, buildToc : true);

                var instance = model.GetSetting <string>(SettingsEnum.VstsInstance);
                var pat      = model.GetSetting <string>(SettingsEnum.VstsPat);
                var stream   = await VstsHelper.GetWorkItemAttachmentStream(path, instance, pat);

                return(File(stream, GetContentTypeFromUrl(fileName), fileName));
            }

            // If we got this far, and the path is a fully qualified URL, then we just retrieve it
            if (path.ToLowerInvariant().StartsWith("http://") || path.ToLowerInvariant().StartsWith("https://"))
            {
                using (var client = new WebClientEx())
                {
                    var data = await client.DownloadDataTaskAsync(new Uri(path));

                    return(File(data, GetContentTypeFromUrl(path), StringHelper.JustFileName(path)));
                }
            }

            // If it is in a VSTS Git repository, we use the API to retrieve it
            if (RepositoryTypeHelper.IsMatch(mode, RepositoryTypeNames.VstsGit))
            {
                if (SqlDataAccess.CanUseSql)
                {
                    var prefix   = ControllerHelper.GetCurrentDomainPrefix(HttpContext.Request);
                    var settings = await SqlDataAccess.GetSqlRepositorySettingsDynamic(prefix);

                    if (settings == null)
                    {
                        return(NotFound($"Document repository {prefix} does not exist."));
                    }
                    var stream = await VstsHelper.GetFileStream(path,
                                                                SettingsHelper.GetSetting <string>(SettingsEnum.VstsInstance, requestRootSettings: settings),
                                                                SettingsHelper.GetSetting <string>(SettingsEnum.VstsProjectName, requestRootSettings: settings),
                                                                SettingsHelper.GetSetting <string>(SettingsEnum.VstsDocsFolder, requestRootSettings: settings),
                                                                SettingsHelper.GetSetting <string>(SettingsEnum.VstsPat, requestRootSettings: settings),
                                                                SettingsHelper.GetSetting <string>(SettingsEnum.VstsApiVersion, requestRootSettings: settings));

                    return(File(stream, GetContentTypeFromUrl(path), StringHelper.JustFileName(path)));
                }
                else
                {
                    var stream = await VstsHelper.GetFileStream(path,
                                                                SettingsHelper.GetSetting <string>(SettingsEnum.VstsInstance),
                                                                SettingsHelper.GetSetting <string>(SettingsEnum.VstsProjectName),
                                                                SettingsHelper.GetSetting <string>(SettingsEnum.VstsDocsFolder),
                                                                SettingsHelper.GetSetting <string>(SettingsEnum.VstsPat),
                                                                SettingsHelper.GetSetting <string>(SettingsEnum.VstsApiVersion));

                    return(File(stream, GetContentTypeFromUrl(path), StringHelper.JustFileName(path)));
                }
            }

            // Otherwise, we got nothing :-)
            return(null);
        }