Overview
========

    >>> import datetime

Datasets provide a versioning system based on a version ID to group certain
objects and sort them based on the effectiveDate (and creationDate, if first
is None) to determine their version number.

Lets use the sandbox.

    >>> portal = layer['portal']
    >>> _ = portal.invokeFactory('Folder', 'sandbox')
    >>> sandbox = portal._getOb('sandbox')

    >>> from plone.app.testing import TEST_USER_ID
    >>> from plone.app.testing import setRoles
    >>> setRoles(portal, TEST_USER_ID, ['Manager'])

Lets add a Sample Data.

    >>> _ = sandbox.invokeFactory('Sample Data', 'data1')
    >>> data1 = sandbox._getOb('data1')
    >>> form = {
    ...   'title': 'Dataset',
    ...   'description': 'Organisation description 1',
    ...	  'somedata':'Some Data 1',
    ... }
    >>> data1.setEffectiveDate(datetime.datetime.now())
    >>> _ = data1.invokeFactory("Document", 'c1')
    >>> data1['c1'].setTitle("Child")
    >>> print list(data1.objectIds())
    ['c1']

We'll also test relatedItems relationships, so let's add a helper content
object.

    >>> _ = sandbox.invokeFactory("Document", 'r1')
    >>> data1.setRelatedItems([sandbox['r1']])
    >>> print data1.getRelatedItems()
    [<ATDocument at /plone/sandbox/r1>]


How to get the versionId
------------------------
All versionable (IVersionEnhanced) objects have a versionId by default. This is
stored in an annotation, and by default is a random string of 10 characters.

    >>> from eea.versions.versions import VERSION_ID
    >>> vid = data1.__annotations__[VERSION_ID]
    >>> len(vid) == 10
    True

The recommended way to get the versionId is using the IGetVersions adapter:

    >>> from eea.versions.interfaces import IGetVersions
    >>> IGetVersions(data1).versionId == vid
    True

There's also a view that can be used:

    >>> view = data1.unrestrictedTraverse('@@getVersions')
    >>> view.versionId == vid
    True

You can manually assign a new version using IVersionControl:

    >>> from eea.versions.interfaces import IVersionControl
    >>> IVersionControl(data1).setVersionId("1234567890")
    >>> print IGetVersions(data1).versionId
    1234567890


Versions keep the original data
-------------------------------
    >>> data1.processForm(values=form, data=1, metadata=1)

Now lets create a new version of the above dataset.

    >>> createVersionView = data1.unrestrictedTraverse('@@createVersion')
    >>> vertmp = createVersionView()
    >>> id = vertmp[vertmp.rfind('/')+1:]
    >>> dataVer = sandbox._getOb(id)

The id of the dataVer is based on the old id, but with a number suffix:

    >>> dataVer.id == 'data1-1'
    True

Verify if properties were copied on the new version.

    >>> dataVer.Title() == data1.Title()
    True
    >>> dataVer.getSomedata() == data1.getSomedata()
    True

Effective date of the new version should be set to None, while the original
keeps its effective date:

    >>> dataVer.getEffectiveDate() == None
    True
    >>> data1.getEffectiveDate() != None
    True

Both objects should have the same version ID.

    >>> from eea.versions.interfaces import IVersionControl
    >>> IVersionControl(dataVer).getVersionId() == IVersionControl(data1).getVersionId()
    True

Children objects which where present in the original are also copied:

    >>> print dataVer['c1'].absolute_url()
    http://nohost/plone/sandbox/data1-1/c1

Relationships are also copied:

    >>> print dataVer.getRelatedItems()
    [<ATDocument at /plone/sandbox/r1>]


The IGetVersions API
--------------------
    >>> from eea.versions.interfaces import IGetVersions
    >>> from eea.versions.versions import create_version
    >>> dataVer1 = create_version(dataVer)
    >>> adapter = IGetVersions(dataVer)

Calling the adapter returns the enumerated versions, to mimic the old API:

    >>> print adapter()
    {1: <SampleData at /plone/sandbox/data1>, 2: <SampleData at /plone/sandbox/data1-1>, 3: <SampleData at /plone/sandbox/data1-2>}
    >>> print adapter.enumerate_versions()
    {1: <SampleData at /plone/sandbox/data1>, 2: <SampleData at /plone/sandbox/data1-1>, 3: <SampleData at /plone/sandbox/data1-2>}

