PoC : Python Document and DocumentType helpers

Making Umbraco life easier with a little help of Python

I needed to copy all properties from one document type to another. The web site structure is not made with parent document types from the beginning since I had problems with that approach (mostly because of different standard values and descriptions on different document types).

Also – I like to be able to do structure by code and not only by UI. So I went for the approach creating documenttype properties by code.

C# might of course be the language of most peoples choice but I prefer the possibility for immediate response that I have with Python. I have created a “PyPad for Umbraco” which I’m using sometimes. Its an instant code window for Python in the Umbraco dev section, the only thing it does is to provide a multi line textbox and a button which executes the code in the textbox with the umbraco IronPython Engine.

So with my script in place I just want to write this code in PyPad:

dtSource = web.DocumentType.GetByAlias("oneDocTypeAlias")
dtTarget = web.DocumentType.GetByAlias("anotherDocTypeAlias")
copyDocumentTypeProperties(dtSource,dtTarget)

and the result given would be:

Added tab "Content"
Added property "Header"
Existing property "Introduction"
Added property "BodyText"

In Umbraco 4.5 code is actually being run on save in Umbraco UI code editor, so there the need of a “PyPad” there is not obvious, but my current site is running 4.0x and PyPad also gives me a possibility to print results.

Copy document content

I also need to copy document content occassionally, I want to copy all existing properties from one document to another. (With an boolean option makeChanges to make changes+save or just check for changes)

docSource = web.Document(2764)
docTarget = web.Document(19213)
copyAllPropertyValues(docSource,docTarget,True)

and the result given would be:

Changed property with alias "Header" from "Nnnno" to "Yyyyes"

Here’s the complete Python scripts

Copy document type properties

Use it at your own risk, and not on a live site until you are 100% sure it works as you’d expect!:

from umbraco.cms.businesslogic import web

def findTabCaptionById(dt, id):
  for t in dt.getVirtualTabs:
    if t.Id == id:
      return t.Caption
  return ""

def findTabByCaption(dt, caption):
  for tab in dt.getVirtualTabs:
    if tab.Caption == caption:
      return tab.Id
  return -1

def findOrAddTabByCaption(dt,caption):
  id = findTabByCaption(dt,caption)
  if id ==-1:
    print "Added tab : " + caption + "<br/>"
    return dt.AddVirtualTab(caption)
  else:
    return id

def containsPropertyTypeByAlias(dt, alias):
  for c in dt.PropertyTypes:
    if c.Alias == alias:
      return True
  return False

def copyDocumentTypeProperties(dtSource, dtTarget):
  for ptSource in dtSource.PropertyTypes:
    if not containsPropertyTypeByAlias(dtTarget,ptSource.Alias):

      dtTarget.AddPropertyType(ptSource.DataTypeDefinition, ptSource.Alias, ptSource.Name)
      ptTarget = dtTarget.getPropertyType(ptSource.Alias)
      ptTarget.Description = ptSource.Description
      ptTarget.Mandatory = ptSource.Mandatory
      ptTarget.ValidationRegExp = ptSource.ValidationRegExp

      tabIdSource = ptSource.TabId
      tabDescriptionSource = findTabCaptionById(dtSource,tabIdSource)
      tabIdTarget = findOrAddTabByCaption(dtTarget,tabDescriptionSource)
      dtTarget.SetTabOnPropertyType(ptTarget, tabIdTarget)

      dtTarget.Save()
      print "Added property : " + ptSource.Alias + "<br/>"

    else:
      print "existing : " + ptSource.Name + "<br/>"

dtSource = web.DocumentType.GetByAlias("oneDocTypeAlias")
dtTarget = web.DocumentType.GetByAlias("anotherDocTypeAlias")

copyDocumentTypeProperties(dtSource,dtTarget)

Copy document property values

Use on your own risk:

from umbraco.cms.businesslogic import web
from umbraco.cms.businesslogic import property
from umbraco import library

'''
   
   Copies an individual property value from one document to another
   with the exact same Alias and Datatypedefinition 
   
   for safety : first run with parameter printLog set to True and parameter makeChanges set to False 

'''
def changePropertyIf(docTarget, alias, dataTypeDefinitionId, newValue, printLog, makeChanges):
  if printLog: print "Looking for property alias: " + alias + "<br/>"
  for p in docTarget.getProperties:
    if p.PropertyType.Alias==alias and p.PropertyType.DataTypeDefinition.Id == dataTypeDefinitionId:
      if p.Value != newValue:
        if printLog:
          print "change from " + p.Value.ToString() + " to " + newValue.ToString() + "<br/>"
        if makeChanges:
          p.Value = newValue
          return True
      else:
        if printLog:
          print "unchanged<br/>"
      return False
  if printLog:
    print "Not found <br/>"
  return False

'''
   
   Copies all property values from one document to another
   with the exact same Alias and Datatypedefinition 

   for safety first run with parameter makeChanges set to False

'''
def copyAllPropertyValues(docSource, docTarget, makeChanges):
  hasChanges = False
  for p in docSource.getProperties:
    if changePropertyIf(docTarget, p.PropertyType.Alias, p.PropertyType.DataTypeDefinition.Id, p.Value, not(makeChanges), makeChanges):
      hasChanges = True
  if makeChanges and hasChanges:
    docTarget.Save
    docTarget.Publish(docTarget.User)
    library.UpdateDocumentCache(docTarget.Id)
  return hasChanges


# Example 

docSource = web.Document(2764)
docTarget = web.Document(19213)

hasChanges = copyAllPropertyValues(docSource,docTarget,True)

if hasChanges:
  print "Target document has/had differences"
else:
  print "No changes found"

List all document types

from umbraco.cms.businesslogic import web
def printAllDocumentTypes():
  for d in web.DocumentType.GetAll:
    i = d.MasterContentType
    if i==0:
      master = ""
    else:
      master = ", Master : " + web.DocumentType(i).Alias
    print d.Text + "," + d.Alias + master

Leave a comment