Skip to content

Commit

Permalink
refactorings & examples updates
Browse files Browse the repository at this point in the history
  • Loading branch information
vgrem committed Feb 25, 2024
1 parent 2c0c2ec commit bcd5c76
Show file tree
Hide file tree
Showing 17 changed files with 849 additions and 540 deletions.
27 changes: 19 additions & 8 deletions examples/sharepoint/listitems/system_update.py
@@ -1,29 +1,40 @@
"""
Demonstrates how to update system metadata properties of List Item
"""

import sys
from datetime import datetime, timedelta

from office365.sharepoint.client_context import ClientContext
from office365.sharepoint.fields.user_value import FieldUserValue
from office365.sharepoint.listitems.listitem import ListItem
from tests import test_client_credentials, test_team_site_url, test_user_principal_name
from tests import (
test_client_credentials,
test_site_url,
test_user_principal_name,
)

ctx = ClientContext(test_team_site_url).with_credentials(test_client_credentials)
ctx = ClientContext(test_site_url).with_credentials(test_client_credentials)

list_tasks = ctx.web.lists.get_by_title("Company Tasks")
items = list_tasks.items.get().top(1).execute_query()
target_list = ctx.web.lists.get_by_title("Documents")
items = target_list.items.get().top(1).execute_query()
if len(items) == 0:
sys.exit("No items were found")

item_to_update = items[0] # type: ListItem
item_to_update = items[0]
author = ctx.web.site_users.get_by_email(test_user_principal_name)

modified_date = datetime.utcnow() - timedelta(days=3)
created_date = datetime.utcnow() - timedelta(days=14)
modified_date = datetime.utcnow() - timedelta(days=7)
result = item_to_update.validate_update_list_item(
{
"Title": "Task (updated)",
"Author": FieldUserValue.from_user(author),
"Editor": FieldUserValue.from_user(author),
"Modified": modified_date,
"Created": created_date,
"Author": FieldUserValue.from_user(author),
},
dates_in_utc=True,
new_document_update=True,
).execute_query()

has_any_error = any([item.HasException for item in result.value])
Expand Down
6 changes: 3 additions & 3 deletions examples/sharepoint/taxonomy/export_term_store.py
Expand Up @@ -9,7 +9,7 @@
ctx = ClientContext(test_team_site_url).with_credentials(test_client_credentials)

store = ctx.taxonomy.term_store
term_groups = ctx.taxonomy.term_store.term_groups.get_all().execute_query()
term_groups = ctx.taxonomy.term_store.term_groups.get().execute_query()
for term_group in term_groups:
term_sets = term_group.term_sets.get_all().execute_query()
print(json.dumps(term_sets.to_json(), indent=4))
term_sets = term_group.term_sets.get().execute_query()
print(json.dumps(term_groups.to_json(), indent=4))
4 changes: 2 additions & 2 deletions generator/import_metadata.py
Expand Up @@ -21,13 +21,13 @@ def export_to_file(path, content):
"--endpoint",
dest="endpoint",
help="Import metadata endpoint",
default="sharepoint",
default="microsoftgraph",
)
parser.add_argument(
"-p",
"--path",
dest="path",
default="./metadata/SharePoint.xml",
default="./metadata/MicrosoftGraph.xml",
help="Import metadata endpoint",
)

Expand Down
1,213 changes: 700 additions & 513 deletions generator/metadata/MicrosoftGraph.xml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions generator/metadata/SharePoint.xml
Expand Up @@ -39966,6 +39966,7 @@
<Property Name="TextColumnCNU6FEFD" Type="Edm.String"/>
<Property Name="TextColumnG5FNNYDX" Type="Edm.String"/>
<Property Name="TextColumn4164USLJ" Type="Edm.String"/>
<Property Name="MediaServiceSearchProperties" Type="Edm.String"/>
<Property Name="ID" Type="Edm.Int32"/>
<Property Name="Created" Type="Edm.DateTime"/>
<Property Name="AuthorId" Type="Edm.Int32"/>
Expand Down
@@ -0,0 +1,5 @@
from office365.entity import Entity


class LandingPage(Entity):
"""Represents an attack simulation landing page."""
5 changes: 5 additions & 0 deletions office365/directory/security/attacksimulations/operation.py
@@ -0,0 +1,5 @@
from office365.onedrive.operations.long_running import LongRunningOperation


class AttackSimulationOperation(LongRunningOperation):
"""Represents the status of a long-running attack simulation training operation."""
31 changes: 31 additions & 0 deletions office365/directory/security/attacksimulations/root.py
@@ -1,6 +1,10 @@
from office365.directory.security.attacksimulations.automation import (
SimulationAutomation,
)
from office365.directory.security.attacksimulations.landing_page import LandingPage
from office365.directory.security.attacksimulations.operation import (
AttackSimulationOperation,
)
from office365.directory.security.attacksimulations.simulation import Simulation
from office365.entity import Entity
from office365.entity_collection import EntityCollection
Expand All @@ -11,6 +15,32 @@ class AttackSimulationRoot(Entity):
"""Represents an abstract type that provides the ability to launch a realistic phishing attack that organizations
can learn from."""