The adapter is bound to the middle of the three versions:

    >>> print adapter.earlier_versions()
    [{'url': 'http://nohost/plone/sandbox/data1', 'date': DateTime('...'), 'review_state': 'visible', 'title_state': 'Public draft', 'title': 'Dataset'}]
    >>> print adapter.later_versions()
    [{'url': 'http://nohost/plone/sandbox/data1-2', 'date': DateTime('...'), 'review_state': 'visible', 'title_state': 'Public draft', 'title': 'Dataset'}]
    >>> print adapter.isLatest()
    False
    >>> print adapter.first_version()
    <SampleData at data1>
    >>> print adapter.latest_version()
    <SampleData at data1-2>
    >>> print adapter.version_number()
    2
    >>> print adapter.versions()
    [<SampleData at /plone/sandbox/data1>, <SampleData at /plone/sandbox/data1-1>, <SampleData at /plone/sandbox/data1-2>]
    >>> print adapter.getLatestVersionUrl()
    http://nohost/plone/sandbox/data1-2

The last created version is indeed the latest version:

    >>> adapter = IGetVersions(dataVer1)
    >>> adapter.isLatest()
    True


Anonymous users and the IGetVersions API
----------------------------------------
Anonymous users will only see as versions the objects that are published:

    >>> wftool = adapter.wftool()
    >>> wftool.doActionFor(dataVer, 'publish')
    >>> from plone.app.testing import logout
    >>> logout()

Since the original object is not published dataVer will be marked as the first
version number:

    >>> adapter = IGetVersions(dataVer)
    >>> print adapter.version_number()
    1

And calling earlier_versions will return no results:

    >>> print adapter.earlier_versions()
    []

As such the first version will return the SampleData object that is referenced
by our adapter:

    >>> print adapter.first_version()
    <SampleData at data1-1>

And if dataVar1 is published it will be the latest version:

    >>> from plone.app.testing import login
    >>> from plone.app.testing import TEST_USER_NAME
    >>> login(portal, TEST_USER_NAME)
    >>> wftool.doActionFor(dataVer1, 'publish')
    >>> adapter = IGetVersions(dataVer)
    >>> print adapter.latest_version() == dataVer1
    True


How new ids are calculated
--------------------------
We use a custom naming scheme to calculate new ids when versioning:

    >>> from eea.versions.versions import generateNewId
    >>> print sorted(sandbox.objectIds())
    ['data1', 'data1-1', 'data1-2', 'r1']

Names will be generated in numeric sequences, taking into consideration
what names are available in the given location:

    >>> print generateNewId(sandbox, 'data1')
    data1-3
    >>> print generateNewId(sandbox, 'data2')
    data2
    >>> del sandbox['data1-2']
    >>> print generateNewId(sandbox, 'data1')
    data1-2


Talkbacks
---------
When versioning, the discussion items should be removed and unindexed:

    >>> from Products.CMFCore.utils import getToolByName
    >>> hasNewDiscussion = True
    >>> try:
    ...     from plone.app.discussion.interfaces import IConversation
    ...     from zope.component import createObject
    ... except:
    ...     hasNewDiscussion = False
    >>> catalog = getToolByName(data1, "portal_catalog")
    >>> dtool = getToolByName(data1, "portal_discussion")
    >>> data1.allow_discussion = True
    >>> if hasNewDiscussion:
    ...     conversation = IConversation(data1)
    ...     comment = createObject('plone.Comment')
    ...     comment.title = 'title'
    ...     comment.text = 'text'
    ...     comment_id = conversation.addComment(comment)
    ...     print len(catalog.searchResults(path="/".join(data1.getPhysicalPath()) + "/++conversation++default/"))
    ... else:
    ...     tb = dtool.getDiscussionFor(data1)
    ...     id = tb.createReply('title', 'text')
    ...     print len(catalog.searchResults(path="/".join(data1.getPhysicalPath()) + "/talkback/"))
    1
    >>> createVersionView = data1.unrestrictedTraverse('@@createVersion')
    >>> vertmp = createVersionView()
    >>> id = vertmp[vertmp.rfind('/')+1:]
    >>> dataVer = sandbox._getOb(id)
    >>> if hasNewDiscussion:
    ...     conversationVer = IConversation(dataVer)
    ...     print conversationVer.total_comments
    ... else:
    ...     tb = dtool.getDiscussionFor(dataVer)
    ...     print tb.replyCount(dataVer)
    0
    >>> if hasNewDiscussion:
    ...     print len(dataVer.portal_catalog.searchResults(path="/".join(dataVer.getPhysicalPath()) + "/++conversation++default/"))
    ... else:
    ...     print len(dataVer.portal_catalog.searchResults(path="/".join(dataVer.getPhysicalPath()) + "/talkback/"))
    0
