Monday, August 2, 2010

Viewpoint for Exchange Web Services - Next Generation BETA

I would like to announce the next generation, BETA release of Viewpoint, my Exchange Web Services client library for Ruby. This release has some major changes from the previous one which I'll list below. It was also developed in Ruby 1.9.x and the RSPEC tests have also completed in Ruby 1.8.7. There is much work that needs to be done adding features to the Model, but the SOAP guts have been hashed out fairly well in my mind and adding features from here on out should be fairly incremental. So without further ado, here are some of the major changes found in this BETA release.

Check out the latest code from the Viewpoint Github repository
...or install the gem version 0.1.0 "gem install viewpoint"


New SOAP backend

Viewpoint now uses Handsoap as its back-end instead of soap4r. While soap4r does some very nice things for you automatically, it ends up making your code base fairly large and it complicates any customizations that you might want to make. One example is adding custom headers. Soap4r required you to create a subclass to use as a sort of hook. I can do the same thing in Handsoap with a one-liner in the services #on_create_document method.


Models are completely rewritten

The models are completely new and not backward compatible with the old version of Viewpoint. Some of the methods still exist, but don't count on them. I've tried to make this version much more extensible than the last.

Configuration loader removed

After much thought I determined it really wasn't the place of a client library to provide a configuration loader for credentials. To that end I removed the need for a .viewpointrc file. If this is something you liked it would be relatively easy to write it into your application. Now authentication configuration information is set via class methods:
Viewpoint::EWS::EWS.endpoint = 'https://mysite.com/ews/exchange.asmx'
Viewpoint::EWS::EWS.set_auth('myuser','mypass')

Delegate access is supported

One thing that was often asked for, but missing from the previous version was delegate access to mailboxes and calendars. This is now supported via the 'act_as' parameter to the GenericFolder::get_folder method. For example:

ofolder = Folder.get_folder(:inbox,'otheruser@test.com')

If your user has delegate access to the Inbox for otheruser@test.com this operation will retrieve their inbox and allow you to manipulate it as you would with your own Inbox. There is also some support for manipulation of delegate access itself via the methods MailboxUser#add_delegate!, MailboxUser#update_delegate!, and MailboxUser#get_delegate_info.

Some Exchange 2010 Stubs


Some of the new features of Exchange 2010 are being stubbed in. I do not have access to an Exchange 2010 server to test them on so I cannot verify if they work or not.

Misc other changes

Since it's a complete rewrite there are tons of other changes that you'll notice. I've tried to keep the code comments coming so stay tuned to the API docs for library information. I'll also be posting more examples to my blog.

So at a glance there you have it. If there are any features you would like to see added or comments please add it to the bottom of this post or add an issue on the Github page. Also, if you're interested in sponsoring an Exchange 2010 account for me please let me know. I would love to try out some of the new advanced query stuff that 2010 has to offer.



Cheers!

GITHUB: http://bit.ly/viewpoint_ews
RubyGems: http://rubygems.org/gems/viewpoint
RDOC: http://rdoc.info/projects/zenchild/Viewpoint