@property
def landing_pages(self):
# type: () -> EntityCollection[LandingPage]
"""Represents an attack simulation training landing page."""
return self.properties.get(
"landingPages",
EntityCollection(
self.context,
LandingPage,
ResourcePath("landingPages", self.resource_path),
),
)

@property
def operations(self):
# type: () -> EntityCollection[AttackSimulationOperation]
"""Represents an attack simulation training operation."""
return self.properties.get(
"operations",
EntityCollection(
self.context,
AttackSimulationOperation,
ResourcePath("operations", self.resource_path),
),
)

@property
def simulations(self):
# type: () -> EntityCollection[Simulation]
Expand Down Expand Up @@ -40,6 +70,7 @@ def simulation_automations(self):
def get_property(self, name, default_value=None):
if default_value is None:
property_mapping = {
"landingPages": self.landing_pages,
"simulationAutomations": self.simulation_automations,
}
default_value = property_mapping.get(name, None)
Expand Down
9 changes: 9 additions & 0 deletions office365/onedrive/analytics/item_activity_stat.py
Expand Up @@ -65,3 +65,12 @@ def activities(self):
ResourcePath("activities", self.resource_path),
),
)

def get_property(self, name, default_value=None):
if default_value is None:
property_mapping = {
"endDateTime": self.end_datetime,
"startDateTime": self.start_datetime,
}
default_value = property_mapping.get(name, None)
return super(ItemActivityStat, self).get_property(name, default_value)
1 change: 1 addition & 0 deletions office365/onedrive/analytics/item_analytics.py
Expand Up @@ -19,6 +19,7 @@ def all_time(self):

@property
def item_activity_stats(self):
# type: () -> EntityCollection[ItemActivityStat]
return self.properties.get(
"itemActivityStats",
EntityCollection(
Expand Down
15 changes: 11 additions & 4 deletions office365/sharepoint/fields/collection.py
@@ -1,4 +1,4 @@
from typing import Optional
from typing import TYPE_CHECKING, Optional

from office365.runtime.paths.service_operation import ServiceOperationPath
from office365.runtime.queries.create_entity import CreateEntityQuery
Expand All @@ -20,6 +20,10 @@
from office365.sharepoint.taxonomy.sets.set import TermSet
from office365.sharepoint.taxonomy.stores.store import TermStore

if TYPE_CHECKING:
from office365.sharepoint.lists.list import List
from office365.sharepoint.webs.web import Web


class FieldCollection(EntityCollection[Field]):
"""Represents a collection of Field resource."""
Expand Down Expand Up @@ -148,8 +152,6 @@ def _add_lookup_field(lookup_list_id):
return_type=return_type,
)

from office365.sharepoint.lists.list import List

if isinstance(lookup_list, List):

def _lookup_list_loaded():
Expand Down Expand Up @@ -312,7 +314,7 @@ def get_by_id(self, _id):
)

def get_by_internal_name_or_title(self, value):
"""Returns the first field (2) in the collection based on the internal name or the title specified
"""Returns the first field in the collection based on the internal name or the title specified
by the parameter.
:param str value: The title or internal name to look up the field (2) by.
Expand All @@ -334,3 +336,8 @@ def get_by_title(self, title):
self.context,
ServiceOperationPath("getByTitle", [title], self.resource_path),
)

@property
def parent(self):
# type: () -> Web|List
return self._parent
8 changes: 2 additions & 6 deletions office365/sharepoint/fields/field.py
Expand Up @@ -194,17 +194,13 @@ def group(self, val):
@property
def internal_name(self):
# type: () -> Optional[str]
"""
Gets a value that specifies the field internal name.
"""
"""Gets a value that specifies the field internal name."""
return self.properties.get("InternalName", None)

@property
def can_be_deleted(self):
# type: () -> Optional[bool]
"""
Gets a value that specifies whether the field can be deleted
"""
"""Gets a value that specifies whether the field can be deleted"""
return self.properties.get("CanBeDeleted", None)

@property
Expand Down
18 changes: 17 additions & 1 deletion office365/sharepoint/listitems/form_update_value.py
Expand Up @@ -7,7 +7,14 @@
class ListItemFormUpdateValue(ClientValue):
"""Specifies the properties of a list item field and its value."""

