Determine if Outlook Contact has been deleted using EWS 2007 - exchangewebservices

i am able to retrieve lists of contacts for specified mailboxes using exchange web services. my issue is that some of the contacts returned have been deleted by the outlook user, and i need to determine which ones. how can i do this?
all the examples i've seen online use this method, but never for contacts.
i have tried setting the Traversal property of the ItemView variable to SoftDeleted, but that does not return anything.
below is the pertinent portion of my code:
ItemView itemViewDeleted = new ItemView(100);
itemViewDeleted.Traversal = ItemTraversal.SoftDeleted;
FindItemsResults<Item> deletedItems = svc.FindItems(WellKnownFolderName.Contacts, itemViewDeleted);

You need to check the WellKnownFolderName.DeletedItems folder. That is where my contacts go when I delete them.
There are (3) ways to delete a Contact. See TechNet for Exchange terminology reference.
Delete (moved to Deleted Items folder - WellKnownFolderName.DeletedItems)
Soft Delete (moved to Recoverable Items folder - WellKnownFolderName.RecoverableItemsDeletions)
Hard Delete (purged from mailbox - WellKnownFolderName.RecoverableItemsPurges)

Related

EWS Item.Copy causes ErrorAccessDenied

I want to copy items between mailboxes used EWS managed API. Here I've met strange situation.
When I try first to get destination folder and then copy item using its ID I get an error ErrorAccessDenied.
this.exchangeService.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "test1#test.local");
var folder = Folder.Bind(this.exchangeService, WellKnownFolderName.Inbox);
item.Copy(folder.Id);
This gets an error
If I create a FolderId object instance specifying well known folder name (Inbox) and mailbox name I get no problems.
var folderId = new FolderId(WellKnownFolderName.Inbox, new Mailbox("test1#test.local"));
item.Copy(folderId);
This works
Is such behavior by design? Or I can use destination folder not just well known one?
I believe this behavior is by design. In the first example, the calling account (acct1) is impersonating acct2. I think that the request is being processed as acct2 trying to bind to the inbox of acct1 since the credentials of the call are associated with acct1. The context for calls are based on the identifiers which contain the SMTP address of the target mailbox.
Your second example explicitly identifies the mailbox that should be targeted. All subsequent identifiers accessed based on that folder identifier will have the context of test1#test.local.
I think you can change your first call to this to make it work:
var folder = Folder.Bind(this.exchangeService, new FolderId(WellKnownFolderName.Inbox, new Mailbox("test1#test.local")));
I know you are copying to a folder in to test1#test.local mailbox. Whose mailbox contains 'item'? I can't recall if it works to use impersonation to copy across mailboxes. I'm interested to know how it works for you.

Unable to Change Recurrence Pattern in EWS

I am having a problem that has been reported here and elsewhere before: not being able to change the recurrence pattern on a master via EWS. First, I tried using the old proxy classes against E2010. I have also now tried using the 2.0 Managed API, to no avail. The error FWIW is "Set action is invalid for property". E.g. I want to change the recurrence end date, or the number of recurrences.
In an MSDN post from 2008, Dave Stirling mentions that only the organizer should be able to do this. This is a problem for me because my server application uses a single, full-access id to manage all of the room resource calendars in an enterprise. With this user I can delete appointments on any calendar, regardless of organizer, and I can certainly update a single instance of a recurring series, e.g. changing its start time. I don't understand why manipulating the recurrence pattern would be prohibited because I'm not the organizer while manipulating an instance's spot on the calendar, or deleting the entire series would not be.
I have also tried using impersonation, so that I am (I think) impersonating the Room resource itself, in which case, even though I am not the organizer, I feel I must be the owner of the appointment, and hence entitled to do whatever the heck I want to it. I guess Exchange feels differently. Managed API code below, FWIW.
TIA,
Paul
var Svc = new ExchangeService(ExchangeVersion.Exchange2010, TimeZoneInfo.Local);
Svc.CookieContainer = new CookieContainer();
Svc.Credentials = new WebCredentials(m_SvcUser, m_SvcPswd);
Svc.EnableScpLookup = false;
Svc.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, m_RoomMB);
Svc.AutodiscoverUrl(m_RoomMB, RedirectionCallback);
var Master = Appointment.Bind(Svc, new ItemId(args[0]), m_Props);
if (Master.Recurrence.NumberOfOccurrences != null)
Master.Recurrence.NumberOfOccurrences--;
else
Master.Recurrence.EndDate = DateTime.Now;
Master.Update(ConflictResolutionMode.AlwaysOverwrite, SendInvitationsOrCancellationsMode.SendToNone);
To close this out, I will report that I opened this question as a support issue after getting no responses here or on MSDN. The net of it is this: Exchange does not permit an attendee (in this case a conference room I am impersonating in EWS) to change the recurrence "blob." This is by design. The only user who can do so is the organizer. I'm not sure this really makes complete sense to me, but I don't have much say in the matter, now do I?

