diff --git a/API-implementation-tracking.md b/API-implementation-tracking.md
new file mode 100644
index 0000000..6abc414
--- /dev/null
+++ b/API-implementation-tracking.md
@@ -0,0 +1,118 @@
+
+## Customer Operations
+~~Assign licenses to a user~~
+~~Get licenses assigned to a user~~
+Get licenses assigned to a user by license group
+~~Create a customer~~
+Create a customer for an indirect reseller
+Create user accounts for a customer
+Delete a user account for a customer
+Get a list of customers filtered by a search field
+Get a customer by ID
+~~Get a customer's billing profile~~
+Get a customer's company profile
+Get a customer's orders
+Get a customer's subscriptions
+Get a list of all user accounts for a customer
+Get a list of available licenses
+Get a list of available licenses by license group
+Get a list of customers
+Get a user account by ID
+Get user roles for a customer
+Remove a customer user from a role
+Retrieve a relationship request URL
+Reset user password for a customer
+Restore a deleted user for a customer
+Set user roles for a customer
+Update a customer's billing profile
+Update the nickname for a subscription
+Update user accounts for a customer
+View deleted users for a customer
+
+## Order Operations
+Change the quantity of a subscription
+[Convert a trial subscription to paid](convert-a-trial-subscription-to-paid.md
+Create an order
+Create an order for a customer of an indirect reseller
+Get a list of add-ons for a subscription
+Get a list of offer categories by market
+Get a list of offers for a market
+Get a list of subscriptions by order
+Get a list of trial conversion offers
+Get a subscription by ID
+Get add-ons for an offer ID
+Get an offer by ID
+Get an order by ID
+Get subscription provisioning status
+Purchase an add-on to a subscription
+Reactivate a suspended subscription
+Remove a reseller relationship with a customer
+Suspend a subscription
+Transition a subscription
+
+## Audit Operations
+Get a record of Partner Center activity
+
+## Analytics Operations
+Get partner licenses deployment information
+Get partner licenses usage information
+Get customer licenses deployment information
+Get customer licenses usage information
+
+## Billing Operations
+Get a customer's service costs summary
+Get a customer's service costs line items
+Get a collection of invoices
+Get a customer's utilization records for Azure
+Get an invoice by ID
+Get invoice line items
+Get prices for Microsoft Azure
+Get prices for Microsoft Azure Partner Shared Services
+Get the partner's current account balance
+Get usage data for a subscription
+Get a usage summary for all of a customer's subscriptions
+
+## Support Operations
+Create a service request
+Get a subscription's support contact
+Get all service requests for a customer
+Get service request support topics
+Get the managed services for a customer by ID
+Update a service request
+Update a subscription's support contact
+
+## Accounts and Profile Operations
+Get a customer's subscriptions by partner MPN ID
+Get an organization profile
+Get customers of an indirect reseller
+Get indirect resellers of a customer
+Get Microsoft Partner Network profile
+Get partner billing profile
+Verify a partner MPN ID
+Get support profile
+Get the partner legal business profile
+Retrieve a list of indirect resellers
+Update an organization profile
+Update the partner billing profile
+Update support profile
+Update the partner legal business profile
+
+## Utility Operations
+Validate an address
+Get address formatting rules by market
+Verify domain availability
+Delete a customer account from the integration sandbox
+
+## Device Deployment Operations
+Create a new configuration policy for the specified customer
+Delete a configuration policy for the specified customer
+Get a list of a customer's policies
+Retrieve a customer's configuration policy
+Update a configuration policy for the specified customer
+Get the status of a device batch upload
+Get a list of device batches for the specified customer
+Get a list of devices for the specified batch and customer
+Upload a list of devices to create a new batch for the specified customer
+Upload a list of devices to an existing batch for the specified customer
+Update a list of devices with a policy
+Delete a device for the specified customer
diff --git a/release-notes.md b/release-notes.md
index cbd5025..1760a83 100644
--- a/release-notes.md
+++ b/release-notes.md
@@ -1,5 +1,9 @@
# Release Notes: Spring Social for Microsoft Partner Center
+## 6.2.0
+#### Added
+1. ServiceRequestOperations added to allow for creating and retrieving service requests through the API
+
## 6.1.0
#### Bug Fixes
diff --git a/src/main/java/org/springframework/social/partnercenter/api/customer/AdminCustomerOperations.java b/src/main/java/org/springframework/social/partnercenter/api/customer/AdminCustomerOperations.java
index 21621e1..0e6d7ee 100644
--- a/src/main/java/org/springframework/social/partnercenter/api/customer/AdminCustomerOperations.java
+++ b/src/main/java/org/springframework/social/partnercenter/api/customer/AdminCustomerOperations.java
@@ -7,5 +7,5 @@ public interface AdminCustomerOperations extends CustomerOperations{
ResponseEntity getBillingProfile(String customerTenantId);
ResponseEntity updateBillingProfile(String customerTenantId, String etag, CustomerBillingProfile billingProfile);
ResponseEntity> getCompanyByDomain(int size, String filter);
- ResponseEntity> subscribedSkus(String customerTenantId);
+ ResponseEntity> subscribedSkus(String customerId);
}
diff --git a/src/main/java/org/springframework/social/partnercenter/api/customer/user/AdminUserOperations.java b/src/main/java/org/springframework/social/partnercenter/api/customer/user/AdminUserOperations.java
index 3241564..2d4c439 100644
--- a/src/main/java/org/springframework/social/partnercenter/api/customer/user/AdminUserOperations.java
+++ b/src/main/java/org/springframework/social/partnercenter/api/customer/user/AdminUserOperations.java
@@ -19,4 +19,21 @@ public interface AdminUserOperations extends UserOperations{
ResponseEntity> getUserRoles(String customerTenantId, String userId);
ResponseEntity> getAllRoles(String customerTenantId);
ResponseEntity> getRolesByRoleId(String customerTenantId, String RoleId);
+
+ /**
+ * Gets a list of deleted CustomerUser resources for a customer by customer ID.
+ *
+ * @param customerId The value is a GUID formatted customer-id that identifies the customer.
+ * @return
+ */
+ ResponseEntity> getDeletedUsers(String customerId);
+
+ /**
+ * Gets a list of deleted CustomerUser resources for a customer by customer ID.
+ *
+ * @param customerId The value is a GUID formatted customer-id that identifies the customer.
+ * @param size The maximum size of the list to be returned
+ * @return
+ */
+ ResponseEntity> getDeletedUsers(String customerId, Integer size);
}
diff --git a/src/main/java/org/springframework/social/partnercenter/api/customer/user/impl/AdminUserTemplate.java b/src/main/java/org/springframework/social/partnercenter/api/customer/user/impl/AdminUserTemplate.java
index 77cde9e..9d62523 100644
--- a/src/main/java/org/springframework/social/partnercenter/api/customer/user/impl/AdminUserTemplate.java
+++ b/src/main/java/org/springframework/social/partnercenter/api/customer/user/impl/AdminUserTemplate.java
@@ -1,10 +1,14 @@
package org.springframework.social.partnercenter.api.customer.user.impl;
+import static org.springframework.social.partnercenter.serialization.Json.toJson;
+
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.ResponseEntity;
import org.springframework.social.partnercenter.PartnerCenterAdmin;
import org.springframework.social.partnercenter.api.PartnerCenterResponse;
import org.springframework.social.partnercenter.api.customer.Role;
+import org.springframework.social.partnercenter.api.customer.query.Filter;
+import org.springframework.social.partnercenter.api.customer.query.Operator;
import org.springframework.social.partnercenter.api.customer.user.AdminUserOperations;
import org.springframework.social.partnercenter.api.customer.user.CustomerUser;
import org.springframework.social.partnercenter.api.customer.user.License;
@@ -108,6 +112,23 @@ public ResponseEntity> getRolesByRoleId(String custo
.get(new ParameterizedTypeReference>() {});
}
+ @Override
+ public ResponseEntity> getDeletedUsers(String customerId) {
+ return restResource.request()
+ .pathSegment(customerId, "users")
+ .queryParam("filter", toJson(Filter.builder().field("UserState").operator(Operator.EQUALS).value("Inactive").build()))
+ .get(new ParameterizedTypeReference>() {});
+ }
+
+ @Override
+ public ResponseEntity> getDeletedUsers(String customerId, Integer size) {
+ return restResource.request()
+ .pathSegment(customerId, "users")
+ .queryParam("size", size)
+ .queryParam("filter", toJson(Filter.builder().field("UserState").operator(Operator.EQUALS).value("Inactive").build()))
+ .get(new ParameterizedTypeReference>() {});
+ }
+
@Override
protected String getProviderId() {
return PartnerCenterAdmin.PROVIDER_ID;
diff --git a/src/main/java/org/springframework/social/partnercenter/api/support/SupportOperations.java b/src/main/java/org/springframework/social/partnercenter/api/support/SupportOperations.java
index 729d9ad..98cd9f6 100644
--- a/src/main/java/org/springframework/social/partnercenter/api/support/SupportOperations.java
+++ b/src/main/java/org/springframework/social/partnercenter/api/support/SupportOperations.java
@@ -1,5 +1,7 @@
package org.springframework.social.partnercenter.api.support;
+import java.util.Locale;
+
import org.springframework.http.ResponseEntity;
import org.springframework.social.partnercenter.api.PartnerCenterResponse;
import org.springframework.social.partnercenter.api.support.managedservice.ManagedService;
@@ -12,5 +14,5 @@ public interface SupportOperations {
ResponseEntity> getSupportTopics();
ResponseEntity> getServiceRequests(String customerId);
ResponseEntity updateServiceRequest(ServiceRequest request);
- ResponseEntity createServiceRequest(ServiceRequest request);
+ ResponseEntity createServiceRequest(ServiceRequest request, Locale locale);
}
diff --git a/src/main/java/org/springframework/social/partnercenter/api/support/impl/SupportTemplate.java b/src/main/java/org/springframework/social/partnercenter/api/support/impl/SupportTemplate.java
index badc329..96d983a 100644
--- a/src/main/java/org/springframework/social/partnercenter/api/support/impl/SupportTemplate.java
+++ b/src/main/java/org/springframework/social/partnercenter/api/support/impl/SupportTemplate.java
@@ -1,5 +1,7 @@
package org.springframework.social.partnercenter.api.support.impl;
+import java.util.Locale;
+
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.ResponseEntity;
import org.springframework.social.partnercenter.PartnerCenter;
@@ -69,9 +71,9 @@ public ResponseEntity updateServiceRequest(ServiceRequest reques
}
@Override
- public ResponseEntity createServiceRequest(ServiceRequest request) {
+ public ResponseEntity createServiceRequest(ServiceRequest request, Locale locale) {
return restResource.request()
- .pathSegment(SERVICE_REQUESTS)
+ .pathSegment(SERVICE_REQUESTS, locale.toLanguageTag())
.post(request, ServiceRequest.class);
}
diff --git a/src/main/java/org/springframework/social/partnercenter/api/support/servicerequest/ServiceRequest.java b/src/main/java/org/springframework/social/partnercenter/api/support/servicerequest/ServiceRequest.java
index a8a06d7..ffba6df 100644
--- a/src/main/java/org/springframework/social/partnercenter/api/support/servicerequest/ServiceRequest.java
+++ b/src/main/java/org/springframework/social/partnercenter/api/support/servicerequest/ServiceRequest.java
@@ -13,6 +13,9 @@
public class ServiceRequest {
private String id;
private String title;
+ private String description;
+ private String supportTopicId;
+ private String supportTopicName;
private ServiceRequestSeverity severity;
private ServiceRequestStatus status;
private ServiceRequestOrganization organization;
@@ -29,6 +32,9 @@ public class ServiceRequest {
private String countryCode;
private ResourceAttributes attributes;
+ public ServiceRequest() {
+ }
+
public String getTitle() {
return title;
}
@@ -164,4 +170,117 @@ public String getCountryCode() {
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getSupportTopicId() {
+ return supportTopicId;
+ }
+
+ public void setSupportTopicId(String supportTopicId) {
+ this.supportTopicId = supportTopicId;
+ }
+
+ public String getSupportTopicName() {
+ return supportTopicName;
+ }
+
+ public void setSupportTopicName(String supportTopicName) {
+ this.supportTopicName = supportTopicName;
+ }
+
+ public static class Builder {
+ private String title;
+ private String description;
+ private ServiceRequestSeverity severity;
+ private ServiceRequestOrganization organization;
+ private ServiceRequestContact primaryContact;
+ private String supportTopicId;
+ private String supportTopicName;
+ private String productName;
+ private String productId;
+ private ServiceRequestNote newNote;
+ private String countryCode;
+
+ public Builder title(String title) {
+ this.title = title;
+ return this;
+ }
+
+ public Builder severity(ServiceRequestSeverity severity) {
+ this.severity = severity;
+ return this;
+ }
+
+ public Builder organization(ServiceRequestOrganization organization) {
+ this.organization = organization;
+ return this;
+ }
+
+ public Builder primaryContact(ServiceRequestContact primaryContact) {
+ this.primaryContact = primaryContact;
+ return this;
+ }
+
+ public Builder productName(String productName) {
+ this.productName = productName;
+ return this;
+ }
+
+ public Builder productId(String productId) {
+ this.productId = productId;
+ return this;
+ }
+
+ public Builder newNote(ServiceRequestNote newNote) {
+ this.newNote = newNote;
+ return this;
+ }
+
+ public Builder countryCode(String countryCode) {
+ this.countryCode = countryCode;
+ return this;
+ }
+
+ public Builder description(String description) {
+ this.description = description;
+ return this;
+ }
+
+ public ServiceRequest build() {
+ ServiceRequest request = new ServiceRequest();
+ request.setTitle(title);
+ request.setCountryCode(countryCode);
+ request.setSeverity(severity);
+ request.setOrganization(organization);
+ request.setPrimaryContact(primaryContact);
+ request.setProductName(productName);
+ request.setProductId(productId);
+ request.setNewNote(newNote);
+ request.setSupportTopicId(supportTopicId);
+ request.setSupportTopicName(supportTopicName);
+ request.setDescription(description);
+ return request;
+ }
+
+ public Builder supportTopicId(String supportTopicId) {
+ this.supportTopicId = supportTopicId;
+ return this;
+ }
+
+ public Builder supportTopicName(String supportTopicName) {
+ this.supportTopicName = supportTopicName;
+ return this;
+ }
+ }
}
diff --git a/src/main/java/org/springframework/social/partnercenter/api/support/servicerequest/ServiceRequestNote.java b/src/main/java/org/springframework/social/partnercenter/api/support/servicerequest/ServiceRequestNote.java
index f622d17..c7888db 100644
--- a/src/main/java/org/springframework/social/partnercenter/api/support/servicerequest/ServiceRequestNote.java
+++ b/src/main/java/org/springframework/social/partnercenter/api/support/servicerequest/ServiceRequestNote.java
@@ -35,4 +35,30 @@ public String getText() {
public void setText(String text) {
this.text = text;
}
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private String createdByName;
+ private String text;
+
+ public Builder createdByName(String createdByName) {
+ this.createdByName = createdByName;
+ return this;
+ }
+
+ public Builder text(String text) {
+ this.text = text;
+ return this;
+ }
+
+ public ServiceRequestNote build() {
+ ServiceRequestNote note = new ServiceRequestNote();
+ note.setCreatedByName(createdByName);
+ note.setText(text);
+ return note;
+ }
+ }
}
diff --git a/src/main/java/org/springframework/social/partnercenter/api/utilities/impl/UtilityTemplate.java b/src/main/java/org/springframework/social/partnercenter/api/utilities/impl/UtilityTemplate.java
index 1281e7c..b1cba22 100644
--- a/src/main/java/org/springframework/social/partnercenter/api/utilities/impl/UtilityTemplate.java
+++ b/src/main/java/org/springframework/social/partnercenter/api/utilities/impl/UtilityTemplate.java
@@ -3,12 +3,15 @@
import static java.time.ZoneId.of;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.OK;
+import static org.springframework.http.ResponseEntity.ok;
import static org.springframework.social.partnercenter.serialization.Json.toJson;
import static org.springframework.social.partnercenter.time.PartnerCenterDateTimeFormatter.PARTNER_CENTER_UTC;
import java.time.Instant;
+import java.util.Objects;
import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.social.partnercenter.PartnerCenter;
import org.springframework.social.partnercenter.api.AbstractTemplate;
@@ -47,7 +50,8 @@ public Boolean isDomainAvailable(String domain) {
return !restResource.request()
.pathSegment("domains", domain)
.noRetry()
- .head().getStatusCode().equals(OK);
+ .head().getStatusCode()
+ .equals(OK);
} catch (ApiFaultException fault){
return fault.getHttpStatus().equals(NOT_FOUND);
}
@@ -55,9 +59,17 @@ public Boolean isDomainAvailable(String domain) {
@Override
public ResponseEntity validateAddress(Address address) {
- return restResource.request()
- .pathSegment("validations", "address")
- .post(address, Boolean.class);
+ try {
+ return restResource.request()
+ .pathSegment("validations", "address")
+ .post(address, Boolean.class);
+ } catch (ApiFaultException fault) {
+ if (Objects.equals(fault.getStatusCode(), HttpStatus.BAD_REQUEST)) {
+ return ok(false);
+ } else {
+ throw fault;
+ }
+ }
}
@Override
diff --git a/src/main/java/org/springframework/social/partnercenter/security/AzureADAuthTemplate.java b/src/main/java/org/springframework/social/partnercenter/security/AzureADAuthTemplate.java
index bde4c44..6f38953 100644
--- a/src/main/java/org/springframework/social/partnercenter/security/AzureADAuthTemplate.java
+++ b/src/main/java/org/springframework/social/partnercenter/security/AzureADAuthTemplate.java
@@ -4,8 +4,6 @@
import static org.springframework.social.partnercenter.api.uri.UriProvider.DEFAULT_URL_PROVIDER;
import static org.springframework.util.Assert.notNull;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Map;
@@ -19,7 +17,6 @@
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.social.oauth2.AccessGrant;
-import org.springframework.social.oauth2.GrantType;
import org.springframework.social.partnercenter.api.ApiAuthorizationException;
import org.springframework.social.partnercenter.api.AuthorizationFault;
import org.springframework.social.partnercenter.api.uri.UriProvider;
@@ -32,7 +29,7 @@
import org.springframework.social.support.FormMapHttpMessageConverter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
-import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestTemplate;
public class AzureADAuthTemplate implements AzureADAuthOperations {
@@ -136,7 +133,7 @@ public AccessGrant exchangeForAccess(String authorizationCode, MultiValueMap result) {
return createAccessGrant((String) result.get("access_token"), (String) result.get("scope"), (String) result.get("refresh_token"), getIntegerValue(result, "expires_in"), (String) result.get("id_token"), result);
}
- private String formEncode(String data) {
- try {
- return URLEncoder.encode(data, "UTF-8");
- }
- catch (UnsupportedEncodingException ex) {
- // should not happen, UTF-8 is always supported
- throw new IllegalStateException(ex);
- }
- }
-
// Retrieves object from map into an Integer, regardless of the object's actual type. Allows for flexibility in object type (eg, "3600" vs 3600).
private Long getIntegerValue(Map map, String key) {
try {
@@ -319,7 +310,7 @@ private Long getIntegerValue(Map map, String key) {
}
}
- private ApiAuthorizationException buildAuthFault(HttpClientErrorException e){
+ private ApiAuthorizationException buildAuthFault(HttpStatusCodeException e){
String responseBody = e.getResponseBodyAsString();
try {
AuthorizationFault authorizationFault = Json.fromJson(responseBody, AuthorizationFault.class);
@@ -331,9 +322,6 @@ private ApiAuthorizationException buildAuthFault(HttpClientErrorException e){
}
}
- private PartnerCenterGrantType convertGrantType(GrantType grantType){
- return grantType.equals(GrantType.AUTHORIZATION_CODE) ? PartnerCenterGrantType.JWT_TOKEN : PartnerCenterGrantType.CLIENT_CREDENTIALS;
- }
}