Cloud Kit how to re fetch records when error - swift3

Cloud WWDC says When you get a CKError.changeTokenExpired re-fetch changes by setting the previous server change token to nil. I tried something like this:
let operation = CKFetchRecordZoneChangesOperation()
operation.qualityOfService = .userInitiated
operation.recordZoneIDs = appDelegate.changedZoneIDs
let fetchOptions = CKFetchRecordZoneChangesOptions()
fetchOptions.previousServerChangeToken = nil
operation.optionsByRecordZoneID = [ recordZoneID : fetchOptions]
But the optionsByRecordZoneID has been deprecated. So how can I pass the previous server token to the server and continue fetching past the error handling?

You should use the instance property configurationsByRecordZoneID on your CKFetchRecordZoneChangesOperation().
How about:
let operation = CKFetchRecordZoneChangesOperation()
operation.qualityOfService = .userInitiated
operation.recordZoneIDs = appDelegate.changedZoneIDs
let fetchOptions = CKFetchRecordZoneChangesOperation.ZoneConfiguration()
fetchOptions.previousServerChangeToken = nil
var zoneConfiguration: [CKRecordZone.ID : CKFetchRecordZoneChangesOperation.ZoneConfiguration] = [:]
for zoneID in operation.recordZoneIDs {
zoneConfiguration[zoneID] = fetchOptions
}
operation.configurationsByRecordZoneID = zoneConfiguration

Related

Kotlin & DynamoDB: Unable to resolve host "dynamodb.us-east-1.amazonaws.com": No address associated with hostname

I'm trying to connect my Kotlin Android app to DynamoDB in AWS using Android Studio. My credential details are replaced in the code below and it is connecting to an AWS sandbox. The created database client is below:
val staticCredentials = StaticCredentialsProvider {
accessKeyId = MY_ACCESS_KEY_HERE
secretAccessKey = MY_SECRET_ACCESS_KEY
}
ddb = DynamoDbClient{
region = MY_REGION_HERE
credentialsProvider = staticCredentials
}
Then I attempted to create the table using this client following these steps :
val tableNameVal = "Users"
val attDef = AttributeDefinition {
attributeName = key
attributeType = ScalarAttributeType.S
}
val keySchemaVal = KeySchemaElement {
attributeName = key
keyType = KeyType.Hash
}
val provisionedVal = ProvisionedThroughput {
readCapacityUnits = 10
writeCapacityUnits = 10
}
val request = CreateTableRequest {
attributeDefinitions = listOf(attDef)
keySchema = listOf(keySchemaVal)
provisionedThroughput = provisionedVal
tableName = tableNameVal
}
var tableArn: String
val response = ddb.createTable(request)
ddb.waitUntilTableExists { // suspend call
tableName = tableNameVal
}
tableArn = response.tableDescription!!.tableArn.toString()
println("Table $tableArn is ready")
However when I do this, I get an error when the createTable method is called:
java.net.UnknownHostException: Unable to resolve host "dynamodb.us-east-1.amazonaws.com": No address associated with hostname
I've tried doing a scan instead but I also get the same error. I thought that with AWS, if you provide the correct credentials and region, it wouldn't need any extra endpoints yet I'm still getting this "no hostname" error. I've looked at other code in JS with similar issues but couldn't get it working. Any help would be appreciated.

SharePoint WebsInfo Description is always Null

I'm trying to get the Description of a Site but it's always null in WebsInfo! Can someone please help me understand this? I also tried using OpenWeb but that was messing up the URL that I passed in.
var site = new SPSite(currentWeb.Url);
string url = currentWeb.Url + #"/" + siteName;
var webObject = site.AllWebs;
foreach (var web in webObject.WebsInfo)
{
siteDescription = web.Description;
}
I guess there is a bug in the WebsInfo that has never been resolved!! I ended up using SPWebCollection.
//This will find the current URL and iterate through it's site Collection
var oSiteCollection = new SPSite(SPContext.Current.Web.Url);
//Gets all webs meaning sub webs and their webs.
var collWebsites = oSiteCollection.AllWebs;
foreach (SPWeb web in collWebsites)
{
if (web.ServerRelativeUrl.StartsWith(kpi.BusinessUnitUrl))
{
kpi.BusinessUnitDescription = web.Description;
kpi.SiteSpecificAreaDescription = web.Description;
var collLists = web.Lists;
IterateLists(collLists, false, ref kpi);
}
}

