Skip to content

Commit 7243f97

Browse files
committed
workbooks (#926), and sharepoint alm namespaces enhancements
1 parent dd92579 commit 7243f97

File tree

18 files changed

+246
-23
lines changed

18 files changed

+246
-23
lines changed
Binary file not shown.
Binary file not shown.

examples/sharepoint/alm/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Application Lifecycle Management (ALM) API
2+
3+
### ALM APIs provide simple APIs to manage deployment of your SharePoint Framework solutions and add-ins across your tenant.
294 KB
Binary file not shown.

office365/directory/authentication/methods/root.py

+11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
from office365.directory.authentication.methods.details import UserRegistrationDetails
22
from office365.entity import Entity
33
from office365.entity_collection import EntityCollection
4+
from office365.reports.userregistration.feature_summary import (
5+
UserRegistrationFeatureSummary,
6+
)
47
from office365.reports.userregistration.method_summary import (
58
UserRegistrationMethodSummary,
69
)
@@ -12,6 +15,14 @@
1215
class AuthenticationMethodsRoot(Entity):
1316
"""Container for navigation properties for Azure AD authentication methods resources."""
1417

18+
def users_registered_by_feature(self):
19+
"""Get the number of users capable of multi-factor authentication, self-service password reset,
20+
and passwordless authentication."""
21+
return_type = ClientResult(self.context, UserRegistrationFeatureSummary())
22+
qry = FunctionQuery(self, "usersRegisteredByFeature", None, return_type)
23+
self.context.add_query(qry)
24+
return return_type
25+
1526
def users_registered_by_method(self):
1627
"""Get the number of users registered for each authentication method."""
1728
return_type = ClientResult(self.context, UserRegistrationMethodSummary())

office365/onedrive/workbooks/charts/chart.py

+29-4
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,46 @@
11
from office365.entity import Entity
22
from office365.onedrive.workbooks.charts.axes import WorkbookChartAxes
33
from office365.onedrive.workbooks.charts.data_labels import WorkbookChartDataLabels
4+
from office365.runtime.client_result import ClientResult
45
from office365.runtime.paths.resource_path import ResourcePath
6+
from office365.runtime.queries.function import FunctionQuery
57
from office365.runtime.queries.service_operation import ServiceOperationQuery
68

79

810
class WorkbookChart(Entity):
911
"""Represents a chart object in a workbook."""
1012

11-
def set_position(self, startCell, endCell):
13+
def image(self, width=None, height=None):
14+
"""Renders the chart as a base64-encoded image by scaling the chart to fit the specified dimensions.
15+
16+
:param int width: Specifies the width of the rendered image in pixels.
17+
:param int height: Specifies the height of the rendered image in pixels.
18+
"""
19+
return_type = ClientResult(self.context)
20+
params = {"width": width, "height": height}
21+
qry = FunctionQuery(self, "image", params, return_type)
22+
self.context.add_query(qry)
23+
return return_type
24+
25+
def set_data(self, source_data, series_by):
26+
"""
27+
Updates the data source of a chart
28+
:param dict source_data:
29+
:param str series_by:
30+
"""
31+
payload = {"sourceData": source_data, "seriesBy": series_by}
32+
qry = ServiceOperationQuery(self, "setData", None, payload)
33+
self.context.add_query(qry)
34+
return self
35+
36+
def set_position(self, start_cell, end_cell):
1237
"""Positions the chart relative to cells on the worksheet.
13-
:param str startCell: The start cell. It is where the chart is moved to. The start cell is the top-left or
38+
:param str start_cell: The start cell. It is where the chart is moved to. The start cell is the top-left or
1439
top-right cell, depending on the user's right-to-left display settings.
15-
:param str endCell: The end cell. If specified, the chart's width and height is set to fully cover up
40+
:param str end_cell: The end cell. If specified, the chart's width and height is set to fully cover up
1641
this cell/range.
1742
"""
18-
payload = {"startCell": startCell, "endCell": endCell}
43+
payload = {"startCell": start_cell, "endCell": end_cell}
1944
qry = ServiceOperationQuery(self, "setPosition", None, payload)
2045
self.context.add_query(qry)
2146
return self

office365/onedrive/workbooks/ranges/range.py

+17
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@
1212
class WorkbookRange(Entity):
1313
"""Range represents a set of one or more contiguous cells such as a cell, a row, a column, block of cells, etc."""
1414

15+
def __repr__(self):
16+
return self.address or self.entity_type_name
17+
18+
def __str__(self):
19+
return self.address or self.entity_type_name
20+
1521
def cell(self, row, column):
1622
"""
1723
Gets the range object containing the single cell based on row and column numbers. The cell can be outside
@@ -55,6 +61,17 @@ def visible_view(self):
5561
self.context.add_query(qry)
5662
return return_type
5763

64+
def used_range(self, values_only=False):
65+
"""Return the used range of the given range object.
66+
67+
:param bool values_only: Optional. Considers only cells with values as used cells.
68+
"""
69+
return_type = WorkbookRange(self.context)
70+
params = {"valuesOnly": values_only}
71+
qry = FunctionQuery(self, "usedRange", params, return_type)
72+
self.context.add_query(qry)
73+
return return_type
74+
5875
@property
5976
def address(self):
6077
# type: () -> Optional[str]

office365/onedrive/workbooks/worksheets/worksheet.py

+11
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,17 @@ def range(self, address=None):
5353
self.context.add_query(qry)
5454
return return_type
5555

56+
def used_range(self, values_only=False):
57+
"""Return the used range of the given range object.
58+
59+
:param bool values_only: Optional. Considers only cells with values as used cells.
60+
"""
61+
return_type = WorkbookRange(self.context)
62+
params = {"valuesOnly": values_only}
63+
qry = FunctionQuery(self, "usedRange", params, return_type)
64+
self.context.add_query(qry)
65+
return return_type
66+
5667
@property
5768
def charts(self):
5869
# type: () -> EntityCollection[WorkbookChart]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from office365.runtime.client_value import ClientValue
2+
3+
4+
class UserRegistrationFeatureSummary(ClientValue):
5+
""""""

office365/sharepoint/marketplace/app_metadata.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
class CorporateCatalogAppMetadata(Entity):
88
"""App metadata for apps stored in the corporate catalog."""
99

10+
def __str__(self):
11+
return self.title or self.entity_type_name
12+
1013
def deploy(self, skip_feature_deployment):
1114
"""This method deploys an app on the app catalog. It MUST be called in the context of the tenant app
1215
catalog web or it will fail.
@@ -18,6 +21,13 @@ def deploy(self, skip_feature_deployment):
1821
self.context.add_query(qry)
1922
return self
2023

24+
def remove(self):
25+
"""This is the inverse of the add step above. One removed from the app catalog,
26+
the solution can't be deployed."""
27+
qry = ServiceOperationQuery(self, "Remove")
28+
self.context.add_query(qry)
29+
return self
30+
2131
def install(self):
2232
"""This method allows an app which is already deployed to be installed on a web."""
2333
qry = ServiceOperationQuery(self, "Install")
@@ -68,7 +78,8 @@ def id(self):
6878

6979
@property
7080
def property_ref_name(self):
71-
return "AadAppId"
81+
# return "AadAppId"
82+
return "ID"
7283

7384
@property
7485
def entity_type_name(self):

office365/sharepoint/marketplace/app_metadata_collection.py

+8
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,11 @@ def get_by_id(self, app_id):
2222
return CorporateCatalogAppMetadata(
2323
self.context, ServiceOperationPath("GetById", [app_id], self.resource_path)
2424
)
25+
26+
def get_by_title(self, title):
27+
"""
28+
Get app metadata by title.
29+
30+
:param str title: The title of the app to retrieve.
31+
"""
32+
return self.first("title eq '{0}'".format(title))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from office365.runtime.client_value import ClientValue
2+
3+
4+
class SPStoreAppRequestInformation(ClientValue):
5+
""""""
6+
7+
@property
8+
def entity_type_name(self):
9+
return "Microsoft.SharePoint.Marketplace.CorporateCuratedGallery.SPStoreAppRequestInformation"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from office365.runtime.client_value import ClientValue
2+
3+
4+
class SPStoreAppResponseInformation(ClientValue):
5+
""""""
6+
7+
@property
8+
def entity_type_name(self):
9+
return "Microsoft.SharePoint.Marketplace.CorporateCuratedGallery.SPStoreAppResponseInformation"

office365/sharepoint/marketplace/tenant/appcatalog/accessor.py

+41-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import os
2+
13
from office365.runtime.client_result import ClientResult
24
from office365.runtime.paths.resource_path import ResourcePath
35
from office365.runtime.paths.service_operation import ServiceOperationPath
@@ -8,6 +10,12 @@
810
from office365.sharepoint.marketplace.app_metadata_collection import (
911
CorporateCatalogAppMetadataCollection,
1012
)
13+
from office365.sharepoint.marketplace.corporatecuratedgallery.app_request_information import (
14+
SPStoreAppRequestInformation,
15+
)
16+
from office365.sharepoint.marketplace.corporatecuratedgallery.app_response_information import (
17+
SPStoreAppResponseInformation,
18+
)
1119
from office365.sharepoint.marketplace.corporatecuratedgallery.app_upgrade_availability import (
1220
AppUpgradeAvailability,
1321
)
@@ -22,7 +30,7 @@
2230
class TenantCorporateCatalogAccessor(Entity):
2331
"""Accessor for the tenant corporate catalog."""
2432

25-
def add(self, content, overwrite, url):
33+
def add(self, content, overwrite, url=None):
2634
"""
2735
Adds a file to the corporate catalog.
2836
@@ -32,8 +40,27 @@ def add(self, content, overwrite, url):
3240
:param str url: Specifies the URL of the file to be added.
3341
"""
3442
return_type = File(self.context)
35-
payload = {"Content": content, "Overwrite": overwrite, "Url": url}
36-
qry = ServiceOperationQuery(self, "Add", None, payload, None, return_type)
43+
params = {"Overwrite": overwrite, "Url": url}
44+
qry = ServiceOperationQuery(self, "Add", params, content, None, return_type)
45+
self.context.add_query(qry)
46+
return return_type
47+
48+
def app_from_path(self, path, overwrite):
49+
"""
50+
Adds a file to the corporate catalog.
51+
"""
52+
with open(path, "rb") as f:
53+
content = f.read()
54+
url = os.path.basename(path)
55+
return self.add(content=content, overwrite=overwrite, url=url)
56+
57+
def app_requests(self):
58+
""""""
59+
return_type = ClientResult(self.context, SPStoreAppResponseInformation())
60+
payload = {"AppRequestInfo": SPStoreAppRequestInformation()}
61+
qry = ServiceOperationQuery(
62+
self, "AppRequests", None, payload, None, return_type
63+
)
3764
self.context.add_query(qry)
3865
return return_type
3966

@@ -70,6 +97,17 @@ def is_app_upgrade_available(self, _id):
7097
self.context.add_query(qry)
7198
return return_type
7299

100+
def upload(self, content, overwrite, url, xor_hash=None):
101+
payload = {
102+
"Content": content,
103+
"Overwrite": overwrite,
104+
"Url": url,
105+
"XorHash": xor_hash,
106+
}
107+
qry = ServiceOperationQuery(self, "Upload", None, payload)
108+
self.context.add_query(qry)
109+
return self
110+
73111
def send_app_request_status_notification_email(self, request_guid):
74112
"""
75113
:param str request_guid:

tests/onedrive/test_excel_charts.py

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from office365.onedrive.driveitems.driveItem import DriveItem
2+
from office365.onedrive.workbooks.charts.chart import WorkbookChart
3+
from office365.onedrive.workbooks.worksheets.worksheet import WorkbookWorksheet
4+
from tests.graph_case import GraphTestCase
5+
6+
7+
class TestExcelCharts(GraphTestCase):
8+
excel_file = None # type: DriveItem
9+
worksheet = None # type: WorkbookWorksheet
10+
chart = None # type: WorkbookChart
11+
12+
@classmethod
13+
def setUpClass(cls):
14+
super(TestExcelCharts, cls).setUpClass()
15+
path = "../../examples/data/templates/Weight loss tracker.xlsx"
16+
cls.excel_file = cls.client.me.drive.root.upload_file(path).execute_query()
17+
assert cls.excel_file.resource_path is not None
18+
cls.worksheet = (
19+
cls.excel_file.workbook.worksheets["Weight loss tracker"]
20+
.get()
21+
.execute_query()
22+
)
23+
assert cls.worksheet.resource_path is not None
24+
25+
@classmethod
26+
def tearDownClass(cls):
27+
cls.excel_file.delete_object().execute_query_retry()
28+
29+
def test1_list_charts(self):
30+
result = self.__class__.worksheet.charts.get().execute_query()
31+
self.assertIsNotNone(result.resource_path)
32+
33+
def test2_get_chart_by_name(self):
34+
result = self.__class__.worksheet.charts["Weight Tracker"].get().execute_query()
35+
self.assertIsNotNone(result.resource_path)
36+
self.__class__.chart = result
37+
38+
def test3_get_image(self):
39+
result = self.__class__.chart.image().execute_query()
40+
self.assertIsNotNone(result.value)

tests/onedrive/test_excel_ranges.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def test1_name_create(self):
3030
self.__class__.named_item = result
3131

3232
def test2_names_get(self):
33-
result = self.__class__.named_item.get().execute_query()
33+
result = self.__class__.named_item.get().execute_query_retry(2)
3434
self.assertIsNotNone(result.resource_path)
3535

3636
def test3_list_range(self):
@@ -42,6 +42,10 @@ def test3_list_range(self):
4242
# result = self.__class__.range.insert("Right").execute_query()
4343
# self.assertIsNotNone(result.address)
4444

45-
def test5_clear_range(self):
45+
def test5_used_range(self):
46+
result = self.__class__.range.used_range().execute_query()
47+
self.assertIsNotNone(result.address)
48+
49+
def test6_clear_range(self):
4650
result = self.__class__.range.clear().execute_query()
4751
self.assertIsNotNone(result.address)

tests/onedrive/test_excel_worksheets.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ def test2_list_worksheets(self):
3535
self.assertGreaterEqual(len(result), 1)
3636
self.__class__.worksheet = result[0]
3737

38-
def test3_protect_worksheet(self):
38+
def test3_used_range(self):
39+
result = self.__class__.worksheet.used_range().execute_query()
40+
self.assertIsNotNone(result.address)
41+
42+
def test4_protect_worksheet(self):
3943
ws = self.__class__.worksheet
4044
options = WorkbookWorksheetProtectionOptions(allowDeleteRows=False)
4145
ws.protection.protect(options).execute_query()

0 commit comments

Comments
 (0)