Concepts

Object containment

In Zadig, objects can be contained in other objects. For example, you can have page /mypage/hobbies, and it can contain /mypage/hobbies/django. There is no separate “folder” object; instead, any object can act as a container of other objects, in addition to having its own content. If a page has no content, then it shows an index of its contained pages (like Plone does for folders when no page has been set as the folder’s default view).

Philosophy

Why don’t we specifically use folders, as Plone does? The reason is that it conflicts with the URL scheme, where any resource can have subresources. Because of this conflict, it is difficult for users to understand the notion of a folder and a page. For example, a user would normally create a page /mypage/hobbies, and then typically ask: how do I now create /mypage/hobbies/django? The Plone reply (hobbies must be made a folder, the current hobbies page must become a page inside the folder, and must be set as default, and a django [page or folder?] must be created inside the folder) is complicated and unintuitive. It also poses a practical problem: the user needs to decide a priori whether the page he is about to create will contain subpages or whether it is likely to remain a single page.

On the other hand, other web management systems, like MoinMoin, have pages and subpages, and each page can have attachments. This is also unintuitive, because, for example, an image does not always belong to a “page”; it rather belongs to a folder. /myfolder/myimage is much better and intuitive than /mypage?attachment=myimage.

Also note that, in Moin, /mypage/mysubpage is a completely different and unrelated page to /mypage: it’s just a name that contains a slash. But in Zadig, /mypage/mysubpage is a page that is contained in /mypage, as if the latter were a folder. Moin is even simpler and maps even better on the URL scheme, but Zadig makes property inheritance (e.g. permissions and skins) much simpler and foolproof: any object simply inherits the properties of its container objects.

Entries and vobjects

The end user uses the word page (and the more general object) with two meanings, owing to the fact that we do automatic versioning like that of a wiki. When we say “delete this page”, we mean delete an entire sequence of pages; when we talk about the content of a page, we mean the content of a specific page version.

When we need to distinguish between the two (and this is when we are writing code), we use the word entry for a sequence of versioned objects, and the word vobject for each specific version of an entry. An entry can be a page entry, an image entry, etc., and a vobject can be a vpage, a vimage, etc. Developers should be very clear about that. The end users should not be bothered, and the word object should be used for everything.

Metatags

Each object has a name, which is what is shown at the URL. Each object has, in addition, a long title and a short title. The long title shows everywhere except where there is a shortage of space, namely in the navigation, breadcrumbs, and possibly other applets. The short title can be omitted, in which case the long title is used. We use title pair to refer to both titles together.

Because of multilinguality, each object can have several title pairs, one for each language. Although this sounds useless for pages, because a page is in a given language, and therefore its title pair could also be in that given language, multilingual title pairs are useful in the following cases:

  • For objects, such as images, that are not bound to a specific language.
  • For objects that act as folders, and whose short title therefore shows in the breadcrumbs when you view a contained object.

As an example, consider the English pages /mypage and /mypage/hobbies, with titles “My Page” and “Hobbies”. Suppose /mypage/loisirs is the French version of /mypage/hobbies, and has title “Loisirs”. The breadcrumbs for that page would show “My Page -> Loisirs”. However, “Mon Page -> Loisirs” would be better. For this, we add a French title to /mypage, although the page is English.

If /mypage/fr is the French version of /mypage, then you don’t want the breadcrumbs to show “Mon Page -> Mon Page”; you want simply “Mon Page”. For this, each object has the option to not show in the breadcrumbs, and this is generally for pages that are a kind of “folder defaults” in languages different from the containing object’s language.

Except for the name and title pairs, an object can also have a description. For pages, the description is a summary of the page, displayed below the title in bold. Objects such as images may have the description in many languages. For uniformity, this applies to all kinds of object, although for some, such as pages, it is mostly useless.

The titles and description of each object are collectively named metatags.

In this section we have been talking of “objects”. To be precise, each entry has a name, and each vobject has a set of metatags (i.e. a set of title pairs and a set of descriptions).

Languages

The user can select the preferred language from the language selector, which on the default template is on the top left, below login. However, the effective language is determined by the object being viewed. If the object being viewed is in a specific language (e.g. it is a page in Greek), then the effective language is the object’s language (Greek in our case); but if the object has no associated language (e.g. it is an image), then the effective language is the preferred language.

The translatable strings (i.e. the elements of the user interface) are shown in the effective language, except for messages that intend to notify the user about the languages chosen and why what he sees is in another language (this is so that the user understands at least that message).

When two or more objects contain the same content in different languages, we say that they form one multilingual group. In that case, when the user changes the preferred language, the system transfers him to the alternative page (which, thus, also becomes the effective language). When an object exists in the preferred language and in another language, the navigation shows only the preferred language; but if an object exists in a language which is not the preferred language and does not have an equivalent in the preferred language, the navigation shows it anyway.

Deletions

