MishkaBlog.Resources.Preparations.ReaderLocks (Mishka Blog v0.0.1)

Copy Markdown View Source

What a reader may open, as the filter of the read that fetches the records: the answer MishkaCmsCore.Accounts.Checks.AccessPermissions gives for a record's lock, worked out by the database in the statement that reads the rows, so that no lock is read beforehand.

The reader is the names its actor holds (of/1): a guest holds none, a user's are loaded with the actor. A lock opens for a reader when it names nothing, or when a name in it is covered by a name the reader holds, as AccessPermissions.match?/3 asks it of a request from the dashboard:

  • a held name with no * segment covers the same name and nothing else;
  • a held name with a * segment covers a name of at least its number of segments whose segments agree with its own, a * standing for any one segment and, as its last segment, for the rest of the name, however many segments that is. * alone covers every name, members:* every name below members;
  • a name admin:api:… counts for nobody, whoever holds what.

The held names with no * are compared as they are and the others as anchored regular expressions. fragment/1 is used for that, and for nothing else of the matching, because Ash has no operator that tests each element of an array against a list of names and patterns. Everything else is an Ash expression.

The page that serves a record

A record is also kept from a reader the runtime page that serves its address is locked to. The pages are those of the site that show the kind of record (page_open/3: extra["record"] is "blog:post", "blog:category", "blog:tag", "blog:author" or "blog:team"), active and not archived, and the kind opens for the reader when no page shows it or when one of them names no permission or names one the reader holds, as the page itself lets them in. It is a subquery of the read that does not depend on the row, so the database runs it once for the statement and no read is made beforehand; a site that locks no page opens every kind. The fragment names the table and the columns of the pages, which MishkaBlog.ReaderLocksTest keeps to the resource's.

Records that inherit

A post opens with its own lock, else with those of the categories it is filed under, each as the nearest category above it, or itself, that names some; it opens when none of them is locked or the reader may open one. A category opens with its own lock, else the nearest above it that names some. A comment opens with its post.

The categories under a lock are found by a recursive query over the site's categories, which Ash has no operator for either. It is a subquery of the read that does not depend on the row, so the database runs it once for the statement, and it starts from the categories that name permissions: a site that locks nothing walks none. The fragments name the tables of the categories and of their posts, which MishkaBlog.ReaderLocksTest keeps to the resources'.

Summary

Functions

Whether a category opens for the reader, in site: its own lock when it names permissions, else those of the nearest category above it that does.

Whether a comment opens for the reader, in site: whoever may open its post. A comment whose post is gone opens, as it does for the posts' read.

The names actor holds, as what a lock is matched against. nil holds none.

Whether a record whose lock is its permissions opens for the reader: it names nothing, or names something the reader holds.

The site of the record itself, for a record asked for by itself.

Whether the runtime page that serves a record of record ("blog:post", "blog:category", "blog:tag", "blog:author" or "blog:team") is open to the reader, in site (see site/1): true when no page shows the kind, or when a page that does names no permission or one the reader holds.

Whether a post opens for the reader, in site (see site/1): its own lock when it names permissions, else those of the categories it is filed under. It opens when none of them is locked or when the reader may open one of them.

The site a read is made in, as the id the categories are walked in: the one a list's query runs for.

Types

t()

@type t() :: %MishkaBlog.Resources.Preparations.ReaderLocks{
  exact: [String.t()],
  patterns: [String.t()]
}

Functions

category(reader, site)

@spec category(t(), Ash.Expr.t()) :: Ash.Expr.t()

Whether a category opens for the reader, in site: its own lock when it names permissions, else those of the nearest category above it that does.

comment(reader, site)

@spec comment(t(), Ash.Expr.t()) :: Ash.Expr.t()

Whether a comment opens for the reader, in site: whoever may open its post. A comment whose post is gone opens, as it does for the posts' read.

of(actor)

@spec of(map() | nil) :: t()

The names actor holds, as what a lock is matched against. nil holds none.

opens(reader)

@spec opens(t()) :: Ash.Expr.t()

Whether a record whose lock is its permissions opens for the reader: it names nothing, or names something the reader holds.

own_site()

@spec own_site() :: Ash.Expr.t()

The site of the record itself, for a record asked for by itself.

page_open(reader_locks, record, site)

@spec page_open(t(), String.t(), Ash.Expr.t()) :: Ash.Expr.t()

Whether the runtime page that serves a record of record ("blog:post", "blog:category", "blog:tag", "blog:author" or "blog:team") is open to the reader, in site (see site/1): true when no page shows the kind, or when a page that does names no permission or one the reader holds.

post(reader, site)

@spec post(t(), Ash.Expr.t()) :: Ash.Expr.t()

Whether a post opens for the reader, in site (see site/1): its own lock when it names permissions, else those of the categories it is filed under. It opens when none of them is locked or when the reader may open one of them.

site(site_id)

@spec site(String.t()) :: Ash.Expr.t()

The site a read is made in, as the id the categories are walked in: the one a list's query runs for.