FindItems() and BindToItems() give inconsistent results for EmailMessage.Sender.Address - exchange-server

After quite a lot of debugging, I've refined a complicated Managed EWS problem down to the following two simple-ish test cases. The first one works, the second one fails:
var view = new ItemView(100) { PropertySet = new PropertySet { EmailMessageSchema.Id } };
var findResults = ews.FindItems(WellKnownFolderName.Inbox, view)
var bindResults = ews.BindToItems(findResults.Select(r => r.Id), new PropertySet { EmailMessageSchema.Sender });
// Sanity check
Assert.AreEqual(1, bindResults.Count());
// The results I care about
Assert.AreEqual("David Seiler", bindResults[0].Sender.Name);
Assert.AreEqual("david.seiler#yahoo.com", bindResults[0].Sender.Address);
One might try to cut out the BindToItems() call, and use FindItems() directly:
var view = new ItemView(100) { PropertySet = new PropertySet { EmailMessageSchema.Sender } };
var findResults = ews.FindItems(WellKnownFolderName.Inbox, view)
// This part still works fine
Assert.AreEqual(1, findResults.Count());
// So does this
Assert.AreEqual("David Seiler", findResults[0].Sender.Name);
// ...but this fails! Sender.Address is null
Assert.AreEqual("david.seiler#yahoo.com", findResults[0].Sender.Address);
Can anyone tell me where I've gone wrong? It really seems, from the documentation, as though this should work. Not all properties can be read through FindItems(), it's true, but those properties usually throw when I try to access them, and anyway there's a list of those properties on MSDN and Sender isn't on it. What's going on?

Actually I don't know why, but in the second option, it only load basic information of the sender like the name, but not the Address.
If you want to load all the sender properties but do not want to bind the full message you can add the following line before the first assert
service.LoadPropertiesForItems(findResults.Items, new PropertySet(EmailMessageSchema.Sender));

Related

Update a user record with a pointer using Parse Cloud Code

I have viewed all the articles on here, and haven't done any javascript coding in the past. Hoping someone can help me.
I have a class called rank and of course the parse _User class. I have added a pointer to the _User class to the rank class (the column name is called user_rank, which allows me to give a user a rank - seems simple enough.
What I am trying to achieve, is to use Cloud Code to change a user's rank as the administrator of the app (so it's something I do in my admin app, not the user does in their app).
This is what I have, but all I get is an error 101 'Object not found'. I have no doubt I am doing this all wrong, but I have tried to piece together responses from other posts with no success.
Any help is greatly appreciated.
Updated code with Davi's change below - now throwing error schema mismatch for _User.user_rank; expected Pointer but got String
Parse.Cloud.define("setUserRank", async (request, response) => {
let { userObjectId, rankObjectId } = request.params;
const userQuery = new Parse.Query(Parse.User);
const rankQuery = new Parse.Query('rank');
// Get the user object to change the rank of
try{
let user = await userQuery.get(userObjectId, { useMasterKey: true});
let rank = await rankQuery.get(rankObjectId, { useMasterKey: true});
console.log(user);
console.log("Running");
const rankRelation = user.relation('user_rank');
rankRelation.add(user_rank);
user.save(null, { useMasterKey: true});
return ("User Rank Changed"));
} catch (err) {
throw new Error(err.message)
}
});
I think the problem happens because of this line:
const rankQuery = new Parse.Query(Parse.rank);
In the case of you custom classes, you need to pass the class name as a string:
const rankQuery = new Parse.Query('rank');

Xceed Docx ReplaceText always throwing newValue cannot be null.

