Esempio n. 1
0
    public static MarkdownItemTestSubclass New(IWikiOptions options, IDataStore dataStore, string?markdown)
    {
        var md = string.IsNullOrEmpty(markdown)
            ? null
            : TransclusionParser.Transclude(
            options,
            dataStore,
            null,
            null,
            markdown,
            out _);
        var wikiLinks = GetWikiLinks(options, dataStore, md);

        return(new MarkdownItemTestSubclass(
                   md,
                   RenderHtml(options, dataStore, md),
                   RenderPreview(
                       options,
                       dataStore,
                       string.IsNullOrEmpty(markdown)
                    ? string.Empty
                    : TransclusionParser.Transclude(
                           options,
                           dataStore,
                           null,
                           null,
                           markdown,
                           out _,
                           isPreview: true)),
                   wikiLinks));
    }
Esempio n. 2
0
    /// <summary>
    /// Revises this <see cref="WikiFile"/> instance.
    /// </summary>
    /// <param name="options">An <see cref="IWikiOptions"/> instance.</param>
    /// <param name="dataStore">An <see cref="IDataStore"/> instance.</param>
    /// <param name="editor">
    /// The ID of the user who made this revision.
    /// </param>
    /// <param name="title">
    /// <para>
    /// The optional new title of the file. Must be unique within its namespace, and non-empty.
    /// </para>
    /// <para>
    /// If left <see langword="null"/> the existing title will be retained.
    /// </para>
    /// </param>
    /// <param name="path">The relative path to the file.</param>
    /// <param name="fileSize">The size of the file, in bytes.</param>
    /// <param name="type">
    /// <para>
    /// The MIME type of the file.
    /// </para>
    /// <para>
    /// If left <see langword="null"/> the existing type will be retained.
    /// </para>
    /// </param>
    /// <param name="markdown">The markdown.</param>
    /// <param name="revisionComment">
    /// An optional comment supplied for this revision (e.g. to explain the changes).
    /// </param>
    /// <param name="isDeleted">Indicates that this file has been marked as deleted.</param>
    /// <param name="owner">
    /// <para>
    /// The new owner of the file.
    /// </para>
    /// <para>
    /// May be a user, a group, or <see langword="null"/>.
    /// </para>
    /// </param>
    /// <param name="allowedEditors">
    /// <para>
    /// The user(s) and/or group(s) allowed to edit this file.
    /// </para>
    /// <para>
    /// If <see langword="null"/> the file can be edited by anyone.
    /// </para>
    /// <para>
    /// If non-<see langword="null"/> the file can only be edited by those listed, plus its
    /// owner (regardless of whether the owner is explicitly listed). An empty (but non-<see
    /// langword="null"/>) list allows only the owner to make edits.
    /// </para>
    /// </param>
    /// <param name="allowedViewers">
    /// <para>
    /// The user(s) and/or group(s) allowed to view this file.
    /// </para>
    /// <para>
    /// If <see langword="null"/> the file can be viewed by anyone.
    /// </para>
    /// <para>
    /// If non-<see langword="null"/> the file can only be viewed by those listed, plus its
    /// owner (regardless of whether the owner is explicitly listed). An empty (but non-<see
    /// langword="null"/>) list allows only the owner to view the file.
    /// </para>
    /// </param>
    public async Task ReviseAsync(
        IWikiOptions options,
        IDataStore dataStore,
        string editor,
        string?title           = null,
        string?path            = null,
        int?fileSize           = null,
        string?type            = null,
        string?markdown        = null,
        string?revisionComment = null,
        bool isDeleted         = false,
        string?owner           = null,
        IEnumerable <string>?allowedEditors = null,
        IEnumerable <string>?allowedViewers = null)
    {
        title ??= title?.ToWikiTitleCase() ?? Title;

        var newFile = false;

        if (!string.IsNullOrWhiteSpace(path))
        {
            newFile  = path != FilePath;
            FilePath = path;
        }
        if (fileSize.HasValue)
        {
            newFile |= fileSize.Value != FileSize;
            FileSize = fileSize.Value;
        }
        if (!string.IsNullOrEmpty(type))
        {
            newFile |= type != FileType;
            FileType = type;
        }

        if (newFile)
        {
            Uploader = editor;
        }

        var previousTitle = Title;

        Title = title;
        var sameTitle = string.Equals(previousTitle, title, StringComparison.Ordinal);

        var previousMarkdown = MarkdownContent;
        var wasDeleted       = IsDeleted || string.IsNullOrWhiteSpace(previousMarkdown);

        if (isDeleted || string.IsNullOrWhiteSpace(markdown))
        {
            if (!wasDeleted)
            {
                Html            = string.Empty;
                IsDeleted       = true;
                MarkdownContent = string.Empty;
                Preview         = string.Empty;
                Categories      = new List <string>().AsReadOnly();

                if (Transclusions is not null)
                {
                    await RemovePageTransclusionsAsync(dataStore, Id, Transclusions)
                    .ConfigureAwait(false);
                }

                await RemovePageLinksAsync(dataStore, Id, WikiLinks)
                .ConfigureAwait(false);

                Transclusions = null;
                WikiLinks     = new List <WikiLink>().AsReadOnly();
            }
        }
        else
        {
            IsDeleted = false;
        }

        if (!sameTitle && !IsDeleted)
        {
            await CreatePageReferenceAsync(dataStore, Id, title, options.FileNamespace)
            .ConfigureAwait(false);
        }
        if (!sameTitle)
        {
            await RemovePageReferenceAsync(dataStore, Id, previousTitle, options.FileNamespace)
            .ConfigureAwait(false);
        }

        var changed = wasDeleted != IsDeleted ||
                      !string.Equals(previousMarkdown, markdown, StringComparison.Ordinal);

        if (!IsDeleted && changed)
        {
            MarkdownContent = markdown !;

            var previousTransclusions = Transclusions?.ToList() ?? new List <Transclusion>();
            var md = TransclusionParser.Transclude(
                options,
                dataStore,
                title,
                $"{options.FileNamespace}:{title}",
                markdown !,
                out var transclusions);
            Transclusions = transclusions.Count == 0
                ? null
                : transclusions.AsReadOnly();
            await RemovePageTransclusionsAsync(dataStore, Id, previousTransclusions.Except(transclusions))
            .ConfigureAwait(false);
            await AddPageTransclusionsAsync(dataStore, Id, transclusions.Except(previousTransclusions))
            .ConfigureAwait(false);

            var previousWikiLinks = WikiLinks.ToList();
            WikiLinks = GetWikiLinks(options, dataStore, md, title, options.FileNamespace).AsReadOnly();
            await RemovePageLinksAsync(dataStore, Id, previousWikiLinks.Except(WikiLinks))
            .ConfigureAwait(false);
            await AddPageLinksAsync(dataStore, Id, WikiLinks.Except(previousWikiLinks))
            .ConfigureAwait(false);
        }

        if (changed)
        {
            Categories = (await UpdateCategoriesAsync(
                              options,
                              dataStore,
                              Id,
                              editor,
                              owner,
                              allowedEditors,
                              allowedViewers,
                              WikiLinks,
                              Categories)
                          .ConfigureAwait(false))
                         .AsReadOnly();

            Update(options, dataStore);
        }

        var oldOwner = Owner;

        Owner          = owner;
        AllowedEditors = allowedEditors?.ToList().AsReadOnly();
        AllowedViewers = allowedViewers?.ToList().AsReadOnly();

        var revision = new Revision(
            Id,
            editor,
            title,
            options.FileNamespace,
            previousMarkdown,
            MarkdownContent,
            revisionComment);
        await dataStore.StoreItemAsync(revision).ConfigureAwait(false);

        TimestampTicks = revision.TimestampTicks;

        await dataStore.StoreItemAsync(this).ConfigureAwait(false);

        await UpdateReferencesAsync(
            options,
            dataStore,
            title,
            options.FileNamespace,
            IsDeleted,
            sameTitle,
            previousTitle,
            options.FileNamespace,
            false,
            false)
        .ConfigureAwait(false);

        if (isDeleted && !wasDeleted)
        {
            if (options.OnDeleted is not null)
            {
                await options.OnDeleted(this, oldOwner, Owner).ConfigureAwait(false);
            }
            else if (options.OnEdited is not null)
            {
                await options.OnEdited(this, revision, oldOwner, Owner).ConfigureAwait(false);
            }
        }
        else if (options.OnEdited is not null)
        {
            await options.OnEdited(this, revision, oldOwner, Owner).ConfigureAwait(false);
        }
    }
