diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2009-03-21 14:10:41 -0700 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2009-03-21 14:10:41 -0700 |
commit | ec8e3b27155297b790cadcfdebbe24fa2cbfa639 (patch) | |
tree | bd710d4964741fddad097b66e7b5e0b6eeca8b1b | |
parent | 4197cf4144223397b3c1aa03eb136b34820c3684 (diff) | |
download | DotNetOpenAuth-ec8e3b27155297b790cadcfdebbe24fa2cbfa639.zip DotNetOpenAuth-ec8e3b27155297b790cadcfdebbe24fa2cbfa639.tar.gz DotNetOpenAuth-ec8e3b27155297b790cadcfdebbe24fa2cbfa639.tar.bz2 |
Added Blogger posting OAuth sample.
-rw-r--r-- | samples/ConsumerWpf/MainWindow.xaml | 41 | ||||
-rw-r--r-- | samples/ConsumerWpf/MainWindow.xaml.cs | 15 | ||||
-rw-r--r-- | samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs | 55 | ||||
-rw-r--r-- | samples/DotNetOpenAuth.ApplicationBlock/Util.cs | 49 |
4 files changed, 150 insertions, 10 deletions
diff --git a/samples/ConsumerWpf/MainWindow.xaml b/samples/ConsumerWpf/MainWindow.xaml index 4fdf4e6..a3794c8 100644 --- a/samples/ConsumerWpf/MainWindow.xaml +++ b/samples/ConsumerWpf/MainWindow.xaml @@ -1,8 +1,8 @@ <Window x:Class="DotNetOpenAuth.Samples.ConsumerWpf.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - Title="DotNetOpenAuth Consumer (sample)" Height="248" Width="429"> - <Grid> + Title="DotNetOpenAuth Consumer (sample)" Height="400" Width="442"> + <Grid Margin="5"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition /> @@ -30,11 +30,36 @@ </Hyperlink> </TextBlock> </Label> - <Grid Grid.ColumnSpan="2" Grid.Row="4" Name="contactsGrid"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="Auto" /> - </Grid.ColumnDefinitions> - </Grid> + <TabControl Grid.ColumnSpan="2" Grid.Row="4" Name="tabControl1" Margin="0,10,0,0"> + <TabItem Header="Gmail Contacts" Name="gmailContactsTab"> + <Grid Name="contactsGrid"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="Auto" /> + </Grid.ColumnDefinitions> + </Grid> + </TabItem> + <TabItem Header="Blogger" Name="bloggerTab"> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="*" /> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + </Grid.RowDefinitions> + <Label>Blog URL</Label> + <TextBox Grid.Column="1" x:Name="blogUrlBox"/> + <Label Grid.Row="1">Title</Label> + <TextBox Grid.Row="1" Grid.Column="1" x:Name="postTitleBox">OAuth Rocks!</TextBox> + <Label Grid.Row="2">Body</Label> + <TextBox Grid.Row="2" Grid.Column="1" x:Name="postBodyBox" AcceptsReturn="True" AcceptsTab="True" AutoWordSelection="True" TextWrapping="WrapWithOverflow"><p xmlns="http://www.w3.org/1999/xhtml">Oauth is cool</p></TextBox> + <Button x:Name="postButton" Grid.Row="3" Grid.Column="1" Click="postButton_Click" IsEnabled="False">Post</Button> + </Grid> + </TabItem> + </TabControl> </Grid> </Window> diff --git a/samples/ConsumerWpf/MainWindow.xaml.cs b/samples/ConsumerWpf/MainWindow.xaml.cs index bcaae6f..ea3ea39 100644 --- a/samples/ConsumerWpf/MainWindow.xaml.cs +++ b/samples/ConsumerWpf/MainWindow.xaml.cs @@ -13,7 +13,9 @@ using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; + using System.Xml; using System.Xml.Linq; + using System.Xml.XPath; using DotNetOpenAuth; using DotNetOpenAuth.ApplicationBlock; using DotNetOpenAuth.Messaging; @@ -27,6 +29,7 @@ private InMemoryTokenManager tokenManager = new InMemoryTokenManager(); private DesktopConsumer google; private string requestToken; + private string accessToken; public MainWindow() { InitializeComponent(); @@ -43,18 +46,23 @@ this.Cursor = Cursors.Wait; beginAuthorizationButton.IsEnabled = false; ThreadPool.QueueUserWorkItem(delegate(object state) { - Uri browserAuthorizationLocation = GoogleConsumer.RequestAuthorization(this.google, GoogleConsumer.Applications.Contacts, out this.requestToken); + Uri browserAuthorizationLocation = GoogleConsumer.RequestAuthorization( + this.google, + GoogleConsumer.Applications.Contacts | GoogleConsumer.Applications.Blogger, + out this.requestToken); System.Diagnostics.Process.Start(browserAuthorizationLocation.AbsoluteUri); this.Dispatcher.BeginInvoke(new Action(() => { this.Cursor = original; beginAuthorizationButton.IsEnabled = true; completeAuthorizationButton.IsEnabled = true; + postButton.IsEnabled = true; })); }); } private void completeAuthorizationButton_Click(object sender, RoutedEventArgs e) { var grantedAccess = this.google.ProcessUserAuthorization(this.requestToken); + this.accessToken = grantedAccess.AccessToken; XDocument contactsDocument = GoogleConsumer.GetContacts(this.google, grantedAccess.AccessToken); var contacts = from entry in contactsDocument.Root.Elements(XName.Get("entry", "http://www.w3.org/2005/Atom")) select new { @@ -73,5 +81,10 @@ contactsGrid.Children.Add(email); } } + + private void postButton_Click(object sender, RoutedEventArgs e) { + XElement postBodyXml = XElement.Parse(postBodyBox.Text); + GoogleConsumer.PostBlogEntry(this.google, this.accessToken, blogUrlBox.Text, postTitleBox.Text, postBodyXml); + } } } diff --git a/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs b/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs index 2206fff..c6f2b89 100644 --- a/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs +++ b/samples/DotNetOpenAuth.ApplicationBlock/GoogleConsumer.cs @@ -7,7 +7,13 @@ namespace DotNetOpenAuth.ApplicationBlock { using System; using System.Collections.Generic; + using System.Diagnostics; + using System.IO; using System.Linq; + using System.Net; + using System.Text; + using System.Text.RegularExpressions; + using System.Xml; using System.Xml.Linq; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OAuth; @@ -33,6 +39,7 @@ namespace DotNetOpenAuth.ApplicationBlock { private static readonly Dictionary<Applications, string> DataScopeUris = new Dictionary<Applications, string> { { Applications.Contacts, "http://www.google.com/m8/feeds/" }, { Applications.Calendar, "http://www.google.com/calendar/feeds/" }, + { Applications.Blogger, "http://www.blogger.com/feeds" }, }; /// <summary> @@ -54,6 +61,11 @@ namespace DotNetOpenAuth.ApplicationBlock { /// Appointments in Google Calendar. /// </summary> Calendar = 0x2, + + /// <summary> + /// Blog post authoring. + /// </summary> + Blogger = 0x4, } /// <summary> @@ -134,6 +146,49 @@ namespace DotNetOpenAuth.ApplicationBlock { return result; } + public static void PostBlogEntry(ConsumerBase consumer, string accessToken, string blogUrl, string title, XElement body) { + string feedUrl; + var getBlogHome = WebRequest.Create(blogUrl); + using (var blogHomeResponse = getBlogHome.GetResponse()) { + using (StreamReader sr = new StreamReader(blogHomeResponse.GetResponseStream())) { + string homePageHtml = sr.ReadToEnd(); + Match m = Regex.Match(homePageHtml, @"http://www.blogger.com/feeds/\d+/posts/default"); + Debug.Assert(m.Success, "Posting operation failed."); + feedUrl = m.Value; + } + } + const string Atom = "http://www.w3.org/2005/Atom"; + XElement entry = new XElement( + XName.Get("entry", Atom), + new XElement(XName.Get("title", Atom), new XAttribute("type", "text"), title), + new XElement(XName.Get("content", Atom), new XAttribute("type", "xhtml"), body), + new XElement(XName.Get("category", Atom), new XAttribute("scheme", "http://www.blogger.com/atom/ns#"), new XAttribute("term", "oauthdemo"))); + + MemoryStream ms = new MemoryStream(); + XmlWriterSettings xws = new XmlWriterSettings() { + Encoding = Encoding.UTF8, + }; + XmlWriter xw = XmlWriter.Create(ms, xws); + entry.WriteTo(xw); + xw.Flush(); + + WebRequest request = consumer.PrepareAuthorizedRequest(new MessageReceivingEndpoint(feedUrl, HttpDeliveryMethods.PostRequest | HttpDeliveryMethods.AuthorizationHeaderRequest), accessToken); + request.ContentType = "application/atom+xml"; + request.Method = "POST"; + request.ContentLength = ms.Length; + ms.Seek(0, SeekOrigin.Begin); + using (Stream requestStream = request.GetRequestStream()) { + ms.CopyTo(requestStream); + } + using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { + if (response.StatusCode == HttpStatusCode.Created) { + // Success + } else { + // Error! + } + } + } + /// <summary> /// Gets the scope URI in Google's format. /// </summary> diff --git a/samples/DotNetOpenAuth.ApplicationBlock/Util.cs b/samples/DotNetOpenAuth.ApplicationBlock/Util.cs index 5001e2e..ea7da97 100644 --- a/samples/DotNetOpenAuth.ApplicationBlock/Util.cs +++ b/samples/DotNetOpenAuth.ApplicationBlock/Util.cs @@ -1,9 +1,10 @@ namespace DotNetOpenAuth.ApplicationBlock { using System; using System.Collections.Generic; + using System.IO; using DotNetOpenAuth.Messaging; - internal class Util { + internal static class Util { /// <summary> /// Enumerates through the individual set bits in a flag enum. /// </summary> @@ -25,5 +26,51 @@ Uri callback = MessagingUtilities.GetRequestUrlFromContext().StripQueryArgumentsWithPrefix("oauth_"); return callback; } + + /// <summary> + /// Copies the contents of one stream to another. + /// </summary> + /// <param name="copyFrom">The stream to copy from, at the position where copying should begin.</param> + /// <param name="copyTo">The stream to copy to, at the position where bytes should be written.</param> + /// <returns>The total number of bytes copied.</returns> + /// <remarks> + /// Copying begins at the streams' current positions. + /// The positions are NOT reset after copying is complete. + /// </remarks> + internal static int CopyTo(this Stream copyFrom, Stream copyTo) { + return CopyTo(copyFrom, copyTo, int.MaxValue); + } + + /// <summary> + /// Copies the contents of one stream to another. + /// </summary> + /// <param name="copyFrom">The stream to copy from, at the position where copying should begin.</param> + /// <param name="copyTo">The stream to copy to, at the position where bytes should be written.</param> + /// <param name="maximumBytesToCopy">The maximum bytes to copy.</param> + /// <returns>The total number of bytes copied.</returns> + /// <remarks> + /// Copying begins at the streams' current positions. + /// The positions are NOT reset after copying is complete. + /// </remarks> + internal static int CopyTo(this Stream copyFrom, Stream copyTo, int maximumBytesToCopy) { + if (copyFrom == null) { + throw new ArgumentNullException("copyFrom"); + } + if (copyTo == null) { + throw new ArgumentNullException("copyTo"); + } + + byte[] buffer = new byte[1024]; + int readBytes; + int totalCopiedBytes = 0; + while ((readBytes = copyFrom.Read(buffer, 0, Math.Min(1024, maximumBytesToCopy))) > 0) { + int writeBytes = Math.Min(maximumBytesToCopy, readBytes); + copyTo.Write(buffer, 0, writeBytes); + totalCopiedBytes += writeBytes; + maximumBytesToCopy -= writeBytes; + } + + return totalCopiedBytes; + } } } |