Working with revisions and culture versions

For every content in WAF there can exists multiple revisions and multiple versions for each culture defined in the installation. The unique key to any content to WAF is therefore the combination of NodeId, Revision and CultureId. For most parts you only refer to the NodeId. The revision is by default 0 which is the published version and the culture is assumed to be the same culture as you current WAF user session.

The revision property

The purpose of revisions is to enable users to work on preliminary versions of a document without affecting published versions and to allow users to archive older versions of a document. Changing the revision of a content is controlled by the access system and can activate workflow mechanisms for controlling the publication process and approval etc.

Each content base object has a property called “.Revision” that return an int. The value is 0 is for the best current version of a content node. A value greater than zero means an older archived version. A value less than zero are special revisions like: preliminary revisions, deleted revisions, etc.

The principal revision values are also represented by the property “.RevisionState” on ContentBase. It returns an enumeration with the following possible values:

  • Published: The published live version (rev. value: 0)
  • Preliminary: The preliminary version. Editable, but not live. (rev. value: -1)
  • Derived: A version derived from another culture or revision. Not editable. (rev. value: 0)
  • Archived: Archived revision. Not editable.  (rev. value: > 0)
  • Deleted: An old deleted revision. Not editable, but it can be restored. (rev. value : > 0)

By default all queries you make with WAF are filtered to include only content you have read access to and contents that are published. By default all queries only return content for the current culture of the session.

Derived revisions

The revision 0 is special and will always exist for any content and in all cultures, even when the content is not published and no content exists for it in a culture. If a content node is unpublished the revision with value 0 will be in a special status called “derived”.  Derived means the content object is a copy of the content from another revision. Derived contents cannot be updated, but all its properties can be read.  For instance, if you have a site with two cultures installed and you have only added content in one culture, the system will generate a derived version in the other culture by copying the content from the first culture. If you have more than two cultures in your site, you can control which culture has the highest priority. Typically you would start by adding English content to all documents. You could then continue to add French or Norwegian content to the site. Then if a visitor request for the French version of a document that you have translated to both Norwegian and English, but not French, the system could automatically choose to return a derived version in English as it is more likely that the visitor understands English than Norwegian.

The purpose of derived revisions is to make sure absolutely all contents have a version with the revision number 0. This makes it easy to query for lists of contents that include contents that are not published or does not have a culture version for language. By default a query includes only published content nodes but it will return derived content versions if the content does not have a version for the culture of the session. As an example:

var articles = WAFContext.Session.GetContents<ArticleBase>();

 

This query will return all published articles in the system even if some of them do not have a content in the culture of the current session. If you want to filter this out you must specifically ask for contents where the content is not derived, like this:

var articles = WAFContext.Session.GetContents<ArticleBase>(AqlArticleBase.IsDerived == false);

 

You may also use the “.IsDerived” property of ContentBase to check content objects directly.

If the content is derived you can call the “GetOriginal()” method to get the revision the content is copied from. This is necessary if you want to make changes to the content as derived revisions cannot be updated.

var article = WAFContext.Request.GetContent<ArticleBase>();
if (article.IsDerived) article = (ArticleBase)article.GetOriginal();
article.Name = DateTime.Now.ToShortDateString();
article.UpdateChanges();

Changing revisions in code

Before we go on to explain how to change revisions in code it is important to explain the difference between what we refer to as a content node and a content revision. A content node is identified with only the node id and is not really represented by any objects in WAF. The content node is simply the collection of all content revisions that share the same NodeId. All content objects you work against in WAF represent a specific revision. For most parts you still only refer to the NodeId as the session will add the correct CultureId and use revision 0 in a query. In sites with only one culture and where the revision system is not in much active use, there is normally only one revision for every content node.

As a content node can have multiple revisions in multiple cultures there are several statuses a node can have. The relevant properties on ContentBase object are:

  •  “.IsNodePublished”:  This property is true if the content has any non-derived revision in any culture with revision 0. That means if you have published content in only one of several languages the whole node is considered published. (You can still filter out content that does not have a version in the culture you are querying using the .IsDerived  property in a AQL query as shown earlier.). This property has the same value for all revisions belonging to a node.
  • “.IsNodeDeleted” :  This property is true if the content node is in the waste bin. The WAF waste bin contains content nodes, not content revisions. Deleting a content in the edit interface to the waste bin, moves all revisions belonging to the content node to the waste bin. This property has the same value for all revisions belonging to a node.

 

There are a number of actions you can perform on a node through a method on the ContentBase class. The methods signature is:

public CKeyNLRC ExecuteNodeAction(NodeAction action, bool withDialogues)

 

The first parameter is an enumeration called “NodeAction”. This indicates which action. The second is a boolean parameter that indicates that the execution of the action should allow dialogues with the user. If you allow dialogues the execution is asynchronous. These dialogues are only relevant to certain operations. For example if you want to delete a node and but need approval from another user. In this case a dialogue will appear where you can type a message to this user. (These dialogues can be overridden and customized).

The available node actions are:

  • “DeleteRequest”
  • “DeleteCancel”
  • “DeleteReject”
  • “DeleteApprove”
  • “Delete”
  • “DeletePermanently”
  • “RestoreRequest”
  • “RestoreApprove”
  • “RestoreReject”
  • “Restore”
  • “RestoreCancel”

 

