Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,96 @@
}
}
},
"/providers/Microsoft.Marketplace/privateStores/{privateStoreId}/queryApprovedPlans": {
"parameters": [
{
"$ref": "#/parameters/PrivateStoreIdParameter"
},
{
"$ref": "#/parameters/ApiVersionParameter"
}
],
"post": {
"tags": [
"PrivateStores"
],
"operationId": "PrivateStore_QueryApprovedPlans",
"description": "Get map of plans and related approved subscriptions.",
"parameters": [
{
"in": "body",
"name": "payload",
"schema": {
"$ref": "#/definitions/QueryApprovedPlansPayload"
}
}
],
"responses": {
"200": {
"description": "Map of plan ids and their related approved subscriptions.",
"schema": {
"$ref": "#/definitions/QueryApprovedPlansResponse"
}
},
"default": {
"description": "Microsoft.Marketplace error response describing why the operation failed.",
"schema": {
"$ref": "#/definitions/ErrorResponse"
}
}
},
"x-ms-examples": {
"QueryApprovedPlans": {
"$ref": "./examples/QueryApprovedPlans.json"
}
}
}
},
"/providers/Microsoft.Marketplace/privateStores/{privateStoreId}/bulkCollectionsAction": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this need a bulk operation instead of performing the operation on each collection individually? Bulk operations are problematic because they may perform actions the user did not have RBAC rights to perform (since the operation is not performed directly on the scope it affects) and they don't expose in the activity log everything they are modifying. It also affects downstream notifications of changes, etc...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, we don't have RBAC per collection. It is on post Ni roadmap.
Once we get there, we have 2 options ( on the RP side):

  1. Check RBAC for each collection and fail the action if there is a least one collection that is not authorized.
  2. Check RBAC for each collection and activate only for the allowed ones. In this case, the response will contain the details for the ones that passed and the ones that failed. The current response already supports this scenario.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify why a bulk operation is needed? RBAC is only one of the side effects mentioned above

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a business requirement to perform an action delete/enable/disable for all collections in a click.
On the server side, we have a transaction(DB stored procedure) performing that operation. If we don't do that in bulk we get conflicts and high-performance impact and not acceptable latency.
Thus the API must be a bulk operation.

"parameters": [
{
"$ref": "#/parameters/PrivateStoreIdParameter"
},
{
"$ref": "#/parameters/ApiVersionParameter"
}
],
"post": {
"tags": [
"PrivateStores"
],
"operationId": "PrivateStore_BulkCollectionsAction",
"description": "Perform an action on bulk collections",
"parameters": [
{
"in": "body",
"name": "payload",
"schema": {
"$ref": "#/definitions/BulkCollectionsPayload"
}
}
],
"responses": {
"200": {
"description": "The collections id and name that the action was performed on",
"schema": {
"$ref": "#/definitions/BulkCollectionsResponse"
}
},
"default": {
"description": "Microsoft.Marketplace error response describing why the operation failed.",
"schema": {
"$ref": "#/definitions/ErrorResponse"
}
}
},
"x-ms-examples": {
"BulkCollectionsAction": {
"$ref": "./examples/BulkCollectionsAction.json"
}
}
}
},
"/providers/Microsoft.Marketplace/privateStores/{privateStoreId}/collections/{collectionId}/offers": {
"parameters": [
{
Expand Down Expand Up @@ -2039,6 +2129,119 @@
}
}
},
"BulkCollectionsPayload": {
"description": "Bulk collections action properties",
"type": "object",
"properties": {
"properties": {
"$ref": "#/definitions/BulkCollectionsDetails",
"description": "bulk collections properties details",
"x-ms-client-flatten": true
}
}
},
"BulkCollectionsDetails": {
"description": "Bulk collection details",
"type": "object",
"properties": {
"collectionIds": {
"description": "collection ids list that the action is performed on",
"type": "array",
"items": {
"type": "string"
}
},
"action": {
"description": "Action to perform (For example: EnableCollections, DisableCollections)",
"type": "string"
}
}
},
"BulkCollectionsResponse": {
"description": "The bulk collections response. The response contains two lists that indicate for each collection whether the operation succeeded or failed",
"type": "object",
"properties": {
"succeeded": {
"description": "Succeeded collections",
"type": "array",
"items": {
"$ref": "#/definitions/CollectionsDetails"
}
},
"failed": {
"description": "Failed collections",
"type": "array",
"items": {
"$ref": "#/definitions/CollectionsDetails"
}
}
}
},
"QueryApprovedPlansPayload": {
"description": "Query approved plans payload",
"type": "object",
"properties": {
"properties": {
"$ref": "#/definitions/QueryApprovedPlans",
"description": "Query approved plans details",
"x-ms-client-flatten": true
}
}
},
"QueryApprovedPlans": {
"description": "Query approved plans details",
"type": "object",
"properties": {
"offerId": {
"description": "Offer id",
"type": "string"
},
"planIds": {
"description": "Offer plan ids",
"type": "array",
"items": {
"type": "string"
}
}
}
},
"QueryApprovedPlansResponse": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be easier to consume if its an array of plan objects with planId as a property in each object. Why does it need to be a dictionary with dynamic keys?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to enforce the plan id uniqueness in the result

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You control the response so you can enforce uniqueness regardless of the response schema. If that is the only reason please use a strict schema instead of dynamic keys

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed to list of objects