def __init__(self, name=None, value=None, has_exception=None, error_code=None):
def __init__(
self,
name=None,
value=None,
has_exception=None,
error_code=None,
error_message=None,
):
"""
:param str name: Specifies the field internal name for a field.
:param str value: Specifies a value for a field.
Expand All @@ -19,6 +26,15 @@ def __init__(self, name=None, value=None, has_exception=None, error_code=None):
self.FieldValue = value
self.HasException = has_exception
self.ErrorCode = error_code
self.ErrorMessage = error_message

def __repr__(self):
if self.HasException:
return "{0} update failed: Message: {1}".format(
self.FieldName, self.ErrorMessage
)
else:
return "{0} update succeeded".format(self.FieldName)

def to_json(self, json_format=None):
json = super(ListItemFormUpdateValue, self).to_json(json_format)
Expand Down
14 changes: 14 additions & 0 deletions office365/sharepoint/taxonomy/field.py
Expand Up @@ -10,6 +10,20 @@
class TaxonomyField(FieldLookup):
"""Represents a taxonomy field."""

def set_field_value_by_value(self, item, tax_value):
"""
Sets the value of the corresponding field in the list item to the value of the specified TaxonomyFieldValue
:param ListItem item: The ListItem object whose field is to be updated.
:param TaxonomyFieldValue tax_value: The TaxonomyFieldValue object whose value is to be used to
update this field.
"""

def _set_field_value_by_value():
item.set_property(self.internal_name, tax_value)

self.ensure_property("InternalName", _set_field_value_by_value)
return self

@staticmethod
def create(
fields,
Expand Down
13 changes: 13 additions & 0 deletions tests/data/ImportTermSet.csv
@@ -0,0 +1,13 @@
"Term Set Name","Term Set Description","LCID","Available for Tagging","Term Description","Level 1 Term","Level 2 Term","Level 3 Term","Level 4 Term","Level 5 Term","Level 6 Term","Level 7 Term"
"Political Geography","A sample term set, describing a simple political geography.",,True,"One of the seven main land masses (Europe, Asia, Africa, North America, South America, Australia, and Antarctica)","Continent",,,,,,
,,,True,"Entity defined by people, not visible to the naked eye","Continent","Political Entity",,,,,
,,,True,"Politically defined state with a geographic area governed by a central government","Continent","Political Entity","Country",,,,
,,,True,"Administrative division of a country","Continent","Political Entity","Country","Province or State",,,
,,,True,"Large sub-region usually containing many cities and towns","Continent","Political Entity","Country","Province or State","County or Region",,
,,,True,"Small village","Continent","Political Entity","Country","Province or State","County or Region","Hamlet",
,,,True,"Collection of homes and business, often incorporated","Continent","Political Entity","Country","Province or State","County or Region","Village",
,,,True,"A small city","Continent","Political Entity","Country","Province or State","County or Region","Town",
,,,True,"An incorporated town with a large population, usually governed by a mayor or council","Continent","Political Entity","Country","Province or State","County or Region","City",
,,,True,"A division of a city, often repesented in the city government","Continent","Political Entity","Country","Province or State","County or Region","City","District"
,,,True,"A sub-section of a city","Continent","Political Entity","Country","Province or State","County or Region","City","Borough"
,,,True,"Unofficial district or area of a city or town","Continent","Political Entity","Country","Province or State","County or Region","City","Neighborhood"
8 changes: 8 additions & 0 deletions tests/directory/test_security.py
Expand Up @@ -16,3 +16,11 @@ def test1_list_incidents(self):
# def test2_list_threat_assessment_requests(self):
# col = self.client.information_protection.threat_assessment_requests.top(10).get().execute_query()
# self.assertIsNotNone(col.resource_path)

# def test3_list_landing_pages(self):
# col = (
# self.client.security.attack_simulation.landing_pages.filter("source eq 'tenant'")
# .get()
# .execute_query()
# )
# self.assertIsNotNone(col.resource_path)
11 changes: 8 additions & 3 deletions tests/onedrive/test_site.py
Expand Up @@ -40,11 +40,16 @@ def test6_unfollow(self):
pass

def test7_get_applicable_content_types_for_list(self):
my_site = self.client.sites.root
doc_lib = my_site.lists["Documents"].get().execute_query()
cts = my_site.get_applicable_content_types_for_list(doc_lib.id).execute_query()
site = self.client.sites.root
doc_lib = site.lists["Documents"].get().execute_query()
cts = site.get_applicable_content_types_for_list(doc_lib.id).execute_query()
self.assertIsNotNone(cts.resource_path)

def test8_get_operations(self):
ops = self.client.sites.root.operations.get().execute_query()
self.assertIsNotNone(ops.resource_path)

def test9_get_analytics(self):
site = self.client.sites.root
result = site.analytics.last_seven_days.get().execute_query()
self.assertIsNotNone(result.resource_path)

0 comments on commit bcd5c76

Please sign in to comment.