Has anyone got a guide on how to upgrade from PowerBi Embeded v2 to v3? Or a tutorial for v3?

This appears to be a nightmare, sure its easy to upgrade the nuget package to 3.11 I think the latest is, but then nothing at all compiles. So you fix the compile errors, and then it doesn't work. I'm getting an error when it tries to create the PowerBI client.
Getting the token and also creating the client appears to be totally different to v2.
This is my code:
public PowerBiConfig GetPowerBiConfig(string reportId)
{
var result = new PowerBiConfig();
try
{
if (!Guid.TryParse(reportId, out var _))
{
result.ErrorMessage = $"Invalid report guid: {reportId}";
return result;
}
var credential = new UserPasswordCredential(_powerBiProMasterUsername, _powerBiProMasterPassword);
var authenticationContext = new AuthenticationContext(AuthorityUrl);
// Taken from https://stackoverflow.com/questions/5095183/how-would-i-run-an-async-taskt-method-synchronously
var authenticationResult = authenticationContext.AcquireTokenAsync(ResourceUrl, dataArchiverSettings.PowerBiApplicationId, credential).GetAwaiter().GetResult();
if (authenticationResult == null)
{
result.ErrorMessage = "Authentication Failed.";
return result;
}
var tokenCredentials = new TokenCredentials(authenticationResult.AccessToken, "Bearer");
using (var client = new PowerBIClient(new Uri(ApiUrl), tokenCredentials))
{
var report = client.Reports.GetReportInGroup(dataArchiverSettings.PowerBiWorkspaceId, reportId);
if (report == null)
{
result.ErrorMessage = $"No report with the ID {reportId} was found in the workspace.";
return result;
}
var datasets = client.Datasets.GetDatasetById(dataArchiverSettings.PowerBiWorkspaceId, report.DatasetId);
result.IsEffectiveIdentityRequired = datasets.IsEffectiveIdentityRequired;
result.IsEffectiveIdentityRolesRequired = datasets.IsEffectiveIdentityRolesRequired;
GenerateTokenRequest tokenRequest;
if (datasets.IsEffectiveIdentityRequired == true)
{
var username = UserHelper.GetCurrentUser();
var roles = _userService.GetRolesForUser(username);
tokenRequest = new GenerateTokenRequest(accessLevel: "view",
identities: new List<EffectiveIdentity>
{
new EffectiveIdentity(username: username,
roles: new List<string> (roles.Select(x=> x.RoleName)),
datasets: new List<string> {datasets.Id})
});
}
else
{
tokenRequest = new GenerateTokenRequest(accessLevel: "view");
}
var tokenResponse =
client.Reports.GenerateTokenInGroup(dataArchiverSettings.PowerBiWorkspaceId, report.Id,
tokenRequest);
if (tokenResponse == null)
{
result.ErrorMessage = "Failed to generate embed token.";
return result;
}
// Generate Embed Configuration.
result.EmbedToken = tokenResponse;
result.EmbedUrl = report.EmbedUrl;
result.Id = report.Id.ToString();
result.WorkloadResourceName = dataArchiverSettings.PowerBiWorkloadResourceName.Trim();
}
}
catch (HttpOperationException exc)
{
result.ErrorMessage =
$"Status: {exc.Response.StatusCode} ({(int)exc.Response.StatusCode})\r\n" +
$"Response: {exc.Response.Content}\r\n" +
$"RequestId: {exc.Response.Headers["RequestId"].FirstOrDefault()}";
}
catch (Exception exc)
{
result.ErrorMessage = exc.ToString();
}
return result;
}
The closest to "upgrade guide" is the announcement in Power BI blog. It looks like your code is using v2 (e.g. reportId is string, while in v3 it should be Guid).
Here is a brief summary of the changes:
What you should know about v3
Here are the key changes with this version update:
Namespaces renaming:
Microsoft.PowerBI.Api.V2 was changed to Microsoft.PowerBI.Api
Microsoft.PowerBI.Api.Extensions.V2 was changed to Microsoft.PowerBI.Api.Extensions
Microsoft.PowerBI.Api.V1 namespace was removed.
SetAllConnections and SetAllConnectionsInGroup operations are deprecated and marked as obsolete. You should use UpdateDatasources or UpdateParameters APIs instead.
PowerBI artifacts IDs typing was changed* from string to Guid, we recommend to work with Guid when possible.
*Dataset ID is an exception and it’s typing will remain string.
ODataResponse[List[Object]] types was changed to Objects, thus returning an objects collection on responses. For example, a response of ODataResponse[List[Report]] type will now return Reports collection as the return type.
New credentials classes allow easier build of credentialDetails. The new classes include: BasicCredentials, WindowsCredentials, OAuth2Credentials, and more.
Read Configure credentials article to learn more.
New encryption helper classes for easier encryption when creating CredentialDetails.
For example, using AsymmetricKeyEncryptor class with a gateway public key:
GatewayPublicKey publicKey = new GatewayPublicKey
{
Exponent = "...",
Modulus = "..."
};
CredentialsBase credentials = new BasicCredentials("<USER>", "<PASSWORD>");
var credentialsEncryptor = new AsymmetricKeyEncryptor(publicKey);
var credentialDetails = new CredentialDetails(credentials, PrivacyLevel.None, EncryptedConnection.Encrypted, credentialsEncryptor);
Read Configure credentials article to learn more.
Consistency on field names.
For example, reportKey, datasetKey, dashboardKey and tileKey was changed to reportId, datasetId, dashboardId and tileId.
Consistency on operations names.
For example, use GetDataset instead of GetDatasetById. The effected opertation names are imports, datasets, gateways and datasources.
Use enum class instead of string for enumerated types.
For example, In the generateTokenRequest, we recommend to use TokenAccessLevel.View, and not explicitly use “view” as value.
Required fields was marked – some fields was changed to required fields are not nullable anymore.
Examples
Change in Get Reports call if WorkspaceId is a string:
var reports = await client.Reports.GetReportsInGroupAsync(WorkspaceId);
var reports = await client.Reports.GetReportsInGroupAsync(new Guid( WorkspaceId ) );
Change in response handling if a string is expected:
report = reports.Value.FirstOrDefault(r => r.Id.Equals(ReportId, StringComparison.InvariantCultureIgnoreCase));
report = reports.Value.FirstOrDefault(r => r.Id .ToString() .Equals(ReportId, StringComparison.InvariantCultureIgnoreCase));
Change in Generate token:
var tokenResponse = await client.Reports.GenerateTokenInGroupAsync(WorkspaceId, report.Id, generateTokenRequestParameters);
var tokenResponse = await client.Reports.GenerateTokenInGroupAsync( new Guid( WorkspaceId ), report.Id, generateTokenRequestParameters);
Change in Generate token response handling if a string is expected:
m_embedConfig.Id = report.Id;
m_embedConfig.Id = report.Id .ToString() ;
Required fields are not nullable, i.e. Expiration is not nullable and the Value property should be removed:
var minutesToExpiration = EmbedToken.Expiration .Value – DateTime.UtcNow;
var minutesToExpiration = EmbedToken.Expiration – DateTime.UtcNow;
Consistency on operations names, i.e. use GetDataset instead of GetDatasetById:
var datasets = await client.Datasets.GetDataset ById InGroupAsync(WorkspaceId, report.DatasetId);
var datasets = await client.Datasets.GetDatasetInGroupAsync(new Guid(WorkspaceId), report.DatasetId);