26 comments:

  1. Can viewpoint be used to update GAL (global address book)?

    ReplyDelete
  2. Joshua,

    Exchange Web Services and therefore Viewpoint only supports resolving names via the GAL and not updating it. Since the GAL is just Active Directory you should be able to use the net-ldap gem to make modifications. However, Viewpoint will let you add contacts and query contacts that you have added to your Contacts folder.

    Cheers,

    Dan

    ReplyDelete
  3. I can't tell you how pleased I am so far with Viewpoint. I'd been dreading our Exchange integration for weeks when I found Viewpoint and I've been working with it for the last several nights. I investigated the old Viewpoint a while ago, and the new stuff is so clean it's just fun to work with.

    Is there a roadmap for additions to Viewpoint?

    Thanks!

    Marc

    ReplyDelete
  4. Marc,

    Glad you find Viewpoint useful. I do not have a roadmap for it, but I would like to get a hold of an Exchange 2010 server soon to play with some of the new features like Unified Messaging and advanced filtering. However, I've been pouring most of my free time into WinRM (http://github.com/zenchild/WinRM) lately so Viewpoint's been on my back-burner. If you have any features you'd like to see add them to the issues list on Github and mark them as a "feature request".
    http://github.com/zenchild/Viewpoint/issues

    Cheers,

    Dan

    ReplyDelete
  5. It is wery usefull. But I cannot find way how to access public folder like \Calendars\Test.

    Viewpoint::EWS::CalendarFolder.find_folders() doesn't return them and Viewpoint::EWS::GenericFolder.get_folder_by_name('\Calendars\Test') doesn't work as well.

    ReplyDelete
  6. Lukas,

    #get_folder_by_name does not work for subfolders yet. You should put in a feature request on the github page for Viewpoint if you would like to see it as an add-on. I did however create a subfolder called "Test" under my calendar folder and Viewpoint::EWS::CalendarFolder.find_folders() did find it. Make sure that "Test" is indeed of type CalendarFolder.

    Dan

    ReplyDelete
  7. Hi,
    Thanks for your great work. I have been using it. It save me lots of time.
    I just do not find how to update exchange items from ruby app. Is this feature implemented ?

    ReplyDelete
  8. This comment has been removed by the author.

    ReplyDelete
  9. @guero

    There really isn't a good way to "update" items today. You can however create new items (Calendar, Mail, etc). Take a look at the Message.send and CalendarItem.create_item class methods in the API docs: http://rdoc.info/github/zenchild/Viewpoint/master/frames

    ReplyDelete
  10. hi zenTourist, thanks for your reply.
    Indeed, today when I want to update a calendar item, I delete it and create a new one.

    When you say that there isn't a good way to update items, is this means that viewpoint does not implement it ? or is it means that exchange api do not allow it ?

    ReplyDelete
  11. @guero, it means I haven't implemented it in Viewpoint yet. Exchange Web Services has it implemented and the stubs are in Viewpoint. See:
    Viewpoint::EWS::SOAP::ExchangeWebService#update_item and
    Viewpoint::EWS::SOAP::ExchangeWebService#update_folder

    Basically, I haven't had a need for it yet so I haven't implemented it.

    ReplyDelete
  12. I have just come across this GEM and have the following:


    require 'rubygems'
    require 'kconv'
    require 'viewpoint'
    require 'json'

    creds = JSON.load(File.open('creds.json','r'))
    Viewpoint::EWS::EWS.endpoint = creds['endpoint']
    Viewpoint::EWS::EWS.set_auth(creds['user'],creds['pass'])
    @ews = Viewpoint::EWS::EWS.instance

    puts "EWS Object:"
    puts @ews.inspect

    begin

    Viewpoint::EWS::CalendarFolder.find_folders()

    rescue Handsoap::HttpError => e
    puts e.response.inspect
    end


    The response is:

    EWS Object:
    #>
    --- Response ---
    HTTP Status: 415
    X-Powered-By: ASP.NET
    X-Aspnet-Version: 2.0.50727
    Server: Microsoft-IIS/7.5
    Date: Mon, 08 Nov 2010 19:39:42 GMT
    Content-Length: 0
    Set-Cookie: exchangecookie=cda2bd5d1178404090b5491582458f23; expires=Tue, 08-Nov-2011 19:39:42 GMT; path=/; HttpOnly
    Cache-Control: private
    ---

    ---


    Any insight as to why I get a 415 HTTP response would be great.

    Note I am new to EWS.

    ReplyDelete
  13. Kayzio, Did you try hitting your EWS endpoint with a browser first to make sure it's returning a WSDL?

    ReplyDelete
  14. I hit it in Firefox, which prompted me for my username and password, I entered my credentials, then it took me to Service.wsdl in the browser without an issue. I am using Excnage Server 2010 in case that makes a difference.

    ReplyDelete
  15. I really don't know why you would be getting the 415 error. I don't think Exchange 2010 should matter, but I do not have access to a 2010 server to test on so I can't say 100% for sure.

    ReplyDelete
  16. I ended up just using CURL instead.

    ReplyDelete
  17. Sorry it wouldn't work for you. Hopefully I can get access to a 2010 server sometime and bang on it for a bit.

    Cheers,

    Dan

    ReplyDelete
  18. I'm trying to use Viewpoint 0.1.21 on Mac OS X 10.6.6 with ruby 1.8.7, but I keep getting an error when running the following basic script:

    require 'rubygems'
    require 'viewpoint'

    Viewpoint::EWS::EWS.endpoint = 'https://my.exchange.server.com/exchange/me@my.org.com'
    Viewpoint::EWS::EWS.set_auth('username','password')
    Viewpoint::EWS::EWS.set_trust_ca('cacert.pem') # from http://curl.haxx.se/docs/caextract.html
    @ews = Viewpoint::EWS::EWS.instance
    puts @ews.me

    The error I'm getting says:


    /Library/Ruby/Gems/1.8/gems/viewpoint-0.1.21/lib/soap/handsoap/parser.rb:28:in `initialize': undefined method `/' for nil:NilClass (NoMethodError)
    from /Library/Ruby/Gems/1.8/gems/viewpoint-0.1.21/lib/soap/handsoap/ews_service.rb:772:in `new'
    from /Library/Ruby/Gems/1.8/gems/viewpoint-0.1.21/lib/soap/handsoap/ews_service.rb:772:in `parse!'
    from /Library/Ruby/Gems/1.8/gems/viewpoint-0.1.21/lib/soap/handsoap/ews_service.rb:120:in `resolve_names'
    from /Library/Ruby/Gems/1.8/gems/viewpoint-0.1.21/lib/model/mailbox_user.rb:36:in `find_user'
    from /Library/Ruby/Gems/1.8/gems/viewpoint-0.1.21/lib/viewpoint.rb:130:in `me'
    from test.rb:9

    Any ideas what's wrong?

    Thank you very much!

    ReplyDelete
  19. Bernd,

    Your endpoint is wrong. The url should end in '/ews/exchange.asmx'

    If you have any additional issues open an issue the the Viewpoint Github site: https://github.com/zenchild/Viewpoint/issues

    Cheers,

    Dan

    ReplyDelete
  20. Oops. My mistake. I changed the URL and Viewpoint works as advertised. Awesome! :-)

    The one thing I don't quite understand is why the implementation of CalendarFolder::items_between overwrites the option max_entries_returned and sets it to 256:

    opts[:calendar_view] = {:max_entries_returned => 256, ...

    Is there an easy work-around to increase max_entries_returned without patching the latest release of Viewpoint? Is there a reason why it has to be 256? Can it be larger?

    Thanks again and awesome work!


    -Bernd

    ReplyDelete
  21. Glad it's working for you.

    There really isn't a good reason for the 256 limit. It was just a good default at the time and I never revisited it to extend the API. If you could open up an issue (feature request) on Github so it doesn't get lost in the fray I'll add a way to increase the max in the next release.

    In the meantime you can use #find_items as a work-around.

    maxnum=512
    opts[:calendar_view] = {:max_entries_returned => maxnum, :start_date => start_date, :end_date => end_date}
    calfolder.find_items(opts)

    ReplyDelete
  22. Great work, love Ruby and love your plugin/gem.

    ReplyDelete
  23. @dejan glad it's working well for you.

    ReplyDelete
  24. This is a great library thanks so much for the efforts!

    A question: I am running into validation trouble:

    folders = Viewpoint::EWS::CalendarFolder.find_folders
    folders[0].search_by_subject("S")
    Handsoap::Fault: Handsoap::Fault { :code => 'soap11:Client', :reason => 'The request failed schema validation: The element 'Contains' in namespace 'http://schemas.microsoft.com/exchange/services/2006/types' has invalid child element 'Constant' in namespace 'http://schemas.microsoft.com/exchange/services/2006/types'. List of possible elements expected: 'Path' in namespace 'http://schemas.microsoft.com/exchange/services/2006/types'.' }
    from /Library/Ruby/Gems/1.8/gems/handsoap-1.1.8/lib/handsoap/service.rb:379:in `on_fault'
    from /Library/Ruby/Gems/1.8/gems/handsoap-1.1.8/lib/handsoap/service.rb:434:in `parse_http_response'
    from /Library/Ruby/Gems/1.8/gems/handsoap-1.1.8/lib/handsoap/service.rb:250:in `invoke'
    from /Library/Ruby/Gems/1.8/gems/viewpoint-0.1.24/lib/soap/handsoap/ews_service.rb:780:in `invoke'
    from /Library/Ruby/Gems/1.8/gems/viewpoint-0.1.24/lib/soap/handsoap/ews_service.rb:184:in `find_item'
    from /Library/Ruby/Gems/1.8/gems/viewpoint-0.1.24/lib/model/generic_folder.rb:225:in `find_items'
    from /Library/Ruby/Gems/1.8/gems/viewpoint-0.1.24/lib/model/generic_folder.rb:300:in `search_by_subject'
    from (irb):48
    from :0

    Any ideas what is going on here? I did some debugging and it looks like the XML getting sent over to my exchange server is correct.

    I can create items and retrieve them fine via folder[0].find_items, so I know I'm on the right track. Any help would be tremendously appreciated!

    ReplyDelete
  25. @dhawt

    It looks like there was a Hash ordering issue with ruby 1.8 clients. I fixed it and pushed out a new gem: 0.1.25 that has the fix.

    ReplyDelete
  26. Looks like it's working now ... thanks!

    ReplyDelete