From c7b305ee2e24d1b38b17b720a4c9144c080b192d Mon Sep 17 00:00:00 2001 From: LukePulverenti Luke Pulverenti luke pulverenti Date: Fri, 7 Sep 2012 21:33:49 -0400 Subject: [PATCH] Added a user api handler, and improved portable ApiClient --- .../{DefaultUserHandler.cs => UserHandler.cs} | 6 +- MediaBrowser.Api/MediaBrowser.Api.csproj | 2 +- MediaBrowser.Api/Plugin.cs | 4 +- .../ApiClient.cs | 424 +++++++++++++++++- MediaBrowser.ApiInteraction/ApiClient.cs | 17 +- .../Net/Handlers/BaseHandler.cs | 2 +- MediaBrowser.Controller/Kernel.cs | 2 +- 7 files changed, 446 insertions(+), 11 deletions(-) rename MediaBrowser.Api/HttpHandlers/{DefaultUserHandler.cs => UserHandler.cs} (61%) diff --git a/MediaBrowser.Api/HttpHandlers/DefaultUserHandler.cs b/MediaBrowser.Api/HttpHandlers/UserHandler.cs similarity index 61% rename from MediaBrowser.Api/HttpHandlers/DefaultUserHandler.cs rename to MediaBrowser.Api/HttpHandlers/UserHandler.cs index 56a05dab84..706908da2f 100644 --- a/MediaBrowser.Api/HttpHandlers/DefaultUserHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/UserHandler.cs @@ -5,11 +5,13 @@ using System.Threading.Tasks; namespace MediaBrowser.Api.HttpHandlers { - class DefaultUserHandler : BaseSerializationHandler + class UserHandler : BaseSerializationHandler { protected override Task GetObjectToSerialize() { - User user = ApiService.GetDefaultUser(false); + string id = QueryString["id"]; + + User user = string.IsNullOrEmpty(id) ? ApiService.GetDefaultUser(false) : ApiService.GetUserById(id, false); ; DTOUser dto = ApiService.GetDTOUser(user); diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index 7b17606a8b..4016a88a34 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -60,7 +60,7 @@ - + diff --git a/MediaBrowser.Api/Plugin.cs b/MediaBrowser.Api/Plugin.cs index 24038767ec..202c5346e7 100644 --- a/MediaBrowser.Api/Plugin.cs +++ b/MediaBrowser.Api/Plugin.cs @@ -109,9 +109,9 @@ namespace MediaBrowser.Api { return new ServerConfigurationHandler(); } - else if (IsUrlMatch("/api/defaultuser", localPath)) + else if (IsUrlMatch("/api/user", localPath)) { - return new DefaultUserHandler(); + return new UserHandler(); } else if (IsUrlMatch("/api/pluginassembly", localPath)) { diff --git a/MediaBrowser.ApiInteraction.Portable/ApiClient.cs b/MediaBrowser.ApiInteraction.Portable/ApiClient.cs index 6cfa5ade55..c870b1c3ee 100644 --- a/MediaBrowser.ApiInteraction.Portable/ApiClient.cs +++ b/MediaBrowser.ApiInteraction.Portable/ApiClient.cs @@ -1,7 +1,13 @@ -using MediaBrowser.Model.DTO; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.DTO; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Weather; using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net; +using System.Text; namespace MediaBrowser.ApiInteraction.Portable { @@ -12,6 +18,47 @@ namespace MediaBrowser.ApiInteraction.Portable return HttpWebRequest.CreateHttp(url); } + /// + /// Gets an image stream based on a url + /// + public void GetImageStreamAsync(string url, Action callback) + { + GetStreamAsync(url, callback); + } + + /// + /// Gets an image stream based on a url + /// + private void GetStreamAsync(string url, Action callback) + { + HttpWebRequest request = GetNewRequest(url); + + request.BeginGetResponse(new AsyncCallback(result => + { + using (WebResponse response = (result.AsyncState as HttpWebRequest).EndGetResponse(result)) + { + Stream stream = response.GetResponseStream(); + callback(stream); + } + + }), request); + } + + /// + /// Gets a BaseItem + /// + public void GetItemAsync(Guid id, Guid userId, Action callback) + { + string url = ApiUrl + "/item?userId=" + userId.ToString(); + + if (id != Guid.Empty) + { + url += "&id=" + id.ToString(); + } + + GetDataAsync(url, callback); + } + /// /// Gets all users /// @@ -19,14 +66,298 @@ namespace MediaBrowser.ApiInteraction.Portable { string url = ApiUrl + "/users"; - GetDataAsync(url, callback); + GetDataAsync(url, callback); } + /// + /// Gets all Genres + /// + public void GetAllGenresAsync(Guid userId, Action callback) + { + string url = ApiUrl + "/genres?userId=" + userId.ToString(); + + GetDataAsync(url, callback); + } + + /// + /// Gets in-progress items + /// + /// The user id. + /// (Optional) Specify a folder Id to localize the search to a specific folder. + public void GetInProgressItemsItemsAsync(Guid userId, Action callback, Guid? folderId = null) + { + string url = ApiUrl + "/itemlist?listtype=inprogressitems&userId=" + userId.ToString(); + + if (folderId.HasValue) + { + url += "&id=" + folderId.ToString(); + } + + GetDataAsync(url, callback); + } + + /// + /// Gets recently added items + /// + /// The user id. + /// (Optional) Specify a folder Id to localize the search to a specific folder. + public void GetRecentlyAddedItemsAsync(Guid userId, Action callback, Guid? folderId = null) + { + string url = ApiUrl + "/itemlist?listtype=recentlyaddeditems&userId=" + userId.ToString(); + + if (folderId.HasValue) + { + url += "&id=" + folderId.ToString(); + } + + GetDataAsync(url, callback); + } + + /// + /// Gets recently added items that are unplayed. + /// + /// The user id. + /// (Optional) Specify a folder Id to localize the search to a specific folder. + public void GetRecentlyAddedUnplayedItemsAsync(Guid userId, Action callback, Guid? folderId = null) + { + string url = ApiUrl + "/itemlist?listtype=recentlyaddedunplayeditems&userId=" + userId.ToString(); + + if (folderId.HasValue) + { + url += "&id=" + folderId.ToString(); + } + + GetDataAsync(url, callback); + } + + /// + /// Gets all Years + /// + public void GetAllYearsAsync(Guid userId, Action callback) + { + string url = ApiUrl + "/years?userId=" + userId.ToString(); + + GetDataAsync(url, callback); + } + + /// + /// Gets all items that contain a given Year + /// + public void GetItemsWithYearAsync(string name, Guid userId, Action callback) + { + string url = ApiUrl + "/itemlist?listtype=itemswithyear&userId=" + userId.ToString() + "&name=" + name; + + GetDataAsync(url, callback); + } + + /// + /// Gets all items that contain a given Genre + /// + public void GetItemsWithGenreAsync(string name, Guid userId, Action callback) + { + string url = ApiUrl + "/itemlist?listtype=itemswithgenre&userId=" + userId.ToString() + "&name=" + name; + + GetDataAsync(url, callback); + } + + /// + /// Gets all items that contain a given Person + /// + public void GetItemsWithPersonAsync(string name, Guid userId, Action callback) + { + string url = ApiUrl + "/itemlist?listtype=itemswithperson&userId=" + userId.ToString() + "&name=" + name; + + GetDataAsync(url, callback); + } + + /// + /// Gets all items that contain a given Person + /// + public void GetItemsWithPersonAsync(string name, string personType, Guid userId, Action callback) + { + string url = ApiUrl + "/itemlist?listtype=itemswithperson&userId=" + userId.ToString() + "&name=" + name; + + url += "&persontype=" + personType; + + GetDataAsync(url, callback); + } + + /// + /// Gets all studious + /// + public void GetAllStudiosAsync(Guid userId, Action callback) + { + string url = ApiUrl + "/studios?userId=" + userId.ToString(); + + GetDataAsync(url, callback); + } + + /// + /// Gets all items that contain a given Studio + /// + public void GetItemsWithStudioAsync(string name, Guid userId, Action callback) + { + string url = ApiUrl + "/itemlist?listtype=itemswithstudio&userId=" + userId.ToString() + "&name=" + name; + + GetDataAsync(url, callback); + } + + /// + /// Gets a studio + /// + public void GetStudioAsync(Guid userId, string name, Action callback) + { + string url = ApiUrl + "/studio?userId=" + userId.ToString() + "&name=" + name; + + GetDataAsync(url, callback); + } + + /// + /// Gets a genre + /// + public void GetGenreAsync(Guid userId, string name, Action callback) + { + string url = ApiUrl + "/genre?userId=" + userId.ToString() + "&name=" + name; + + GetDataAsync(url, callback); + } + + /// + /// Gets a person + /// + public void GetPersonAsync(Guid userId, string name, Action callback) + { + string url = ApiUrl + "/person?userId=" + userId.ToString() + "&name=" + name; + + GetDataAsync(url, callback); + } + + /// + /// Gets a year + /// + public void GetYearAsync(Guid userId, int year, Action callback) + { + string url = ApiUrl + "/year?userId=" + userId.ToString() + "&year=" + year; + + GetDataAsync(url, callback); + } + + /// + /// Gets a list of plugins installed on the server + /// + public void GetInstalledPluginsAsync(Action callback) + { + string url = ApiUrl + "/plugins"; + + GetDataAsync(url, callback); + } + + /// + /// Gets a list of plugins installed on the server + /// + public void GetPluginAssemblyAsync(PluginInfo plugin, Action callback) + { + string url = ApiUrl + "/pluginassembly?assemblyfilename=" + plugin.AssemblyFileName; + + GetStreamAsync(url, callback); + } + + /// + /// Gets the current server configuration + /// + public void GetServerConfigurationAsync(Action callback) + { + string url = ApiUrl + "/ServerConfiguration"; + + // At the moment this can't be retrieved in protobuf format + SerializationFormats format = DataSerializer.CanDeSerializeJsv ? SerializationFormats.Jsv : SerializationFormats.Json; + + GetDataAsync(url, callback, format); + } + + /// + /// Gets weather information for the default location as set in configuration + /// + public void GetPluginConfigurationAsync(PluginInfo plugin, Type configurationType, Action callback) + { + string url = ApiUrl + "/PluginConfiguration?assemblyfilename=" + plugin.AssemblyFileName; + + // At the moment this can't be retrieved in protobuf format + SerializationFormats format = DataSerializer.CanDeSerializeJsv ? SerializationFormats.Jsv : SerializationFormats.Json; + + GetDataAsync(url, callback, configurationType, format); + } + + /// + /// Gets the default user + /// + public void GetDefaultUserAsync(Action callback) + { + string url = ApiUrl + "/user"; + + GetDataAsync(url, callback); + } + + /// + /// Gets a user by id + /// + public void GetUserAsync(Guid id, Action callback) + { + string url = ApiUrl + "/user?id=" + id.ToString(); + + GetDataAsync(url, callback); + } + + /// + /// Gets weather information for the default location as set in configuration + /// + public void GetWeatherInfoAsync(Action callback) + { + string url = ApiUrl + "/weather"; + + GetDataAsync(url, callback); + } + + /// + /// Gets weather information for a specific zip code + /// + public void GetWeatherInfoAsync(string zipCode, Action callback) + { + string url = ApiUrl + "/weather?zipcode=" + zipCode; + + GetDataAsync(url, callback); + } + + /// + /// Authenticates a user and returns the result + /// + public void AuthenticateUserAsync(Guid userId, string password, Action callback) + { + string url = ApiUrl + "/UserAuthentication?dataformat=" + SerializationFormat.ToString(); + + Dictionary formValues = new Dictionary(); + + formValues["userid"] = userId.ToString(); + + if (!string.IsNullOrEmpty(password)) + { + formValues["password"] = password; + } + + PostDataAsync(url, formValues, callback, SerializationFormat); + } + + /// + /// Performs a GET request, and deserializes the response stream to an object of Type T + /// private void GetDataAsync(string url, Action callback) { GetDataAsync(url, callback, SerializationFormat); } + /// + /// Performs a GET request, and deserializes the response stream to an object of Type T + /// private void GetDataAsync(string url, Action callback, SerializationFormats serializationFormat) { if (url.IndexOf('?') == -1) @@ -56,5 +387,94 @@ namespace MediaBrowser.ApiInteraction.Portable }), request); } + + /// + /// Performs a GET request, and deserializes the response stream to an object of Type T + /// + private void GetDataAsync(string url, Action callback, Type type, SerializationFormats serializationFormat) + { + if (url.IndexOf('?') == -1) + { + url += "?dataformat=" + serializationFormat.ToString(); + } + else + { + url += "&dataformat=" + serializationFormat.ToString(); + } + + HttpWebRequest request = GetNewRequest(url); + + request.BeginGetResponse(new AsyncCallback(result => + { + object value; + + using (WebResponse response = (result.AsyncState as HttpWebRequest).EndGetResponse(result)) + { + using (Stream stream = response.GetResponseStream()) + { + value = DataSerializer.DeserializeFromStream(stream, serializationFormat, type); + } + } + + callback(value); + + }), request); + } + + /// + /// Performs a POST request, and deserializes the response stream to an object of Type T + /// + private void PostDataAsync(string url, Dictionary formValues, Action callback, SerializationFormats serializationFormat) + { + if (url.IndexOf('?') == -1) + { + url += "?dataformat=" + serializationFormat.ToString(); + } + else + { + url += "&dataformat=" + serializationFormat.ToString(); + } + + HttpWebRequest request = GetNewRequest(url); + + request.Method = "POST"; + request.ContentType = "application/x-www-form-urlencoded"; + + // Begin getting request stream + request.BeginGetRequestStream(new AsyncCallback(beginGetRequestStreamResult => + { + // Once we have the request stream, write the post data + using (Stream requestStream = request.EndGetRequestStream(beginGetRequestStreamResult)) + { + // Construct the body + string postBody = string.Join("&", formValues.Keys.Select(s => string.Format("{0}={1}", s, formValues[s])).ToArray()); + + // Convert the string into a byte array. + byte[] byteArray = Encoding.UTF8.GetBytes(postBody); + + // Write to the request stream. + requestStream.Write(byteArray, 0, byteArray.Length); + } + + // Begin getting response stream + request.BeginGetResponse(new AsyncCallback(result => + { + // Once we have it, deserialize the data and execute the callback + T value; + + using (WebResponse response = request.EndGetResponse(result)) + { + using (Stream responseStream = response.GetResponseStream()) + { + value = DeserializeFromStream(responseStream); + } + } + + callback(value); + + }), null); + + }), null); + } } } diff --git a/MediaBrowser.ApiInteraction/ApiClient.cs b/MediaBrowser.ApiInteraction/ApiClient.cs index f2fd903093..a621963ec9 100644 --- a/MediaBrowser.ApiInteraction/ApiClient.cs +++ b/MediaBrowser.ApiInteraction/ApiClient.cs @@ -336,11 +336,24 @@ namespace MediaBrowser.ApiInteraction } /// - /// Gets weather information for the default location as set in configuration + /// Gets the default user /// public async Task GetDefaultUserAsync() { - string url = ApiUrl + "/defaultuser"; + string url = ApiUrl + "/user"; + + using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false)) + { + return DeserializeFromStream(stream); + } + } + + /// + /// Gets a user by id + /// + public async Task GetUserAsync(Guid id) + { + string url = ApiUrl + "/user?id=" + id.ToString(); using (Stream stream = await GetSerializedStreamAsync(url).ConfigureAwait(false)) { diff --git a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs index 19674fadd8..0a0f040de7 100644 --- a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs +++ b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs @@ -407,7 +407,7 @@ namespace MediaBrowser.Common.Net.Handlers if (request.HasEntityBody) { - if (request.ContentType.Equals("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase)) + if (request.ContentType.IndexOf("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase) != -1) { using (Stream requestBody = request.InputStream) { diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs index f1d6d4d0fb..2414364c0b 100644 --- a/MediaBrowser.Controller/Kernel.cs +++ b/MediaBrowser.Controller/Kernel.cs @@ -217,7 +217,7 @@ namespace MediaBrowser.Controller } else { - result.Success = GetMD5((password ?? string.Empty)).Equals(user.Password); + result.Success = GetMD5((password ?? string.Empty)).ToString().Equals(user.Password); } // Update LastActivityDate and LastLoginDate, then save