diff --git a/Net.Pokeshot.JiveSdk/Clients/DESClient.cs b/Net.Pokeshot.JiveSdk/Clients/DESClient.cs index 4a93c56..6569be4 100644 --- a/Net.Pokeshot.JiveSdk/Clients/DESClient.cs +++ b/Net.Pokeshot.JiveSdk/Clients/DESClient.cs @@ -4,11 +4,15 @@ using System; using System.Web; using Newtonsoft.Json.Linq; +using System.Threading; namespace Net.Pokeshot.JiveSdk.Clients { public class DESClient : JiveClient { + static volatile string _token = null; + static Mutex mut = new Mutex(); + string _desUrl { get { return "https://api.jivesoftware.com/analytics/v2/export"; } } string _clientId; string _clientSecret; @@ -23,8 +27,9 @@ public List GetActivity(List filter = null, int { // Jive's DES server seems to off by a few seconds. When making calls using before or after, if either is ahead of the Jive's server, we get a 400 Bad Request Error. // For that reason, we push back the these values by 20 seconds. It should be noted that this is problem may get resolved later or not appear on certain clients. - before = before?.AddSeconds(-20); - after = after?.AddSeconds(-20); + // Still getting these errors every once in a while, so bumping up to 30 seconds + before = before?.AddSeconds(-30); + after = after?.AddSeconds(-30); List activityList = new List(); @@ -69,6 +74,9 @@ public List GetActivity(List filter = null, int throw new HttpException(e.WebEventCode, "An input field is missing or malformed", e); case 403: throw new HttpException(e.WebEventCode, "You are not allowed to access this", e); + case 401: // If the token happens to have expired, try once more before giving up. + json = retry(url); + break; default: throw; } @@ -86,9 +94,29 @@ public List GetActivity(List filter = null, int return activityList; } + private string retry(string url, int numTries = 0) + { + int maxTry = 10; + try + { + return GetAbsolute(url, getAuthorization()); + } + catch (HttpException e) + { + if (e.GetHttpCode() == 401) + { + if (numTries > maxTry) + throw; + + return retry(url, ++numTries); + } + else + throw; + } + } /// - /// Gets the Authorization needed for downloading data from the DES. + /// Gets the Authorization needed for downloading data from the DES. This method is thread safe. /// /// string to be used as the authorization header for web request to the des. private string getAuthorization() { @@ -96,7 +124,38 @@ private string getAuthorization() { url += "clientId=" + _clientId; url += "&clientSecret=" + _clientSecret; - return PostAbsolute(url, ""); + mut.WaitOne(); + // The token expires after 30 minutes. However, if a new one is created, the old one quits working. + if (!isValid(_token)) + { + _token = PostAbsolute(url, ""); + } + mut.ReleaseMutex(); + + return _token; + } + + /// + /// Tries the token. If it works, returns true. Otherwise, returns false. + /// + /// + /// + private bool isValid(string _token) + { + if (_token == null) + return false; + + var url = _desUrl + "/activity?count=1&fields=actorID"; + try + { + GetAbsolute(url, _token); + } + catch (Exception) + { + return false; + } + + return true; } } } diff --git a/Net.Pokeshot.JiveSdk/Clients/IdeaVotesClient.cs b/Net.Pokeshot.JiveSdk/Clients/IdeaVotesClient.cs index 24cc847..30a5f93 100644 --- a/Net.Pokeshot.JiveSdk/Clients/IdeaVotesClient.cs +++ b/Net.Pokeshot.JiveSdk/Clients/IdeaVotesClient.cs @@ -18,20 +18,26 @@ public class IdeaVotesClient : JiveClient public IdeaVotesClient(string communityUrl, NetworkCredential credentials) : base(communityUrl, credentials) { } /// - /// Cast a vote on the specified idea, replacing any previous vote by the requesting person. The incoming JSON must include a boolean "promote" field - /// that is true if the requestor is promoting this idea, or false if the requestor is demoting it. + /// Cast a vote on the specified idea, replacing any previous vote by the included voter. The incoming JSON + /// must include a boolean "promote" field and an int "id" field within a People object named "voter" that + /// is true if the voter is promoting this idea, or false if the voter is demoting it. This requires elevated + /// permissions if the requester does not match the voter. /// - /// The ID of the content object for which to cast a "promote" vote - /// The vote entity containing the promote field (assumed to be true if not present) + /// The ID of the content object for which to cast an idea vote + /// The vote entity containing the promote field where true is promoting and false is demoting (assumed to be false if not present), and the voter's id within the voter field public void CreateVote(int contentID, IdeaVote idea_vote) { string url = ideaVotesUrl; url += "/" + contentID.ToString(); - string json = JsonConvert.SerializeObject(idea_vote, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); + // Jive only looks at the authorization when creating the vote, not the voter passed in the json. + // Because of this, we use RunAs() and forget about most of the json. + // This entire function couldn't be run in a RunAs because it doesn't return anything and Func + // must have a return type. + string json = "{\"promote\":" + (idea_vote.promote ? "true" : "false") + "}"; try { - PostAbsolute(url, json); + RunAs(idea_vote.voter.id, () => PostAbsolute(url, json)); } catch (HttpException e) { @@ -47,6 +53,10 @@ public void CreateVote(int contentID, IdeaVote idea_vote) throw new HttpException(e.WebEventCode, "You attempted to vote on an issue for which voting has been disabled", e); case 410: throw new HttpException(e.WebEventCode, "If this Jive instance is not licensed for the Ideation module", e); + case 500: + throw new HttpException(e.WebEventCode, "If there was an internal server error", e); + default: + throw; } } @@ -65,7 +75,7 @@ public List GetVotes(int contentID, int count = 25, int startIndex = 0 { List voteList = new List(); - //construcs the correct url based on the user's specifications + //constructs the correct url based on the user's specifications string url = ideaVotesUrl; url += "/" + contentID.ToString(); url += "?count=" + (count > 1000 ? 1000 : count).ToString(); diff --git a/Net.Pokeshot.JiveSdk/Clients/JiveClient.cs b/Net.Pokeshot.JiveSdk/Clients/JiveClient.cs index 74019cc..fff76a9 100644 --- a/Net.Pokeshot.JiveSdk/Clients/JiveClient.cs +++ b/Net.Pokeshot.JiveSdk/Clients/JiveClient.cs @@ -18,6 +18,7 @@ public abstract class JiveClient private readonly NetworkCredential _credential; protected string JiveCommunityUrl; private int? _imposter = null; + private bool _secondTry = false; private static int _numGets = 0; private static int _numPosts = 0; private static int _numPuts = 0; @@ -76,9 +77,17 @@ public static void ResetApiCounters() public T RunAs(int personId, Func method) { _imposter = personId; - var returnVal = method(); + T returnVal = default(T); + try + { + returnVal = method(); + } + catch (Exception ex) + { + _imposter = null; + throw; + } _imposter = null; - return returnVal; } @@ -115,7 +124,21 @@ protected string GetAbsolute(string url, string authorization) requestMessage.Headers.Add("X-Jive-Run-As", "userid " + _imposter); } - HttpResponseMessage activityResponse = httpClient.SendAsync(requestMessage).Result; + HttpResponseMessage activityResponse; + try + { + activityResponse = httpClient.SendAsync(requestMessage).Result; + } + catch (Exception e) + { + // If timed out, try once more. + if (!_secondTry) + { + _secondTry = true; + return GetAbsolute(url, authorization); + } + else throw; + } if (!activityResponse.IsSuccessStatusCode) { @@ -319,7 +342,7 @@ protected string DeleteAbsolute(string url) protected string jiveDateFormat(DateTime time) { - return time.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fff") + "%2B0000"; + return time.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fff") + "Z"; } } } diff --git a/Net.Pokeshot.JiveSdk/Clients/PeopleClient.cs b/Net.Pokeshot.JiveSdk/Clients/PeopleClient.cs index 92754f5..ecaecf3 100644 --- a/Net.Pokeshot.JiveSdk/Clients/PeopleClient.cs +++ b/Net.Pokeshot.JiveSdk/Clients/PeopleClient.cs @@ -1,8 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Net; using Net.Pokeshot.JiveSdk.Models; using System.Web; @@ -100,7 +97,7 @@ public Person FindPersonByEmail(string email) { try { - person = GetPersonByUsername("anonymous@test.com"); + person = GetPersonByEmail("anonymous@test.com"); } catch (HttpException) { @@ -1665,7 +1662,7 @@ public Person GetPersonByEmail(string email, List fields = null) } catch (HttpException e) { - Console.WriteLine(e.Message); + //Console.WriteLine(e.Message); switch (e.GetHttpCode()) { case 400: @@ -1797,7 +1794,84 @@ public List GetStreams(int personID, List fields = null) //GetReports() //GetResources() //GetRoles() - //GetSecurityGroups() + + /// + /// Return a list of SecurityGroups that the specified user is a member of. Note that this list will NOT include any security groups that this person is an administrator of. Because the number of security groups will generally be very small, pagination is not supported. + /// + /// ID of the user for whom to return security groups + /// Fields to be returned + /// + public List GetSecurityGroups(int personID, List fields = null) + { + string url = peopleUrl + "/" + personID + "/securityGroups"; + if (fields != null && fields.Count > 0) + { + url += "?fields="; + foreach (var field in fields) + { + url += field + ","; + } + // remove last comma + url = url.Remove(url.Length - 1); + } + string json; + try + { + json = GetAbsolute(url); + } + catch (HttpException e) + { + Console.WriteLine(e.Message); + switch (e.GetHttpCode()) + { + case 403: + throw new HttpException(e.WebEventCode, "Requester is not allowed to view security groups for the owning user", e); + case 404: + throw new HttpException(e.WebEventCode, "Specified user cannot be found", e); + default: + throw; + } + } + + JObject results = JObject.Parse(json); + + return results["list"].ToObject>(); + } + + /// + /// Update the specified user based on the contents of updatedPerson. Only modifiable fields that actually provide a value in the incoming entity are processed + /// + /// Updated person + /// Person object reflecting the processed changes + public Person Update(Person updatedPerson) + { + string url = peopleUrl + "/" + updatedPerson.id; + string json = JsonConvert.SerializeObject(updatedPerson, new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore, Formatting = Formatting.Indented }); + try + { + json = PutAbsolute(url, json); + } + catch (HttpException e) + { + Console.WriteLine(e.Message); + switch (e.GetHttpCode()) + { + case 400: + throw new HttpException(e.WebEventCode, "One or more of the input fields is malformed", e); + case 403: + throw new HttpException(e.WebEventCode, "Requesting user is not authorized to make changes to the specified user", e); + case 404: + throw new HttpException(e.WebEventCode, "Specified user does not exist", e); + case 409: + throw new HttpException(e.WebEventCode, "Requested change would cause business rules to be violated (such as more than one user with the same email address)", e); + default: + throw; + } + } + + return JObject.Parse(json).ToObject(); + } + //GetSocialUsers() //GetSupportedFields() //GetTagsUserTaggedOnUser() diff --git a/Net.Pokeshot.JiveSdk/Clients/PlacesClient.cs b/Net.Pokeshot.JiveSdk/Clients/PlacesClient.cs index 7e5be73..e2671ce 100644 --- a/Net.Pokeshot.JiveSdk/Clients/PlacesClient.cs +++ b/Net.Pokeshot.JiveSdk/Clients/PlacesClient.cs @@ -125,7 +125,7 @@ public GenericContent CreateContent(int placeID, GenericContent content, DateTim case 403: throw new HttpException(e.WebEventCode, "You are not allowed to access the specified content or place", e); case 409: - throw new HttpException(e.WebEventCode, "The new entity would conflict with system restrictions (such as two contents of the same type with the same name", e); + throw new HttpException(e.WebEventCode, "The new entity would conflict with system restrictions (such as two contents of the same type with the same name) or would post content more than once every 90 seconds", e); default: throw; } diff --git a/Net.Pokeshot.JiveSdk/Clients/RsvpClient.cs b/Net.Pokeshot.JiveSdk/Clients/RsvpClient.cs index 5ddaf1f..218e9ea 100644 --- a/Net.Pokeshot.JiveSdk/Clients/RsvpClient.cs +++ b/Net.Pokeshot.JiveSdk/Clients/RsvpClient.cs @@ -4,11 +4,49 @@ using System.Text; using System.Threading.Tasks; using System.Net; +using Net.Pokeshot.JiveSdk.Models; +using System.Web; namespace Net.Pokeshot.JiveSdk.Clients { - class RsvpClient : JiveClient + public class RsvpClient : JiveClient { + string rsvpUrl { get { return JiveCommunityUrl + "/api/core/ext/event-type-plugin/v3/rsvp"; } } + public RsvpClient(string communityUrl, NetworkCredential credentials) : base(communityUrl, credentials) { } + + public string Create(int contentID, Person person, RsvpResponse response) + { + string json = "" + (int) response; + string url = rsvpUrl + "/" + contentID.ToString(); + string result; + + try + { + result = RunAs(person.id, () => PostAbsolute(url, json)); + } + catch (HttpException e) + { + switch (e.GetHttpCode()) + { + case 400: + throw new HttpException(e.WebEventCode, "An input field is missing or malformed", e); + case 403: + throw new HttpException(e.WebEventCode, "You are not allowed to perform this operation", e); + case 404: + throw new HttpException(e.WebEventCode, "The specified parent content object (or comment) cannot be found", e); + default: + throw; + } + } + return result; + } + } + + public enum RsvpResponse + { + Yes = 1, + No = 2, + Maybe = 3 } } diff --git a/Net.Pokeshot.JiveSdk/Clients/SearchClient.cs b/Net.Pokeshot.JiveSdk/Clients/SearchClient.cs index 7638cfb..ed99d20 100644 --- a/Net.Pokeshot.JiveSdk/Clients/SearchClient.cs +++ b/Net.Pokeshot.JiveSdk/Clients/SearchClient.cs @@ -4,11 +4,80 @@ using System.Text; using System.Threading.Tasks; using System.Net; +using Net.Pokeshot.JiveSdk.Models; +using System.Web; +using Newtonsoft.Json.Linq; namespace Net.Pokeshot.JiveSdk.Clients { - class SearchClient : JiveClient + public class SearchClient : JiveClient { + string searchUrl { get { return JiveCommunityUrl + "/api/core/v3/search"; } } public SearchClient(string communityUrl, NetworkCredential credentials) : base(communityUrl, credentials) { } + + + /// + /// Search for and return tags that match the specified filter criteria. When calling this endpoint, you must specify a search filter with at least one keyword. + /// + /// One or more search terms. You must escape any of the following special characters embedded in the search terms: comma (","), backslash ("\"), left parenthesis ("("), and right parenthesis (")") by preceding them with a backslash. Remember to URL encode any special character. + /// Maximum number of matches to return + /// Zero-relative index of the first matching result to return + /// Client that sent this search request + /// + public List GetTags(List search = null, int count = 25, int startIndex = 0, string origin = null) + { + List tagList = new List(); + + string searchString = ""; + if (search != null && search.Count > 0) + { + foreach (var item in search) + { + searchString += item + ","; + } + // remove last comma + searchString = searchString.Remove(searchString.Length - 1); + } + + string url = searchUrl + "/tags"; + url += "?filter=" + "search(" + searchString + ")"; + url += "&startIndex=" + startIndex.ToString(); + url += "&count=" + (count > 100 ? 100 : count).ToString(); + url += origin != null ? "&origin=" + origin : ""; + + while (true) + { + string json; + try + { + json = GetAbsolute(url); + } + catch (HttpException e) + { + Console.WriteLine(e.Message); + switch (e.GetHttpCode()) + { + case 400: + throw new HttpException(e.WebEventCode, "An input parameter is missing or malformed.", e); + case 403: + throw new HttpException(e.WebEventCode, "Requesting user is attempting to reference an object that they do not have access to.", e); + case 404: + throw new HttpException(e.WebEventCode, "Requesting user is attempting to reference an object that does not exist."); + default: + throw; + } + } + + JObject results = JObject.Parse(json); + + tagList.AddRange(results["list"].ToObject>()); + + if (results["links"] == null || results["links"]["next"] == null) + break; + else + url = results["links"]["next"].ToString(); + } + return tagList; + } } } diff --git a/Net.Pokeshot.JiveSdk/Clients/SecurityGroupsClient.cs b/Net.Pokeshot.JiveSdk/Clients/SecurityGroupsClient.cs index 8f5efba..43eb7be 100644 --- a/Net.Pokeshot.JiveSdk/Clients/SecurityGroupsClient.cs +++ b/Net.Pokeshot.JiveSdk/Clients/SecurityGroupsClient.cs @@ -4,11 +4,142 @@ using System.Text; using System.Threading.Tasks; using System.Net; +using Net.Pokeshot.JiveSdk.Models; +using System.Web; +using Newtonsoft.Json.Linq; namespace Net.Pokeshot.JiveSdk.Clients { - class SecurityGroupsClient : JiveClient + public class SecurityGroupsClient : JiveClient { + string securityGroupsUrl { get { return JiveCommunityUrl + "/api/core/v3/securityGroups"; } } + public SecurityGroupsClient(string communityUrl, NetworkCredential credentials) : base(communityUrl, credentials) { } + + + /// + /// Return the specified fields in a paginated list of security groups that match the specified selection criteria (or all security groups if no criteria are specified). + /// This service supports the following filters.Parameters, when used, should be wrapped in parentheses, and multiple values separated by commas. See the examples for clarification. + /// + /// One or two DateTimes. If one timestamp is specified, all security groups updated since that timestamp will be selected. If two timestamps are specified, all security groups updated in the specified range will be selected. + /// Maximum number of security groups to be returned (default value is 25) + /// Zero-relative index of the first matching security group to be returned (default value is 0) + /// Fields to be returned for each security group (default value is @standard) + /// Optional sort to apply to the search results. Since 3.6. + /// + public List GetSecurityGroups(Tuple updated, int count = 25, int startIndex = 0, List fields = null, string sort = "nameAsc") + { + List securityGroupsList = new List(); + + List filter = new List(); + + if (updated != null) + { + string dateString = "updated("; + dateString += jiveDateFormat(updated.Item1); + dateString += (updated.Item2 != null ? ("," + jiveDateFormat(updated.Item2.Value)) : "") + ")"; + filter.Add(dateString); + } + + string url = securityGroupsUrl; + url += "?sort=" + sort; + url += "&startIndex=" + startIndex.ToString(); + url += "&count=" + (count > 100 ? 100 : count).ToString(); + if (fields != null && fields.Count > 0) + { + url += "&fields="; + foreach (var field in fields) + { + url += field + ","; + } + // remove last comma + url = url.Remove(url.Length - 1); + } + + while (true) + { + string json; + try + { + json = GetAbsolute(url); + } + catch (HttpException e) + { + Console.WriteLine(e.Message); + switch (e.GetHttpCode()) + { + case 400: + throw new HttpException(e.WebEventCode, "Any of the input fields are malformed", e); + case 403: + throw new HttpException(e.WebEventCode, "The requesting user is not authorized to retrieve security groups", e); + default: + throw; + } + } + + JObject results = JObject.Parse(json); + + securityGroupsList.AddRange(results["list"].ToObject>()); + + if (results["links"] == null || results["links"]["next"] == null) + break; + else + url = results["links"]["next"].ToString(); + } + return securityGroupsList; + } + + public List GetMembers(int securityGroupID, int startIndex = 0, int count = 25, List fields = null) + { + List memberList = new List(); + + string url = securityGroupsUrl + "/" + securityGroupID + "/members"; + url += "?startIndex=" + startIndex.ToString(); + url += "&count=" + (count > 100 ? 100 : count).ToString(); + if (fields != null && fields.Count > 0) + { + url += "&fields="; + foreach (var field in fields) + { + url += field + ","; + } + // remove last comma + url = url.Remove(url.Length - 1); + } + + while (true) + { + string json; + try + { + json = GetAbsolute(url); + } + catch (HttpException e) + { + Console.WriteLine(e.Message); + switch (e.GetHttpCode()) + { + case 400: + throw new HttpException(e.WebEventCode, "An input field is missing or malformed", e); + case 403: + throw new HttpException(e.WebEventCode, "The requesting user is not authorized to retrieve security groups information", e); + case 404: + throw new HttpException(e.WebEventCode, "The specified security group does not exist", e); + default: + throw; + } + } + + JObject results = JObject.Parse(json); + + memberList.AddRange(results["list"].ToObject>()); + + if (results["links"] == null || results["links"]["next"] == null) + break; + else + url = results["links"]["next"].ToString(); + } + return memberList; + } } } diff --git a/Net.Pokeshot.JiveSdk/Models/Content.cs b/Net.Pokeshot.JiveSdk/Models/Content.cs index a6ba83a..c6f4e2d 100644 --- a/Net.Pokeshot.JiveSdk/Models/Content.cs +++ b/Net.Pokeshot.JiveSdk/Models/Content.cs @@ -1,8 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Net.Pokeshot.JiveSdk.Models { diff --git a/Net.Pokeshot.JiveSdk/Models/ContentTag.cs b/Net.Pokeshot.JiveSdk/Models/ContentTag.cs new file mode 100644 index 0000000..b80e278 --- /dev/null +++ b/Net.Pokeshot.JiveSdk/Models/ContentTag.cs @@ -0,0 +1,12 @@ +namespace Net.Pokeshot.JiveSdk.Models +{ + public class ContentTag + { + public string id { get; set; } + public string index { get; set; } + public string name { get; set; } + public Resources.Resources resources { get; set; } + public string type { get; set; } + public string uuid { get; set; } + } +} diff --git a/Net.Pokeshot.JiveSdk/Models/Dto/JiveDEAActivityInstance.cs b/Net.Pokeshot.JiveSdk/Models/Dto/JiveDEAActivityInstance.cs index 02b0e94..ea75c9b 100644 --- a/Net.Pokeshot.JiveSdk/Models/Dto/JiveDEAActivityInstance.cs +++ b/Net.Pokeshot.JiveSdk/Models/Dto/JiveDEAActivityInstance.cs @@ -13,14 +13,14 @@ public class JiveDEAActivityInstance public string uuid { get; set; } public JiveDEAContext context { get; set; } public long actorID { get; set; } - public int actorType { get; set; } + public ObjectType actorType { get; set; } public string activityType { get; set; } public int actionObjectId { get; set; } - public int actionObjectType { get; set; } + public ObjectType actionObjectType { get; set; } public JiveDEAActivityInstanceElement activity { get; set; } public bool isHistoricalReplay { get; set; } public int containerId { get; set; } - public int containerType { get; set; } + public ObjectType containerType { get; set; } public object payload { get; set; } } } diff --git a/Net.Pokeshot.JiveSdk/Models/Dto/ObjectType.cs b/Net.Pokeshot.JiveSdk/Models/Dto/ObjectType.cs new file mode 100644 index 0000000..e3f4eb2 --- /dev/null +++ b/Net.Pokeshot.JiveSdk/Models/Dto/ObjectType.cs @@ -0,0 +1,375 @@ +using System.Collections; +using System.Linq; + +namespace Net.Pokeshot.JiveSdk.Models.Dto +{ + public static class ObjectTypeExtensions + { + private readonly static ObjectType[] _contentTypes = {ObjectType.THREAD, ObjectType.DOCUMENT, ObjectType.QUESTION, ObjectType.POLL, ObjectType.TASK, + ObjectType.FAVORITE, ObjectType.VIDEO, ObjectType.IDEA, ObjectType.DIRECTMESSAGE, ObjectType.BLOGPOST, ObjectType.EVENT, ObjectType.WALLENTRY}; + private readonly static ObjectType[] _placeTypes = { ObjectType.COMMUNITY, ObjectType.BLOG, ObjectType.PROJECT, ObjectType.SOCIAL_GROUP}; + private readonly static ObjectType[] _personTypes = { ObjectType.USER }; + + public static bool IsContent(this ObjectType type) + { + return _contentTypes.Contains(type); + } + + public static bool IsPerson(this ObjectType type) + { + return _personTypes.Contains(type); + } + + public static bool IsPlace(this ObjectType type) + { + return _placeTypes.Contains(type); + } + + /// + /// Returns the name the type is known as in the Jive API. + /// + /// + /// + public static string GetAlias(this ObjectType type) + { + switch (type) + { + case ObjectType.THREAD: + return "discussion"; + case ObjectType.MESSAGE: + return "message"; + case ObjectType.USER: + return "person"; + case ObjectType.GROUP: + goto default; + case ObjectType.THREAD_NAME: + goto default; + case ObjectType.MESSAGE_SUBJECT: + goto default; + case ObjectType.MESSAGE_BODY: + goto default; + case ObjectType.CREATION_DATE: + goto default; + case ObjectType.MODIFICATION_DATE: + goto default; + case ObjectType.EXTENDED_PROPERTY: + goto default; + case ObjectType.ANONYMOUS: + goto default; + case ObjectType.REGISTERED_USERS: + goto default; + case ObjectType.ATTACHMENT: + goto default; + case ObjectType.COMMUNITY: + return "space"; + case ObjectType.COMMUNITY_NAME: + goto default; + case ObjectType.SYSTEM: + goto default; + case ObjectType.POLL: + return "poll"; + case ObjectType.COMMUNITY_SEARCH_QUERY: + goto default; + case ObjectType.PRIVATE_MESSAGE: + goto default; + case ObjectType.PRIVATE_MESSAGE_FOLDER: + goto default; + case ObjectType.ANNOUNCEMENT: + goto default; + case ObjectType.SEARCH: + goto default; + case ObjectType.CRONTASK: + goto default; + case ObjectType.STATUS_LEVEL: + goto default; + case ObjectType.AVATAR: + goto default; + case ObjectType.QUESTION: + goto default; + case ObjectType.COMMUNITY_QUESTION: + goto default; + case ObjectType.SYSTEM_QUESTION: + goto default; + case ObjectType.GATEWAY: + goto default; + case ObjectType.BAN: + goto default; + case ObjectType.ABUSE: + goto default; + case ObjectType.WATCH_SETTINGS: + goto default; + case ObjectType.DRAFT: + goto default; + case ObjectType.BLOG: + return "blog"; + case ObjectType.BLOGPOST: + return "post"; + case ObjectType.TRACKBACK: + goto default; + case ObjectType.TAG: + goto default; + case ObjectType.TAG_SET: + goto default; + case ObjectType.CONTENT_OBJECT: + goto default; + case ObjectType.STATUS_LEVEL_POINT: + goto default; + case ObjectType.STATUS_LEVEL_SCENARIO: + goto default; + case ObjectType.WATCHABLE_OBJECT: + goto default; + case ObjectType.SEARCH_ENGINE: + goto default; + case ObjectType.USER_STATUS: + goto default; + case ObjectType.USER_RELATIONSHIP: + goto default; + case ObjectType.USER_RELATIONSHIP_GRAPH: + goto default; + case ObjectType.PROJECT_QUESTION: + goto default; + case ObjectType.SOCIAL_GROUP_QUESTION: + goto default; + case ObjectType.USER_RELATIONSHIP_LIST: + goto default; + case ObjectType.PLUGIN: + goto default; + case ObjectType.DOCUMENT: + return "document"; + case ObjectType.DOCUMENT_TITLE: + goto default; + case ObjectType.DOCUMENT_FIELD: + goto default; + case ObjectType.COMMENT: + goto default; + case ObjectType.EXPIRATION_DATE: + goto default; + case ObjectType.RATING: + goto default; + case ObjectType.DOCUMENT_TYPE: + goto default; + case ObjectType.SEARCH_QUERY: + goto default; + case ObjectType.DOCUMENT_BODY: + goto default; + case ObjectType.IMAGE: + goto default; + case ObjectType.DOCUMENT_PRESENTER: + goto default; + case ObjectType.DOCUMENT_STATE: + goto default; + case ObjectType.DOCUMENT_FIELD_OPTION: + goto default; + case ObjectType.DOCUMENT_VERSION: + goto default; + case ObjectType.DOCUMENT_VERSION_COMMENT: + goto default; + case ObjectType.DOCUMENT_FIELD_TYPE: + goto default; + case ObjectType.DOCUMENT_ID: + goto default; + case ObjectType.DOCUMENT_TYPE_ELEMENT: + goto default; + case ObjectType.TEMPORARY_DOCUMENT_ID: + goto default; + case ObjectType.DOCUMENT_BACKCHANNEL: + goto default; + case ObjectType.READ_STAT_SESSION: + goto default; + case ObjectType.READ_STAT: + goto default; + case ObjectType.WORKGROUP_AGENT: + goto default; + case ObjectType.WORKGROUP_QUEUE: + goto default; + case ObjectType.WORKGROUP_GROUP: + goto default; + case ObjectType.ACTIVITY: + goto default; + case ObjectType.POPULARITY: + goto default; + case ObjectType.IMPORT: + goto default; + case ObjectType.I18N_TEXT: + goto default; + case ObjectType.WIDGET: + goto default; + case ObjectType.WIDGET_FRAME: + goto default; + case ObjectType.WIDGET_LAYOUT: + goto default; + case ObjectType.INVITATION: + goto default; + case ObjectType.ENTITLEMENT: + goto default; + case ObjectType.ROSTER: + goto default; + case ObjectType.OFFLINE: + goto default; + case ObjectType.PROFILE_FIELD: + goto default; + case ObjectType.PROJECT: + return "project"; + case ObjectType.CHECKPOINT: + goto default; + case ObjectType.TASK: + goto default; + case ObjectType.DUE_DATE: + goto default; + case ObjectType.PROJECT_STATUS: + goto default; + case ObjectType.SOCIAL_GROUP: + return "group"; + case ObjectType.SOCIAL_GROUP_MEMBER: + goto default; + case ObjectType.FAVORITE: + goto default; + case ObjectType.EXTERNAL_URL: + goto default; + case ObjectType.LABEL: + goto default; + case ObjectType.BRIDGE: + goto default; + case ObjectType.VIDEO: + return "video"; + case ObjectType.VIDEO_WATERMARK: + goto default; + case ObjectType.OSWORKFLOW_ENTRY: + goto default; + case ObjectType.OSWORKFLOW_STEP: + goto default; + case ObjectType.AUDIT_MESSAGE: + goto default; + case ObjectType.REFERENCE: + goto default; + case ObjectType.SYSTEM_CONTAINER: + goto default; + case ObjectType.USER_CONTAINER: + goto default; + case ObjectType.IDEA: + return "idea"; + case ObjectType.DIRECTMESSAGE: + return "dm"; + case ObjectType.EVENT: + return "event"; + case ObjectType.WALLENTRY: + return "update"; + default: + return type.ToString().ToLower(); + } + } + } + public enum ObjectType + { + THREAD = 1, + MESSAGE, + USER, + GROUP, + THREAD_NAME, + MESSAGE_SUBJECT, + MESSAGE_BODY, + CREATION_DATE, + MODIFICATION_DATE, + EXTENDED_PROPERTY, + ANONYMOUS, + REGISTERED_USERS, + ATTACHMENT, + COMMUNITY, + COMMUNITY_NAME = 16, + SYSTEM, + POLL, + COMMUNITY_SEARCH_QUERY, + PRIVATE_MESSAGE, + PRIVATE_MESSAGE_FOLDER, + ANNOUNCEMENT, + SEARCH, + CRONTASK, + STATUS_LEVEL, + AVATAR, + QUESTION, + COMMUNITY_QUESTION = 29, + SYSTEM_QUESTION, + GATEWAY, + BAN, + ABUSE, + WATCH_SETTINGS = 35, + DRAFT, + BLOG, + BLOGPOST, + TRACKBACK = 40, + TAG, + TAG_SET, + CONTENT_OBJECT, + STATUS_LEVEL_POINT, + STATUS_LEVEL_SCENARIO, + WATCHABLE_OBJECT, + SEARCH_ENGINE, + USER_STATUS, + USER_RELATIONSHIP, + USER_RELATIONSHIP_GRAPH, + PROJECT_QUESTION, + SOCIAL_GROUP_QUESTION, + USER_RELATIONSHIP_LIST, + PLUGIN = 69, + DOCUMENT = 102, + DOCUMENT_TITLE, + DOCUMENT_FIELD, + COMMENT, + EXPIRATION_DATE, + RATING, + DOCUMENT_TYPE, + SEARCH_QUERY, + DOCUMENT_BODY, + IMAGE, + DOCUMENT_PRESENTER = 117, + DOCUMENT_STATE, + DOCUMENT_FIELD_OPTION, + DOCUMENT_VERSION, + DOCUMENT_VERSION_COMMENT, + DOCUMENT_FIELD_TYPE = 123, + DOCUMENT_ID, + DOCUMENT_TYPE_ELEMENT, + TEMPORARY_DOCUMENT_ID = 127, + DOCUMENT_BACKCHANNEL = 129, + READ_STAT_SESSION = 201, + READ_STAT, + WORKGROUP_AGENT = 300, + WORKGROUP_QUEUE, + WORKGROUP_GROUP, + ACTIVITY = 310, + POPULARITY, + IMPORT = 320, + I18N_TEXT = 330, + WIDGET = 340, + WIDGET_FRAME, + WIDGET_LAYOUT, + INVITATION = 350, + ENTITLEMENT = 360, + ROSTER = 400, + OFFLINE, + PROFILE_FIELD = 500, + PROJECT = 600, + CHECKPOINT, + TASK, + DUE_DATE, + PROJECT_STATUS, + SOCIAL_GROUP = 700, + SOCIAL_GROUP_MEMBER, + FAVORITE = 800, + EXTERNAL_URL, + LABEL = 900, + BRIDGE = 1000, + VIDEO = 1100, + VIDEO_WATERMARK, + OSWORKFLOW_ENTRY = 2001, + OSWORKFLOW_STEP, + AUDIT_MESSAGE, + REFERENCE = 2010, + SYSTEM_CONTAINER = -2, + USER_CONTAINER = 2020, + IDEA = 3227383, + DIRECTMESSAGE = 109016030, + EVENT = 96891546, + WALLENTRY = 1464927464 + } +} diff --git a/Net.Pokeshot.JiveSdk/Models/GenericContent.cs b/Net.Pokeshot.JiveSdk/Models/GenericContent.cs index 1b31af0..b819c11 100644 --- a/Net.Pokeshot.JiveSdk/Models/GenericContent.cs +++ b/Net.Pokeshot.JiveSdk/Models/GenericContent.cs @@ -11,6 +11,7 @@ namespace Net.Pokeshot.JiveSdk.Models /// public class GenericContent : Content { + public string status { get; set; } // Specific to Discussions public string answer { get; set; } public List helpful { get; set; } diff --git a/Net.Pokeshot.JiveSdk/Models/SecurityGroup.cs b/Net.Pokeshot.JiveSdk/Models/SecurityGroup.cs new file mode 100644 index 0000000..4c1b0c0 --- /dev/null +++ b/Net.Pokeshot.JiveSdk/Models/SecurityGroup.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; + +namespace Net.Pokeshot.JiveSdk.Models +{ + public class SecurityGroup + { + public int administratorCount { get; set; } + public string description { get; set; } + public bool federated { get; set; } + public string id { get; set; } + public int memberCount { get; set; } + public string name { get; set; } + public object properties { get; set; } + public DateTime published { get; set; } + public Resources.Resources resources { get; set; } + public List tags { get; set; } + public string type { get; set; } + public DateTime updated { get; set; } + } +} diff --git a/Net.Pokeshot.JiveSdk/Net.Pokeshot.JiveSdk.csproj b/Net.Pokeshot.JiveSdk/Net.Pokeshot.JiveSdk.csproj index b40aafc..4044c54 100644 --- a/Net.Pokeshot.JiveSdk/Net.Pokeshot.JiveSdk.csproj +++ b/Net.Pokeshot.JiveSdk/Net.Pokeshot.JiveSdk.csproj @@ -138,6 +138,7 @@ + @@ -149,6 +150,7 @@ + @@ -273,6 +275,7 @@ +