using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using LinkedIn.NET; using LinkedIn.NET.Options; using LinkedIn.NET.Groups; namespace LinkedInDesktopUI { public static class ExtensionMethods { public static string LimitLength(this string s, int len) { string ret = s; if (s.Length > len) { ret = s.Substring(0, len - 3) + "..."; } return ret; } } public partial class LinkedInUI : Form { protected LinkedInClient linkedInClient; protected string consumerKey; protected string consumerSecret; protected string accessToken; protected bool haveAccessToken; protected LinkedInGroupPost selectedPost; protected TreeNode selectedPostNode; const string CRLF = "\r\n"; const string REDIRECT_URL = "http://pnotes.sourceforge.net/auth.htm"; const string STATE = "DCEEFWF45453sdffef424"; public LinkedInUI() { InitializeComponent(); LoadConfiguration(); InitializeClient(); btnComment.Enabled = false; if (String.IsNullOrEmpty(accessToken)) { Authenticate(); } else { LoadGroups(); } } protected void MakeComment(object sender, EventArgs args) { AddComment(selectedPost, tbComment.Text); } protected void OnNodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) { StringBuilder sb = new StringBuilder(); if (e.Node.Tag is LinkedInGroup) { LinkedInGroup group = (LinkedInGroup)e.Node.Tag; sb.Append("Group: " + group.Name); sb.Append(CRLF); sb.Append(CRLF); sb.Append("Category: " + group.Category); sb.Append(CRLF); sb.Append(CRLF); sb.Append("Description: " + group.ShortDescription); btnComment.Enabled = false; } else if (e.Node.Tag is LinkedInGroupPost) { LinkedInGroupPost post = (LinkedInGroupPost)e.Node.Tag; sb.Append("Title: " + post.Title); sb.Append(CRLF); sb.Append(CRLF); sb.Append("By: " + post.Creator.FirstName + " " + post.Creator.LastName); sb.Append(CRLF); sb.Append(CRLF); sb.Append("On: " + post.CreationTime.ToString()); sb.Append(CRLF); sb.Append(CRLF); sb.Append("Summary: " + post.Summary); btnComment.Enabled = true; selectedPost = post; selectedPostNode = e.Node; } else if (e.Node.Tag is LinkedInGroupComment) { LinkedInGroupComment comment = (LinkedInGroupComment)e.Node.Tag; sb.Append("By: " + comment.Creator.FirstName + " " + comment.Creator.LastName); sb.Append(CRLF); sb.Append(CRLF); sb.Append("On: " + comment.CreationTime.ToString()); sb.Append(CRLF); sb.Append(CRLF); sb.Append(comment.Text); btnComment.Enabled = true; } tbInfo.Text = sb.ToString(); } protected void OnNodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) { if (e.Node.Tag is LinkedInGroup) { LinkedInGroup group = (LinkedInGroup)e.Node.Tag; LoadPostsForGroup(e.Node, group); } else if (e.Node.Tag is LinkedInGroupPost) { LinkedInGroupPost post = (LinkedInGroupPost)e.Node.Tag; LoadCommentsForPost(e.Node, post); } } /// /// Load the configuration and check for the access token. /// protected void LoadConfiguration() { try { string[] linkedInConfig = File.ReadAllLines("linkedin.config"); consumerKey = linkedInConfig[0]; consumerSecret = linkedInConfig[1]; if (linkedInConfig.Length == 3) { accessToken = linkedInConfig[2]; haveAccessToken = true; } } catch (Exception ex) { EmitException("LinkedIn.config file is missing or corrupt." + "\r\n" + ex.Message); } } protected void SaveConfiguration() { File.WriteAllLines("linkedin.config", new string[] { consumerKey, consumerSecret, accessToken, }); } protected void InitializeClient() { if ((!String.IsNullOrEmpty(consumerKey)) && (!String.IsNullOrEmpty(consumerSecret))) { linkedInClient = new LinkedInClient(consumerKey, consumerSecret); if (haveAccessToken) { linkedInClient.AccessToken = accessToken; } } } // The code in this method is heavily borrowed from the LinkedIn.NET's LNTest "authenticate" method (DlgExample.cs) protected void Authenticate() { if (linkedInClient != null) { var options = new LinkedInAuthorizationOptions { RedirectUrl = REDIRECT_URL, Permissions = LinkedInPermissions.Connections | LinkedInPermissions.ContactsInfo | LinkedInPermissions.EmailAddress | LinkedInPermissions.FullProfile | LinkedInPermissions.GroupDiscussions | LinkedInPermissions.Messages | LinkedInPermissions.Updates, State = STATE }; //create new instance of authorization dialog using authorization link built by _Client var dlgAuth = new DlgAuthorization(linkedInClient.GetAuthorizationUrl(options)); if (dlgAuth.ShowDialog(this) == DialogResult.OK) { //get access token using authorization code received var response = linkedInClient.GetAccessToken(dlgAuth.AuthorizationCode, REDIRECT_URL); if (response.Result != null && response.Status == LinkedInResponseStatus.OK) { accessToken = response.Result.AccessToken; SaveConfiguration(); } } else { //show error information MessageBox.Show(dlgAuth.OauthErrorDescription, dlgAuth.OauthError); } } } protected async void LoadGroups() { if (haveAccessToken) { tvGroups.Nodes.Clear(); tvGroups.Nodes.Add("Loading..."); LinkedInGetGroupOptions options = new LinkedInGetGroupOptions(); options.GroupOptions.SelectAll(); LinkedInResponse> result = await Task.Run(() => linkedInClient.GetMemberGroups(options)); if (result.Result != null && result.Status == LinkedInResponseStatus.OK) { ShowMemberGroups(result); } else { ReRun(result.Status, result.Message); } } } protected async void LoadPostsForGroup(TreeNode node, LinkedInGroup group) { LinkedInGetGroupPostsOptions options = new LinkedInGetGroupPostsOptions(); options.PostOptions.SelectAll(); options.GroupId = group.Id; ShowLoading(node); await Task.Run(() => group.LoadPosts(options)); ShowGroupPosts(node, group); node.ExpandAll(); } protected async void LoadCommentsForPost(TreeNode node, LinkedInGroupPost post) { LinkedInGetGroupPostCommentsOptions options = new LinkedInGetGroupPostCommentsOptions(); options.CommentOptions.SelectAll(); options.PostId = post.Id; ShowLoading(node); await Task.Run(() => post.LoadComments(options)); ShowGroupPostComments(node, post); node.ExpandAll(); } protected void ShowMemberGroups(LinkedInResponse> result) { tvGroups.Nodes.Clear(); foreach (LinkedInGroup group in result.Result) { TreeNode node = tvGroups.Nodes.Add(group.Name); node.Tag = group; } } protected void ShowGroupPosts(TreeNode node, LinkedInGroup group) { node.Nodes.Clear(); foreach (LinkedInGroupPost post in group.Posts) { TreeNode childNode = node.Nodes.Add(post.Title); childNode.Tag = post; } } protected void ShowGroupPostComments(TreeNode node, LinkedInGroupPost post) { node.Nodes.Clear(); foreach (LinkedInGroupComment comment in post.Comments) { TreeNode childNode = node.Nodes.Add(comment.Text.LimitLength(64)); childNode.Tag = comment; } } protected void AddComment(LinkedInGroupPost post, string comment) { post.Comment(comment); // After posting the comment, add it to the post's comment collection, select it, and display the comment in the info box. tbComment.Text = "(posted)"; TreeNode childNode = selectedPostNode.Nodes.Add(comment.LimitLength(64)); tvGroups.SelectedNode = childNode; tbInfo.Text = comment; } protected void ShowLoading(TreeNode node) { node.Nodes.Clear(); node.Nodes.Add("Loading..."); node.ExpandAll(); } protected void ReRun(LinkedInResponseStatus status, string message) { switch (status) { case LinkedInResponseStatus.ExpiredToken: case LinkedInResponseStatus.InvalidAccessToken: case LinkedInResponseStatus.UnauthorizedAction: Authenticate(); break; default: MessageBox.Show(message); break; } } protected void EmitException(string exception) { MessageBox.Show(exception, "An Error Has Occurred", MessageBoxButtons.OK, MessageBoxIcon.Error); } } }