There are two ways to “delete” an object: one is to mark it as deleted. In this case, the entry history is retained, and the “deletion” is an event recorded in the entry history. Marking an entry as deleted is creating a new vobject. Since the entry exists, another entry with the same name cannot be created.

The second way to delete is to remove the entry, in which case the entry, including the history, is permanently and irrevocably deleted.

Not implemented yet

Removing the entry is not yet implemented in the user interface.

Actions

There are several things you can do with an entry or vobject: view it, edit it, view its contents or its history, delete it, change its state, and so on. We call these operations actions: there is the “show action”, the “edit action”, the “contents action”, the “change state action”, and so on.

The show action is the normal mode of viewing an entry; for an image, for example, the show action results in a “image/jpeg” or similar response that contains binary data. The info action results in a page that includes information about the image, buttons for initiating editing, and so on, and is intended mainly for users who have permissions to modify the image. For some object types, such as pages, the show action and the info action may be identical. http://localhost/myobject/ produces the show action for myobject, whereas http://localhost/myobject/__info__/ provides the info action.

In GET requests, the action is specified by an item in the URL path which has a prefix and a suffix of two underscores; for example, http://localhost/mypage/__edit__/ is a request to edit mypage. If there is no such item in the URL, then the request is to view the entry, that is, for the show action. In POST requests, the action is specified by the action parameter.

Permissions and workflows

There are users, and each user can belong to one or more groups. When someone has not logged on then we say that they are the anonymous user. Each user and group has certain permissions on each object. There are five kinds of permissions: view, edit, admin, search, and delete. Someone with edit permission, besides editing the entry, can also mark the entry as deleted, view the list of all subobjects regardless of whether they have any permission on them, and add subobjects to the entry; you also need edit permission to view the entry history; with view permission you can only view the current entry version (the last vobject). Someone with admin permissions can modify the object’s permissions and state. Someone with delete permission can remove the entry, recursively including its subentries (irrespective of their permissions). Someone with search permission can see the entry in listings; e.g. the anonymous user has view permission on a public draft, but not search permission; you can view it if you know its URL, but it won’t show in indexes or searches. Each entry has an owner, and the owner has all permissions on the object.

Note

Why do you need edit permission to view the entry history? This can be useful if old versions contain confidential information. There are alternative ways of doing it, such as adding a view_history permission, or allowing individual vobjects to have separate view permissions. This, however, adds complication. Zadig is not primarily a wiki, and the possibility for unprivileged users to view the history is not considered essential. Therefore, we chose to keep it simple for the moment, and leave it for the future to find a way around this problem.

At a given time, each entry is in a state. A state is a collection of permissions. For example, these are common states:

Private
Logged on users can view.
Public draft
Anonymous user can view.
Published
Anonymous user can view and search.

A workflow is a collection of states and state-transition rules. A state-transition rule is a many-to-one relationship between states: it shows which are the possible states that follow a given state. Each state-transition rule can be followed by a specific user or group. Usually the owner has permissions to follow any state-transition rule; but this is not true in all workflows. For example, in some blogs, the blog editor, and not the post author, has permission to publish the post.

In the default installation, two states are created, private and published, two state-transition rules (from private to published and vice-versa), and one workflow named “Simple publication workflow” containing all those. The private state has the view and search permissions on logged on users; the published state has the view and search permissions on the anonymous user. There are no other permissions defined, which means that only the owner can edit, admin and delete.

Not implemented yet

Currently only the owner and the state can be changed through the user interface. The user interface for directly assigning permissions to users has not been developed yet.

Applets and portlets

An applet is essentially a Django custom template tag. The breadcrumbs, for example, is an applet; when you include {% breadcrumbs %} in a template, this is replaced by the breadcrumbs. The reason we don’t call them simply tags is that applets also have standard ways of storing configuration options; they can have configuration options per entry, or global. But don’t worry if you don’t understand this yet; just think of “applet” as a synonym for a custom template tag.

A portlet is a special kind of applet. There are two things that are special about portlets: the first one is that they have a certain kind of look: they have a title and a body, and the body consists of items (some portlets, like navigation, have only one item in the body). The template tag of the portlet renders the portlet in a very specific manner:

<dl class="portlet">
  <dt>Portlet title</dt>
  <dd class="odd">
    First item title
    <span class="details">Details</span>
  </dd>
  <dd class="even">Second item</dd>
  ...
</dl>

Because portlets conform to that specification, the CSS style sheet can define a common look for all portlets. (Some portlets might contain only one item, and others might not contain items consisting of title and details; but all portlets are DL elements containing a DT and at least one DD.)

The second thing that is special about portlets is that they are registered: Zadig knows what portlets are available; this makes possible to have user interface where the user can select portlets from a list, instead of having to specify them in a Django template.

Not implemented yet

The portlets for recent changes, pending events, news, and calendar have not been implemented yet. In addition, no functionality that uses registered portlets has been implemented. I think it might be nice if the left and right panes, where portlets are shown, were applets themselves.