From ac52f43ce2ea5480ce611fb083a7988e5bf47fae Mon Sep 17 00:00:00 2001 From: Jims Date: Fri, 14 Aug 2015 23:28:50 -0400 Subject: [PATCH] added support for workflow task approval/rejection --- README.rst | 10 +++++++++ sharepoint/lists/__init__.py | 40 +++++++++++++++++++++++++----------- sharepoint/xml.py | 4 ++++ 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/README.rst b/README.rst index 51264c7..2659f36 100644 --- a/README.rst +++ b/README.rst @@ -92,6 +92,16 @@ using the list's ``save()`` method:: sp_list.save() +You can also approve or reject sharepoint workflow tasks:: + + sp_list = site.lists['ListName'] + + # Approve a task + sp_list.rows[0].approve() + + # Reject a task + sp_list.rows[1].reject() + Consult the ``descriptor_set()`` methods in ``sharepoint.lists.types`` module for more information about setting SharePoint list fields. diff --git a/sharepoint/lists/__init__.py b/sharepoint/lists/__init__.py index 5f92c99..037568b 100644 --- a/sharepoint/lists/__init__.py +++ b/sharepoint/lists/__init__.py @@ -10,7 +10,7 @@ from lxml import etree from lxml.builder import E -from sharepoint.xml import SP, namespaces, OUT +from sharepoint.xml import SP, namespaces, OUT, SPW, MY from sharepoint.lists import moderation from sharepoint.lists.types import type_mapping, default_type, UserField, LookupField from sharepoint.lists.attachments import SharePointAttachments @@ -19,12 +19,6 @@ uuid_re = re.compile(r'^\{?([\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12})\}?$') -try: - str = basestring -except NameError: - pass - - class SharePointLists(object): def __init__(self, opener): self.opener = opener @@ -34,11 +28,11 @@ def all_lists(self): if not hasattr(self, '_all_lists'): xml = SP.GetListCollection() result = self.opener.post_soap(LIST_WEBSERVICE, xml) - + self._all_lists = [] for list_element in result.xpath('sp:GetListCollectionResult/sp:Lists/sp:List', namespaces=namespaces): self._all_lists.append(SharePointList(self.opener, self, list_element)) - + # Explicitly request information about the UserInfo list. # This can be accessed with the name "User Information List" result = self.opener.post_soap(LIST_WEBSERVICE, SP.GetList(SP.listName("UserInfo"))) @@ -90,7 +84,7 @@ def __getitem__(self, key): if list_object.id == key: return list_object raise KeyError('No list with ID {0}'.format(key)) - elif isinstance(key, str): + elif isinstance(key, basestring): for list_object in self.all_lists: if list_object.meta['Title'] == key: return list_object @@ -141,7 +135,7 @@ def settings(self): response = self.opener.post_soap(LIST_WEBSERVICE, xml) self._settings = response[0][0] return self._settings - + @property def moderation(self): if self._meta['EnableModeration'] != 'True': @@ -254,7 +248,7 @@ def append(self, row): self.rows # Make sure self._rows exists. self._rows.append(row) return row - + def append_from(self, other_list): for row in other_list.rows: self.append(row.as_row(self.Row)) @@ -438,6 +432,28 @@ def open(self): request.add_header('Translate', 'f') return self.opener.open(request) + def approve(self, approved=True): + if not self.WorkflowInstanceID: + raise AttributeError('Not a workflow task') + else: + if approved: + taskstatus = 'Approved' + else: + taskstatus = 'Rejected' + xml = SPW.AlterToDo(SPW.item(self.ServerUrl), + SPW.todoId(str(self.id)), + SPW.todoListId(self.list.id), + SPW.taskData( + MY.myFields( + MY.TaskStatus(taskstatus), + MY.Status('Completed'), + MY.Completed('1')))) + result = self.list.opener.post_soap('_vti_bin/workflow.asmx', xml, + soapaction="http://schemas.microsoft.com/sharepoint/soap/workflow/AlterToDo") + + def reject(self): + self.approve(approved=False) + @property def attachments(self): if not hasattr(self, '_attachments'): diff --git a/sharepoint/xml.py b/sharepoint/xml.py index 39c2b2b..c41c463 100644 --- a/sharepoint/xml.py +++ b/sharepoint/xml.py @@ -1,11 +1,13 @@ from lxml import builder namespaces = { + 'my': "http://schemas.microsoft.com/office/infopath/2003/myXSD", 'xs': 'http://www.w3.org/2001/XMLSchema', 'wsdl': 'http://schemas.xmlsoap.org/wsdl/', 'soap': 'http://schemas.xmlsoap.org/soap/envelope/', 't': 'http://schemas.microsoft.com/exchange/services/2006/types', 'sp': 'http://schemas.microsoft.com/sharepoint/soap/', + 'spw': 'http://schemas.microsoft.com/sharepoint/soap/workflow/', 'spd': 'http://schemas.microsoft.com/sharepoint/soap/directory/', 'rs': 'urn:schemas-microsoft-com:rowset', 'ups': 'http://microsoft.com/webservices/SharePointPortalServer/UserProfileService/GetUserProfileByIndex', @@ -19,9 +21,11 @@ 'sharepoint': 'https://github.com/ox-it/python-sharepoint/', # Ours } +MY = builder.ElementMaker(namespace=namespaces['my'], nsmap=namespaces) SOAP = builder.ElementMaker(namespace=namespaces['soap'], nsmap=namespaces) T = builder.ElementMaker(namespace=namespaces['t'], nsmap=namespaces) SP = builder.ElementMaker(namespace=namespaces['sp'], nsmap=namespaces) +SPW = builder.ElementMaker(namespace=namespaces['spw'], nsmap=namespaces) SPD = builder.ElementMaker(namespace=namespaces['spd'], nsmap=namespaces) UPS = builder.ElementMaker(namespace=namespaces['ups'], nsmap=namespaces) SQ = builder.ElementMaker(namespace=namespaces['sq'], nsmap=namespaces)