Cake ACLs with Groups and Users added to Projects

I'm currently working on a platform which is planned to coordinate the communication with customers in future. Users can be added to projects and have certain rights. Therefore users are assigned to different user roles (admin/manager/member/viewer). Admins can view all projects and are allowed to add other users to a project. If a user (e.g. role:member) is added to a project, he will have certain rights (depending on the role), if not, he is not allowed to access the project at all.
I'm using Cake's ACL Component and everything is working great, when i disregard if a user is added to a project or not. The only solution I can think of, is not to grant rights on the group-level, but on the user-level when an admin adds an user to the project.
Is there an easier way to solve this issue? Otherwise I'm afraid that the code would become totally confusing.
There is a another way (I don't really know if easier, depends on your point of view). The ACL component only helps you to create roles, but you need a role and project-access management, right?
What I do in this cases:
Create a Project_Permission table in your database (give it a better name, I'm lacking imagination). Depending on your project, create the associations: a user can be related to many projects and a project can have many users accesing it. If you are following the cake conventions (and your tables are named users and projects) and it doesn't interfere with what you already have, the table should be
PROJECTS_USERS
id
project_id
user_id
created and modified //if you want to
Create appropriate actions where the admin (or other type if users, that's up to you)
can add users to projects and save that many-to-many association in
the previously created table.
Since the authorization for the project does not come from the ACL component, you have to create an "authorization" function yourself. I recommend putting this in the beforeFilter() function of the AppController (if you don't have an AppController, you'll have to do it in every controller you want this to work). In this function, check if the logged user is in the existing table and has an association with the project. Something like:
function beforeFilter() {
//let's assume you have the project id somewhere, in a global variable like $this->_projectID
$user = $this->Session->read('Auth.User.id');
$project = $this->Project->find('first', array('conditions'=>array('id'=>$this->_projectID, 'User.id'=>$user)
if (count($project) > 0) {
//the user has permission to see the project
} else {
//he doesn't
}
}
It's difficult to give an actual code because I'm not sure of your model associations nor where do you want the code or if you have the variables needed for this available everywhere, but I hope you get the idea. After that it's just a matter of how you want to handle the restriction of access (normally a flash message and redirection is involved).
I hope this is clear enough :S

Google Drive/OAuth - Can't figure out how to get re-usable GoogleCredentials

I've successfully installed and run the Google Drive Quick Start application called DriveCommandLine. I've also adapted it a little to GET file info for one of the files in my Drive account.
What I would like to do now is save the credentials somehow and re-use them without the user having to visit a web page each time to get an authorization code. I have checked out this page with instructions to Retrieve and Use OAuth 2.0 credentials. In order to use the example class (MyClass), I have modified the line in DriveCommandLine where the Credential object is instantiated:
Credential credential = MyClass.getCredentials(code, "");
This results in the following exception being thrown:
java.lang.NullPointerException
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:187)
at com.google.api.client.json.jackson.JacksonFactory.createJsonParser(JacksonFactory.java:84)
at com.google.api.client.json.JsonFactory.fromInputStream(JsonFactory.java:247)
at com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets.load(GoogleClientSecrets.java:168)
at googledrive.MyClass.getFlow(MyClass.java:145)
at googledrive.MyClass.exchangeCode(MyClass.java:166)
at googledrive.MyClass.getCredentials(MyClass.java:239)
at googledrive.DriveCommandLine.<init>(DriveCommandLine.java:56)
at googledrive.DriveCommandLine.main(DriveCommandLine.java:115)
I've been looking at these APIs (Google Drive and OAuth) for 2 days now and have made very little progress. I'd really appreciate some help with the above error and the problem of getting persistent credentials in general.
This whole structure seems unnecessarily complicated to me. Anybody care to explain why I can't just create a simple Credential object by passing in my Google username and password?
Thanks,
Brian O Carroll, Dublin, Ireland
* Update *
Ok, I've just gotten around the above error and now I have a new one.
The way I got around the first problem was by modifying MyClass.getFlow(). Instead of creating a GoogleClientServices object from a json file, I have used a different version of GoogleAuthorizationCodeFlow.Builder that allows you to enter the client ID and client secret directly as Strings:
flow = new GoogleAuthorizationCodeFlow.Builder(httpTransport, jsonFactory, "<MY CLIENT ID>", "<MY CLIENT SECRET>", SCOPES).setAccessType("offline").setApprovalPrompt("force").build();
The problem I have now is that I get the following error when I try to use flow (GoogleAuthorizationCodeFlow object) to exchange the authorization code for the Credentials object:
An error occurred: com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
"error" : "invalid_scope"
}
googledrive.MyClass$CodeExchangeException
at googledrive.MyClass.exchangeCode(MyClass.java:185)
at googledrive.MyClass.getCredentials(MyClass.java:262)
at googledrive.DriveCommandLine.<init>(DriveCommandLine.java:56)
at googledrive.DriveCommandLine.main(DriveCommandLine.java:115)
Is there some other scope I should be using for this? I am currently using the array of scopes provided with MyClass:
private static final List<String> SCOPES = Arrays.asList(
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile");
Thanks!
I feel your pain. I'm two months in and still getting surprised.
Some of my learnings...
When you request user permissions, specify "offline=true". This will ("sometimes" sic) return a refreshtoken, which is as good as a password with restricted permissions. You can store this and reuse it at any time (until the user revokes it) to fetch an access token.
My feeling is that the Google SDKs are more of a hinderence than a help. One by one, I've stopped using them and now call the REST API directly.
On your last point, you can (just) use the Google clientlogin protocol to access the previous generation of APIs. However this is totally deprecated and will shortly be turned off. OAuth is designed to give fine grained control of authorisation which is intrinsically complex. So although I agree it's complicated, I don't think it's unnecessarily so. We live in a complicated world :-)
Your and mine experiences show that the development community is still in need of a consolidated document and recipes to get this stuff into our rear-view mirrors so we can focus on the task at hand.
Oath2Scopes is imported as follows:
import com.google.api.services.oauth2.Oauth2Scopes;
You need to have the jar file 'google-api-services-oauth2-v2-rev15-1.8.0-beta.jar' in your class path to access that package. It can be downloaded here.
No, I don't know how to get Credentials without having to visit the authorization URL at least once and copy the code. I've modified MyClass to store and retrieve credentials from a database (in my case, it's a simple table that contains userid, accesstoken and refreshtoken). This way I only have to get the authorization code once and once I get the access/refresh tokens, I can reuse them to make a GoogleCredential object. Here's how Imake the GoogleCredential object:
GoogleCredential credential = new GoogleCredential.Builder().setJsonFactory(jsonFactory)
.setTransport(httpTransport).setClientSecrets(clientid, clientsecret).build();
credential.setAccessToken(accessToken);
credential.setRefreshToken(refreshToken);
Just enter your clientid, clientsecret, accessToken and refreshToken above.
I don't really have a whole lot of time to separate and tidy up my entire code to post it up here but if you're still having problems, let me know and I'll see what I can do. Although, you are effectively asking a blind man for directions. My understanding of this whole system is very sketchy!
Cheers,
Brian
Ok, I've finally solved the second problem above and I'm finally getting a working GoogleCredential object with an access token and a refresh token.
I kept trying to solve the scopes problem by modifying the list of scopes in MyClass (the one that manages credentials). In the end I needed to adjust the scopes in my modified version of DriveCommandLine (the one that's originally used to get an authorization code). I added 2 scopes from Oauth2Scopes:
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET,
Arrays.asList(DriveScopes.DRIVE, Oauth2Scopes.USERINFO_EMAIL, Oauth2Scopes.USERINFO_PROFILE))
.setAccessType("offline").setApprovalPrompt("force").build();
Adding the scopes for user information allowed me to get the userid later in MyClass. I can now use the userid to store the credentials in a database for re-use (without having to get the user to go to a URL each time). I also set the access type to "offline" as suggested by pinoyyid.

Struggling with DDD, Repository Pattern, and Associated Domain Models

I'm really struggling to wrap my head around some of this stuff. Let me give an example of where I'm struggling.
I'm using Linq-2-Sql as the DAL for my app and the IRepository pattern used in the MVC Storefront sample app from Rob Conery.
In my domain I have a Customer Model which has a collection of Address Models. In my UI there is a button which allows the user to add a new address to the customer. This opens up an address editor which let's them fill in all the information.
What happens next? Does the address get saved to the database, then added to the list in my customer object? Does it just get added to the list but not updated until the Customer object get's saved? What if the user wants to delete an address? Do I delete the address in the database and then remove it from the list? Or do they just make all the deletes/adds they want and I dump everything from the database everytime and update it with whatever is in the Customer.Addresses collection? What's the right flow here?
Should the collection of addresses only get updated via the Repository by calling something like this:
public void AddAddressToCustomer(Customer c, Address a)
{
//validate and save address to db
//add the newly saved address to the Customer Object
}
Help...
DDD is an area where I have a lot of interest but but very little experience so please treat my suggestions cautiously. I only offer them because of the absence of other, more authoritative, answers.
In 'the book' by Eric Evans address is given as an example of something that should typically be treated as a Value Object rather than as an Entity. So I believe the Add method would belong to the Customer:
customer.Add(address);
There would be a Customer Repository (but not one for addresses). This might be used like this:
customerRepository.Update(customer);
The intentional affect of this is that all the difficult questions you ask about how this is then implemented at the DB layer are not the concern of the domain objects (i.e. the customer object). I'm afraid I can't help beyond that point either.
Sounds like you don't know the context of your domain as well as you need to. Ask some more questions and get a better user story. Potentially any of your proposed scenarios may meet the business need, depending on what it is. When you understand the need then I believe this issue will iron itself out.
it depends had a great start on the answer. Once you add the address to the customer and save the customer using:
customer.Add(address);
customerRepository.Update(customer);
Your repository would then map your customer and address domain layer entities to LINQ to SQL. This will likely involve creating a new DataContext object, getting the related LINQ to SQL entities (or creating new ones) and then mapping the domain layer entities to your LINQ to SQL entities.
var context = new MyDataContext();
var linqCustomer = MapCustomerToLinqCustomer(context, customer);
var linqAddress = MapAddressToLinqAddress(context, customer.Addresses.First());
context.SubmitChanges();
You could also use DataMapper classes for mapping, but the MapXYZ methods more closely follow Rob Conery's example. If you need more help with the MapXYZ methods, let me know.