I've tried a number of different options, but no matter what I do it either won't do anything or always return newValue error.
newValue cannot be null.
It seems I'm not the only one but it's had updates since the link below.
docX ReplaceText works incorrect
Below is my original example:-
if (sur.RequestType)
{
templateDoc.ReplaceText("[#1]", "x");
templateDoc.ReplaceText("[#2]", "");
}
else
{
templateDoc.ReplaceText("[#1]", "");
templateDoc.ReplaceText("[#2]", "x");
}
When debugging this it would get to line 4 then jump to line 9 where it would return the newValue cannot be null error on next step.
So I tried:-
string temp1 = "temp1";
if (sur.RequestType)
{
templateDoc.ReplaceText("[#1]", "x");
templateDoc.ReplaceText("[#2]", temp1, false, RegexOptions.IgnoreCase, paraFormat, paraFormat, MatchFormattingOptions.SubsetMatch);
}
else
{
templateDoc.ReplaceText("[#1]", "x.x");
templateDoc.ReplaceText("[#2]", "x", false, RegexOptions.IgnoreCase, paraFormat, paraFormat, MatchFormattingOptions.SubsetMatch);
}
Along with a couple other tweaks but all returning the same error.
Prior to using ReplaceText I'd used the example from the sample project:-
templateDoc.AddCustomProperty( new CustomProperty( "CompanySlogan", "Always with you" ) );
templateDoc.AddCustomProperty( new CustomProperty( "ClientName", "James Doh" ) );
Here it would step through each line but the produced document wouldn't have replaced anything.
Lastly more off topic but if anybody has a better solution, I'd been stuck going back and forth trying to output the file without saving it but had issues converting it from the Xceed DocX type to a HttpResponseMessage.
Below was my least favourable implementation of such as I'd either like to save it to a database or skip saving the file and just provide it directly to the user to save where they want instead of having a server side copy.
[HttpGet]
public HttpResponseMessage DownloadRecord(int id)
{
SURequest sur = _sURequestsService.GetRequestData(id);
var fullPath = System.Web.Hosting.HostingEnvironment.MapPath(#"~/Content/RequestForm.docx");
var fullPath2 = System.Web.Hosting.HostingEnvironment.MapPath(#"~/Content/RequestFormUpdated.docx");
var templateDoc = DocX.Load(fullPath);
var template = CreateRequestFromTemplate(templateDoc, sur);
template.SaveAs(fullPath2);
//using (FileStream fs2 = new FileStream(#"~/Content/RequestFormUpdated.docx", FileMode.Create))
//{
// template.SaveAs(fs2);
//}
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(fullPath2, FileMode.Open);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = Path.GetFileName(fullPath2);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentLength = stream.Length;
return result;
//return fs2;
}
I'm stuck with no clue how to proceed further with Xceed so am going to branch my present code and try using OpenXML to see if I have any better luck or if someone else can spot what I'm doing wrong or how to get past the issue in Xceed?
Any help would be much appreciated.
Turned out to be an issue with VS17 which was behaving stranging with replacetext and seemed to have cached an earlier issue in it's compiler.
This behaved like the issue was somewhere it wasn't and could only be resolved by manually stopping the compiler process.
Still no resolution for AddCustomProperty or with skipping generating a local file.
I'm going to work on trying to get it not to generate a local file but likely will need to either open a new question specific to that or setup something else to cleanup old files.

Cloud code causes "Tried to save an object with a pointer to a new, unsaved object" when saving pointers

In my app, I have users and posts, and I am trying to instantiate my Activity class which has pointers to user and post objects. Here is my code:
var Activity = Parse.Object.extend("Activity");
var User = Parse.Object.extend("_User");
var Post = Parse.Object.extend("Posts");
var activityHandler = function(request, response){
//toUser is the objectId of the User not the object itself.
var toUserId = request.toUser;
var fromUserId = request.fromUser;
var postId = request.post;
var arg = request.argument;
var toUser = new User();
toUser.set("objectId",toUserId);
var fromUser = new User();
fromUser.set("objectId",fromUserId);
var post = new Post();
post.set("objectId",postId);
var activity = new Activity();
activity.set("activityFrom", fromUser);
activity.set("activityTo", toUser);
activity.set("argument", arg);
activity.set("post", post);
activity.save(null, {
useMasterKey: true,
success: function(o){
console.log("activity logged successfully");
response.success();
},
error: function(err){
console.log(err);
},
}
);
};
Parse.Cloud.define("createActivity", activityHandler);
The code is self-explanatory, but just to summarize, the client sends the appropriate user and post IDs, and the cloud function should instantiate a new Activity object, with pointers to the users and post. However, when I try to save, I'm getting:
{"code":141,"error":"Uncaught Tried to save an object with a pointer to a new, unsaved object."}
The problem is that, the object IDs sent to the function are completely valid, already-existing objects in the database. ACL is also not an issue as I'm on the master key.
What am I doing wrong?
It was my bad.
There were multiple problems with my code.
I was using object.set("objectId", id); syntax, which actually should be object.id = id. I'm not sure if it is necessary, maybe it would work without that change too, but I've read everywhere that it's a bad practice.
I wasn't getting the request parameters correctly. I was using request.param1 instead of request.params.param1, and the parameter variable was undefined. I haven't checked if it was undefined or not for a long time, as the error message wasn't really helpful about parameter being undefined, from my perspective back then. (now it makes sense, no ID, and it automatically tries to create a new object)
I've corrected them and it does save correctly now.
This also happens when you forget to call the method:
response.success(object);

Xamarin Social post without interface prompt - ShareItemAsync

I'm trying to post directly to facebook/twitter without prompting the user with a UIViewController using the following code:
// 1. Create the service
var facebook = new FacebookService {
ClientId = "<App ID from developers.facebook.com/apps>",
RedirectUrl = new System.Uri ("<Redirect URL from developers.facebook.com/apps>")
};
// 2. Create an item to share
var item = new Item { Text = "Xamarin.Social is the bomb.com." };
item.Links.Add (new Uri ("http://github.com/xamarin/xamarin.social"));
// 3. Present the UI on iOS
var shareController = facebook.GetShareUI (item, result => {
// result lets you know if the user shared the item or canceled
DismissViewController (true, null);
});
PresentViewController (shareController, true, null);
BUT the Xamarin.Social instructions say:
As an alternative to presenting the share UI, you can share items directly using the **ShareItemAsync** method of the service.
https://github.com/xamarin/Xamarin.Social
I can't find any examples or explicit tutorials on how to use this. Can anyone help me on this please?
If you look at the source of Xamarin.Social, internally ShareItemAsync is used anyways to carry out the requests. GetShareUI is just a wrapper around ShareItemAsync.
From the source of ShareViewController (which gets the UI), you can see how they are using ShareItemAsync to carry out the requests. Here's the snippet for you.
try {
service.ShareItemAsync (item, account).ContinueWith (shareTask => {
StopSharing ();
.
.
.
.
.
}, TaskScheduler.FromCurrentSynchronizationContext ());
}
So all you need to do is create the item, get hold of the account and call the method on the service, something like this
var item = new Item { Text = "Xamarin.Social is the bomb.com." };
item.Links.Add (new Uri ("http://github.com/xamarin/xamarin.social"));
var account = facebook.GetAccountsAsync().FirstOrDefault();
facebook.ShareItemAsync(item, account);

Filtering a loaded kml file in OpenLayers

I'm trying to create an interactive search engine (for finding event tickets) of which one of its features is a visual map that shows related venues using OpenLayers. I have a plethora of venues (3000+) in a kml file that I would like to selectively show a filtered subsection of. Below is the code I have but when I try to run it has a JavaScript error. Running firebug and chrome developer tools makes me think that it is not getting passed the parameters I give because it says that the variables are null. However, I cannot figure out why they are not getting passed. Any insight is greatly appreciated.
var map, drawControls, selectControl, selectedFeature, select;
$('#kml').load('venuesComplete.kml');
kml=$('#kml').html();
function showVenues(state, city, venue){
filterStrategy = new OpenLayers.Strategy.Filter({});
var kmllayer = new OpenLayers.Layer.Vector("KML", {
strategies: [filterStrategy,
new OpenLayers.Strategy.Fixed()],
protocol: new OpenLayers.Protocol.HTTP({
url: "venuesComplete.kml",
format: new OpenLayers.Format.KML({
extractStyles: true,
extractAttributes: true
})
})
});
select = new OpenLayers.Control.SelectFeature(kmllayer);
kmllayer.events.on({
"featureselected": onFeatureSelect,
"featureunselected": onFeatureUnselect
});
map.addControl(select);
select.activate();
filter = new OpenLayers.Filter.Comparison({
type: OpenLayers.Filter.Comparison.LIKE,
property: "",
value: ""
});
function clearFilter(){
filterStrategy.setFilter(null);
}
function setFilter(property, value){
filter.value = value;
filter.property = property;
filterStrategy.setFilter(filter);
}
var vector_style = new OpenLayers.Style();
if(venue!=""){
setFilter('name', venue);
}else if(city!=""){
setFilter('description', city);
}else if(state!=""){
setFilter('description', state);
}
map.addLayer(kmllayer);
function onPopupClose(evt) {
select.unselectAll();
}
function onFeatureSelect(event) {
var feature = event.feature;
var selectedFeature = feature;
var popup = new OpenLayers.Popup.FramedCloud("chicken",
feature.geometry.getBounds().getCenterLonLat(),
new OpenLayers.Size(100,100),
"<h2>"+feature.attributes.name + "</h2>" + feature.attributes.description +'<br>'+feature.attributes,
null,
true,
onPopupClose
);
document.getElementById('venueName').value=feature.attributes.name;
document.getElementById("output").innerHTML=event.feature.id;
feature.popup = popup;
map.addPopup(popup);
}
function onFeatureUnselect(event) {
var feature = event.feature;
if(feature.popup) {
map.removePopup(feature.popup);
feature.popup.destroy();
delete feature.popup;
}
}
}
function init() {
map = new OpenLayers.Map('map');
var google_map_layer = new OpenLayers.Layer.Google(
'Google Map Layer',
{type: google.maps.MapTypeId.HYBRID}
);
map.addLayer(google_map_layer);
state="";
state+=document.getElementById('stateProvDesc').value;
city="";
city+=document.getElementById('cityZip').value;
venue="";
venue+=document.getElementById('venueName').value;
showVenues(state,city,'Michie Stadium');
map.addControl(new OpenLayers.Control.LayerSwitcher({}));
map.zoomToMaxExtent();
}
IF I UNDERSTAND CORRECTLY, your kml does not load properly. if this is not the case, please disconsider my answer.
it is very important to check if your kml layer was properly loaded. i have a map that loads multiple dynamic (from php) kml layers and it is not uncommon to have a large layer simply not load. when that happens, the operation is aborted, but, as far as openlayers is concerned, the layer was properly loaded.
so i do 2 things: i check if the amount of loaded data meets the expected number of features in my orginal php kml parser (i use a jquery or ajax call for that) and then, in case there is a discrepancy, i try reloading (since this is a loop, i limit it to 5 attempts, so as not to loop infinitely).
check out some of my code here

Resources