scala elasticsearch using high level rest java client: regexp and scroll

I am using scala (2.12) to query the Elasticsearch (6.5) using the High level java rest client(6.5).
libraryDependencies += "org.elasticsearch" % "elasticsearch" % "6.5.4"
libraryDependencies += "org.elasticsearch.client" % "elasticsearch-rest-high-level-client" % "6.5.4"
Basic query (matchQuery) and scroll works fine for me.
val credentialsProvider = new BasicCredentialsProvider
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("user", "password"))
val builder = RestClient.builder(new HttpHost("host", port, "https"))
builder.setHttpClientConfigCallback(new HttpClientConfigCallback() {
override def customizeHttpClient(httpClientBuilder: HttpAsyncClientBuilder): HttpAsyncClientBuilder = httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
})
var client = new RestHighLevelClient(builder)
val scroll = new Scroll(TimeValue.timeValueMinutes(1L))
// Index
val searchRequest = new SearchRequest("index")
val searchSourceBuilder = new SearchSourceBuilder()
searchSourceBuilder.query(QueryBuilders.matchQuery("name.field", "value"))
searchSourceBuilder.size(500)
searchRequest.source(searchSourceBuilder)
searchRequest.scroll(scroll)
var searchResponse = client.search(searchRequest, RequestOptions.DEFAULT)
var scrollId = searchResponse.getScrollId
var searchHits = searchResponse.getHits().getHits
while (searchHits != null && searchHits.length > 0) {
val scrollRequest = new SearchScrollRequest(scrollId)
scrollRequest.scroll(scroll)
searchResponse = client.scroll(scrollRequest, RequestOptions.DEFAULT)
println(searchResponse.getHits.getHits.toList)
scrollId = searchResponse.getScrollId
searchHits = searchResponse.getHits.getHits
}
Basically above query works as expected with all the data returned.
Now, my case is I need the regex (and not mathQuery).
So I just change that line; but it does not fetch anything now.
searchSourceBuilder.query(QueryBuilders.regexpQuery("name.field", "value"))
What am I missing here? How to use Regexp ?