"description": "Query approved plans response",
"type": "object",
"properties": {
"details": {
"$ref": "#/definitions/QueryApprovedPlansResponseDetails"
}
}
},
"QueryApprovedPlansResponseDetails": {
"description": "A list indicating for each plan which subscriptions are approved. Plan Id is unique",
"type": "array",
"items": {
"$ref": "#/definitions/QueryApprovedPlansDetails"
}
},
"QueryApprovedPlansDetails": {
"description": "Query approved plans response",
"type": "object",
"properties": {
"planId": {
"description": "Plan id",
"type": "string"
},
"subscriptionIds": {
"description": "Approved subscription ids list. In case all subscriptions are approved for a plan, allSubscriptions flag is true and list is empty ( else flag is set to false). In case both subscriptions list is empty and allSubscriptions flag is false, the plan is not approved for any subscription.",
"type": "array",
"items": {
"type": "string"
}
},
"allSubscriptions": {
"description": "Indicates whether all subscriptions are approved for this plan",
"type": "boolean"
}
}
},
"CollectionsDetails": {
"description": "Collection name and id.",
"type": "object",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"parameters": {
"privateStoreId": "a0e28e55-90c4-41d8-8e34-bb7ef7775406",
"api-version": "2021-06-01",
"payload": {
"properties": {
"collectionIds": [
"c752f021-1c37-4af5-b82f-74c51c27b44a",
"f47ef1c7-e908-4f39-ae29-db181634ad8d"
],
"action": "EnableCollections"
}
}
},
"responses": {
"200": {
"body": {
"succeeded": [
{
"collectionId": "c752f021-1c37-4af5-b82f-74c51c27b44a",
"collectionName": "Test collection"
}
],
"failed": [
{
"collectionId": "f47ef1c7-e908-4f39-ae29-db181634ad8d",
"collectionName": "Test collection 2"
}
]
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"parameters": {
"privateStoreId": "a0e28e55-90c4-41d8-8e34-bb7ef7775406",
"api-version": "2021-06-01",
"payload": {
"properties": {
"offerId": "marketplacetestthirdparty.md-test-third-party-2",
"planIds": [
"testPlanA",
"testPlanB",
"testPlanC"
]
}
}
},
"responses": {
"200": {
"body": {
"details": [
{
"planId": "testPlanA",
"subscriptionIds": [
"85e3e079-c718-4e4c-abbe-f72fceba8305",
"7752d461-4bf1-4185-8b56-8a3f11486ac6"
],
"allSubscriptions": false
},
{
"planId": "testPlanB",
"subscriptionIds": [],
"allSubscriptions": true
},
{
"planId": "testPlanC",
"subscriptionIds": [],
"allSubscriptions": false
}
]
}
}
}
}