def get_rows(self, folder=''): rows = [] attribs = collections.defaultdict(dict) field_groups, lookup_count = [[]], 0 for field in self.fields.values(): if isinstance(field, (UserField, LookupField)): lookup_count += 1 if lookup_count >= 8: lookup_count = 0 field_groups.append([]) field_groups[-1].append(field) for field_group in field_groups: # Request all fields, not just the ones in the default view view_fields = E.ViewFields(*(E.FieldRef(Name=field.name) for field in field_group)) #query_options = E.QueryOptions(E.ViewAttributes(Scope="Recursive")) query_options = E.QueryOptions(E.Folder(folder)) xml = SP.GetListItems(SP.listName(self.id), SP.rowLimit("100000"), SP.viewFields(view_fields), SP.queryOptions(query_options)) response = self.opener.post_soap(LIST_WEBSERVICE, xml) for row in list(response[0][0][0]): attrib = attribs[row.attrib['ows_ID']] attrib.update(row.attrib) for attrib in attribs.values(): rows.append(self.Row(attrib=attrib)) return list(rows)
def remove(self, list): """ Removes a list from the site. """ xml = SP.DeleteList(SP.listName(list.id)) result = self.opener.post_soap(LIST_WEBSERVICE, xml, soapaction='http://schemas.microsoft.com/sharepoint/soap/DeleteList') self.all_lists.remove(list)
def save(self): """ Updates the list with changes. """ # Based on the documentation at # http://msdn.microsoft.com/en-us/library/lists.lists.updatelistitems%28v=office.12%29.aspx # Note, this ends up un-namespaced. SharePoint doesn't care about # namespaces on this XML node, and will bork if any of these elements # have a namespace prefix. Likewise Method and Field in # SharePointRow.get_batch_method(). batches = E.Batch(ListVersion="1", OnError="Return") # Here's the root element of our SOAP request. xml = SP.UpdateListItems(SP.listName(self.id), SP.updates(batches)) # rows_by_batch_id contains a mapping from new rows to their batch # IDs, so we can set their IDs when they are returned by SharePoint. rows_by_batch_id, batch_id = {}, 1 for row in self._rows: batch = row.get_batch_method() if batch is None: continue # Add the batch ID batch.attrib["ID"] = unicode(batch_id) rows_by_batch_id[batch_id] = row batches.append(batch) batch_id += 1 for row in self._deleted_rows: batch = E.Method(E.Field(unicode(row.id), Name="ID"), ID=unicode(batch_id), Cmd="Delete") rows_by_batch_id[batch_id] = row batches.append(batch) batch_id += 1 if len(batches) == 0: return response = self.opener.post_soap( LIST_WEBSERVICE, xml, soapaction="http://schemas.microsoft.com/sharepoint/soap/UpdateListItems" ) for result in response.xpath(".//sp:Result", namespaces=namespaces): batch_id, batch_result = result.attrib["ID"].split(",") row = rows_by_batch_id[int(batch_id)] error_code = result.find("sp:ErrorCode", namespaces=namespaces) error_text = result.find("sp:ErrorText", namespaces=namespaces) if error_code is not None and error_code.text != "0x00000000": raise UpdateFailedError(row, batch_result, error_code.text, error_text.text) if batch_result in ("Update", "New"): row._update(result.xpath("z:row", namespaces=namespaces)[0], clear=True) else: self._deleted_rows.remove(row) assert not self._deleted_rows assert not any(row._changed for row in self.rows)
def remove(self, list): """ Removes a list from the site. """ xml = SP.DeleteList(SP.listName(list.id)) self.opener.post_soap( LIST_WEBSERVICE, xml, soapaction='http://schemas.microsoft.com/sharepoint/soap/DeleteList' ) self.all_lists.remove(list)
def __iter__(self): """ Returns an iterator over attachments for a list item. Implements http://msdn.microsoft.com/en-us/library/websvclists.lists.getattachmentcollection.aspx """ xml = SP.GetAttachmentCollection(SP.listName(self.list_id), SP.listItemID(str(self.row_id))) response = self.opener.post_soap(LIST_WEBSERVICE, xml, soapaction='http://schemas.microsoft.com/sharepoint/soap/GetAttachmentCollection') for url in response.xpath('//sp:Attachment', namespaces=namespaces): yield SharePointAttachment(self, url.text)
def __iter__(self): """ Returns an iterator over attachments for a list item. Implements http://msdn.microsoft.com/en-us/library/websvclists.lists.getattachmentcollection.aspx """ xml = SP.GetAttachmentCollection(SP.listName(self.list_id), SP.listItemID(str(self.row_id))) response = self.opener.post_soap( LIST_WEBSERVICE, xml, soapaction='http://schemas.microsoft.com/sharepoint/soap/GetAttachmentCollection') for url in response.xpath('//sp:Attachment', namespaces=namespaces): yield SharePointAttachment(self, url.text)
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"))) list_element = result.xpath('.//sp:List', namespaces=namespaces)[0] self._all_lists.append(SharePointList(self.opener, self, list_element)) return self._all_lists
def set_status(self, rows, status, comment=None): rows_by_batch_id, batch_id = {}, 1 if isinstance(status, int): status = moderation_statuses[status] batches = E.Batch(ListVersion='1', OnError='Return') # Here's the root element of our SOAP request. xml = SP.UpdateListItems(SP.listName(self._list.id), SP.updates(batches)) if comment: comment = E.Field(text_type(comment), Name='_ModerationComment') for row in rows: batch = E.Method(E.Field(text_type(row.id), Name='ID'), E.Field(text_type(status.value), Name='_ModerationStatus'), ID=text_type(batch_id), Cmd='Moderate') if comment: batch.append(comment) rows_by_batch_id[batch_id] = row batches.append(batch) batch_id += 1 response = self._list.opener.post_soap( LIST_WEBSERVICE, xml, soapaction= 'http://schemas.microsoft.com/sharepoint/soap/UpdateListItems') for result in response.xpath('.//sp:Result', namespaces=namespaces): batch_id, batch_result = result.attrib['ID'].split(',') row = rows_by_batch_id[int(batch_id)] error_code = result.find('sp:ErrorCode', namespaces=namespaces) error_text = result.find('sp:ErrorText', namespaces=namespaces) if error_code is not None and error_code.text != '0x00000000': raise UpdateFailedError(row, batch_result, error_code.text, error_text.text) if batch_result == 'Moderate': row._update(result.xpath('z:row', namespaces=namespaces)[0], clear=True)
def create(self, name, description="", template=100): """ Creates a new list in the site. """ try: template = int(template) except ValueError: template = LIST_TEMPLATES[template] if name in self: raise ValueError("List already exists: '{0}".format(name)) if uuid_re.match(name): raise ValueError("Cannot create a list with a UUID as a name") xml = SP.AddList(SP.listName(name), SP.description(description), SP.templateID(unicode(template))) result = self.opener.post_soap( LIST_WEBSERVICE, xml, soapaction="http://schemas.microsoft.com/sharepoint/soap/AddList" ) list_element = result.xpath("sp:AddListResult/sp:List", namespaces=namespaces)[0] self._all_lists.append(SharePointList(self.opener, self, list_element))
def set_status(self, rows, status, comment=None): rows_by_batch_id, batch_id = {}, 1 if isinstance(status, int): status = moderation_statuses[status] batches = E.Batch(ListVersion='1', OnError='Return') # Here's the root element of our SOAP request. xml = SP.UpdateListItems(SP.listName(self._list.id), SP.updates(batches)) if comment: comment = E.Field(text_type(comment), Name='_ModerationComment') for row in rows: batch = E.Method(E.Field(text_type(row.id), Name='ID'), E.Field(text_type(status.value), Name='_ModerationStatus'), ID=text_type(batch_id), Cmd='Moderate') if comment: batch.append(comment) rows_by_batch_id[batch_id] = row batches.append(batch) batch_id += 1 response = self._list.opener.post_soap( LIST_WEBSERVICE, xml, soapaction='http://schemas.microsoft.com/sharepoint/soap/UpdateListItems') for result in response.xpath('.//sp:Result', namespaces=namespaces): batch_id, batch_result = result.attrib['ID'].split(',') row = rows_by_batch_id[int(batch_id)] error_code = result.find('sp:ErrorCode', namespaces=namespaces) error_text = result.find('sp:ErrorText', namespaces=namespaces) if error_code is not None and error_code.text != '0x00000000': raise UpdateFailedError(row, batch_result, error_code.text, error_text.text) if batch_result == 'Moderate': row._update(result.xpath('z:row', namespaces=namespaces)[0], clear=True)
def set_status(self, rows, status, comment=None): rows_by_batch_id, batch_id = {}, 1 if isinstance(status, int): status = moderation_statuses[status] batches = E.Batch(ListVersion="1", OnError="Return") # Here's the root element of our SOAP request. xml = SP.UpdateListItems(SP.listName(self._list.id), SP.updates(batches)) if comment: comment = E.Field(unicode(comment), Name="_ModerationComment") for row in rows: batch = E.Method( E.Field(unicode(row.id), Name="ID"), E.Field(unicode(status.value), Name="_ModerationStatus"), ID=unicode(batch_id), Cmd="Moderate", ) if comment: batch.append(comment) rows_by_batch_id[batch_id] = row batches.append(batch) batch_id += 1 response = self._list.opener.post_soap( LIST_WEBSERVICE, xml, soapaction="http://schemas.microsoft.com/sharepoint/soap/UpdateListItems" ) for result in response.xpath(".//sp:Result", namespaces=namespaces): batch_id, batch_result = result.attrib["ID"].split(",") row = rows_by_batch_id[int(batch_id)] error_code = result.find("sp:ErrorCode", namespaces=namespaces) error_text = result.find("sp:ErrorText", namespaces=namespaces) if error_code is not None and error_code.text != "0x00000000": raise UpdateFailedError(row, batch_result, error_code.text, error_text.text) if batch_result == "Moderate": row._update(result.xpath("z:row", namespaces=namespaces)[0], clear=True)
def create(self, name, description='', template=100): """ Creates a new list in the site. """ try: template = int(template) except ValueError: template = LIST_TEMPLATES[template] if name in self: raise ValueError("List already exists: '{0}".format(name)) if uuid_re.match(name): raise ValueError("Cannot create a list with a UUID as a name") xml = SP.AddList(SP.listName(name), SP.description(description), SP.templateID(text_type(template))) result = self.opener.post_soap( LIST_WEBSERVICE, xml, soapaction='http://schemas.microsoft.com/sharepoint/soap/AddList') list_element = result.xpath('sp:AddListResult/sp:List', namespaces=namespaces)[0] self._all_lists.append(SharePointList(self.opener, self, list_element))
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"))) list_element = result.xpath('.//sp:List', namespaces=namespaces)[0] self._all_lists.append( SharePointList(self.opener, self, list_element)) return self._all_lists
def rows(self): if not hasattr(self, "_rows"): attribs = collections.defaultdict(dict) field_groups, lookup_count = [[]], 0 for field in self.fields.values(): if isinstance(field, (UserField, LookupField)): lookup_count += 1 if lookup_count >= 8: lookup_count = 0 field_groups.append([]) field_groups[-1].append(field) for field_group in field_groups: # Request all fields, not just the ones in the default view view_fields = E.ViewFields(*(E.FieldRef(Name=field.name) for field in field_group)) xml = SP.GetListItems(SP.listName(self.id), SP.rowLimit("100000"), SP.viewFields(view_fields)) response = self.opener.post_soap(LIST_WEBSERVICE, xml) for row in list(response[0][0][0]): attrib = attribs[row.attrib["ows_ID"]] attrib.update(row.attrib) self._rows = [] for attrib in attribs.values(): self._rows.append(self.Row(attrib=attrib)) return list(self._rows)
def settings(self): if self._settings is None or not len(self._settings): xml = SP.GetList(SP.listName(self.id)) response = self.opener.post_soap(LIST_WEBSERVICE, xml) self._settings = response[0][0] return self._settings
def delete(self, url): xml = SP.DeleteAttachment(SP.listName(self.list_id), SP.listItemID(str(self.row_id)), SP.url(url)) response = self.opener.post_soap(LIST_WEBSERVICE, xml, soapaction='http://schemas.microsoft.com/sharepoint/soap/DeleteAttachment')
def add(self, filename, content): xml = SP.AddAttachment(SP.listName(self.list_id), SP.listItemID(str(self.row_id)), SP.fileName(filename), SP.attachment(content)) response = self.opener.post_soap(LIST_WEBSERVICE, xml, soapaction='http://schemas.microsoft.com/sharepoint/soap/AddAttachment')
def save(self): """ Updates the list with changes. """ # Based on the documentation at # http://msdn.microsoft.com/en-us/library/lists.lists.updatelistitems%28v=office.12%29.aspx # Note, this ends up un-namespaced. SharePoint doesn't care about # namespaces on this XML node, and will bork if any of these elements # have a namespace prefix. Likewise Method and Field in # SharePointRow.get_batch_method(). batches = E.Batch(ListVersion='1', OnError='Return') # Here's the root element of our SOAP request. xml = SP.UpdateListItems(SP.listName(self.id), SP.updates(batches)) # rows_by_batch_id contains a mapping from new rows to their batch # IDs, so we can set their IDs when they are returned by SharePoint. rows_by_batch_id, batch_id = {}, 1 for row in self._rows: batch = row.get_batch_method() if batch is None: continue # Add the batch ID batch.attrib['ID'] = text_type(batch_id) rows_by_batch_id[batch_id] = row batches.append(batch) batch_id += 1 for row in self._deleted_rows: batch = E.Method(E.Field(text_type(row.id), Name='ID'), ID=text_type(batch_id), Cmd='Delete') rows_by_batch_id[batch_id] = row batches.append(batch) batch_id += 1 if len(batches) == 0: return response = self.opener.post_soap( LIST_WEBSERVICE, xml, soapaction= 'http://schemas.microsoft.com/sharepoint/soap/UpdateListItems') for result in response.xpath('.//sp:Result', namespaces=namespaces): batch_id, batch_result = result.attrib['ID'].split(',') row = rows_by_batch_id[int(batch_id)] error_code = result.find('sp:ErrorCode', namespaces=namespaces) error_text = result.find('sp:ErrorText', namespaces=namespaces) if error_code is not None and error_code.text != '0x00000000': raise UpdateFailedError(row, batch_result, error_code.text, error_text.text) if batch_result in ('Update', 'New'): row._update(result.xpath('z:row', namespaces=namespaces)[0], clear=True) else: self._deleted_rows.remove(row) assert not self._deleted_rows assert not any(row._changed for row in self.rows)