Using GP Web Service: How do I delete a SalesOrderLine from a SalesOrder?

Can someone help me delete a SalesOrderLine from a SalesOrder?
I'm using the GP WS Native Endpoint
My code executes without an error.
However, after updating the SalesOrder, the line I removed still remains.
var salesDocumentKeyObject = new SalesDocumentKey {Id = salesDocumentKey, CompanyKey = this.CompanyKey};
var salesOrder = this.DynamicsGpClient.GetSalesOrderByKey(salesDocumentKeyObject, this.Context);
var newLines = salesOrder.Lines.Where(l => l.Key.LineSequenceNumber != lineItemSequence).ToArray();
salesOrder.Lines = newLines;
var salesOrderUpdatePolicy = this.DynamicsGpClient.GetPolicyByOperation("UpdateSalesOrder", this.Context);
this.DynamicsGpClient.UpdateSalesOrder(salesOrder, this.Context, salesOrderUpdatePolicy);
Thank you for any help,
Karl
Microsoft Dynamics GP Web Service has poor documentation and examples.
Do delete a sales order line, you retrieve the order, locate the line to delete and set the sales order line property, DeleteOnUpdate to true, and then save the order.
Updated code below:
var salesDocumentKeyObject = new SalesDocumentKey {Id = salesDocumentKey, CompanyKey = this.CompanyKey};
var salesOrder = this.DynamicsGpClient.GetSalesOrderByKey(salesDocumentKeyObject, this.Context);
var target= salesOrder.Lines.FirstOrDefault(l => l.Key.LineSequenceNumber == lineItemSequence);
if (target != null) {
target.DeleteOnUpdate = true;
}
var salesOrderUpdatePolicy = this.DynamicsGpClient.GetPolicyByOperation("UpdateSalesOrder", this.Context);
this.DynamicsGpClient.UpdateSalesOrder(salesOrder, this.Context, salesOrderUpdatePolicy);