I am trying to work as The "Sandbox Editor"
function getClonedWorkItem(entityType, entityId) {
var clonedManager = entityManager.createEmptyCopy();
var oentity = entityManager.getEntityByKey(_mapEntityTypeToSingleType(entityType), entityId);
//export it to the new manager
var exportData = entityManager.exportEntities([oentity], true);
clonedManager.importEntities(exportData);
var cloned = clonedManager.getEntityByKey(_mapEntityTypeToSingleType(entityType), entityId);
return {
entity: cloned,
__context: clonedManager
};
}
the problem is that the cloned item dont have the extrametadata under the aspect, so i cannot sent it to the server to update - as it fails on
function updateDeleteMergeRequest(request, aspect, prefix) {
var extraMetadata = aspect.extraMetadata;
var uri = extraMetadata.uri || extraMetadata.id;
if (__stringStartsWith(uri, prefix)) {
uri = uri.substring(prefix.length);
}
request.requestUri = uri;
if (extraMetadata.etag) {
request.headers["If-Match"] = extraMetadata.etag;
}
}
Related
I have a scenario where I need to use an OnPrem-SharePoint for File Upload/Download. It's SharePoint 2016 and I found a helper class from the old days that uses WebRequests to communicate. I must use the same class in my .net 7 Minimal API project. It works but I don't like the tech debt I have to carry by using WebRequests. There are quite a few methods there but I need help converting these main ones and I can manage the rest as they are somewhat copy-paste:
public partial class SharePointService : ISharePointService
{
private const string AuthUrl = "https://accounts.accesscontrol.windows.net/{0}/tokens/OAuth/2";
private readonly SPAppInit spAppInit;
public SharePointService(SPAppInit spAppInit) => this.spAppInit = spAppInit;
public SPAuthToken? GetAuthToken()
{
var postParameters = new[]
{
new KeyValuePair<string, string>("grant_type", spAppInit.GrantType),
new KeyValuePair<string, string>("client_id", $"{spAppInit.AppClientId}#{spAppInit.TenantId}"),
new KeyValuePair<string, string>("client_secret", spAppInit.AppSecret),
new KeyValuePair<string, string>("resource", $"00000000-0000-0aaa-ce00-000000000000/{spAppInit.TenantName}#{spAppInit.TenantId}"),
};
var postData = postParameters.Aggregate("", (current, t) => current + HttpUtility.UrlEncode(t.Key) + "=" + HttpUtility.UrlEncode(t.Value) + "&");
var myHttpWebRequest = (HttpWebRequest)WebRequest.Create(string.Format(AuthUrl, spAppInit.TenantId));
myHttpWebRequest.Method = "POST";
var data = Encoding.ASCII.GetBytes(postData);
myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
myHttpWebRequest.ContentLength = data.Length;
var requestStream = myHttpWebRequest.GetRequestStream();
requestStream.Write(data, 0, data.Length);
requestStream.Close();
var myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
var responseStream = myHttpWebResponse.GetResponseStream();
var myStreamReader = new StreamReader(responseStream, Encoding.Default);
var result = myStreamReader.ReadToEnd();
var authToken = JsonSerializer.Deserialize<SPAuthToken>(result, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
myStreamReader.Close();
responseStream.Close();
myHttpWebResponse.Close();
return authToken;
}
public string GetRequestDigest(string authToken)
{
const string endpoint = "/_api/contextInfo";
var request = (HttpWebRequest)WebRequest.Create(spAppInit.SPSiteUrl + endpoint);
request.CookieContainer = new CookieContainer();
request.Method = "POST";
request.Headers["Authorization"] = $"Bearer {authToken}";
//request.Accept = "application/json;odata=verbose";
request.ContentLength = 0;
using var response = (HttpWebResponse)request.GetResponse();
using var reader = new StreamReader(response.GetResponseStream());
var result = reader.ReadToEnd();
// parse the ContextInfo response
var resultXml = XDocument.Parse(result);
// get the form digest value
var e = from r in resultXml.Descendants()
where r.Name == XName.Get("FormDigestValue", "http://schemas.microsoft.com/ado/2007/08/dataservices")
select r;
return e.First().Value;
}
public string CreateFolder(string authToken, string requestDigest, string folderName)
{
var request = (HttpWebRequest)WebRequest.Create($"{spAppInit.SPSiteUrl}/_api/web/getfolderbyserverrelativeurl('{spAppInit.SPDocLibServerRelativeUrl}/')/folders");
request.CookieContainer = new CookieContainer();
request.Method = "POST";
request.Headers["Authorization"] = $"Bearer {authToken}";
request.Headers["X-RequestDigest"] = requestDigest;
request.Accept = "application/json;";
request.ContentType = "application/json";
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
var requestParams = CreateRequest(folderName);
var json = JsonSerializer.Serialize(requestParams);
streamWriter.Write(json);
}
using var response = (HttpWebResponse)request.GetResponse();
using var reader = new StreamReader(response.GetResponseStream());
var result = reader.ReadToEnd();
var folderCreationResponse = JsonSerializer.Deserialize<SPFolderCreationResponse>(result, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
return folderCreationResponse?.ServerRelativeUrl ?? string.Empty;
}
public void UploadLargeFile(string authToken, string formDigest, string sourcePath, string targetFolderUrl, int chunkSizeBytes = 2048)
{
using var client = new WebClient();
client.BaseAddress = spAppInit.SPSiteUrl;
client.Headers.Add("X-RequestDigest", formDigest);
client.Headers.Add("content-type", "application/json;odata=verbose");
client.Headers.Add("Authorization", $"Bearer {authToken}");
var fileName = Path.GetFileName(sourcePath);
var createFileRequestUrl = $"{spAppInit.SPSiteUrl}/_api/web/getFolderByServerRelativeUrl('{targetFolderUrl}')/files/add(url='{fileName}',overwrite=true)";
client.UploadString(createFileRequestUrl, "POST");
var targetUrl = Path.Combine(targetFolderUrl, fileName);
var firstChunk = true;
var uploadId = Guid.NewGuid();
var offset = 0L;
using var inputStream = File.OpenRead(sourcePath);
var buffer = new byte[chunkSizeBytes];
int bytesRead;
while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
{
if (firstChunk)
{
var endpointUrl = $"{spAppInit.SPSiteUrl}/_api/web/getFileByServerRelativeUrl('{targetUrl}')/startUpload(uploadId=guid'{uploadId}')";
client.UploadData(endpointUrl, buffer);
firstChunk = false;
}
else if (inputStream.Position == inputStream.Length)
{
var endpointUrl = $"{spAppInit.SPSiteUrl}/_api/web/getFileByServerRelativeUrl('{targetUrl}')/finishUpload(uploadId=guid'{uploadId}',fileOffset={offset})";
var finalBuffer = new byte[bytesRead];
Array.Copy(buffer, finalBuffer, finalBuffer.Length);
client.UploadData(endpointUrl, finalBuffer);
}
else
{
var endpointUrl = $"{spAppInit.SPSiteUrl}/_api/web/getFileByServerRelativeUrl('{targetUrl}')/continueUpload(uploadId=guid'{uploadId}',fileOffset={offset})";
client.UploadData(endpointUrl, buffer);
}
offset += bytesRead;
Console.WriteLine("%{0:P} completed", offset / (float)inputStream.Length);
}
}
public void UploadLargeFileUsingBytes(string authToken, string formDigest, string fileName, byte[] fileBytes, string targetFolderUrl, int chunkSizeBytes = 2048)
{
if (fileBytes.Length < chunkSizeBytes)
{
UploadSmallFile(authToken, formDigest, targetFolderUrl, fileName, fileBytes);
}
else
{
using var client = new WebClient();
client.BaseAddress = spAppInit.SPSiteUrl;
client.Headers.Add("X-RequestDigest", formDigest);
client.Headers.Add("content-type", "application/json;odata=verbose");
client.Headers.Add("Authorization", $"Bearer {authToken}");
var createFileRequestUrl = $"{spAppInit.SPSiteUrl}/_api/web/GetFolderByServerRelativeUrl('{targetFolderUrl}')/files/add(url='{fileName}',overwrite=true)";
client.UploadString(createFileRequestUrl, "POST");
var targetUrl = Path.Combine(targetFolderUrl, fileName);
var firstChunk = true;
var uploadId = Guid.NewGuid();
var offset = 0L;
using var inputStream = ReadFileStreamFromByte(fileBytes);
var buffer = new byte[chunkSizeBytes];
int bytesRead;
while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
{
if (firstChunk && inputStream.Length > chunkSizeBytes)
{
var endpointUrl = $"{spAppInit.SPSiteUrl}/_api/web/GetFileByServerRelativeUrl('{targetUrl}')/startUpload(uploadId=guid'{uploadId}')";
client.UploadData(endpointUrl, buffer);
firstChunk = false;
}
else if (inputStream.Position == inputStream.Length)
{
var endpointUrl = $"{spAppInit.SPSiteUrl}/_api/web/GetFileByServerRelativeUrl('{targetUrl}')/finishUpload(uploadId=guid'{uploadId}',fileOffset={offset})";
var finalBuffer = new byte[bytesRead];
Array.Copy(buffer, finalBuffer, finalBuffer.Length);
client.UploadData(endpointUrl, finalBuffer);
}
else
{
var endpointUrl = $"{spAppInit.SPSiteUrl}/_api/web/GetFileByServerRelativeUrl('{targetUrl}')/continueUpload(uploadId=guid'{uploadId}',fileOffset={offset})";
client.UploadData(endpointUrl, buffer);
}
offset += bytesRead;
Console.WriteLine("%{0:P} completed", offset / (float)inputStream.Length);
}
}
}
}
I don't like pasting the whole project. However, even after being very selective, this is still a lot of code, but its communication code that I do not understand as I started with the newer HttpClient only as (some random HttpClient injection in my API):
services.AddCustomHttpClient<ILetterServiceApi, LetterServiceApi>(Constants.ApiServiceNamedClientLetter, baseAddress!);
Where AddCustomHttpClient is,
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddCustomHttpClient<TInterface, TImplementation>(this IServiceCollection services, string serviceName, string baseAddress)
where TInterface: class
where TImplementation: class, TInterface
{
services.AddHttpClient<TInterface, TImplementation>(serviceName, config =>
{
config.BaseAddress = new Uri(baseAddress);
config.Timeout = new TimeSpan(0, 0, 30);
})
.AddHttpMessageHandler<RequestHandler>();
return services;
}
}
I have made a lot of modern modifications to the code and also Am in the process of converting this class (in a remote assembly) to conform to the .Net Core's .AddSharePoint() DI pattern, and for that, I need to get rid of obsolete (HttpWebRequest)WebRequest
Update:
I managed to convert a rather simple method:
private SPFolderResponse? GetFolderFiles(string authToken, string requestDigest, string folderName)
{
using var client = new HttpClient();
var serverRelativeFolderUrl = $"{spAppInit.RelativeUrl}/{folderName}";
var folderApiUrl = $"{spAppInit.SiteUrl}/_api/web/GetFolderByServerRelativeUrl('/{serverRelativeFolderUrl}')/Files";
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("X-RequestDigest", requestDigest);
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {authToken}");
var result = client.GetStringAsync(folderApiUrl).GetAwaiter().GetResult();
var response = JsonSerializer.Deserialize<SPFolderResponse>(result, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
return response;
}
But the other ones like the Token, Digest and Upload ones are still dodgy...
I'm trying to install Umbraco without using the visual interface, in order to increase my productivity.
Currently my code looks like this:
var installApiController = new InstallApiController();
var installSetup = installApiController.GetSetup();
var instructions = new Dictionary<string, JToken>();
var databaseModel = new DatabaseModel
{
DatabaseType = DatabaseType.SqlCe
};
var userModel = new UserModel
{
Email = "my#email.com",
Name = "My name",
Password = "somepassword",
SubscribeToNewsLetter = false
};
foreach (var step in installSetup.Steps)
{
if (step.StepType == typeof(DatabaseModel))
{
instructions.Add(step.Name, JToken.FromObject(databaseModel));
}
else if (step.StepType == typeof(UserModel))
{
instructions.Add(step.Name, JToken.FromObject(userModel));
}
}
var installInstructions = new InstallInstructions
{
InstallId = installSetup.InstallId,
Instructions = instructions
};
InstallProgressResultModel progressInfo = null;
do
{
string stepName = "";
if (progressInfo != null)
{
stepName = progressInfo.NextStep;
}
try
{
progressInfo = installApiController.PostPerformInstall(installInstructions);
}
catch (Exception e)
{
throw new Exception(stepName, e);
}
}
while (progressInfo.ProcessComplete == false);
The code fails at this line: https://github.com/umbraco/Umbraco-CMS/blob/dev-v7.8/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs#L47, and I believe it's because the ApplicationContext isnt updated for each of the installation steps (e.g. not updated after the database is created).
Is it possible to update the ApplicationContext manually after each step in the installation progress, or do I have to trigger all installation steps in separate HTTP requests?
The code works, if I run each step in separate HTTP requests.
I have got following script in Google docs spreadsheet which is fetching data from Fitbit. Script worked fine so far but recently on 6th July Google stopped using OAuthConfig so script is not working since:-(
I am not programmer, I am just advanced user. So I would like to kindly ask some programmer to help tune script below in order to make it work again.
// Key of ScriptProperty for Firtbit consumer key.
var CONSUMER_KEY_PROPERTY_NAME = "fitbitConsumerKey";
// Key of ScriptProperty for Fitbit consumer secret.
var CONSUMER_SECRET_PROPERTY_NAME = "fitbitConsumerSecret";
// Default loggable resources (from Fitbit API docs).
var LOGGABLES = ["activities/log/steps", "activities/log/distance",
"activities/log/activeScore", "activities/log/activityCalories",
"activities/log/calories", "foods/log/caloriesIn",
"activities/log/minutesSedentary",
"activities/log/minutesLightlyActive",
"activities/log/minutesFairlyActive",
"activities/log/minutesVeryActive", "sleep/timeInBed",
"sleep/minutesAsleep", "sleep/minutesAwake", "sleep/awakeningsCount",
"body/weight", "body/bmi", "body/fat",];
// function authorize() makes a call to the Fitbit API to fetch the user profile
function authorize() {
var oAuthConfig = UrlFetchApp.addOAuthService("fitbit");
oAuthConfig.setAccessTokenUrl("https://api.fitbit.com/oauth/access_token");
oAuthConfig.setRequestTokenUrl("https://api.fitbit.com/oauth/request_token");
oAuthConfig.setAuthorizationUrl("https://api.fitbit.com/oauth/authorize");
oAuthConfig.setConsumerKey(getConsumerKey());
oAuthConfig.setConsumerSecret(getConsumerSecret());
var options = {
"oAuthServiceName": "fitbit",
"oAuthUseToken": "always",
};
// get the profile to force authentication
Logger.log("Function authorize() is attempting a fetch...");
try {
var result = UrlFetchApp.fetch("https://api.fitbit.com/1/user/-/profile.json", options);
var o = Utilities.jsonParse(result.getContentText());
return o.user;
}
catch (exception) {
Logger.log(exception);
Browser.msgBox("Error attempting authorization");
return null;
}
}
// function setup accepts and stores the Consumer Key, Consumer Secret, firstDate, and list of Data Elements
function setup() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var app = UiApp.createApplication().setTitle("Setup Fitbit Download");
app.setStyleAttribute("padding", "10px");
var consumerKeyLabel = app.createLabel("Fitbit OAuth Consumer Key:*");
var consumerKey = app.createTextBox();
consumerKey.setName("consumerKey");
consumerKey.setWidth("100%");
consumerKey.setText(getConsumerKey());
var consumerSecretLabel = app.createLabel("Fitbit OAuth Consumer Secret:*");
var consumerSecret = app.createTextBox();
consumerSecret.setName("consumerSecret");
consumerSecret.setWidth("100%");
consumerSecret.setText(getConsumerSecret());
var firstDate = app.createTextBox().setId("firstDate").setName("firstDate");
firstDate.setName("firstDate");
firstDate.setWidth("100%");
firstDate.setText(getFirstDate());
// add listbox to select data elements
var loggables = app.createListBox(true).setId("loggables").setName(
"loggables");
loggables.setVisibleItemCount(4);
// add all possible elements (in array LOGGABLES)
var logIndex = 0;
for (var resource in LOGGABLES) {
loggables.addItem(LOGGABLES[resource]);
// check if this resource is in the getLoggables list
if (getLoggables().indexOf(LOGGABLES[resource]) > -1) {
// if so, pre-select it
loggables.setItemSelected(logIndex, true);
}
logIndex++;
}
// create the save handler and button
var saveHandler = app.createServerClickHandler("saveSetup");
var saveButton = app.createButton("Save Setup", saveHandler);
// put the controls in a grid
var listPanel = app.createGrid(6, 3);
listPanel.setWidget(1, 0, consumerKeyLabel);
listPanel.setWidget(1, 1, consumerKey);
listPanel.setWidget(2, 0, consumerSecretLabel);
listPanel.setWidget(2, 1, consumerSecret);
listPanel.setWidget(3, 0, app.createLabel(" * (obtain these at dev.fitbit.com)"));
listPanel.setWidget(4, 0, app.createLabel("Start Date for download (yyyy-mm-dd)"));
listPanel.setWidget(4, 1, firstDate);
listPanel.setWidget(5, 0, app.createLabel("Data Elements to download:"));
listPanel.setWidget(5, 1, loggables);
// Ensure that all controls in the grid are handled
saveHandler.addCallbackElement(listPanel);
// Build a FlowPanel, adding the grid and the save button
var dialogPanel = app.createFlowPanel();
dialogPanel.add(listPanel);
dialogPanel.add(saveButton);
app.add(dialogPanel);
doc.show(app);
}
// function sync() is called to download all desired data from Fitbit API to the spreadsheet
function sync() {
// if the user has never performed setup, do it now
if (!isConfigured()) {
setup();
return;
}
var user = authorize();
// Spatny kod, oprava nize - var doc = SpreadsheetApp.getActiveSpreadsheet();
var doc = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Pavel');
doc.setFrozenRows(1);
var options = {
"oAuthServiceName": "fitbit",
"oAuthUseToken": "always",
"method": "GET"
};
// prepare and format today's date, and a list of desired data elements
var dateString = formatToday();
var activities = getLoggables();
// for each data element, fetch a list beginning from the firstDate, ending with today
for (var activity in activities) {
var currentActivity = activities[activity];
try {
var result = UrlFetchApp.fetch("https://api.fitbit.com/1/user/-/"
+ currentActivity + "/date/" + getFirstDate() + "/"
+ dateString + ".json", options);
} catch (exception) {
Logger.log(exception);
Browser.msgBox("Error downloading " + currentActivity);
}
var o = Utilities.jsonParse(result.getContentText());
// set title
var titleCell = doc.getRange("a1");
titleCell.setValue("date");
var cell = doc.getRange('a2');
// fill the spreadsheet with the data
var index = 0;
for (var i in o) {
// set title for this column
var title = i.substring(i.lastIndexOf('-') + 1);
titleCell.offset(0, 1 + activity * 1.0).setValue(title);
var row = o[i];
for (var j in row) {
var val = row[j];
cell.offset(index, 0).setValue(val["dateTime"]);
// set the date index
cell.offset(index, 1 + activity * 1.0).setValue(val["value"]);
// set the value index index
index++;
}
}
}
}
function isConfigured() {
return getConsumerKey() != "" && getConsumerSecret() != "";
}
function setConsumerKey(key) {
ScriptProperties.setProperty(CONSUMER_KEY_PROPERTY_NAME, key);
}
function getConsumerKey() {
var key = ScriptProperties.getProperty(CONSUMER_KEY_PROPERTY_NAME);
if (key == null) {
key = "";
}
return key;
}
function setLoggables(loggable) {
ScriptProperties.setProperty("loggables", loggable);
}
function getLoggables() {
var loggable = ScriptProperties.getProperty("loggables");
if (loggable == null) {
loggable = LOGGABLES;
} else {
loggable = loggable.split(',');
}
return loggable;
}
function setFirstDate(firstDate) {
ScriptProperties.setProperty("firstDate", firstDate);
}
function getFirstDate() {
var firstDate = ScriptProperties.getProperty("firstDate");
if (firstDate == null) {
firstDate = "2012-01-01";
}
return firstDate;
}
function formatToday() {
var todayDate = new Date;
return todayDate.getFullYear()
+ '-'
+ ("00" + (todayDate.getMonth() + 1)).slice(-2)
+ '-'
+ ("00" + todayDate.getDate()).slice(-2);
}
function setConsumerSecret(secret) {
ScriptProperties.setProperty(CONSUMER_SECRET_PROPERTY_NAME, secret);
}
function getConsumerSecret() {
var secret = ScriptProperties.getProperty(CONSUMER_SECRET_PROPERTY_NAME);
if (secret == null) {
secret = "";
}
return secret;
}
// function saveSetup saves the setup params from the UI
function saveSetup(e) {
setConsumerKey(e.parameter.consumerKey);
setConsumerSecret(e.parameter.consumerSecret);
setLoggables(e.parameter.loggables);
setFirstDate(e.parameter.firstDate);
var app = UiApp.getActiveApplication();
app.close();
return app;
}
// function onOpen is called when the spreadsheet is opened; adds the Fitbit menu
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [{
name: "Sync",
functionName: "sync"
}, {
name: "Setup",
functionName: "setup"
}, {
name: "Authorize",
functionName: "authorize"
}];
ss.addMenu("Fitbit", menuEntries);
}
// function onInstall is called when the script is installed (obsolete?)
function onInstall() {
onOpen();
}
Problem solved with updated code at https://github.com/loghound/Fitbit-for-Google-App-Script
I have re-written the getting-started-with-event-store project to learn what's going on and now for the test CanSaveExistingAggregate() I am getting a WrongExpectedVersionException. The thing is, in order to try and work out what's going on I would like to know what the expected version should be, how can I find this out? In the test, the line repository.Save(firstSaved, Guid.NewGuid(), d => { }); calculates the expected version as 101 and this is where it fails:
[Test]
public void CanSaveExistingAggregate()
{
var savedId = SaveTestAggregateWithoutCustomHeaders(repository, 100 /* excludes TestAggregateCreated */);
var firstSaved = repository.GetById<TestAggregate>(savedId);
Console.WriteLine("version:" + firstSaved.Id);
firstSaved.ProduceEvents(50);
repository.Save(firstSaved, Guid.NewGuid(), d => { });
var secondSaved = repository.GetById<TestAggregate>(savedId);
Assert.AreEqual(150, secondSaved.AppliedEventCount);
}
And the code where the exception is thrown:
public void Save(CommonDomain.IAggregate aggregate, Guid commitId, Action<IDictionary<string, object>> updateHeaders)
{
var commitHeaders = new Dictionary<string, object>
{
{CommitIdHeader, commitId},
{AggregateClrTypeHeader, aggregate.GetType().AssemblyQualifiedName}
};
updateHeaders(commitHeaders);
var streamName = aggregateIdToStreamName(aggregate.GetType(), aggregate.Id);
var newEvents = aggregate.GetUncommittedEvents().Cast<object>().ToList();
var originalVersion = aggregate.Version - newEvents.Count;
var expectedVersion = originalVersion == 0 ? ExpectedVersion.NoStream : originalVersion;
var eventsToSave = newEvents.Select(e => ToEventData(Guid.NewGuid(), e, commitHeaders)).ToList();
if (eventsToSave.Count < WritePageSize)
{
eventStoreConnection.AppendToStream(streamName, expectedVersion, eventsToSave);
}
else
{
var transaction = eventStoreConnection.StartTransaction(streamName, expectedVersion);
var position = 0;
while (position < eventsToSave.Count)
{
var pageEvents = eventsToSave.Skip(position).Take(WritePageSize);
transaction.Write(pageEvents);
position += WritePageSize;
}
transaction.Commit();
}
aggregate.ClearUncommittedEvents();
}
All the other tests pass (except ThrowsOnGetDeletedAggregate() but I'll ask about that later) but I think this is the only test that has expectedVersion != ThrowsOnGetDeletedAggregate()
Well it turns out it was just a mistake when writing the code, rather than
var expectedVersion = originalVersion == 0 ? ExpectedVersion.NoStream : originalVersion;
it should be
var expectedVersion = originalVersion == 0 ? ExpectedVersion.NoStream : originalVersion - 1;
In my firefox extension I'm creating a xul:browser element. I want to have an observer that intercepts any url changes within the embedded browser and opens the url in a new browser tab (in the main browser). I'd also like new windows spawned by the xul:browser window to open in a tab instead of a new browser window.
I've created an observer which works, but I don't yet know how to apply that observer only to the xul:browser element.
function myFunction(){
var container = jQuery("#container")[0];
var new_browser_element = document.createElement('browser');
container.appendChild(new_browser_element);
var observerService = Components.classes["#mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
observerService.addObserver(myObserver, "http-on-modify-request", false);
}
var myObserver = {
observe: function(aSubject, aTopic, aData){
if (aTopic != 'http-on-modify-request'){
aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
// alert(aSubject.URI.spec);
// Now open url in new tab
}
},
QueryInterface: function(iid){
if (!iid.equals(Components.interfaces.nsISupports) &&
!iid.equals(Components.interfaces.nsIObserver))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
You could try:
var myObserver = {
observe: function(aSubject, aTopic, aData){
if (aTopic == 'http-on-modify-request')
{
aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
var url = aSubject.URI.spec;
var postData ;
if (aSubject.requestMethod.toLowerCase() == "post")
{
var postText = this.readPostTextFromRequest(request);
if (postText)
{
var dataString = parseQuery(postText);
postData = postDataFromString(dataString);
}
}
var oHttp = aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
var interfaceRequestor = oHttp.notificationCallbacks.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
var DOMWindow = interfaceRequestor.getInterface(Components.interfaces.nsIDOMWindow);
//check if it is one of your mini browser windows
if (jQuery(DOMWindow).hasClass('mini_browser'))
{
openInTab(url, postData);
var request = aSubject.QueryInterface(Components.interfaces.nsIRequest);
request.cancel(Components.results.NS_BINDING_ABORTED);
}
}
},
QueryInterface: function(iid){
if (!iid.equals(Components.interfaces.nsISupports) &&
!iid.equals(Components.interfaces.nsIObserver))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
},
readPostTextFromRequest : function(request) {
var is = request.QueryInterface(Components.interfaces.nsIUploadChannel).uploadStream;
if (is)
{
var ss = is.QueryInterface(Components.interfaces.nsISeekableStream);
var prevOffset;
if (ss)
{
prevOffset = ss.tell();
ss.seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, 0);
}
// Read data from the stream..
var charset = "UTF-8";
var text = this.readFromStream(is, charset, true);
// Seek locks the file so, seek to the beginning only if necko hasn't read it yet,
// since necko doesn't seek to 0 before reading (at lest not till 459384 is fixed).
if (ss && prevOffset == 0)
ss.seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, 0);
return text;
}
else {
dump("Failed to Query Interface for upload stream.\n");
}
}
return null;
},
readFromStream : function(stream, charset, noClose)
{
var sis = Components.classes["#mozilla.org/binaryinputstream;1"]
.getService(Components.interfaces.nsIBinaryInputStream);
sis.setInputStream(stream);
var segments = [];
for (var count = stream.available(); count; count = stream.available())
segments.push(sis.readBytes(count));
if (!noClose)
sis.close();
var text = segments.join("");
return text;
}
};
function openInTab(url, postData)
{
var wm = Components.classes["#mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var recentWindow = wm.getMostRecentWindow("navigator:browser");
if (recentWindow)
{
// Use an existing browser window, open tab and "select" it
recentWindow.gBrowser.selectedTab = recentWindow.gBrowser.addTab(url, null, null, postData);
}
}
function parseQuery() {
var qry = this;
var rex = /[?&]?([^=]+)(?:=([^&#]*))?/g;
var qmatch, key;
var paramValues = {};
// parse querystring storing key/values in the ParamValues associative array
while (qmatch = rex.exec(qry)) {
key = decodeURIComponent(qmatch[1]);// get decoded key
val = decodeURIComponent(qmatch[2]);// get decoded value
paramValues[key] = val;
}
return paramValues;
}
function postDataFromString(dataString)
{
// POST method requests must wrap the encoded text in a MIME
// stream
var stringStream = Components.classes["#mozilla.org/io/string-input-stream;1"]
.createInstance(Components.interfaces.nsIStringInputStream);
if ("data" in stringStream) // Gecko 1.9 or newer
stringStream.data = dataString;
else // 1.8 or older
stringStream.setData(dataString, dataString.length);
var postData = Components.classes["#mozilla.org/network/mime-input-stream;1"].
createInstance(Components.interfaces.nsIMIMEInputStream);
postData.addHeader("Content-Type", "application/x-www-form-urlencoded");
postData.addContentLength = true;
postData.setData(stringStream);
return postData;
}
I'll update this to fill in the blanks in a bit.
edit: see http://forums.mozillazine.org/viewtopic.php?p=2772951#p2772951 for how to get the source window of a request.
Request cancellation code from http://zenit.senecac.on.ca/wiki/index.php/Support_For_OpenID.
see http://mxr.mozilla.org/mozilla-central/source/netwerk/base/public/nsIRequest.idl for details on nsIRequest.
See http://forums.mozillazine.org/viewtopic.php?p=2404533#p2404533 and https://developer.mozilla.org/en/XUL/Method/addTab for the definition of addTab.
parseQuery comes from http://blog.strictly-software.com/2008/10/using-javascript-to-parse-querystring.html.
See https://developer.mozilla.org/en/Code_snippets/Post_data_to_window#Preprocessing_POST_data for how to process post data in a form suitable for addTab.
ReadPostFromText and ReadTextFromStream both come from firebug (though slightly modified)