Esempio n. 3
0
    /// <summary>
    /// Gets a new <see cref="WikiFile"/> instance.
    /// </summary>
    /// <param name="options">An <see cref="IWikiOptions"/> instance.</param>
    /// <param name="dataStore">An <see cref="IDataStore"/> instance.</param>
    /// <param name="title">The title of the file. Must be unique and non-empty.</param>
    /// <param name="editor">
    /// The ID of the user who created this file.
    /// </param>
    /// <param name="filePath">The relative path to the file.</param>
    /// <param name="fileSize">The size of the file, in bytes.</param>
    /// <param name="type">
    /// The MIME type of the file.
    /// </param>
    /// <param name="markdown">The raw markdown content.</param>
    /// <param name="revisionComment">
    /// An optional comment supplied for this revision (e.g. to explain the upload).
    /// </param>
    /// <param name="owner">
    /// <para>
    /// The ID of the intended owner of the file.
    /// </para>
    /// <para>
    /// May be a user, a group, or <see langword="null"/>.
    /// </para>
    /// </param>
    /// <param name="allowedEditors">
    /// <para>
    /// The user(s) and/or group(s) allowed to edit this file.
    /// </para>
    /// <para>
    /// If <see langword="null"/> the file can be edited by anyone.
    /// </para>
    /// <para>
    /// If non-<see langword="null"/> the file can only be edited by those listed, plus its
    /// owner (regardless of whether the owner is explicitly listed). An empty (but non-<see
    /// langword="null"/>) list allows only the owner to make edits.
    /// </para>
    /// </param>
    /// <param name="allowedViewers">
    /// <para>
    /// The user(s) and/or group(s) allowed to view this file.
    /// </para>
    /// <para>
    /// If <see langword="null"/> the file can be viewed by anyone.
    /// </para>
    /// <para>
    /// If non-<see langword="null"/> the file can only be viewed by those listed, plus its
    /// owner (regardless of whether the owner is explicitly listed). An empty (but non-<see
    /// langword="null"/>) list allows only the owner to view the file.
    /// </para>
    /// </param>
    public static async Task <WikiFile> NewAsync(
        IWikiOptions options,
        IDataStore dataStore,
        string title,
        string editor,
        string filePath,
        int fileSize,
        string type,
        string?markdown        = null,
        string?revisionComment = null,
        string?owner           = null,
        IEnumerable <string>?allowedEditors = null,
        IEnumerable <string>?allowedViewers = null)
    {
        if (string.IsNullOrWhiteSpace(title))
        {
            throw new ArgumentException($"{nameof(title)} cannot be empty.", nameof(title));
        }
        title = title.ToWikiTitleCase();

        var wikiId = dataStore.CreateNewIdFor <WikiFile>();

        await CreatePageReferenceAsync(dataStore, wikiId, title, options.FileNamespace)
        .ConfigureAwait(false);

        var revision = new Revision(
            wikiId,
            editor,
            title,
            options.FileNamespace,
            null,
            markdown,
            revisionComment);
        await dataStore.StoreItemAsync(revision).ConfigureAwait(false);

        var md = markdown;
        List <Transclusion> transclusions;

        if (string.IsNullOrEmpty(markdown))
        {
            transclusions = new List <Transclusion>();
        }
        else
        {
            md = TransclusionParser.Transclude(
                options,
                dataStore,
                title,
                $"{options.FileNamespace}:{title}",
                markdown,
                out transclusions);
        }

        var wikiLinks = GetWikiLinks(options, dataStore, md, title, options.FileNamespace);

        var categories = await UpdateCategoriesAsync(
            options,
            dataStore,
            wikiId,
            editor,
            owner,
            allowedEditors,
            allowedViewers,
            wikiLinks)
                         .ConfigureAwait(false);

        var file = new WikiFile(
            wikiId,
            title,
            filePath,
            fileSize,
            editor,
            type,
            markdown,
            RenderHtml(options, dataStore, PostprocessArticleMarkdown(options, dataStore, title, options.FileNamespace, markdown)),
            RenderPreview(options, dataStore, PostprocessArticleMarkdown(options, dataStore, title, options.FileNamespace, markdown, true)),
            new ReadOnlyCollection <WikiLink>(wikiLinks),
            revision.TimestampTicks,
            options.FileNamespace,
            isDeleted: false,
            owner,
            allowedEditors,
            allowedViewers,
            categories,
            transclusions);
        await dataStore.StoreItemAsync(file).ConfigureAwait(false);

        await AddPageTransclusionsAsync(dataStore, wikiId, transclusions)
        .ConfigureAwait(false);

        await AddPageLinksAsync(dataStore, wikiId, wikiLinks)
        .ConfigureAwait(false);

        await UpdateReferencesAsync(
            options,
            dataStore,
            title,
            options.FileNamespace,
            false,
            true,
            null,
            null,
            false,
            false)
        .ConfigureAwait(false);

        if (options.OnCreated is not null)
        {
            await options.OnCreated.Invoke(file, editor).ConfigureAwait(false);
        }

        return(file);
    }