Example #1
0
 /// <summary>
 /// Identifies the <see cref="WikiLink"/>s in the given <paramref name="markdown"/>.
 /// </summary>
 /// <param name="options">An <see cref="WikiOptions"/> instance.</param>
 /// <param name="dataStore">An <see cref="IDataStore"/> instance.</param>
 /// <param name="markdown">The markdown.</param>
 /// <param name="title">The title of the item.</param>
 /// <param name="wikiNamespace">The namespace of the item.</param>
 /// <returns>
 /// A <see cref="List{T}"/> of <see cref="WikiLink"/>s.
 /// </returns>
 protected static List <WikiLink> GetWikiLinks(
     IWikiOptions options,
     IDataStore dataStore,
     string?markdown,
     string?title         = null,
     string?wikiNamespace = null)
 => string.IsNullOrEmpty(markdown)
     ? new List <WikiLink>()
     : Markdown.Parse(markdown, WikiConfig.GetMarkdownPipeline(options, dataStore))
 .Descendants <WikiLinkInline>()
 .Where(x => !x.IsWikipedia &&
Example #2
0
        public WikiSite(WikiConfig config, MasterRepository masterRepository, ISourceWatcher sourceWatcher, IPageCache pageCache)
        {
            wikiConfig = config;

            repository = masterRepository;

            watcher = sourceWatcher;
            generator = new WikiGenerator(wikiConfig.Convertor, wikiConfig.RootWikiPath, pageCache);

            siteGeneratorScheduler = new EventLoopScheduler(threadStart => new Thread(threadStart) { Name = "SiteGenerator" });
        }
Example #3
0
        public TestWikiSite()
        {
            // setup initial site structure
            Directory.CreateDirectory(Path.Combine(".", "subdir1"));
            Directory.CreateDirectory(Path.Combine(".", "subdir1", "subdir2"));
            Directory.CreateDirectory(Path.Combine(".", "subdir1", "subdir2", "subdir3"));
            Directory.CreateDirectory(Path.Combine(".", "subdir1", "subdir2", "subdir3", "subdir4"));
            System.IO.File.AppendAllText(Path.Combine(".", "index.md"), "Hello World");
            System.IO.File.AppendAllText(Path.Combine(".", "subdir1", "index.md"), "Hello World Sub Directory");
            System.IO.File.AppendAllText(Path.Combine(".", "subdir1", "subdir2", "index.md"), "Hello World Sub Sub Directory");

            createdDirectories = new List <string>();
            updatedDirectories = new List <string>();
            deletedDirectories = new List <string>();
            movedDirectories   = new List <string>();

            createdPages = new List <string>();
            updatedPages = new List <string>();
            deletedPages = new List <string>();
            movedPages   = new List <string>();

            Convertor  convertor  = new Convertor(new MarkdownSharpDialogue());
            WikiConfig wikiConfig = new WikiConfig()
            {
                SiteName       = "Tester",
                RootSourcePath = PathHelper.GetFullPath("."),
                RootWikiPath   = PathHelper.GetFullPath(".", "wiki"),
                Convertor      = new Convertor(new MarkdownSharpDialogue())
            };

            site = new WikiSite(wikiConfig,
                                new MasterRepository(convertor.FileExtension),
                                new SourceWatcher(wikiConfig.RootSourcePath, wikiConfig.Convertor.FileSearchString),
                                new PageCache()
                                );

            // setup event handlers
            site.DirectoryAdded   += (source, args) => createdDirectories.Add(args.WikiUrl);
            site.DirectoryUpdated += (source, args) => updatedDirectories.Add(args.WikiUrl);
            site.DirectoryDeleted += (source, args) => deletedDirectories.Add(args.WikiUrl);
            site.DirectoryMoved   += (source, args) => movedDirectories.Add(args.WikiUrl);

            site.PageAdded   += (source, args) => createdPages.Add(args.WikiUrl);
            site.PageUpdated += (source, args) => updatedPages.Add(args.WikiUrl);
            site.PageDeleted += (source, args) => deletedPages.Add(args.WikiUrl);
            site.PageMoved   += (source, args) => movedPages.Add(args.WikiUrl);

            site.Start();

            Thread.Sleep(1000);
        }
Example #4
0
        public TestWikiSite()
        {
            // setup initial site structure
            Directory.CreateDirectory(Path.Combine(".", "subdir1"));
            Directory.CreateDirectory(Path.Combine(".", "subdir1", "subdir2"));
            Directory.CreateDirectory(Path.Combine(".", "subdir1", "subdir2", "subdir3"));
            Directory.CreateDirectory(Path.Combine(".", "subdir1", "subdir2", "subdir3", "subdir4"));
            System.IO.File.AppendAllText(Path.Combine(".", "index.md"), "Hello World");
            System.IO.File.AppendAllText(Path.Combine(".", "subdir1", "index.md"), "Hello World Sub Directory");
            System.IO.File.AppendAllText(Path.Combine(".", "subdir1", "subdir2", "index.md"), "Hello World Sub Sub Directory");

            createdDirectories = new List<string>();
            updatedDirectories = new List<string>();
            deletedDirectories = new List<string>();
            movedDirectories = new List<string>();

            createdPages = new List<string>();
            updatedPages = new List<string>();
            deletedPages = new List<string>();
            movedPages = new List<string>();

            Convertor convertor = new Convertor(new MarkdownSharpDialogue());
            WikiConfig wikiConfig = new WikiConfig()
                {
                    SiteName = "Tester",
                    RootSourcePath = PathHelper.GetFullPath("."),
                    RootWikiPath = PathHelper.GetFullPath(".", "wiki"),
                    Convertor = new Convertor(new MarkdownSharpDialogue())
                };

            site = new WikiSite(wikiConfig,
                new MasterRepository(convertor.FileExtension),
                new SourceWatcher(wikiConfig.RootSourcePath, wikiConfig.Convertor.FileSearchString),
                new PageCache()
            );

            // setup event handlers
            site.DirectoryAdded += (source, args) => createdDirectories.Add(args.WikiUrl);
            site.DirectoryUpdated += (source, args) => updatedDirectories.Add(args.WikiUrl);
            site.DirectoryDeleted += (source, args) => deletedDirectories.Add(args.WikiUrl);
            site.DirectoryMoved += (source, args) => movedDirectories.Add(args.WikiUrl);

            site.PageAdded += (source, args) => createdPages.Add(args.WikiUrl);
            site.PageUpdated += (source, args) => updatedPages.Add(args.WikiUrl);
            site.PageDeleted += (source, args) => deletedPages.Add(args.WikiUrl);
            site.PageMoved += (source, args) => movedPages.Add(args.WikiUrl);

            site.Start();

            Thread.Sleep(1000);
        }
Example #5
0
        public WikiSite(WikiConfig config, MasterRepository masterRepository, ISourceWatcher sourceWatcher, IPageCache pageCache)
        {
            wikiConfig = config;

            repository = masterRepository;

            watcher   = sourceWatcher;
            generator = new WikiGenerator(wikiConfig.Convertor, wikiConfig.RootWikiPath, pageCache);

            siteGeneratorScheduler = new EventLoopScheduler(threadStart => new Thread(threadStart)
            {
                Name = "SiteGenerator"
            });
        }
Example #6
0
        public bool TryGetConfig(string siteName, out WikiConfig value)
        {
            string safeName = CreateSafeName(siteName);

            Tuple <WikiConfig, MasterRepository, IPageCache> tuple;

            if (configMap.TryGetValue(siteName, out tuple))
            {
                value = tuple.Item1;
                return(true);
            }
            else
            {
                value = null;
                return(false);
            }
        }
Example #7
0
        public static async Task SetupClient(TestContext context)
        {
            generalConfig = GeneralConfig.Instance.Value;
            var conf = new BacklogJpConfigure(generalConfig.SpaceKey);

            conf.ApiKey = generalConfig.ApiKey;
            client      = new BacklogClientFactory(conf).NewClient();
            var users = await client.GetUsersAsync();

            projectKey = generalConfig.ProjectKey;
            var project = await client.GetProjectAsync(projectKey);

            projectId = project.Id;

            wikiConfig = WikiConfig.Instance.Value;

            ownUser = await client.GetMyselfAsync();
        }
Example #8
0
    /// <summary>
    /// Gets a preview of the given markdown's rendered HTML.
    /// </summary>
    /// <param name="options">An <see cref="IWikiOptions"/> instance.</param>
    /// <param name="dataStore">An <see cref="IDataStore"/> instance.</param>
    /// <param name="markdown">The markdown content.</param>
    /// <returns>A preview of the rendered HTML.</returns>
    public static string RenderPreview(IWikiOptions options, IDataStore dataStore, string?markdown)
    {
        if (string.IsNullOrWhiteSpace(markdown))
        {
            return(string.Empty);
        }

        var document = Markdown.Parse(markdown, WikiConfig.GetMarkdownPipeline(options, dataStore));

        if (AnyPreviews(document))
        {
            TrimNonPreview(document);
        }
        else
        {
            var minCharactersAvailable = PreviewCharacterMin;
            var maxCharactersAvailable = PreviewCharacterMax;
            Trim(document, ref minCharactersAvailable, ref maxCharactersAvailable);
        }

        string html;

        using (var writer = new StringWriter())
        {
            var renderer = new HtmlRenderer(writer);
            WikiConfig.GetMarkdownPipeline(options, dataStore).Setup(renderer);
            renderer.Render(document);
            html = writer.ToString();
        }

        if (!string.IsNullOrWhiteSpace(html) &&
            options.Postprocessors is not null)
        {
            foreach (var preprocessor in options.Postprocessors)
            {
                html = preprocessor.Process.Invoke(html);
            }
        }

        return(WikiConfig.GetHtmlSanitizer(options).Sanitize(html) ?? string.Empty);
    }
Example #9
0
    /// <summary>
    /// Renders the given <paramref name="markdown"/> as HTML.
    /// </summary>
    /// <param name="options">An <see cref="IWikiOptions"/> instance.</param>
    /// <param name="dataStore">An <see cref="IDataStore"/> instance.</param>
    /// <param name="markdown">The markdown content.</param>
    /// <returns>The rendered HTML.</returns>
    public static string RenderHtml(IWikiOptions options, IDataStore dataStore, string?markdown)
    {
        if (string.IsNullOrWhiteSpace(markdown))
        {
            return(string.Empty);
        }

        var html = Markdown.ToHtml(markdown, WikiConfig.GetMarkdownPipeline(options, dataStore));

        if (string.IsNullOrWhiteSpace(html))
        {
            return(string.Empty);
        }

        if (options.Postprocessors is not null)
        {
            foreach (var preprocessor in options.Postprocessors)
            {
                html = preprocessor.Process.Invoke(html);
            }
        }

        return(WikiConfig.GetHtmlSanitizer(options).Sanitize(html));
    }
Example #10
0
    /// <summary>
    /// Gets the given markdown content as plain text (i.e. strips all formatting).
    /// </summary>
    /// <param name="options">An <see cref="IWikiOptions"/> instance.</param>
    /// <param name="dataStore">An <see cref="IDataStore"/> instance.</param>
    /// <param name="markdown">The markdown content.</param>
    /// <param name="characterLimit">The maximum number of characters to return.</param>
    /// <param name="singleParagraph">
    /// If true, stops after the first paragraph break, even still under the allowed character limit.
    /// </param>
    /// <returns>The plain text.</returns>
    public static string FormatPlainText(
        IWikiOptions options,
        IDataStore dataStore,
        string?markdown,
        int?characterLimit   = 200,
        bool singleParagraph = true)
    {
        if (string.IsNullOrEmpty(markdown))
        {
            return(string.Empty);
        }

        if (singleParagraph && markdown.Length > 1)
        {
            var paraIndex = markdown.IndexOf(Environment.NewLine + Environment.NewLine, 1);
            if (paraIndex > 0)
            {
                markdown = markdown.Substring(0, paraIndex);
            }
        }

        if (characterLimit.HasValue && markdown.Length > characterLimit.Value * 5)
        {
            markdown = markdown.Substring(0, characterLimit.Value * 5);
        }

        var html = Markdown.ToHtml(markdown, WikiConfig.GetMarkdownPipelinePlainText(options, dataStore));

        if (string.IsNullOrWhiteSpace(html))
        {
            return(string.Empty);
        }

        if (options.Postprocessors is not null)
        {
            foreach (var preprocessor in options.Postprocessors)
            {
                html = preprocessor.Process.Invoke(html);
            }
        }

        var sanitized = WikiConfig.HtmlSanitizerFull.Sanitize(html);

        if (characterLimit.HasValue && sanitized.Length > characterLimit)
        {
            var substring  = sanitized.Substring(0, characterLimit.Value);
            var i          = substring.Length - 1;
            var whitespace = false;
            for (; i > 0; i--)
            {
                if (substring[i].IsWhiteSpaceOrZero())
                {
                    whitespace = true;
                }
                else if (whitespace)
                {
                    break;
                }
            }
            sanitized = whitespace
                ? substring.Substring(0, i + 1)
                : substring;
        }
        return(sanitized);
    }
Example #11
0
        public WikiModule(ServerConfig serverConfig)
            : base("/wiki")
        {
            config     = serverConfig;
            fileReader = new FileReader(FileReaderPolicy.LimitedBlock, 500);

            // add top level "site" route
            Get["/{site}"] = parameters =>
            {
                WikiConfig       wikiConfig       = null;
                MasterRepository masterRepository = null;
                if (config.TryGetConfig(parameters["site"], out wikiConfig) &&
                    config.TryGetMasterRepository(parameters["site"], out masterRepository))
                {
                    // TODO: Async-ify this
                    var pageResults = masterRepository.GetAvailableAssets().Result;

                    SiteModel model = new SiteModel()
                    {
                        IsPartialView = Request.Query.isPartial,
                        WikiUrl       = "/",
                        SiteMap       = pageResults
                    };

                    Context.ViewBag.SiteName = wikiConfig.SiteName;

                    return(View["Site.cshtml", model]);
                }
                else
                {
                    return(HttpStatusCode.NotFound);
                }
            };

            // add "directory" route, subpath should not contain a "." or a "/"
            Get[@"/{site}/(?<directory>[^\.]*)"] = parameters =>
            {
                WikiConfig wikiConfig;
                if (config.TryGetConfig(parameters["site"], out wikiConfig) &&
                    Directory.Exists(Path.Combine(wikiConfig.RootWikiPath, parameters["directory"])))
                {
                    DirectoryModel model = new DirectoryModel()
                    {
                        IsPartialView = Request.Query.isPartial,
                        WikiUrl       = parameters["directory"],
                    };

                    Context.ViewBag.SiteName = wikiConfig.SiteName;

                    return(View["Directory.cshtml", model]);
                }
                else
                {
                    return(HttpStatusCode.NotFound);
                }
            };

            // add "page" route, subpath should always have a file extension (and therefore at least one ".")
            Get[@"/{site}/(?<page>.*\..*)"] = parameters =>
            {
                WikiConfig       wikiConfig       = null;
                MasterRepository masterRepository = null;
                if (config.TryGetConfig(parameters["site"], out wikiConfig) &&
                    config.TryGetMasterRepository(parameters["site"], out masterRepository))
                {
                    // Async-ify
                    var results = masterRepository.GetPageByWikiUrl(parameters["page"]).Result;

                    if (results.Item1)
                    {
                        var results2 = TryGetPageContents(parameters["site"], results.Item2);

                        if (results2.Item1)
                        {
                            PageModel model = new PageModel()
                            {
                                IsPartialView = Request.Query.isPartial,
                                WikiUrl       = parameters["page"],
                                Contents      = results2.Item2
                            };

                            Context.ViewBag.SiteName = wikiConfig.SiteName;

                            return(View["Page.cshtml", model]);
                        }
                        else
                        {
                            // TODO: If the file doesn't exist we could potentially remove it from the cache
                            return(HttpStatusCode.NotFound);
                        }
                    }
                    else
                    {
                        // TODO: If the file doesn't exist we could potentially remove it from the cache
                        return(HttpStatusCode.NotFound);
                    }
                }
                else
                {
                    return(HttpStatusCode.NotFound);
                }
            };
        }