All of these actions require read and write access to the content and some require publication access. Every content object in WAF has three principal access settings: The Read, Edit and Publish access user group.  The general rule is that any change that can result in direct changes to publish content on the website require membership in the publish access group.  If you are not a member of the publish  group but you are a member of the edit group, you can only request certain operations. This puts the content in a request state and the enumeration property “.NodeStateRequest” holds this status value.

Because it can be a little complicated to know if a certain user has access to perform a certain node and if the action is relevant there are methods on the ContentBase class that can help you with this: “.IsNodeActionLegal()” and “.GetLegalNodeActions()”

Just as there are actions that apply to the node, there are actions that apply to individual content revisions. The method signature is:

public CKeyNLRC ExecuteRevisionAction(RevisionAction action, bool withDialogues)

 

The first parameter is an enumeration called “RevisionAction”. This  indicates which action. The second is a boolean parameter that indicates that the execution of the action should allow dialogues with the user. If you allow dialogues the execution is asynchronous. As with node actions, these dialogues are only relevant to certain operations. For example if you want to request publication but need approval from another user. In this case a dialogue will appear that allow you to type a message to this user. (These dialogues can be overridden and customized).

The available revision actions are:

  • UpdateChanges” : Saves changes to database and updates last change date.
  • New” : Creates a new revision of the content.
  • Archive” : Moves revision into a archived state.
  • Restore” : Restores a deleted revision. (not the same as wastebin)
  • DeleteRequest”: Puts the revision in to a state where it is waiting for a Delete Cancel or Approve action. You only need EDIT access to do this. 
  • DeleteCancel”: Cancel a DeleteRequest state. 
  • DeleteReject”: Reject a DeleteRequest state. You need PUBLISH access to do this.
  • DeleteApprove“: Approve a DeleteRequest and delete the revision. You need PUBLISH access to do this.
  • Delete”: Delete the revision. You need PUBLISH access to do this. (You can still restore the revision).
  • DeletePermanently”: Permanently deletes the revision. You need PUBLISH access to do this.
  • PublishRequest”: Puts the revision in to a state where it is waiting for a Publish Cancel or Approve action. You only need EDIT access to do this. 
  • PublishCancel”: Cancel a PublishRequest state. 
  • PublishReject”: Reject a PublishRequest state. You need PUBLISH access to do this.
  • PublishApprove”: Approve a PublishRequest and publish the revision. You need PUBLISH access to do this.
  • Publish”: Publish the revision. You need PUBLISH access to do this. Existing published revision will be archived.
  • UnPublishRequest”: Puts the revision in to a state where it is waiting for a UnPublish Cancel or Approve action. You only need EDIT access to do this. 
  • UnPublishCancel”: Cancel a UnPublishRequest state. 
  • UnPublishReject”: Reject a UnPublishRequest state. You need PUBLISH access to do this.
  • UnPublishApprove”: Approve a UnPublishRequest and unpublish the revision. You need PUBLISH access to do this.
  • UnPublish”: UnPublishes the revision, by archiving it. You need PUBLISH access to do this. Revision will be archived.
  • AddLanguage”: Adds a preliminary revision to the node in the selected language, content is based on the selected revision.
  • ActivateLanguage”: Publishes the preliminary revision in selected language. (Deletes other revision, does not archive them like "Publish" does). 
  • DeactivateLanguage”: Makes current published revision a preliminary revision in selected language. (Deletes other revision, does not archive them like "UnPublish" does). 
  • RemoveLanguage”: Deletes all revisions in selected language.

 

Just as with node actions, all of these actions require read and write access to the content and some require publication access. The general rule is that any change that can result in direct changes to publish content on the website require membership in the publish access group.  If you are not a member of the publish group but you are a member of the edit group, you can only request certain operations. This puts the content revision in a request state and the enumeration property “.RevisionStateRequest” holds this status value.

Because it can be a little complicated to know if a certain user has access to perform a certain revision and if the action is relevant there are methods on the ContentBase class that can help you with this: “.IsRevisionActionLegal()” and “.GetLegalRevisionActions()”

Release and Retain dates

In addition to the revision system and the publication status of each content you can also control the visibility of content on the site with the “ReleaseDate” and “RetainDate” property. By default these properties have the WAF date time null value (01.01.1800 00:00 or Utils.DateTimeNull) and by default these values are ignored until you set a specific date and time.

Change culture of existing site

The demo/starter sites usually comes with English as the installed language. If your site is in another language, we recommend changing the culture of the site. This is a delicate process, and you must follow the instructions below to the letter:

  1. Change Content.definition: Add a new culture, for example norwegian 1044. Delete English 1033.
  2. Rightclick on Default.aspx in WAF/Setup folder and choose "View in browser".
  3. Change lcid from 1033 to 1044.
  4. Kill the IIS process
  5. Restart the site. It should now come up with Norwegian language.
  6. Go to WAF/setup again and run "Ensure integrity"
  7. Login to edit. Everything should be in order now, or it might happen that none of the modules are shown. If none of the modules are shown, follow this recipe:
    1. The error is due to the fact that there are two Installation nodes.
    2. Click on the search icon to open the search dialog.
    3. Check the «Hidden content» checkbox.
    4. Filter on the type Installation.
    5. Choose on of the Installation nodes and click on «Open in window». If the Modules relation is empty, you can delete it.. The node with modules in the relation must not be deleted.